实现单品种连续多合约回测

This commit is contained in:
2025-06-19 15:28:26 +08:00
parent ce5ad27bab
commit 355e451aac
6 changed files with 2016 additions and 22 deletions

View File

@@ -20,6 +20,7 @@ class BacktestEngine:
data_manager: DataManager,
strategy_class: Type[Strategy],
strategy_params: Dict[str, Any],
current_segment_symbol: str,
initial_capital: float = 100000.0,
slippage_rate: float = 0.0001,
commission_rate: float = 0.0002):
@@ -41,6 +42,7 @@ class BacktestEngine:
commission_rate=commission_rate
)
self.context = BacktestContext(self.data_manager, self.simulator)
self.current_segment_symbol = current_segment_symbol
# 实例化策略
self.strategy = strategy_class(self.context, **strategy_params)
@@ -107,6 +109,8 @@ class BacktestEngine:
self.portfolio_snapshots.append(snapshot)
self.all_bars.append(current_bar)
last_processed_bar = current_bar
# 记录交易历史(从模拟器获取)
# 简化处理每次获取模拟器中的所有交易历史并更新引擎的trade_history
# 更好的做法是模拟器提供一个方法,返回自上次查询以来的新增交易
@@ -117,7 +121,25 @@ class BacktestEngine:
# 这里可以做一个增量获取,或者简单地在循环结束后统一获取
# 目前我们在执行模拟器中已经将成交记录在了 trade_log 中,所以这里不用重复记录,
# 而是等到回测结束后再统一获取。
pass # 不在此处记录 self.trade_history
# 不在此处记录 self.trade_history
print("\n--- 回测片段结束,检查并平仓所有持仓 ---")
if last_processed_bar: # 确保至少有一根Bar被处理过
positions_to_close = self.simulator.get_current_positions()
for symbol_held, quantity in positions_to_close.items():
if quantity != 0:
print(f"[{last_processed_bar.datetime}] 回测结束平仓: 平仓 {symbol_held} ({quantity} 手) @ {last_processed_bar.close:.2f}")
direction = "SELL" if quantity > 0 else "BUY"
volume = abs(quantity)
# 使用当前合约的最后一根Bar的价格进行平仓
# 注意这里假设平仓的symbol_held就是当前segment的symbol
# 如果策略可能同时持有其他旧合约的仓位(多主力同时持有),这里需要更复杂的逻辑来获取正确的平仓价格
# 但在主力合约切换场景下,通常只持有当前主力合约的仓位。
rollover_order = Order(symbol=symbol_held, direction=direction, volume=volume, price_type="MARKET")
self.simulator.send_order(rollover_order, current_bar=last_processed_bar)
else:
print("没有处理任何Bar无需平仓。")
# 回测结束后,获取所有交易记录
self.trade_history = self.simulator.get_trade_history()
@@ -135,4 +157,10 @@ class BacktestEngine:
"trade_history": self.trade_history,
"initial_capital": self.simulator.initial_capital, # 或 self.initial_capital
"all_bars": self.all_bars
}
}
def get_simulator(self) -> ExecutionSimulator: # <--- 新增的方法
"""
返回引擎内部的 ExecutionSimulator 实例,以便外部可以访问和修改其状态。
"""
return self.simulator