首页 > 解决方案 > 在不上采样 1 分钟的情况下合并 1 分钟、5 分钟和每日 OHLC 数据帧?

问题描述

为了简单起见,假设我有 3 个数据集,一个 1 分钟的 OHLCV 数据集,一个 5 分钟的数据集和一个 Daily。鉴于这 3 个数据集:

1分钟

1分钟

5分钟

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)

标签: pythonpython-3.xpandasalpha-vantage

解决方案


推荐阅读