feat: implement stop-loss/take-profit execution in backtest engine

- Track SL/TP conditions from BUY signals in _generate_signals loop
- Check active conditions against each bar's high/low price range
- Auto-generate SELL signal at trigger price when condition is met
- Modify OrderSimulator to respect signal.price for direct execution
  (previously signal.price was stored but never used in execution)
- SL/TP activates on bar AFTER BUY signal (consistent with next_open)
- Stop-loss checked before take-profit (conservative for holder)
- Add 4 tests: SL trigger, TP trigger, no-trigger, priority over manual sell
This commit is contained in:
Justin Gu
2026-06-11 01:53:11 +08:00
parent 06b2617ebc
commit 815b3ddf7c
3 changed files with 268 additions and 11 deletions
+16 -8
View File
@@ -72,15 +72,23 @@ class OrderSimulator:
if bar_idx is None:
continue
# 确定成交的 K 线索引
exec_idx = self._resolve_exec_index(bar_idx)
if exec_idx is None or exec_idx >= len(self.df):
continue
# 当信号指定了价格(止损/止盈/限价单),
# 直接在信号所在 bar 以信号价格成交
if signal.price is not None:
exec_idx: int = bar_idx
price: float = signal.price
else:
# 确定成交的 K 线索引
exec_idx_raw = self._resolve_exec_index(bar_idx)
if exec_idx_raw is None or exec_idx_raw >= len(self.df):
continue
exec_idx = exec_idx_raw
# 获取成交价
price = self._get_price(exec_idx, signal.direction)
if price is None:
continue
# 获取成交价
price_raw = self._get_price(exec_idx, signal.direction)
if price_raw is None:
continue
price = price_raw
# 执行交易
if signal.direction == "BUY":