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

Upload Quasar_axrvi_ranker.py

Browse files
Files changed (1) hide show
  1. Quasar_axrvi_ranker.py +50 -7
Quasar_axrvi_ranker.py CHANGED
@@ -5036,6 +5036,10 @@ 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
 
5040
  # ── Terminal state check ──────────────────────────────────────────────
5041
  is_terminal = (
@@ -5462,15 +5466,18 @@ class QuasarAXRVIBridge:
5462
  G_t = sgn(direction) Β· log(S_t / S_entry) βˆ’ fees (immediate liquidation value)
5463
  C_t = model value estimate of future return (continuation value)
5464
 
5465
- Exit when G_t β‰₯ C_t + stopping_value_buffer,
5466
- OR when the fallback max duration is exceeded (safety net only).
 
 
 
5467
 
5468
  Minimum holding guard: do not evaluate stopping until
5469
  _trade_tick_counts[trade_id] >= shreve_config.min_holding_ticks.
5470
 
5471
  REFILL TRIGGER (v7):
5472
- After any position is closed, if open_trade_count drops below 2, immediately
5473
- call rank_and_gate() to refill. This ensures the 2-trade minimum is maintained
5474
  continuously without waiting for the next scheduled _rank_loop cycle.
5475
 
5476
  CLOSING TIMEOUT FIX (v6.1):
@@ -5580,10 +5587,46 @@ class QuasarAXRVIBridge:
5580
  f"+ buffer={sc.stopping_value_buffer:.5f}"
5581
  )
5582
 
5583
- # ── Fallback: hard max duration (safety net only) ─────────
5584
- if not should_stop and trade.holding_duration > self.trade_config.expiry_time:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5585
  should_stop = True
5586
- stop_reason = f"Max duration {self.trade_config.expiry_time}s exceeded"
 
 
 
5587
 
5588
  if should_stop:
5589
  logger.info(f"[{trade.asset}] EXIT | {stop_reason}")
 
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 ──────────────────────────────────────────────
5045
  is_terminal = (
 
5466
  G_t = sgn(direction) Β· log(S_t / S_entry) βˆ’ fees (immediate liquidation value)
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):
 
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 = (
5606
+ f"MaxLoss: live_pnl={live_loss:+.4f} ≀ "
5607
+ f"sl_threshold={sl_threshold:+.4f} "
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
5618
+ stop_reason = (
5619
+ f"HARD WALL: held {trade.holding_duration:.0f}s "
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 = (
5627
+ f"SoftExpiry: held {trade.holding_duration:.0f}s "
5628
+ f"> expiry_time={self.trade_config.expiry_time}s"
5629
+ )
5630
 
5631
  if should_stop:
5632
  logger.info(f"[{trade.asset}] EXIT | {stop_reason}")