You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python和Pandas的交易策略回测:实现单一持仓控制

针对问题的解决方案

你的核心问题在于没有跟踪当前持仓状态——代码不知道现在是不是已经持有仓位,所以会在持仓期间不断触发新的买入信号。我们可以通过添加状态变量来解决这个问题,以下是优化后的完整代码:

import pandas as pd

# 先把日期转成pandas可识别的datetime格式,避免后续出错
data = {
    'date': pd.to_datetime([
        '1/3/2000','1/4/2000','1/5/2000','1/6/2000','1/7/2000','1/10/2000','1/11/2000','1/12/2000','1/13/2000','1/14/2000',
        '1/18/2000','1/19/2000','1/20/2000','1/21/2000','1/24/2000','1/25/2000','1/26/2000','1/27/2000','1/28/2000','1/31/2000',
        '2/1/2000','2/2/2000','2/3/2000','2/4/2000','2/7/2000','2/8/2000','2/9/2000','2/10/2000','2/11/2000','2/14/2000',
        '2/15/2000','2/16/2000','2/17/2000','2/18/2000','2/22/2000','2/23/2000','2/24/2000','2/25/2000','2/28/2000','2/29/2000'
    ]),
    'close': [308.3,315.3,314.4,307.5,309.8,313.4,310.7,324.2,332.5,348.8,351.1,348.2,348.7,343.5,343,343.3,342.4,343,334.4,334.6,336,333.8,331.6,332.8,335.9,341.2,338.4,342.1,343.2,339.5,346.9,342,339.6,337.4,335,330.8,331.3,331.1,332.6,335.1]
}
df = pd.DataFrame(data)

# 生成高低点标记(和你原代码逻辑一致)
df['prev_close'] = df['close'].shift(1)
df['next_close'] = df['close'].shift(-1)
df['high_high'] = (df['prev_close'] > df['close']) & (df['next_close'] > df['close'])  # 局部高点(卖出基准)
df['low_low'] = (df['prev_close'] < df['close']) & (df['next_close'] < df['close'])    # 局部低点(买入基准)

# 填充基准价格:保留最近的有效基准价
df['comp_price'] = df['close'].where(df['low_low'] == True).ffill()  # 买入基准价
df['sell_comp'] = df['close'].where(df['high_high'] == True).ffill() # 卖出基准价

# 新增持仓状态列,初始为False(空仓)
df['in_position'] = False
df['buy_sig'] = False
df['sell_sig'] = False

# 逐行遍历,根据持仓状态生成有效信号
for i in range(1, len(df)):
    prev_state = df.iloc[i-1]['in_position']
    current_close = df.iloc[i]['close']
    current_buy_price = df.iloc[i]['comp_price']
    current_sell_price = df.iloc[i]['sell_comp']
    
    if not prev_state:
        # 空仓状态:只检查买入信号
        if current_close > current_buy_price:
            df.at[i, 'buy_sig'] = True
            df.at[i, 'in_position'] = True
        else:
            df.at[i, 'in_position'] = False
    else:
        # 持仓状态:只检查卖出信号
        if current_close < current_sell_price:
            df.at[i, 'sell_sig'] = True
            df.at[i, 'in_position'] = False
        else:
            df.at[i, 'in_position'] = True

# 标记开平仓点
df['open_pos'] = df['buy_sig']
df['close_pos'] = df['sell_sig']

# 填充开仓信息到持仓期间的所有行
df['open_pos_date'] = df['date'].where(df['open_pos']).ffill()
df['open_pos_price'] = df['close'].where(df['open_pos']).ffill()

# 提取最终的完整交易记录(每个开仓对应唯一平仓)
strat_df = df.loc[df['close_pos'], ['open_pos_date','open_pos_price', 'date','close']]
strat_df.rename(columns={'date':'close_pos_date', 'close':'close_pos_price'}, inplace=True)
strat_df['gain'] = strat_df['close_pos_price'] - strat_df['open_pos_price']

print(strat_df)

关键优化点说明

  1. 持仓状态跟踪:新增in_position列,用布尔值记录当前是否持有仓位,这是解决多持仓问题的核心——空仓时才响应买入信号,持仓时只关注卖出信号。
  2. 逐行逻辑判断:不再依赖向量运算批量生成信号,而是逐行根据前一天的持仓状态决定当天的信号逻辑,从根源上避免了持仓期间触发新买入信号。
  3. 日期格式修正:将原日期字符串转换为pd.datetime格式,避免后续日期处理出现异常。
  4. 交易记录清理:最终生成的strat_df只会保留完整的开平仓配对,不会出现一个开仓对应多个平仓的情况,完全符合你的需求。

内容的提问来源于stack exchange,提问作者serranzau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:24:46