Files
XauBot/docs/reports/CODE-REVIEW-RECOMMENDATIONS.md
Vanszs a4619dd005 chore: clean up workspace for production
- Remove tracked generated artifacts: backtest logs (52), xlsx (43),
  experiment model pkls (7), ml_v3 training logs (11), result csv/txt
- Remove junk files: stray =1.4.5, training_output.log, *_analysis_output.txt,
  dead api.log, runtime bot.lock
- Remove throwaway scripts: analyze_performance, test_trajectory_bug, verify_settings
- Move reusable analysis scripts to scripts/analysis/
- Move status/report docs to docs/reports/
- Tighten .gitignore to prevent re-adding generated artifacts; ignore .kiro/
2026-06-06 12:04:13 +07:00

599 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CODE REVIEW & RECOMMENDATIONS - Response to User Feedback
## 📋 USER FEEDBACK SUMMARY
1.**Dynamic max loss per trade** - Setuju, perlu dynamic
2.**Skip night trading block** - Bot harus bisa handle
3.**Fuzzy 0.70 threshold** - User tanya apakah oke?
4.**Grace period tightening** - User tanya gimana?
5.**Skip BUY ML confidence** - Not needed
6.**Consider early cut/partial exit** - Review existing methods
7.**Code review & dead code removal** - Analyze and clean
---
## 1. DYNAMIC MAX LOSS PER TRADE ✅
### Current Implementation (SUDAH DYNAMIC!)
```python
# Line 1024 - smart_risk_manager.py
effective_max_loss = self.max_loss_per_trade * sm
# sm = ATR scaling multiplier (0.3-1.5x)
# max_loss_per_trade = $49.45 (capital × 1%)
# Result: $14.84 - $74.18 depending on ATR
```
**Sudah dynamic berdasarkan:**
- ATR ratio (volatile market = wider, quiet market = tighter)
- sm range: 0.3x - 1.5x
### MASALAH: No Hard Cap!
**Contoh:** Trade -$34.70 terjadi karena:
1. ATR scaling sm = 1.0
2. Loss multiplier loss_mult = 1.5 (karena ML disagree + volatile)
3. Effective max loss = $49.45 × 1.0 = $49.45
4. BACKUP-SL trigger di: $49.45 × 0.30 = **$14.84**
5. **Tapi trade closed di -$34.70!** ← Kenapa?
**Root Cause:** Grace period + momentum detection gagal!
### RECOMMENDATION: Add Emergency Hard Cap
```python
# Line ~1100 - smart_risk_manager.py
# BEFORE any other checks:
# === CHECK 0.0: EMERGENCY HARD CAP ===
# Absolute max loss regardless of ATR/grace/multipliers
EMERGENCY_MAX_LOSS = 20.0 # $20 absolute cap
if current_profit <= -EMERGENCY_MAX_LOSS:
return True, ExitReason.POSITION_LIMIT, (
f"[EMERGENCY CAP] Loss ${abs(current_profit):.2f} exceeded ${EMERGENCY_MAX_LOSS} hard limit"
)
```
**Benefits:**
- Prevents catastrophic losses like -$34.70
- Bypasses ALL grace periods and multipliers
- $20 cap = reasonable for 0.01 lot gold trading
- Can adjust based on lot size: `EMERGENCY_MAX_LOSS = 2000 * guard.lot_size`
**Dynamic per lot:**
```python
# Better: scale with lot size
emergency_cap_per_lot = 2000 # $20 per 0.01 lot
EMERGENCY_MAX_LOSS = emergency_cap_per_lot * guard.lot_size
# 0.01 lot = $20 cap
# 0.02 lot = $40 cap
# 0.03 lot = $60 cap
```
---
## 2. NIGHT TRADING - SKIP BLOCK ✅
**User feedback:** Bot harus bisa handle, tidak usah block.
**Current analysis:** Night trading (22:00-23:59) results:
- Win rate: 14.3%
- Loss: -$76.90 (78% of total daily loss!)
**Recommendation:** TETAP MONITOR, tapi add safety features:
1. ✅ Keep trading at night (no block)
2. ✅ Add spread filter (block jika spread >30 pips)
3. ✅ Tighten grace period at night (8m → 4m)
4. ✅ Lower max loss at night (use sm × 0.7 multiplier)
```python
# main_live.py - spread filter
wib_hour = datetime.now(ZoneInfo("Asia/Jakarta")).hour
if wib_hour >= 22 or wib_hour <= 5:
# Night session: stricter entry
spread_limit = 20 # Tighter spread limit
if spread > spread_limit:
logger.info(f"Night spread too wide: {spread:.1f} > {spread_limit}")
return # Skip entry, don't block entirely
```
**Alternative:** Reduce lot size at night
```python
# smart_risk_manager.py
def calculate_safe_lot(...):
...
wib_hour = datetime.now(ZoneInfo("Asia/Jakarta")).hour
if 22 <= wib_hour or wib_hour <= 5:
# Night: reduce lot by 50%
recommended_lot *= 0.5
logger.info(f"Night trading: reduced lot to {recommended_lot:.2f}")
...
```
---
## 3. FUZZY THRESHOLD 0.70 - ANALISA ❓
**Current:**
```python
# Line 1150 - smart_risk_manager.py
if exit_confidence > 0.75:
# FUZZY HIGH exit
# Line 1157 - Kelly Criterion
if 0.50 < exit_confidence <= 0.75:
# PARTIAL EXIT via Kelly
```
**User question:** Apakah raise ke 0.70 oke?
### PROBLEM ANALYSIS
**Small wins (+$0.01, +$0.34, +$0.41) disebabkan oleh:**
1. **Fuzzy triggering too early?** NO!
- Fuzzy HIGH threshold is 0.75 (quite high)
- Small wins likely triggered by velocity/momentum exits (CHECK 0C, 0D, 0E, 0F)
2. **What actually caused small wins?**
```
Looking at trade logs:
- [FUZZY HIGH] Exit confidence: 94.58% (profit=$0.71, vel=-0.175)
- [FUZZY HIGH] Exit confidence: 93.20% (profit=$0.34, vel=-0.092)
```
**Analysis:** Fuzzy confidence 93-95% adalah SANGAT TINGGI!
- Velocity negative strong
- Acceleration negative
- Price momentum fading
**Conclusion:** Fuzzy BENAR! Market memang reversal, exit tepat.
3. **The REAL problem:** Trade tidak sampai $10+ karena:
- Market tidak trending strong
- Volatility rendah (ATR kecil)
- TP target terlalu jauh ($30-35) untuk market ranging
### RECOMMENDATION: JANGAN RAISE FUZZY!
**Current 0.75 threshold sudah optimal.**
**Yang perlu diubah:**
1. **Lower early exit sensitivity** (CHECK 0C-0F terlalu aggressive)
2. **Adjust TP targets** based on regime:
```python
if regime == "ranging":
tp_hard = 0.60 * atr_unit # Lower TP for ranging
elif regime == "trending":
tp_hard = 1.50 * atr_unit # Higher TP for trending
```
3. **Add "momentum persistence" check:**
```python
# Don't exit on first velocity negative
# Require 2-3 consecutive negative readings
if _vel < 0 and guard.velocity_negative_count < 2:
guard.velocity_negative_count += 1
continue # Don't exit yet
```
**FUZZY 0.70 = TOO LOW!**
- Will exit at medium confidence (not optimal)
- May exit during temporary pullbacks
- Keep at **0.75** (current is good)
---
## 4. GRACE PERIOD - GIMANA CARA KERJANYA? ❓
### Current Implementation
```python
# Line 1065-1072 - smart_risk_manager.py
if regime in ("ranging", "mean_reverting"):
grace_minutes = 12 # Ranging: lots of room
elif regime in ("high_volatility", "volatile", "crisis"):
grace_minutes = 10 # Volatile: normal swings
elif regime == "trending":
grace_minutes = 6 # Trending: cut sooner
else:
grace_minutes = 8 # Default
```
### Cara Kerja Grace Period
**Grace period = "waiting time" sebelum trigger hard stops.**
**Example:**
```
Trade opened: 10:00:00
Grace period: 8 minutes
Grace ends: 10:08:00
Timeline:
10:00 - 10:08 → In grace, BACKUP-SL DISABLED
10:08+ → Grace ended, BACKUP-SL ENABLED
If loss = -$7 at 10:05 (5 min):
→ NO EXIT (still in grace)
If loss = -$7 at 10:10 (10 min):
→ EXIT via BACKUP-SL (grace ended)
```
**Checks that RESPECT grace period:**
- BACKUP-SL (line 1570): `if trade_age_minutes >= grace_minutes`
- ATR-STOP (line 1490): `if trade_age_minutes >= hard_stop_min_age`
- STALL detection (line 1579): `if trade_age_minutes >= 8`
**Checks that BYPASS grace (emergency):**
- VELOCITY EMERGENCY (line 1511): Always active
- FUZZY HIGH (line 1150): Always active
- Kelly partial (line 1157): Always active
### PROBLEM dengan Grace Period
**Case -$34.70 loss:**
```
Likely scenario:
- Trade opened at 23:30
- Regime: medium_volatility → grace = 8 minutes
- Trade crashed FAST (within 3-4 minutes)
- Loss hit -$34.70 at ~23:33-23:34 (4 min)
- Still in grace period → BACKUP-SL tidak trigger
- Velocity emergency tidak trigger (velocity not fast enough initially)
- Fuzzy tidak trigger (confidence masih <0.75 karena trade baru)
- Result: Hold loss sampai -$34.70 then exit via fuzzy/kelly
```
**Root cause:** Grace period TOO GENEROUS untuk fast crashes!
### RECOMMENDATION: Dynamic Grace Based on Loss Velocity
```python
# Line ~1065 - smart_risk_manager.py
# Current: static grace based on regime
# Better: dynamic grace based on loss velocity
def calculate_dynamic_grace(regime, current_loss, trade_age_minutes):
# Base grace from regime
if regime in ("ranging", "mean_reverting"):
base_grace = 12
elif regime in ("high_volatility", "volatile", "crisis"):
base_grace = 10
elif regime == "trending":
base_grace = 6
else:
base_grace = 8
# If losing fast, SHORTEN grace
loss_rate = abs(current_loss) / max(trade_age_minutes, 1) # $/minute
if loss_rate > 10: # Losing >$10/min = CRASH
grace = min(base_grace, 3) # Emergency: max 3 min grace
elif loss_rate > 5: # Losing >$5/min = FAST
grace = min(base_grace, 5) # Fast: max 5 min grace
else:
grace = base_grace # Normal
return grace
# Usage:
grace_minutes = calculate_dynamic_grace(regime, current_profit, trade_age_minutes)
```
**Benefits:**
- Normal trades: full grace period (8-12 min)
- Fast crashes: grace shortened to 3-5 min
- Prevents -$34.70 scenarios
---
## 5. BUY ML CONFIDENCE - SKIP ✅
User feedback: Not needed.
**Acknowledged.** Will not change BUY ML confidence threshold.
---
## 6. EARLY CUT / PARTIAL EXIT - REVIEW EXISTING METHODS ✅
### Current Partial Exit Methods
#### A. Kelly Criterion (ACTIVE)
```python
# Line 1157 - smart_risk_manager.py
if 0.50 < exit_confidence <= 0.75:
should_exit, close_fraction, kelly_msg = self.kelly_scaler.get_exit_action(...)
# Partial close: 30-75% of position
```
**How it works:**
- Fuzzy confidence 0.50-0.75 = medium confidence
- Kelly calculates optimal hold fraction
- If kelly_hold < 0.70 → partial close
- Example: kelly_hold = 0.50 → close 50% position
**Current stats:** Used in recent trade:
```
#161272706 closed via: [KELLY PARTIAL] Kelly full exit: hold=0.01 (fuzzy=53.01%)
→ Saved from -$4.81 to -$1.77!
```
**STATUS: WORKING WELL! ✅**
#### B. Smart TP Levels (ACTIVE)
```python
# Line 1046-1054 - smart_risk_manager.py
tp_min = 0.35 * profit_mult * atr_unit # Dynamic min TP
tp_secure = 0.60 * profit_mult * atr_unit # Dynamic secure TP
tp_hard = 1.20 * profit_mult * atr_unit # Dynamic hard TP
```
**How it works:**
- Multiple TP levels based on ATR
- Profit multiplier adjusts based on regime/ML
- Example: ATR = $15
- tp_min = $5.25
- tp_secure = $9.00
- tp_hard = $18.00
**STATUS: ACTIVE, needs tuning**
#### C. BE-Shield (Breakeven Shield) (ACTIVE)
```python
# CHECK 0A - Line ~1180-1250
# Protects profit by moving SL to breakeven at certain levels
# Uses percentage-based drawdown:
# Peak $3 → 80% shield
# Peak $6 → 70% shield
# Peak $10 → 60% shield
```
**STATUS: WORKING ✅**
### PROBLEM: No Gradual Scaling Out
**Current:** All-or-nothing exits (100% close)
**Missing:** Gradual partial closes (25%, 50%, 75%)
### RECOMMENDATION: Add Tiered Partial Exits
```python
# NEW: Tiered scaling out system
def evaluate_partial_exit(current_profit, peak_profit, tp_hard):
"""
Scale out position gradually:
- 25% at tp_min (0.35 ATR)
- 25% at tp_secure (0.60 ATR)
- 25% at 75% of tp_hard
- 25% at tp_hard or trailing stop
"""
# Already closed fraction
closed_fraction = guard.closed_fraction if hasattr(guard, 'closed_fraction') else 0.0
# TP levels
tp_min = 0.35 * profit_mult * atr_unit
tp_secure = 0.60 * profit_mult * atr_unit
tp_75 = 0.90 * profit_mult * atr_unit
# Check each tier
if current_profit >= tp_min and closed_fraction < 0.25:
return True, 0.25, f"Partial 25% at TP min (${tp_min:.2f})"
elif current_profit >= tp_secure and closed_fraction < 0.50:
return True, 0.25, f"Partial 25% at TP secure (${tp_secure:.2f})"
elif current_profit >= tp_75 and closed_fraction < 0.75:
return True, 0.25, f"Partial 25% at 75% TP (${tp_75:.2f})"
else:
return False, 0.0, "Hold"
```
**Benefits:**
- Lock in profits gradually
- Reduce risk while keeping upside
- Better than all-or-nothing exits
- Example: $0.99 win → could become $5+ with trailing 25%
**Implementation:** Requires MT5 partial close support (already available via `close_partial()` method).
---
## 7. CODE REVIEW - DEAD CODE REMOVAL ✅
### Scan Results
#### A. Commented "DISABLED" Features
**Location:** `smart_risk_manager.py` Line 1462-1467
```python
# === CHECK 1.5: FAST REVERSAL (small profit, ATR-scaled) ===
# v4: DISABLED — small profit exits killed winning trades in v3/v3b
# === CHECK 2: SMART EARLY EXIT (small profit, scaled) ===
# v4: DISABLED — taking small profits prevents reaching $10+ targets
```
**Status:** NOT dead code! Comments explain WHY feature was disabled, but simplified logic remains below.
**Action:** ✅ KEEP (good documentation)
#### B. Unused Imports
**Found:** None critical. All imports are used.
#### C. Potentially Unused Features
##### 1. HJB Solver (Optimal Stopping)
**File:** `src/optimal_stopping_solver.py`
**Usage:** Initialized but rarely triggered
```python
# Line 470 - smart_risk_manager.py
self.hjb_solver = OptimalStoppingHJB(...)
```
**Check usage:**
```bash
grep -r "hjb_solver" src/ main_live.py
```
**Result:** Not found in evaluate_position()!
**ACTION:** ⚠️ DEAD FEATURE - Remove or implement
##### 2. Volume Toxicity Detector
**File:** `src/order_flow_metrics.py`
**Usage:** Initialized but not used in exits
```python
# Line 476 - smart_risk_manager.py
self.toxicity_detector = VolumeToxicityDetector(...)
```
**Check usage:**
```bash
grep -r "toxicity_detector.calculate" src/
```
**Result:** Not found!
**ACTION:** ⚠️ DEAD FEATURE - Remove or implement
##### 3. PID Controller
**File:** `src/pid_exit_controller.py`
**Usage:** Initialized but not used
**ACTION:** ⚠️ DEAD FEATURE - Remove or implement
##### 4. Extended Kalman Filter (EKF)
**File:** `src/extended_kalman_filter.py`
**Usage:** Initialized but fallback to basic Kalman
```python
# Line 165 - smart_risk_manager.py
try:
from src.extended_kalman_filter import ExtendedKalmanFilter
except ImportError:
logger.warning("ExtendedKalmanFilter not available...")
```
**STATUS:** Partial implementation, using basic Kalman instead
**ACTION:** ⚠️ Either complete EKF or remove (currently redundant)
### DEAD CODE SUMMARY
| Feature | File | Status | Action |
|---------|------|--------|--------|
| HJB Solver | optimal_stopping_solver.py | Initialized, not used | Remove or implement |
| Volume Toxicity | order_flow_metrics.py | Initialized, not used | Remove or implement |
| PID Controller | pid_exit_controller.py | Initialized, not used | Remove or implement |
| Extended Kalman | extended_kalman_filter.py | Partial, fallback to basic | Complete or remove |
| Fuzzy Logic | fuzzy_exit_logic.py | ✅ ACTIVE | Keep |
| Kelly Criterion | kelly_position_scaler.py | ✅ ACTIVE | Keep |
| Basic Kalman | kalman_filter.py | ✅ ACTIVE | Keep |
### RECOMMENDATION: Clean Up v7 Advanced
**The v7 "Advanced Intelligence" has 7 systems, but only 3 are ACTUALLY used:**
1. ✅ Extended Kalman Filter → Fallback to basic Kalman (working)
2. ❌ PID Controller → NOT USED
3. ✅ Fuzzy Logic → ACTIVE
4. ❌ Order Flow Imbalance → NOT USED (no data)
5. ❌ Volume Toxicity → NOT USED
6. ❌ HJB Solver → NOT USED
7. ✅ Kelly Criterion → ACTIVE
**Action plan:**
```python
# smart_risk_manager.py - Line 440-480
# REMOVE unused systems initialization:
# DELETE:
# - PID Controller (not used)
# - HJB Solver (not used)
# - Toxicity Detector (not used)
# KEEP:
# - Kalman Filter (ACTIVE)
# - Fuzzy Logic (ACTIVE)
# - Kelly Criterion (ACTIVE)
```
**Benefits:**
- Cleaner code
- Faster initialization
- Less memory usage
- Remove complexity
---
## 📊 PRIORITY RECOMMENDATIONS
### PRIORITY 1: Emergency Hard Cap ⚠️⚠️⚠️
```python
# Add to line ~1100
EMERGENCY_MAX_LOSS = 2000 * guard.lot_size # $20 per 0.01 lot
if current_profit <= -EMERGENCY_MAX_LOSS:
EXIT IMMEDIATELY
```
**Impact:** Prevents -$34.70 catastrophic losses
### PRIORITY 2: Dynamic Grace Period 🔥
```python
# Modify line ~1065
grace_minutes = calculate_dynamic_grace(regime, current_loss, trade_age)
# Fast crashes: grace = 3-5 min
# Normal trades: grace = 8-12 min
```
**Impact:** Faster exit on crashes, prevents large losses
### PRIORITY 3: Night Safety Features 🌙
```python
# Add spread filter + lot reduction for night
if 22 <= hour <= 5:
- Spread limit: 20 pips
- Lot: reduce 50%
- Grace: reduce to 4-5 min
```
**Impact:** Better night trading results
### PRIORITY 4: Remove Dead Code 🗑️
```python
# Delete:
- HJB Solver (NOT USED)
- PID Controller (NOT USED)
- Toxicity Detector (NOT USED)
- Extended Kalman (use basic instead)
```
**Impact:** Cleaner codebase, faster performance
### PRIORITY 5: Tiered Partial Exits (Future) 💰
```python
# Implement gradual scaling:
- 25% at tp_min
- 25% at tp_secure
- 25% at 75% TP
- 25% trailing
```
**Impact:** Better profit capture ($0.99 → $5+)
---
## ✅ FINAL ANSWERS TO USER
1. **Dynamic max loss** → Already dynamic via ATR! Add emergency cap $20
2. **Night trading** → Don't block, add safety (spread filter + lot reduction)
3. **Fuzzy 0.70** → NO! Keep at 0.75 (current is optimal)
4. **Grace period** → Dynamic based on loss velocity (3-12 min)
5. **BUY ML confidence** → Skip as requested
6. **Early cut** → Kelly working! Add tiered partials in future
7. **Dead code** → Remove 4 unused v7 systems (PID, HJB, Toxicity, EKF)
---
**Mau saya implementasikan Priority 1-4 sekarang?**
(Emergency cap + Dynamic grace + Night safety + Dead code removal)