python - 在不上采样 1 分钟的情况下合并 1 分钟、5 分钟和每日 OHLC 数据帧?
问题描述
为了简单起见,假设我有 3 个数据集,一个 1 分钟的 OHLCV 数据集,一个 5 分钟的数据集和一个 Daily。鉴于这 3 个数据集:
1分钟
5分钟
日常的
...我如何合并它们并使用 Pandas/Python 3 将它们变成这样的东西?
如您所见,每次在 1min 数据帧中击中新的 5 分钟时,来自 5min 图表的匹配时间 <= 1min 时间被添加到它们各自的列中。我在其中留下了空白以帮助可视化正在发生的事情,但为了简单起见,我可以向前填充这些值。没有回填,以免引入前瞻偏差。每日值将是前一天的 OHLCV 数据,下午 4:00 除外,这将是当天的数据。这是因为 Alpha Vantage 如何构建他们的数据帧。我还有一个 15 分钟和 60 分钟的数据集,但我认为一旦 1 到 5 分钟的合并完成,同样的逻辑可以适用。
我在下面包含了一个可重现的代码,以获取我正在使用的确切数据帧,但是您必须从这里pip install alpha_vantage
获取免费的 API 密钥。
简单的所需解决方案 - 我在上面概述的内容。
高级所需解决方案 - 理想情况下,这些空白区域将由各自的运行价格组成,而不是向前填充 5 分钟数据。例如,5min_open 列中的下一个空开盘价将与该 5 分钟开始时的 1min_open 相同。想一想:
conversion = {'Open' : 'first', 'High' : 'max', 'Low' : 'min', 'Close' : 'last', 'Volume' : 'sum'}
这样 5min 列中的空白将按应有的方式更新,但简单的解决方案就足够了。
我不想只对 1min 数据帧进行上采样,因为我想包含过去每日数据帧中的所有先前数据,所以要将 1min 上采样到每日数据集,我会丢失一堆过去的每日数据,所以我希望解决方案不包括上采样,而是按日期时间合并不同的df。谢谢!
Windows 10、Python 3:
from alpha_vantage.timeseries import TimeSeries
import pandas as pd
import sys, os
import os.path
from time import sleep
# Make a historical folder if it's not created already
if not os.path.exists("data/historical/"):
os.makedirs("data/historical/")
api_call_limit_daily = 500
total_api_count = 0
timeframes = ['1min','5min','15min','60min','daily']
ts = TimeSeries(key='YOUR_API_KEY_HERE', output_format='csv')
tickers = ['SPY']
for ticker in tickers:
# Ensure uppercase
ticker = str(ticker.upper())
for timeframe in timeframes:
print("Downloading dataset for", ticker, "-", timeframe, "...")
if total_api_count > api_call_limit_daily:
print("Daily API call limit reached. Closing...")
sys.exit(0)
if timeframe != 'daily':
data, meta_data = ts.get_intraday_extended(symbol=ticker, interval=timeframe)
elif timeframe == 'daily':
data, meta_data = ts.get_daily(symbol=ticker)
# Convert the data object to a dataframe, and reverse the order so oldest date's on top
csv_list = list(data)
data = pd.DataFrame.from_records(csv_list[1:], columns=csv_list[0])
data = data.iloc[::-1]
if timeframe == 'daily':
data = data.rename(columns={"timestamp": "time"})
print(data)
df = data.set_index('time')
total_api_count += 1
df.to_csv("data/historical/" + ticker + "_" + timeframe + ".csv", index=True)
print("Success...")
# Sleep if we're not through tickers/timeframes yet re: api limits
sleep(15)
print("Done!")
更新
对于适用于每个数据帧的简单解决方案,我有一个 frankenstein 的迭代过程,除了每天。仍在努力解决这个问题。基本上对于1分钟行的任何时间,我想显示YESTERDAY的每日数据,除非时间> = 16:00:00,否则它可以是当天的。我希望这样不要引入前向峰值。无论如何,这是完成我正在寻找的迭代的代码,但希望有一种更快/更清洁的方法来做到这一点:
import numpy as np
# Merge all timeframes together into one dataframe
for ticker in tickers:
# Ensure uppercase
ticker = str(ticker.upper())
for timeframe in timeframes:
# Define the 1min timeframe as the main df we'll add other columns to
if timeframe == "1min":
main_df = pd.read_csv("./data/historical/" + ticker + "_" + timeframe + ".csv")
main_df['time'] = pd.to_datetime(main_df['time'])
continue
# Now add in some nan's for the next timeframe's columns
main_df[timeframe + "_open"] = np.nan
main_df[timeframe + "_high"] = np.nan
main_df[timeframe + "_low"] = np.nan
main_df[timeframe + "_close"] = np.nan
main_df[timeframe + "_volume"] = np.nan
# read in the next timeframe's dataset
df = pd.read_csv("./data/historical/" + ticker + "_" + timeframe + ".csv")
df['time'] = pd.to_datetime(df['time'])
# Rather than doing a double for loop to iterate through both datasets, just keep a counter
# of what row we're at in the second dataframe. Used as a row locater
curr_df_row = 0
# Do this for all datasets except the daily one
if timeframe != 'daily':
# Iterate through the main_df
for i in range(len(main_df)):
# If the time in the main df is >= the current timeframe's row's df, add the values to their columns
if main_df['time'].iloc[i] >= df['time'].iloc[curr_df_row]:
main_df[timeframe + "_open"].iloc[i] = df['open'].iloc[curr_df_row]
main_df[timeframe + "_high"].iloc[i] = df['high'].iloc[curr_df_row]
main_df[timeframe + "_low"].iloc[i] = df['low'].iloc[curr_df_row]
main_df[timeframe + "_close"].iloc[i] = df['close'].iloc[curr_df_row]
main_df[timeframe + "_volume"].iloc[i] = df['volume'].iloc[curr_df_row]
curr_df_row += 1
# Daily dataset logic would go here
print(main_df)
main_df.to_csv("./TEST.csv", index=False)
解决方案
推荐阅读
- php - Wordpress/nginx wp-admin 卡在刷新循环中
- mysql - Golang mysql select * 语句只返回第一个值
- github - Composer 没有收到我从 Packagist 发布的版本
- c - 阵列扫描两次?
- javascript - gapi 有时在角度 6 中未定义
- html - 当写入操作 HttpPostedFileBase[] fileName 返回 Null
- docker - 将本地目录安装到 docker(docker 卷)中的容器时出现问题。
- php - 教义:通过关系发现了一个新实体
- python - root after 不调用回调函数
- dart - 全宽按钮,如何对齐文本