KarlQuant commited on
Commit
e0da561
Β·
verified Β·
1 Parent(s): 73510a5

Upload Quasar_axrvi_ranker.py

Browse files
Files changed (1) hide show
  1. Quasar_axrvi_ranker.py +30 -25
Quasar_axrvi_ranker.py CHANGED
@@ -3904,11 +3904,17 @@ class PositionManager:
3904
  """
3905
  Mark a trade as CLOSING after a sell request is sent.
3906
  Actual close happens in close_trade_from_broker() when broker confirms.
 
 
 
 
 
3907
  """
3908
  with self._lock:
3909
  trade = self._open_trades.get(trade_id)
3910
  if trade:
3911
- trade.state = PositionState.CLOSING
 
3912
  logger.info(f"[{trade_id}] ⏳ SELL SENT β€” awaiting broker terminal event")
3913
 
3914
  # ── Phase 4: broker terminal event ────────────────────────────────────────
@@ -5036,9 +5042,9 @@ class QuasarAXRVIBridge:
5036
  # βœ… FIX 1: Cache live broker profit so rotation closes use the real P&L.
5037
  # trade.profit stays None only if Deriv never sent a profit field at all.
5038
  trade.profit = float(raw_profit)
5039
- # βœ… FIX-MAXLOSS: cache on dedicated field so OptStop max-loss stop
5040
- # can read the broker-authoritative live P&L without touching trade.profit
5041
- # (which is also used for the terminal-event authoritative close).
5042
  trade._last_poc_profit = float(raw_profit)
5043
 
5044
  # ── Terminal state check ──────────────────────────────────────────────
@@ -5467,22 +5473,22 @@ class QuasarAXRVIBridge:
5467
  C_t = model value estimate of future return (continuation value)
5468
 
5469
  Exit priority (evaluated in order, first match wins):
5470
- 1. OptStop β€” G_t β‰₯ C_t + stopping_value_buffer (profit target)
5471
- 2. MaxLoss β€” broker live P&L ≀ βˆ’(sl_frac Γ— stake) (stop-loss)
5472
- 3. HARD WALL β€” holding_duration > 120 s (absolute failsafe)
5473
- 4. SoftExpiry β€” holding_duration > expiry_time (default 60 s)
5474
 
5475
  Minimum holding guard: do not evaluate stopping until
5476
  _trade_tick_counts[trade_id] >= shreve_config.min_holding_ticks.
5477
 
5478
  REFILL TRIGGER (v7):
5479
  After any position is closed, if open_trade_count drops below 3, immediately
5480
- call rank_and_gate() to refill. This ensures the 3-trade minimum is maintained
5481
- continuously without waiting for the next scheduled _rank_loop cycle.
5482
 
5483
  CLOSING TIMEOUT FIX (v6.1):
5484
  If a trade remains in CLOSING state for > 10 seconds without a terminal
5485
  event from the broker, force-close it locally to prevent stuck trades.
 
5486
  """
5487
  sc = self.config.shreve_config
5488
  CLOSING_TIMEOUT_SECONDS = 10.0 # Maximum time to wait for broker terminal event
@@ -5587,19 +5593,19 @@ class QuasarAXRVIBridge:
5587
  f"+ buffer={sc.stopping_value_buffer:.5f}"
5588
  )
5589
 
5590
- # ── Max-loss stop: exit when broker live P&L hits stop-loss ──
5591
- # Uses the broker-authoritative profit cached from poc stream.
5592
- # This fires even when G_t < 0 (price moved against us), which
5593
- # the pure OptStop rule misses because it only exits on G_t >= C_t.
 
5594
  if not should_stop:
5595
- sl_frac = ASSET_STOP_LOSS_FRAC.get(trade.asset, 0.50)
5596
- stake = trade.buy_price if (trade.buy_price and trade.buy_price > 0) else self.trade_config.amount
 
5597
  sl_threshold = -(sl_frac * stake)
5598
- # Prefer broker-authoritative live P&L from poc stream
5599
- live_loss = getattr(trade, "_last_poc_profit", None)
5600
  if live_loss is None:
5601
- # Fallback: approximate from spot price (less accurate)
5602
- live_loss = trade.unrealized_pnl
5603
  if live_loss is not None and live_loss <= sl_threshold:
5604
  should_stop = True
5605
  stop_reason = (
@@ -5608,10 +5614,9 @@ class QuasarAXRVIBridge:
5608
  f"(SL={sl_frac:.0%} Γ— stake={stake:.2f})"
5609
  )
5610
 
5611
- # ── Hard absolute wall: 120 s regardless of everything ────────
5612
- # Safety net for cases where OptStop & MaxLoss both fail to fire
5613
- # (e.g. G_t oscillating near zero, poc profit not yet received).
5614
- # 120 s = 2Γ— the intended 60 s expiry β€” generous but finite.
5615
  MAX_HOLDING_SECONDS = 120
5616
  if not should_stop and trade.holding_duration > MAX_HOLDING_SECONDS:
5617
  should_stop = True
@@ -5620,7 +5625,7 @@ class QuasarAXRVIBridge:
5620
  f"> {MAX_HOLDING_SECONDS}s absolute limit"
5621
  )
5622
 
5623
- # ── Soft expiry: configured expiry_time (default 60 s) ────────
5624
  elif not should_stop and trade.holding_duration > self.trade_config.expiry_time:
5625
  should_stop = True
5626
  stop_reason = (
 
3904
  """
