diff --git a/src/oneshot.js b/src/oneshot.js index 652a387..d9189f9 100644 --- a/src/oneshot.js +++ b/src/oneshot.js @@ -175,6 +175,13 @@ async function onSignal(evt) { // Only enter from IDLE — one position per market slot if (!sm.is(State.IDLE)) return; + // Global position limit: never open a new position while any other market + // is still being held. The engine is designed to focus on one bet at a time. + if (posEngine.hasAnyPosition()) { + dbg('SIGNAL', `${marketSlug} | blocked — position already open in another market`); + return; + } + // ── Risk gate ───────────────────────────────────────────────────────── const riskCheck = riskEngine.canTrade(); diff --git a/src/oneshot/PositionEngine.js b/src/oneshot/PositionEngine.js index bbad5a3..912f23a 100644 --- a/src/oneshot/PositionEngine.js +++ b/src/oneshot/PositionEngine.js @@ -68,6 +68,11 @@ export class PositionEngine { return this._positions.has(marketSlug); } + /** True if ANY position is open across all tracked markets */ + hasAnyPosition() { + return this._positions.size > 0; + } + /** * Close the position actively (adverse-move emergency exit) and return exit data. *