如何在金融资产 DataFrame 中将买入日与下一个卖出日配对
How to pairwise the buy days with the next sell day in a financial asset DataFrame
我有一个 DataFrame,其中包含金融资产的收盘价和 buy/sell 信号。我的目标是用买卖日对创建一个新的数据框。
目前,我通过迭代原始 DataFrame 并保存价值和购买日期来创建这个新的 DataFrame。
import pandas as pd
df = pd.DataFrame({
'close': [30.0,29.39,29.24,22.2,19.01,26.9,13.92,5.05,13.11,14.94,16.33,14.57,15.91,21.06,22.05,
24.66,18.96,6.6,5.35,7.76],
'buy_signal': [False,False,True,False,False,False,False,False,True,True,False,False,False,False,
False,False,True,False,False,True],
'sell_signal': [True,False,False,False,True,True,True,False,False,False,False,False,False,True,
False,False,False,False,False,False],
})
df['date'] = ['2022-02-28','2022-03-01','2022-03-02','2022-03-03','2022-03-04','2022-03-07',
'2022-03-08','2022-03-09','2022-03-10','2022-03-11','2022-03-14','2022-03-15',
'2022-03-16','2022-03-17','2022-03-18','2022-03-21','2022-03-22','2022-03-23',
'2022-03-24','2022-03-25',]
df = df.set_index('date')
def get_positions(dt):
positions = {
'buy_price': [],
'sell_price': [],
'buy_date': [],
'sell_date': [],
}
buying = False
for row in df.itertuples():
if buying is False and row.buy_signal is True:
buying = True
positions['buy_date'].append(row.Index)
positions['buy_price'].append(row.close)
if buying is True and row.sell_signal is True:
buying = False
positions['sell_date'].append(row.Index)
positions['sell_price'].append(row.close)
positions['buy_price'] = positions['buy_price'][:len(positions['sell_price'])]
positions['buy_date'] = positions['buy_date'][:len(positions['sell_date'])]
positions = pd.DataFrame(positions)
positions['profit'] = positions['sell_price'] - positions['buy_price']
return positions
positions = get_positions(df)
positions
尽管这种方法很有效,但我发现 iterating over a DataFrame is an anti-pattern 并且对于非常大的 DataFrames 来说是一个非常慢的例程。
所以我想知道是否有另一种方法来做这些买卖日对。
我认为您可以将数据帧拆分为卖出信号(下面代码中的df_sell
)和买入信号(下面代码中的df_buy
)信号,然后使用 pd.merge_asof 将它们合并forward
方向,然后过滤掉带有 NaN 的行。
def get_positions(df):
df.index = pd.to_datetime(df.index)
df['date_col'] = df.index
df_buy = df.loc[df['buy_signal'] == True]
df_sell = df.loc[df['sell_signal'] == True]
df_positions = pd.merge_asof(left=df_buy, right=df_sell, right_index=True, left_index=True, direction='forward')
df_positions.drop_duplicates(subset=['date_col_y'], keep='first', inplace=True)
df_positions.dropna(inplace=True)
positions = pd.DataFrame({
'buy_price': df_positions['close_x'],
'sell_price': df_positions['close_y'],
'buy_date': df_positions['date_col_x'],
'sell_date': df_positions['date_col_y'],
'profit': df_positions['close_y'] - df_positions['close_x'] })
return positions
如果您还希望将共享它们的买入日期与之前的日期(示例数据中的 2022-03-11)保持相同的卖出日期,则可以删除该行
df_positions.drop_duplicates(subset=['date_col_y'], keep='first', inplace=True)
我有一个 DataFrame,其中包含金融资产的收盘价和 buy/sell 信号。我的目标是用买卖日对创建一个新的数据框。
目前,我通过迭代原始 DataFrame 并保存价值和购买日期来创建这个新的 DataFrame。
import pandas as pd
df = pd.DataFrame({
'close': [30.0,29.39,29.24,22.2,19.01,26.9,13.92,5.05,13.11,14.94,16.33,14.57,15.91,21.06,22.05,
24.66,18.96,6.6,5.35,7.76],
'buy_signal': [False,False,True,False,False,False,False,False,True,True,False,False,False,False,
False,False,True,False,False,True],
'sell_signal': [True,False,False,False,True,True,True,False,False,False,False,False,False,True,
False,False,False,False,False,False],
})
df['date'] = ['2022-02-28','2022-03-01','2022-03-02','2022-03-03','2022-03-04','2022-03-07',
'2022-03-08','2022-03-09','2022-03-10','2022-03-11','2022-03-14','2022-03-15',
'2022-03-16','2022-03-17','2022-03-18','2022-03-21','2022-03-22','2022-03-23',
'2022-03-24','2022-03-25',]
df = df.set_index('date')
def get_positions(dt):
positions = {
'buy_price': [],
'sell_price': [],
'buy_date': [],
'sell_date': [],
}
buying = False
for row in df.itertuples():
if buying is False and row.buy_signal is True:
buying = True
positions['buy_date'].append(row.Index)
positions['buy_price'].append(row.close)
if buying is True and row.sell_signal is True:
buying = False
positions['sell_date'].append(row.Index)
positions['sell_price'].append(row.close)
positions['buy_price'] = positions['buy_price'][:len(positions['sell_price'])]
positions['buy_date'] = positions['buy_date'][:len(positions['sell_date'])]
positions = pd.DataFrame(positions)
positions['profit'] = positions['sell_price'] - positions['buy_price']
return positions
positions = get_positions(df)
positions
尽管这种方法很有效,但我发现 iterating over a DataFrame is an anti-pattern 并且对于非常大的 DataFrames 来说是一个非常慢的例程。
所以我想知道是否有另一种方法来做这些买卖日对。
我认为您可以将数据帧拆分为卖出信号(下面代码中的df_sell
)和买入信号(下面代码中的df_buy
)信号,然后使用 pd.merge_asof 将它们合并forward
方向,然后过滤掉带有 NaN 的行。
def get_positions(df):
df.index = pd.to_datetime(df.index)
df['date_col'] = df.index
df_buy = df.loc[df['buy_signal'] == True]
df_sell = df.loc[df['sell_signal'] == True]
df_positions = pd.merge_asof(left=df_buy, right=df_sell, right_index=True, left_index=True, direction='forward')
df_positions.drop_duplicates(subset=['date_col_y'], keep='first', inplace=True)
df_positions.dropna(inplace=True)
positions = pd.DataFrame({
'buy_price': df_positions['close_x'],
'sell_price': df_positions['close_y'],
'buy_date': df_positions['date_col_x'],
'sell_date': df_positions['date_col_y'],
'profit': df_positions['close_y'] - df_positions['close_x'] })
return positions
如果您还希望将共享它们的买入日期与之前的日期(示例数据中的 2022-03-11)保持相同的卖出日期,则可以删除该行
df_positions.drop_duplicates(subset=['date_col_y'], keep='first', inplace=True)