3905
  Mark a trade as CLOSING after a sell request is sent.
3906
  Actual close happens in close_trade_from_broker() when broker confirms.
3907
+
3908
+ FIX: exit_time is stamped here so the CLOSING-timeout handler in
3909
+ monitor_positions() can correctly compute closing_duration.
3910
+ Without this stamp, closing_duration is always 0 and the 10-second
3911
+ timeout never fires, leaving trades stuck in CLOSING forever.
3912
  """
3913
  with self._lock:
3914
  trade = self._open_trades.get(trade_id)
3915
  if trade:
3916
+ trade.state = PositionState.CLOSING
3917
+ trade.exit_time = time.time() # ← FIX: stamp so timeout works
3918
  logger.info(f"[{trade_id}] ⏳ SELL SENT β€” awaiting broker terminal event")
3919
 
3920
  # ── Phase 4: broker terminal event ────────────────────────────────────────
 
5042
  # βœ… FIX 1: Cache live broker profit so rotation closes use the real P&L.
5043
  # trade.profit stays None only if Deriv never sent a profit field at all.
5044
  trade.profit = float(raw_profit)
5045
+ # βœ… FIX-MAXLOSS: dedicated field for OptStop max-loss check so the
5046
+ # monitor can read broker-authoritative live P&L without confusion
5047
+ # with the terminal-event authoritative profit set on close.
5048
  trade._last_poc_profit = float(raw_profit)
5049
 
5050
  # ── Terminal state check ──────────────────────────────────────────────
 
5473
  C_t = model value estimate of future return (continuation value)
5474
 
5475
  Exit priority (evaluated in order, first match wins):
5476
+ 1. OptStop β€” G_t β‰₯ C_t + stopping_value_buffer (profit target)
5477
+ 2. MaxLoss β€” broker live P&L ≀ βˆ’(sl_frac Γ— stake) (stop-loss)
5478
+ 3. HARD WALL β€” holding_duration > 120 s (absolute failsafe)
5479
+ 4. SoftExpiry β€” holding_duration > expiry_time (default 60 s)
5480
 
5481
  Minimum holding guard: do not evaluate stopping until
5482
  _trade_tick_counts[trade_id] >= shreve_config.min_holding_ticks.
5483
 
5484
  REFILL TRIGGER (v7):
5485
  After any position is closed, if open_trade_count drops below 3, immediately
5486
+ call rank_and_gate() to refill.
 
5487
 
5488
  CLOSING TIMEOUT FIX (v6.1):
5489
  If a trade remains in CLOSING state for > 10 seconds without a terminal
5490
  event from the broker, force-close it locally to prevent stuck trades.
5491
+ NOTE: requires mark_closing() to stamp exit_time (fixed in this version).
5492
  """
5493
  sc = self.config.shreve_config
5494
  CLOSING_TIMEOUT_SECONDS = 10.0 # Maximum time to wait for broker terminal event
 
5593
  f"+ buffer={sc.stopping_value_buffer:.5f}"
5594
  )
5595
 
5596
+ # ── [2] Max-loss stop: broker live P&L hit stop-loss ─────────
5597
+ # Fires when price moved against us β€” G_t is negative so
5598
+ # OptStop never triggers, but we still need to cut losses.
5599
+ # Uses _last_poc_profit: broker-authoritative live P&L cached
5600
+ # from the poc stream on every tick (set in _on_poc_update).
5601
  if not should_stop:
5602
+ sl_frac = ASSET_STOP_LOSS_FRAC.get(trade.asset, 0.50)
5603
+ stake = (trade.buy_price if (trade.buy_price and trade.buy_price > 0)
5604
+ else self.trade_config.amount)
5605
  sl_threshold = -(sl_frac * stake)
5606
+ live_loss = getattr(trade, "_last_poc_profit", None)
 
5607
  if live_loss is None:
5608
+ live_loss = trade.unrealized_pnl # approx fallback
 
5609
  if live_loss is not None and live_loss <= sl_threshold:
5610
  should_stop = True
5611
  stop_reason = (
 
5614
  f"(SL={sl_frac:.0%} Γ— stake={stake:.2f})"
5615
  )
5616
 
5617
+ # ── [3] Hard absolute wall: 120 s no matter what ──────────────
5618
+ # Fires when OptStop and MaxLoss both failed (e.g. G_t oscillating
5619
+ # near zero, poc profit stream delayed). 120 s = 2Γ— the soft expiry.
 
5620
  MAX_HOLDING_SECONDS = 120
5621
  if not should_stop and trade.holding_duration > MAX_HOLDING_SECONDS:
5622
  should_stop = True
 
5625
  f"> {MAX_HOLDING_SECONDS}s absolute limit"
5626
  )
5627
 
5628
+ # ── [4] Soft expiry: configured expiry_time (default 60 s) ────
5629
  elif not should_stop and trade.holding_duration > self.trade_config.expiry_time:
5630
  should_stop = True
5631
  stop_reason = (