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

使用backtesting.py回测单CSV交易数据:交易仅执行5笔的问题

问题:Backtest.py回测仅触发5笔交易,无法执行更多重叠交易
  • 需求:使用包含买卖日期、收盘价的单个CSV文件,替代价格数据、买入信号、卖出信号三个独立文件,基于backtesting.py开展回测
  • 现状:回测仅执行5笔交易,无法触发更多重叠交易
  • 已尝试操作:设置hedging=True、exclusive_orders=False以允许重叠交易,配置日期校验规避节假日,问题仍未解决

核心问题分析

  1. 重复买入日期被覆盖:用dict(zip(data['Buy Dates'], data['Sell Dates']))创建买卖映射时,CSV中重复的买入日期(如2015-09-10、2017-02-15)会被字典自动去重,导致后续对应的卖出日期丢失
  2. 买入信号被去重:self.buy_dates = set(data['Buy Dates'])将重复买入日期转为唯一值,直接忽略了重复的买入信号
  3. 卖出信号匹配混乱:仅判断当前日期是否在卖出日期集合中,无法区分对应哪笔持仓,会错误关闭所有持仓而非指定配对的持仓

修复后的完整代码

import pandas as pd
from backtesting import Backtest as OriginalBacktest, Strategy
from io import StringIO
from pandas.tseries.holiday import USFederalHolidayCalendar

# 包含买卖日期和收盘价的CSV数据
csv_data = """
Buy Dates,Sell Dates,Buy Close,Sell Close
2010-01-15,2010-03-20,120.45,130.23
2011-02-25,2011-05-10,125.67,135.89
2012-08-21,2013-07-22,130.54,140.67
2014-05-23,2014-08-28,135.78,145.34
2015-09-10,2016-01-12,140.23,150.56
2017-02-15,2017-06-18,145.45,155.78
2013-04-18,2014-08-28,135.78,145.34
2015-09-10,2016-01-12,140.23,150.56
2017-02-15,2017-06-18,145.45,155.78
"""

# 读取CSV数据
data = pd.read_csv(StringIO(csv_data), parse_dates=['Buy Dates', 'Sell Dates'])

# 调整日期规避节假日和周末
cal = USFederalHolidayCalendar()
holidays = cal.holidays(start=data['Buy Dates'].min(), end=data['Sell Dates'].max())

def adjust_date(date):
    while date in holidays or date.weekday() > 4:
        date += pd.Timedelta(days=1)
    return date

data['Buy Dates'] = data['Buy Dates'].apply(adjust_date)
data['Sell Dates'] = data['Sell Dates'].apply(adjust_date)

# 构建回测用的股票数据
date_range = pd.date_range(start=data['Buy Dates'].min(), end=data['Sell Dates'].max(), freq='B')
stock_data = pd.DataFrame(index=date_range, columns=['Open', 'High', 'Low', 'Close', 'Volume'])

# 填充收盘价:匹配最近的买入收盘价,再做前后填充
def get_close_price(date):
    matching = data[data['Buy Dates'] <= date]
    if not matching.empty:
        return matching['Buy Close'].iloc[-1]
    return data['Buy Close'].iloc[0]

stock_data['Close'] = stock_data.index.map(get_close_price)
stock_data.ffill(inplace=True)
stock_data.bfill(inplace=True)
stock_data['Open'] = stock_data['Close']
stock_data['High'] = stock_data['Close']
stock_data['Low'] = stock_data['Close']
stock_data['Volume'] = 1000  # 设定固定成交量

# 定义策略:保留所有买卖配对,精准触发每笔交易
class LinkedTrade(Strategy):
    def init(self):
        # 保存所有买卖日期配对(保留重复项)
        self.buy_sell_pairs = list(zip(data['Buy Dates'], data['Sell Dates']))
        # 用于跟踪已触发的买入和对应的卖出日期
        self.active_positions = []

    def next(self):
        current_date = self.data.index[-1]

        # 检查是否有需要触发的买入信号
        for buy_date, sell_date in self.buy_sell_pairs:
            if buy_date == current_date:
                # 执行买入,并记录该笔持仓对应的卖出日期
                position = self.buy()
                self.active_positions.append((position, sell_date))
        
        # 检查是否有需要平仓的持仓
        positions_to_remove = []
        for idx, (position, sell_date) in enumerate(self.active_positions):
            if sell_date == current_date and position.is_long:
                position.close()
                positions_to_remove.append(idx)
        
        # 移除已平仓的持仓记录
        for idx in reversed(positions_to_remove):
            del self.active_positions[idx]

# 自定义Backtest类,传递hedging和exclusive_orders参数
class Backtest(OriginalBacktest):
    def __init__(self, data, strategy, *, cash=10000, commission=0.0, margin=1.0, trade_on_close=False, hedging=True, exclusive_orders=False):
        self.hedging = hedging
        self.exclusive_orders = exclusive_orders
        super().__init__(data, strategy, cash=cash, commission=commission, margin=margin, trade_on_close=trade_on_close)

# 初始化回测
bt = Backtest(stock_data, LinkedTrade, cash=10_000, commission=.002, hedging=True, exclusive_orders=False)

# 运行回测
stats = bt.run()
print(stats)

# 绘制回测结果
bt.plot()

# 保存交易记录
trades = stats['_trades']
trades.to_csv('linked_trades.csv')

关键修复说明

  • 保留所有交易配对:将买卖日期存储为列表而非字典/集合,完整保留CSV中的所有交易信号,包括重复的买入日期
  • 跟踪每笔持仓的卖出日期:买入时记录该笔持仓对应的卖出日期,存入active_positions列表,实现精准配对
  • 精准平仓逻辑:遍历活跃持仓,仅在对应卖出日期到达时平仓该笔持仓,避免误操作其他持仓
  • 修复价格填充逻辑:调整收盘价映射逻辑,确保价格序列更贴合实际交易场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:24:53