Skip to content

fix(api): refuse to start a second trading engine (BUG-04) - #23

Merged
sijie-Z merged 1 commit into
mainfrom
fix/trading-start-guard
Sep 13, 2026
Merged

sijie-Z merged 1 commit into
mainfrom
fix/trading-start-guard

Conversation

@sijie-Z

@sijie-Z sijie-Z commented Sep 13, 2026

Copy link
Copy Markdown
Owner

P0/P1 — trading safety. POST /api/trading/start built and started a new engine unconditionally; _live_engine was only ever overwritten:

engine = LiveTradingEngine(...)
engine.start()
_live_engine = engine      # replaces, never checks

What a second call used to do

  • the first engine's TradingScheduler thread and broker kept running
  • no handle remained, so POST /api/trading/stop could never reach it
  • both engines wrote positions / P&L / orders into the same store — and positions is keyed on code alone, so their rows overwrote each other
  • its kill switch became unreachable too, because _core_risk was rebound

LiveTradingEngine.start() does have if self._running: return, but that is per-instance and cannot see the newly constructed object.

Realistic trigger: a double-clicked button, two browser tabs, or a script — anything that sends the request twice before the first response returns.

Fix

Returns 409 with an explicit message. The guard keys on the engine's _running flag rather than on the global merely being set, so a stopped engine does not block a restart.

Tests

Test Asserts
test_a_second_start_is_refused_while_one_is_running 409 + message
test_a_stopped_engine_does_not_block_a_restart 200, engine actually started
test_the_orphaned_engine_is_the_one_the_guard_protects repeated attempts stay refused

Verified by removing the guard: tests 1 and 3 fail there, test 2 still passes — which is the point, it is the one asserting the guard does not over-block.

1326 passed, 1 skipped.

🤖 Generated with Claude Code

`POST /api/trading/start` built and started a new engine unconditionally.
`_live_engine` was only ever overwritten:

    engine = LiveTradingEngine(...)
    engine.start()
    _live_engine = engine      # replaces, never checks

A second call therefore orphaned the first engine:

  - its TradingScheduler thread and its broker kept running
  - no handle remained, so `POST /api/trading/stop` could never reach it
  - both engines wrote positions / P&L / orders into the same store, and
    `positions` is keyed on `code` alone, so their rows overwrote each other
  - its kill switch became unreachable too, because `_core_risk` was rebound

`LiveTradingEngine.start()` has its own `if self._running: return` guard, but
that is per-instance and cannot see the new object.

Realistic trigger: a double-clicked button, two browser tabs, or a script --
anything that sends the request twice before the first response returns.

Now returns 409 with an explicit message, and the guard keys on the engine's
`_running` flag rather than on the global merely being set, so a stopped engine
does not block a restart.

Tests (tests/test_api/test_trading_start_guard.py):
  - a second start while one is running -> 409
  - a stopped engine does not block a restart
  - repeated attempts stay refused

Verified by removing the guard: the first and third fail there, the second
still passes (it is the one asserting the guard does not over-block).

1326 passed, 1 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 0f57b6cc-5127-4021-8089-9ac00536f092


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sijie-Z
sijie-Z merged commit 71aeb44 into main Sep 13, 2026
9 checks passed
@sijie-Z
sijie-Z deleted the fix/trading-start-guard branch September 13, 2026 06:16
@sijie-Z
sijie-Z restored the fix/trading-start-guard branch September 23, 2026 05:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant