Spaces:
Running
Running
Upload Quasar_axrvi_ranker.py
Browse files- 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
|
|
|
|
| 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:
|
| 5040 |
-
# can read
|
| 5041 |
-
#
|
| 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
|
| 5471 |
-
2. MaxLoss
|
| 5472 |
-
3. HARD WALL
|
| 5473 |
-
4. SoftExpiry
|
| 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.
|
| 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:
|
| 5591 |
-
#
|
| 5592 |
-
#
|
| 5593 |
-
#
|
|
|
|
| 5594 |
if not should_stop:
|
| 5595 |
-
sl_frac
|
| 5596 |
-
stake
|
|
|
|
| 5597 |
sl_threshold = -(sl_frac * stake)
|
| 5598 |
-
|
| 5599 |
-
live_loss = getattr(trade, "_last_poc_profit", None)
|
| 5600 |
if live_loss is None:
|
| 5601 |
-
|
| 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
|
| 5612 |
-
#
|
| 5613 |
-
#
|
| 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 = (
|