C5: Remove duplicate entry_fee deduction in backtester (balance and net_pnl) C1: Add SL/TP retry (3x) with emergency market close on final failure C3: Add _close_lock to prevent PnL double recording between callback and monitor C8: Add SIGTERM/SIGINT handler with per-symbol order cancellation before exit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2.2 KiB
Critical Bugfixes Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Fix 4 critical bugs identified in code review (C5, C1, C3, C8)
Architecture: Direct fixes to backtester.py, bot.py, main.py — no new files needed
Tech Stack: Python asyncio, signal handling
Task 1: C5 — Backtester double fee deduction + atr≤0 fee leak
Files:
-
Modify:
src/backtester.py:494-501 -
Remove
self.balance -= entry_feeat L496. The fee is already deducted in_close_positionvianet_pnl = gross_pnl - entry_fee - exit_fee. -
This also fixes the atr≤0 early return bug — since balance is no longer modified before ATR check, early return doesn't leak fees.
Task 2: C1 — SL/TP atomicity with retry and emergency close
Files:
-
Modify:
src/bot.py:461-475 -
Wrap SL/TP placement in
_place_sl_tp_with_retry()with 3 retries and 1s backoff -
Track
sl_placedandtp_placedindependently to avoid re-placing successful orders -
On final failure, call
_emergency_close()which market-closes the position and notifies via Discord -
_emergency_closealso handles its own failure with critical log + Discord alert
Task 3: C3 — PnL double recording race condition
Files:
-
Modify:
src/bot.py(init, _on_position_closed, _position_monitor) -
Add
self._close_lock = asyncio.Lock()to__init__ -
Wrap
_on_position_closedbody withasync with self._close_lock -
Wrap SYNC path in
_position_monitorwithasync with self._close_lock -
Add double-check after lock acquisition in monitor (callback may have already processed)
Task 4: C8 — Graceful shutdown with signal handler
Files:
-
Modify:
main.py -
Add
signal.SIGTERMandsignal.SIGINThandlers vialoop.add_signal_handler() -
Use
asyncio.Event+asyncio.wait(FIRST_COMPLETED)pattern -
_graceful_shutdown(): cancel all open orders per bot (with 5s timeout), then cancel tasks -
Log shutdown progress for each symbol
Verification
- All 138 existing tests pass (0 failures)