fix(v0.2.6): critical grace period & threshold unit bugs

- Fuzzy/Kelly grace threshold: 200 ($200) → 2.0 ($2) — was suppressing ALL loss exits
- Fuzzy/Kelly grace period: unified with dynamic grace_minutes (respects ever_profitable, Golden)
- NO_RECOVERY: 1500 ($1500) → 15.0 ($15) — safety net now actually triggers
- EMERGENCY_MAX_LOSS: 2000 ($2000) → 20.0 ($20) — safety net now actually triggers
- Golden emergency exit: never-profitable + loss >$5 + 45s → immediate cut
- Golden grace floor: 1.0 min (never-prof) / 1.5 min (ever-prof), was 2.0 min

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
GifariKemal
2026-02-11 22:14:20 +07:00
parent 0b98ffdaf3
commit 03cff429f7
3 changed files with 66 additions and 27 deletions
+33
View File
@@ -9,6 +9,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
---
## [0.2.6] - 2026-02-11
### Fixed (Critical: Grace Period & Threshold Unit Bugs)
**Problem:** Trade #162554401 lost -$8.01 in Golden Session. Fuzzy exit confidence was 94.58% at t=86s but was SUPPRESSED by grace period. Three critical bugs discovered:
#### BUG FIX 1: Fuzzy/Kelly Grace Threshold Wrong Unit
- `abs(current_profit) < 200` was meant to be $2.00 but current_profit is in DOLLARS
- So `200` = $200 threshold — effectively suppressed ALL loss exits during grace
- **Fix:** Changed to `abs(current_profit) < 2.0` — only suppress micro-losses (<$2)
#### BUG FIX 2: Fuzzy/Kelly Grace Period Not Unified
- Fuzzy/Kelly section had its OWN hardcoded grace (90s for high_volatility)
- This IGNORED all v0.2.5 fixes (ever_profitable cap, Golden Session reduction)
- **Fix:** Replaced hardcoded dict with `grace_minutes * 60` (unified dynamic grace)
#### BUG FIX 3: NO_RECOVERY & EMERGENCY Thresholds Wrong Unit
- `NO_RECOVERY_THRESHOLD = 1500` ($1500) and `EMERGENCY_MAX_LOSS = 2000` ($2000)
- These safety nets NEVER trigger for 0.01 lot trades (max ~$25 loss)
- **Fix:** Changed to 15.0 ($15) and 20.0 ($20) respectively
#### NEW: Golden Session Emergency Exit
- Never-profitable trades in Golden Session with loss > $5 after 45s → immediate exit
- No grace period, no fuzzy threshold — just cut the loss fast
- Golden Session floor reduced: 1.0 min (never-profitable) / 1.5 min (ever-profitable)
#### Impact Analysis
- Trade #162554401 scenario: fuzzy 94.58% at -$7.93 would now EXIT (not suppressed)
- Grace period in Golden + never-profitable: 72s (was 90s hardcoded)
- Losses > $2 no longer suppressed during grace period at all
- Safety nets (NO_RECOVERY $15, EMERGENCY $20) now actually functional
---
## [0.2.5] - 2026-02-11
### Fixed (Professor AI Analysis: Golden Session + Loss Protection)
+1 -1
View File
@@ -1 +1 @@
0.2.5
0.2.6
+32 -26
View File
@@ -1218,9 +1218,11 @@ class SmartRiskManager:
if not guard.ever_profitable:
grace_minutes = min(grace_minutes, 2.0)
# v0.2.5: Golden Session — reduce grace by 40% (extreme vol = fast moves)
# v0.2.5f: Golden Session — reduce grace by 40% (extreme vol = fast moves)
# Lower floor for never-profitable trades (1 min vs 1.5 min)
if is_golden:
grace_minutes = max(2.0, grace_minutes * 0.60)
golden_floor = 1.0 if not guard.ever_profitable else 1.5
grace_minutes = max(golden_floor, grace_minutes * 0.60)
# Log dynamic multipliers periodically (every 60s)
if len(guard.profit_timestamps) > 0:
@@ -1496,27 +1498,19 @@ class SmartRiskManager:
else:
# === LOSS TRADES: Exit faster to minimize damage ===
# FIX v0.1.2: Grace period untuk loss trades - cegah early exit pada micro swings
grace_period_sec = {
"ranging": 120,
"mean_reverting": 120,
"volatile": 90,
"high_volatility": 90,
"crisis": 60,
"trending": 60,
"normal": 90,
}.get(regime, 90)
time_since_entry = time.time() - guard.entry_time.timestamp()
in_grace_period = time_since_entry < grace_period_sec
# v0.2.5f: Unified grace — use dynamic grace_minutes (respects
# ever_profitable cap, Golden Session reduction, velocity-based)
grace_period_sec = grace_minutes * 60
in_grace_period = trade_age_seconds < grace_period_sec
# Lower threshold for losses (75%)
if exit_confidence > 0.75:
# Suppress exit during grace period for small losses (<$2)
if in_grace_period and abs(current_profit) < 200: # $2.00
# v0.2.5f: Only suppress tiny losses (<$2) during grace
# BUG FIX: was 200 (=$200, never triggers) → 2.0 (=$2)
if in_grace_period and abs(current_profit) < 2.0:
logger.info(
f"[GRACE PERIOD] Loss fuzzy={exit_confidence:.2%} suppressed "
f"(t={time_since_entry:.0f}s < {grace_period_sec}s, loss=${current_profit:.2f})"
f"(t={trade_age_seconds:.0f}s < {grace_period_sec:.0f}s, loss=${current_profit:.2f})"
)
else:
return True, ExitReason.POSITION_LIMIT, (
@@ -1531,11 +1525,11 @@ class SmartRiskManager:
exit_confidence, current_profit, tp_hard
)
if should_exit and close_fraction > 0.3:
# Suppress kelly exit during grace period for small losses
if in_grace_period and abs(current_profit) < 200: # $2.00
# v0.2.5f: Only suppress tiny losses (<$2) during grace
if in_grace_period and abs(current_profit) < 2.0:
logger.info(
f"[GRACE PERIOD] Kelly loss exit suppressed "
f"(t={time_since_entry:.0f}s < {grace_period_sec}s)"
f"(t={trade_age_seconds:.0f}s < {grace_period_sec:.0f}s)"
)
else:
return True, ExitReason.POSITION_LIMIT, (
@@ -1546,20 +1540,32 @@ class SmartRiskManager:
# CHECK -1: NO RECOVERY ZONE ($15 threshold)
# If loss >= $15, exit immediately - no point waiting for recovery
NO_RECOVERY_THRESHOLD = 1500 # $15.00 per 0.01 lot
# v0.2.5f: Fixed unit — current_profit is in DOLLARS (was 1500=$1500, never triggered)
NO_RECOVERY_THRESHOLD = 15.0 # $15.00
if current_profit <= -NO_RECOVERY_THRESHOLD:
return True, ExitReason.POSITION_LIMIT, (
f"[NO RECOVERY] Loss ${abs(current_profit):.2f} too deep "
f"(threshold ${NO_RECOVERY_THRESHOLD/100:.2f}) - cut immediately"
f"(threshold ${NO_RECOVERY_THRESHOLD:.2f}) - cut immediately"
)
# CHECK 0: EMERGENCY CAP ($20 per 0.01 lot)
# CHECK 0: EMERGENCY CAP ($20)
# Absolute maximum loss cap - last resort protection
EMERGENCY_MAX_LOSS = 2000 # $20.00 per 0.01 lot
# v0.2.5f: Fixed unit — current_profit is in DOLLARS (was 2000=$2000, never triggered)
EMERGENCY_MAX_LOSS = 20.0 # $20.00
if current_profit <= -EMERGENCY_MAX_LOSS:
return True, ExitReason.POSITION_LIMIT, (
f"[EMERGENCY CAP] Max loss ${abs(current_profit):.2f} exceeded "
f"${EMERGENCY_MAX_LOSS/100:.2f} limit - emergency exit!"
f"${EMERGENCY_MAX_LOSS:.2f} limit - emergency exit!"
)
# === v0.2.5f: GOLDEN EMERGENCY EXIT ===
# Never-profitable trades in Golden Session with steep loss → cut fast
# Golden = extreme volatility, if -$5+ in 45s and never profitable, it's going wrong
if (is_golden and not guard.ever_profitable
and current_profit < -5.0 and trade_age_seconds >= 45):
return True, ExitReason.POSITION_LIMIT, (
f"[GOLDEN EMERGENCY] Loss ${abs(current_profit):.2f} never-profitable "
f"after {trade_age_seconds:.0f}s in Golden Session — cutting fast"
)
# === CHECK 0A: BREAKEVEN SHIELD (percentage-based, dynamic) ===