From ce4e96154135bf8277e7d9050f7ef217ea971ad5 Mon Sep 17 00:00:00 2001 From: cbazza Date: Fri, 30 Jan 2026 09:46:40 +0100 Subject: [PATCH] feat: Add Trend Reversal Detector with multi-signal analysis New features: - Reversal Detector with 5 detection signals: - RSI Divergence (bearish/bullish) - EMA Slope Change detection - Volume Spike analysis - Candlestick patterns (Doji, Engulfing, Hammer, Pin Bar) - Break of Structure detection - Integrated into enhanced_trading_check_wrapper (SCHRITT 2.5) - Defensive mode: blocks trades at 70%+ reversal score - Lot size reduction at 30-69% reversal score - Enable Overlap session (13:00-16:00 UTC) Files added: - reversal_detector.py: Core detection algorithms - reversal_integration.py: Bot integration wrapper - REVERSAL_DETECTOR_INTEGRATION.md: Documentation Modified: - TradingBot notebook: Added reversal check integration - session_filter_patch.py: Enabled overlap session Co-Authored-By: Claude Opus 4.5 --- REVERSAL_DETECTOR_INTEGRATION.md | 221 ++++++ ...Bot_V1.6_Adaptive_Complete_CORRECTED.ipynb | 651 +++++++++++++----- reversal_detector.py | 633 +++++++++++++++++ reversal_integration.py | 287 ++++++++ session_filter_patch.py | 8 +- 5 files changed, 1623 insertions(+), 177 deletions(-) create mode 100644 REVERSAL_DETECTOR_INTEGRATION.md create mode 100644 reversal_detector.py create mode 100644 reversal_integration.py diff --git a/REVERSAL_DETECTOR_INTEGRATION.md b/REVERSAL_DETECTOR_INTEGRATION.md new file mode 100644 index 0000000..3cebd5a --- /dev/null +++ b/REVERSAL_DETECTOR_INTEGRATION.md @@ -0,0 +1,221 @@ +# 🔄 Reversal Detector Integration Guide + +## Schnell-Integration + +### Schritt 1: Import hinzufügen (neue Cell nach den Imports) + +```python +# ========================================== +# 🔄 REVERSAL DETECTOR INTEGRATION +# ========================================== + +from reversal_integration import ( + reversal_detector, + check_reversal_risk, + get_reversal_status, + enable_reversal_check, + disable_reversal_check, + REVERSAL_CONFIG +) + +print(get_reversal_status()) +``` + +### Schritt 2: In `enhanced_trading_check_wrapper` einfügen + +Füge nach **SCHRITT 2: Signal Analysis** und vor **SCHRITT 3: ENHANCED SIGNAL SCORING** folgenden Code ein: + +```python + # ========================================== + # ⭐ SCHRITT 2.5: REVERSAL CHECK (NEU!) + # ========================================== + from reversal_integration import check_reversal_risk + + reversal_result = check_reversal_risk(signal_info, symbol) + + print(f"\n🔄 Reversal Check: {reversal_result['action']}") + print(f" Score: {reversal_result['reversal_score']}%") + print(f" Reason: {reversal_result['reason']}") + + if not reversal_result['should_trade']: + print(f"⛔ TRADE BLOCKIERT durch Reversal Detector!") + return None + + # Reversal Lot Multiplier mit Equity Curve kombinieren + if reversal_result['lot_multiplier'] < 1.0: + lot_multiplier *= reversal_result['lot_multiplier'] + print(f"📉 Reversal: Lot Multiplier angepasst auf {lot_multiplier:.0%}") + # ========================================== +``` + +--- + +## Vollständige enhanced_trading_check_wrapper mit Reversal Check + +```python +def enhanced_trading_check_wrapper(symbol="XAUUSD", debug=False): + """ + Enhanced wrapper around execute_trade_v2_adaptive + Adds multi-factor signal scoring before execution + + Reversal Detection (NEU!) + """ + + try: + # ⭐ SCHRITT 0: SESSION CHECK + from session_filter_patch import is_session_allowed + current_session = rhythm_manager.get_current_session() + session_allowed, session_reason = is_session_allowed(current_session) + + if not session_allowed: + print(f"⛔ SESSION BLOCKED: {current_session.upper()}") + print(f" Reason: {session_reason}") + return None + + print(f"✅ Session OK: {current_session.upper()}") + + # SCHRITT 1: Position Check + max_positions = TRADING_CONFIG['risk']['max_positions'] + has_position, position_info = check_existing_positions(symbol) + + if position_info['count'] >= max_positions: + if debug: + print(f"🛑 TRADE BLOCKIERT: {position_info['count']}/{max_positions} Positionen aktiv") + return None + + print(f"✅ Position-Check OK: {position_info['count']}/{max_positions}") + + # SCHRITT 1.5: EQUITY CURVE CHECK + ec_allowed, ec_reason, lot_multiplier = equity_curve_manager.should_trade() + print(f"📈 Equity Curve: {ec_reason}") + + if not ec_allowed: + print(f"⛔ TRADE BLOCKIERT durch Equity Curve Filter") + return None + + # SCHRITT 2: Signal Analysis + signal_info = extended_top_down_v2_adaptive(symbol) + if signal_info is None: + print("❌ Signal-Analyse fehlgeschlagen") + return None + + entry_signal = signal_info["entry_signal"] + base_confidence = signal_info["confidence"] + adaptive_threshold = signal_info["adaptive_threshold"] + + print(f"\n📊 Base Signal Analysis:") + print(f" Direction: {entry_signal}") + print(f" Base Confidence: {base_confidence:.1f}%") + print(f" Adaptive Threshold: {adaptive_threshold:.1f}%") + + # ========================================== + # ⭐ SCHRITT 2.5: REVERSAL CHECK (NEU!) + # ========================================== + from reversal_integration import check_reversal_risk + + reversal_result = check_reversal_risk(signal_info, symbol) + + print(f"\n🔄 Reversal Check: {reversal_result['action']}") + print(f" Score: {reversal_result['reversal_score']}%") + print(f" Reason: {reversal_result['reason']}") + + if not reversal_result['should_trade']: + print(f"⛔ TRADE BLOCKIERT durch Reversal Detector!") + return None + + # Reversal Lot Multiplier kombinieren + if reversal_result['lot_multiplier'] < 1.0: + lot_multiplier *= reversal_result['lot_multiplier'] + print(f"📉 Reversal: Lot Multiplier angepasst auf {lot_multiplier:.0%}") + # ========================================== + + # ⭐ SCHRITT 3: ENHANCED SIGNAL SCORING (HYBRID 60/40) + # ... (Rest des Codes bleibt unverändert) +``` + +--- + +## Kontroll-Befehle + +Nach der Integration kannst du folgende Befehle nutzen: + +```python +# Status anzeigen +print(get_reversal_status()) + +# Reversal Check deaktivieren +disable_reversal_check() + +# Reversal Check aktivieren +enable_reversal_check() + +# Thresholds anpassen +REVERSAL_CONFIG['block_threshold'] = 80 # Weniger strikt +REVERSAL_CONFIG['reduce_threshold'] = 60 +REVERSAL_CONFIG['caution_threshold'] = 40 +``` + +--- + +## Erwartetes Output + +``` +✅ Session OK: ASIAN +✅ Position-Check OK: 0/1 +📈 Equity Curve: ✅ Equity $108,500.00 > MA $107,200.00 (+1.2%) + +📊 Base Signal Analysis: + Direction: 1 + Base Confidence: 87.5% + Adaptive Threshold: 60.0% + +🔄 REVERSAL CHECK (UPTREND): +-------------------------------------------------- + Rsi Divergence : ✅ No divergence + Ema Slope Change : ✅ Slope: 0.0045% + Volume Spike : ✅ Volume: 1.3x average + Candlestick : ✅ No reversal pattern + Break Of Structure : ✅ Structure intact +-------------------------------------------------- + ✅ Reversal Score: 15% (LOW) + Action: ALLOW | Lot Mult: 100% + +🔄 Reversal Check: ALLOW + Score: 15% + Reason: No significant reversal risk (15%) + +🎯 Calculating Enhanced Signal Score... +``` + +--- + +## Bei hohem Reversal-Risiko + +``` +🔄 REVERSAL CHECK (UPTREND): +-------------------------------------------------- + Rsi Divergence : ⚠️ Bearish Divergence: Price HH, RSI LH (RSI diff: 8.5) + Strength: 65% + Ema Slope Change : ⚠️ Slope weakening: 0.0089% -> 0.0012% + Strength: 45% + Volume Spike : ⚠️ Volume: 2.8x average (SPIKE!) + Strength: 40% + Candlestick : ⚠️ Shooting Star: Potential bearish reversal + Strength: 60% + Break Of Structure : ✅ Structure intact +-------------------------------------------------- + 🔴 Reversal Score: 78% (CRITICAL) + Action: BLOCK | Lot Mult: 0% + +🔄 Reversal Check: BLOCK + Score: 78% + Reason: High reversal risk (78% >= 70%) +⛔ TRADE BLOCKIERT durch Reversal Detector! +``` + +--- + +## Dateien + +- `reversal_detector.py` - Haupt-Modul mit allen Algorithmen +- `reversal_integration.py` - Integration für den Trading Bot +- `REVERSAL_DETECTOR_INTEGRATION.md` - Diese Anleitung diff --git a/TradingBot_V1.6_Adaptive_Complete_CORRECTED.ipynb b/TradingBot_V1.6_Adaptive_Complete_CORRECTED.ipynb index eae11de..00373dc 100644 --- a/TradingBot_V1.6_Adaptive_Complete_CORRECTED.ipynb +++ b/TradingBot_V1.6_Adaptive_Complete_CORRECTED.ipynb @@ -3022,6 +3022,7 @@ "from enhanced_trailing_stop import EnhancedTrailingStopManager, create_enhanced_position_monitor\n", "from equity_curve_trading import EquityCurveManager\n", "from demo_test_tracker import DemoTestTracker\n", + "from reversal_integration import check_reversal_risk, get_reversal_status, REVERSAL_CONFIG\n", "\n", "print(\"🚀 INITIALIZING ADVANCED OPTIMIZATIONS...\")\n", "print(\"=\" * 70)\n", @@ -3114,6 +3115,10 @@ "print(\"✅ Demo Test Tracker initialized\")\n", "print()\n", "\n", + "# 6. Reversal Detector\n", + "print(\"✅ Reversal Detector initialized\")\n", + "print(get_reversal_status())\n", + "\n", "# 4. Run initial threshold optimization\n", "print(\"🔄 Running initial threshold optimization...\")\n", "try:\n", @@ -3133,6 +3138,7 @@ "print(\" • Enhanced Trailing: ✅ (multi-tier protection)\")\n", "print(\" • Equity Curve Trading: ✅ (auto-pause on drawdown)\")\n", "print(\" • Demo Test Tracker: ✅ (go-live readiness check)\")\n", + "print(\" • Reversal Detector: ✅ (multi-signal protection)\")\n", "print()\n", "print(\"💡 Tip: Use 'threshold_optimizer.generate_report()' for details\")" ] @@ -3719,6 +3725,26 @@ " print(f\" Base Confidence: {base_confidence:.1f}%\")\n", " print(f\" Adaptive Threshold: {adaptive_threshold:.1f}%\")\n", "\n", + " # ==========================================\n", + " # ⭐ SCHRITT 2.5: REVERSAL CHECK (NEU!)\n", + " # ==========================================\n", + " from reversal_integration import check_reversal_risk\n", + "\n", + " reversal_result = check_reversal_risk(signal_info, symbol)\n", + "\n", + " print(f\"🔄 Reversal Check: {reversal_result['action']}\")\n", + " print(f\" Score: {reversal_result['reversal_score']}%\")\n", + " print(f\" Reason: {reversal_result['reason']}\")\n", + "\n", + " if not reversal_result['should_trade']:\n", + " print(f\"⛔ TRADE BLOCKIERT durch Reversal Detector!\")\n", + " return None\n", + "\n", + " # Reversal Lot Multiplier mit Equity Curve kombinieren\n", + " if reversal_result['lot_multiplier'] < 1.0:\n", + " lot_multiplier *= reversal_result['lot_multiplier']\n", + " print(f\"📉 Reversal: Lot Multiplier angepasst auf {lot_multiplier:.0%}\")\n", + "\n", " # ⭐ SCHRITT 3: ENHANCED SIGNAL SCORING (HYBRID 60/40)\n", " print(f\"\\n🎯 Calculating Enhanced Signal Score...\")\n", "\n", @@ -3899,99 +3925,10 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": null, "id": "a5c25689", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "======================================================================\n", - "📊 DEMO TEST TRACKER\n", - "======================================================================\n", - "\n", - "======================================================================\n", - "📊 DEMO TEST TRACKER - PERFORMANCE REPORT\n", - "======================================================================\n", - "\n", - "📅 Demo Period:\n", - " Start: 2026-01-28\n", - " Days Running: 1\n", - " Last Trade: 2026-01-29\n", - "\n", - "📈 PERFORMANCE METRICS:\n", - " Total Trades: 348\n", - " Wins/Losses: 177/171\n", - " Win Rate: 50.9%\n", - " Profit Factor: 1.42\n", - "\n", - "💰 PROFIT/LOSS:\n", - " Total Profit: $4,598.21\n", - " Avg Win: $88.50\n", - " Avg Loss: $64.72\n", - " Avg Trade: $13.21\n", - " Best Trade: $915.60\n", - " Worst Trade: $-345.70\n", - "\n", - "📉 RISK METRICS:\n", - " Max Drawdown: 100.0% ($1,972.65)\n", - " Current Equity: $4,598.21\n", - " Peak Equity: $4,914.21\n", - "\n", - "⏱️ TIMING:\n", - " Avg Duration: 49 min\n", - "\n", - "🌍 SESSION BREAKDOWN:\n", - " ASIAN | Trades: 155 | Win Rate: 54.2% | Profit: $3,270.77\n", - " LONDON | Trades: 81 | Win Rate: 46.9% | Profit: $654.12\n", - " NY | Trades: 112 | Win Rate: 49.1% | Profit: $673.32\n", - "\n", - "🎯 SIGNAL QUALITY BREAKDOWN:\n", - " UNKNOWN | Trades: 348 | Win Rate: 50.9% | Profit: $4,598.21\n", - "\n", - "======================================================================\n", - "\n", - "\n", - "\n", - "======================================================================\n", - "🚦 GO-LIVE READINESS CHECK\n", - "======================================================================\n", - " ✅ Trades: 348/50\n", - " ⬜ Win Rate: 50.9% (min 55%)\n", - " ✅ Profit Factor: 1.42 (min 1.3)\n", - " ⬜ Max Drawdown: 100.0% (max 15%)\n", - " ⬜ Days Running: 1/14\n", - " ✅ Errors: 0 (max 5)\n", - " ✅ Sessions Tested: 3/2\n", - "----------------------------------------------------------------------\n", - " Passed: 4/7\n", - "\n", - " ⏳ STATUS: NOT READY YET\n", - " Still needed:\n", - " • Win Rate: 50.9% (min 55%)\n", - " • Max Drawdown: 100.0% (max 15%)\n", - " • Days Running: 1/14\n", - "======================================================================\n", - "\n", - "📊 Daily Summary - 2026-01-29\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Today: 16 trades | 9 wins | WR: 56% | P/L: $+1111.80\n", - "Overall: 348 trades | WR: 50.9% | Total: $+4598.21\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\n", - "⏳ Weiter testen... Der Bot sammelt noch Daten.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-01-29 10:46:29,000 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n" - ] - } - ], + "outputs": [], "source": [ "# ==========================================\n", "# 📊 DEMO TEST TRACKER - REPORTS & GO-LIVE CHECK\n", @@ -4561,90 +4498,11 @@ "id": "cf605503", "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "💰 MT5 P&L TRACKER - LIVE PERFORMANCE DASHBOARD\n", - "================================================================================\n", - "\n", - "Generated: 2026-01-29 10:46:35\n", - "\n", - "================================================================================\n", - "📊 ALL TIME PERFORMANCE\n", - "================================================================================\n", - "\n", - "Total Trades: 408\n", - "Winning Trades: 202 (49.5%)\n", - "Losing Trades: 206\n", - "\n", - "Net Profit: $3513.54\n", - "Total Profit: $12873.24\n", - "Total Loss: $9359.70\n", - "Profit Factor: 1.38\n", - "\n", - "Average Win: $63.73\n", - "Average Loss: $-45.44\n", - "Largest Win: $499.30\n", - "Largest Loss: $-151.75\n", - "\n", - "Max Drawdown: $-1981.78\n", - "Avg Duration: 1.0 hours\n", - "Total Pips: 5626600.0\n", - "\n", - "================================================================================\n", - "📅 THIS MONTH\n", - "================================================================================\n", - "\n", - "Trades: 332 (50.6% WR)\n", - "Net Profit: $3486.41\n", - "Profit/Loss: +$12558.73 / -$9072.32\n", - "\n", - "================================================================================\n", - "📅 THIS WEEK\n", - "================================================================================\n", - "\n", - "Trades: 166 (58.4% WR)\n", - "Net Profit: $3545.17\n", - "Profit/Loss: +$9536.97 / -$5991.80\n", - "\n", - "================================================================================\n", - "📅 TODAY\n", - "================================================================================\n", - "\n", - "❌ No trades today\n", - "\n", - "================================================================================\n", - "\n", - "================================================================================\n", - "📜 RECENT TRADES (Last 10)\n", - "================================================================================\n", - "\n", - " position_id symbol type entry_time exit_time net_profit pips duration_hours status\n", - " 719790790 XAUUSD LONG 2026-01-28 18:31 2026-01-28 21:24 499.30 499300.0 2.9 ✅ WIN\n", - " 719088260 XAUUSD LONG 2026-01-28 17:07 2026-01-28 17:58 153.20 306400.0 0.9 ✅ WIN\n", - " 718932869 XAUUSD LONG 2026-01-28 16:39 2026-01-28 17:06 -59.05 -118100.0 0.5 ❌ LOSS\n", - " 718905388 XAUUSD LONG 2026-01-28 16:35 2026-01-28 16:38 -87.76 -109700.0 0.1 ❌ LOSS\n", - " 718788969 XAUUSD LONG 2026-01-28 16:12 2026-01-28 16:34 34.45 68900.0 0.4 ✅ WIN\n", - " 718746714 XAUUSD LONG 2026-01-28 16:05 2026-01-28 16:11 -106.10 -106100.0 0.1 ❌ LOSS\n", - " 718592815 XAUUSD LONG 2026-01-28 15:29 2026-01-28 16:04 131.10 262200.0 0.6 ✅ WIN\n", - " 718467996 XAUUSD LONG 2026-01-28 15:03 2026-01-28 15:28 15.00 30000.0 0.4 ✅ WIN\n", - " 718377011 XAUUSD LONG 2026-01-28 14:38 2026-01-28 15:03 15.00 30000.0 0.4 ✅ WIN\n", - " 718312889 XAUUSD LONG 2026-01-28 14:22 2026-01-28 14:37 15.00 30000.0 0.3 ✅ WIN\n", - "\n", - "================================================================================\n", - "✅ Dashboard refresh complete!\n", - "Last updated: 2026-01-29 10:46:35\n", - "================================================================================\n" - ] - }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-01-29 10:46:39,047 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", - "2026-01-29 10:46:49,067 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n" + "2026-01-30 09:33:47,749 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n" ] } ], @@ -4691,8 +4549,455 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🧪 Testing Reversal Detector...\n", + "============================================================\n", + "✅ Import erfolgreich\n", + "\n", + "============================================================\n", + "🔄 REVERSAL DETECTOR STATUS\n", + "============================================================\n", + " Enabled: True\n", + " Mode: defensive\n", + " Block Threshold: 70%\n", + " Reduce Threshold: 50%\n", + " Caution Threshold: 30%\n", + "============================================================\n", + "\n", + "🔍 Testing with live market data...\n", + "🔍 Analyzing XAUUSD with V1.6 ADAPTIVE COMPLETE parameters...\n", + "\n", + "📊 V1.6 ADAPTIVE COMPLETE Trend-Analyse für XAUUSD\n", + "⚡ Adaptive Interval: 5 min | Session: LONDON\n", + "🎯 Market Regime: RANGING (Strength: 21%)\n", + "🎚️ Adaptive Threshold: 70% (RELAXED)\n", + "\n", + "+------+-----------+------------+----------+----------+---------+\n", + "| TF | Trend | Strength | ATR | Slope | Price |\n", + "|------+-----------+------------+----------+----------+---------|\n", + "| D1 | uptrend | 463.42 | 157.145 | 10.9236 | 5069.5 |\n", + "| H4 | uptrend | 362.48 | 116.225 | 6.31934 | 5069.18 |\n", + "| H1 | uptrend | 349.09 | 82.1467 | 4.30149 | 5069.18 |\n", + "| M30 | uptrend | 228.93 | 63.3682 | 2.17604 | 5069.18 |\n", + "| M15 | downtrend | 273.87 | 44.4494 | -1.82601 | 5068.79 |\n", + "| M5 | downtrend | 490.87 | 25.6075 | -1.88549 | 5068.66 |\n", + "+------+-----------+------------+----------+----------+---------+\n", + "\n", + "➡️ Standard-Trend: uptrend (Strength: 423.04)\n", + "➡️ Fast-Trend: uptrend (Required: 2/4)\n", + "➡️ Top-Down-Trend: uptrend\n", + "➡️ Confidence: 83.69% (Threshold: 70%)\n", + "➡️ Risk-Adjusted Strength: 79947.2 (Min: 80)\n", + "➡️ Signal Quality: EXCELLENT\n", + "\n", + "🚀 V1.6 Adaptive Complete: Full Features + Adaptive Rhythm\n", + "\n", + "📊 Signal Info:\n", + " Entry Signal: 1\n", + " Standard Trend: uptrend\n", + " Confidence: 83.69%\n", + "\n", + "🔄 Running Reversal Check...\n", + "\n", + "🔄 REVERSAL CHECK (UPTREND):\n", + "--------------------------------------------------\n", + " Rsi Divergence : ✅ No divergence\n", + " Ema Slope Change : ⚠️ Slope weakening: -0.1010% -> -0.4427%\n", + " Strength: 100%\n", + " Volume Spike : ✅ Volume: 0.4x average\n", + " Candlestick : ⚠️ Bearish Engulfing: Strong reversal signal\n", + " Strength: 70%\n", + " Break Of Structure : ✅ Structure intact\n", + "--------------------------------------------------\n", + " ⚠️ Reversal Score: 30% (MODERATE)\n", + " Action: CAUTION | Lot Mult: 75%\n", + "\n", + "📊 Reversal Check Result:\n", + " Should Trade: True\n", + " Reversal Score: 30%\n", + " Action: CAUTION\n", + " Lot Multiplier: 75%\n", + " Reason: Low reversal risk (30%), lot reduced to 75%\n", + "\n", + "🔍 Signal Details:\n", + " rsi_divergence: ✅ No divergence\n", + " ema_slope_change: ⚠️ Slope weakening: -0.1010% -> -0.4427%\n", + " volume_spike: ✅ Volume: 0.4x average\n", + " candlestick: ⚠️ Bearish Engulfing: Strong reversal signal\n", + " break_of_structure: ✅ Structure intact\n", + "\n", + "============================================================\n", + "✅ Reversal Detector Test Complete\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:35:18,013 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:35:28,040 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:35:38,065 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:35:48,079 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:35:54,233 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:36:54 CET)\" (scheduled at 2026-01-30 09:35:54.085516+01:00)\n", + "2026-01-30 09:35:54,233 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:36:54 CET)\" executed successfully\n", + "2026-01-30 09:35:58,110 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:35:58,259 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:36:58 CET)\" (scheduled at 2026-01-30 09:35:58.257297+01:00)\n", + "2026-01-30 09:35:58,261 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:36:58 CET)\" executed successfully\n", + "2026-01-30 09:36:01,020 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:01 CET)\" (scheduled at 2026-01-30 09:36:01.013912+01:00)\n", + "2026-01-30 09:36:01,020 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:36:08,139 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:18,153 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:28,187 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:38,216 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:48,244 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:54,086 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:54 CET)\" (scheduled at 2026-01-30 09:36:54.085516+01:00)\n", + "2026-01-30 09:36:54,090 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:54 CET)\" executed successfully\n", + "2026-01-30 09:36:58,280 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:36:58,808 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:58 CET)\" (scheduled at 2026-01-30 09:36:58.257297+01:00)\n", + "2026-01-30 09:36:58,809 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:37:58 CET)\" executed successfully\n", + "2026-01-30 09:37:01,074 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:01 CET)\" (scheduled at 2026-01-30 09:37:01.013912+01:00)\n", + "2026-01-30 09:37:01,076 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:37:01,731 - INFO - Running job \"Demo Tracker Sync (trigger: interval[0:05:00], next run at: 2026-01-30 09:42:01 CET)\" (scheduled at 2026-01-30 09:37:01.544620+01:00)\n", + "2026-01-30 09:37:01,842 - INFO - 📊 Trade logged: 🔴 #734745233 LONG XAUUSD | Profit: $-129.50\n", + "2026-01-30 09:37:01,844 - INFO - Job \"Demo Tracker Sync (trigger: interval[0:05:00], next run at: 2026-01-30 09:42:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "📊 Auto-synced #734745233: LONG XAUUSD | stop_loss | P/L: $-129.50\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:37:08,306 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:37:18,332 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:37:28,357 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:37:38,382 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:37:48,405 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:37:54,087 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:54 CET)\" (scheduled at 2026-01-30 09:37:54.085516+01:00)\n", + "2026-01-30 09:37:54,089 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:54 CET)\" executed successfully\n", + "2026-01-30 09:37:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:58 CET)\" (scheduled at 2026-01-30 09:37:58.257297+01:00)\n", + "2026-01-30 09:37:58,261 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:38:58 CET)\" executed successfully\n", + "2026-01-30 09:37:58,433 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:01,018 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:01 CET)\" (scheduled at 2026-01-30 09:38:01.013912+01:00)\n", + "2026-01-30 09:38:01,020 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:38:08,458 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:18,483 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:28,509 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:38,532 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:48,771 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:38:54,088 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:54 CET)\" (scheduled at 2026-01-30 09:38:54.085516+01:00)\n", + "2026-01-30 09:38:54,090 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:54 CET)\" executed successfully\n", + "2026-01-30 09:38:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:58 CET)\" (scheduled at 2026-01-30 09:38:58.257297+01:00)\n", + "2026-01-30 09:38:58,260 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:39:58 CET)\" executed successfully\n", + "2026-01-30 09:38:58,795 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:01,015 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:01 CET)\" (scheduled at 2026-01-30 09:39:01.013912+01:00)\n", + "2026-01-30 09:39:01,019 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:39:08,820 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:18,844 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:28,867 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:38,892 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:48,916 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:39:54,093 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:54 CET)\" (scheduled at 2026-01-30 09:39:54.085516+01:00)\n", + "2026-01-30 09:39:54,096 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:54 CET)\" executed successfully\n", + "2026-01-30 09:39:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:58 CET)\" (scheduled at 2026-01-30 09:39:58.257297+01:00)\n", + "2026-01-30 09:39:58,260 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:40:58 CET)\" executed successfully\n", + "2026-01-30 09:39:58,939 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:01,016 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:01 CET)\" (scheduled at 2026-01-30 09:40:01.013912+01:00)\n", + "2026-01-30 09:40:01,020 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:40:08,963 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:18,987 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:29,011 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:39,039 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:49,063 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:40:54,089 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:54 CET)\" (scheduled at 2026-01-30 09:40:54.085516+01:00)\n", + "2026-01-30 09:40:54,091 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:54 CET)\" executed successfully\n", + "2026-01-30 09:40:58,259 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:58 CET)\" (scheduled at 2026-01-30 09:40:58.257297+01:00)\n", + "2026-01-30 09:40:58,261 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:41:58 CET)\" executed successfully\n", + "2026-01-30 09:40:59,086 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:01,018 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:01 CET)\" (scheduled at 2026-01-30 09:41:01.013912+01:00)\n", + "2026-01-30 09:41:01,020 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:41:09,111 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:19,137 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:29,164 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:39,187 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:49,210 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:41:54,087 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:54 CET)\" (scheduled at 2026-01-30 09:41:54.085516+01:00)\n", + "2026-01-30 09:41:54,089 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:54 CET)\" executed successfully\n", + "2026-01-30 09:41:58,257 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:58 CET)\" (scheduled at 2026-01-30 09:41:58.257297+01:00)\n", + "2026-01-30 09:41:58,259 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:42:58 CET)\" executed successfully\n", + "2026-01-30 09:41:59,259 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:01,017 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:01 CET)\" (scheduled at 2026-01-30 09:42:01.013912+01:00)\n", + "2026-01-30 09:42:01,019 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:42:01,545 - INFO - Running job \"Demo Tracker Sync (trigger: interval[0:05:00], next run at: 2026-01-30 09:47:01 CET)\" (scheduled at 2026-01-30 09:42:01.544620+01:00)\n", + "2026-01-30 09:42:01,553 - INFO - Job \"Demo Tracker Sync (trigger: interval[0:05:00], next run at: 2026-01-30 09:47:01 CET)\" executed successfully\n", + "2026-01-30 09:42:09,291 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:19,314 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:29,336 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:39,359 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:49,382 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:42:54,087 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:54 CET)\" (scheduled at 2026-01-30 09:42:54.085516+01:00)\n", + "2026-01-30 09:42:54,088 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:54 CET)\" executed successfully\n", + "2026-01-30 09:42:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:58 CET)\" (scheduled at 2026-01-30 09:42:58.257297+01:00)\n", + "2026-01-30 09:42:58,260 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:43:58 CET)\" executed successfully\n", + "2026-01-30 09:42:59,407 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:01,015 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:01 CET)\" (scheduled at 2026-01-30 09:43:01.013912+01:00)\n", + "2026-01-30 09:43:01,018 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:43:09,429 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:19,454 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:29,478 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:39,502 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:49,527 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:43:54,087 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:54 CET)\" (scheduled at 2026-01-30 09:43:54.085516+01:00)\n", + "2026-01-30 09:43:54,089 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:54 CET)\" executed successfully\n", + "2026-01-30 09:43:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:58 CET)\" (scheduled at 2026-01-30 09:43:58.257297+01:00)\n", + "2026-01-30 09:43:58,260 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:44:58 CET)\" executed successfully\n", + "2026-01-30 09:43:59,551 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:01,066 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:01 CET)\" (scheduled at 2026-01-30 09:44:01.013912+01:00)\n", + "2026-01-30 09:44:01,068 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:44:09,573 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:19,597 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:29,620 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:39,643 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:49,667 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:44:54,103 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:54 CET)\" (scheduled at 2026-01-30 09:44:54.085516+01:00)\n", + "2026-01-30 09:44:54,105 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:54 CET)\" executed successfully\n", + "2026-01-30 09:44:58,257 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:58 CET)\" (scheduled at 2026-01-30 09:44:58.257297+01:00)\n", + "2026-01-30 09:44:58,259 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:45:58 CET)\" executed successfully\n", + "2026-01-30 09:44:59,692 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:01,014 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:01 CET)\" (scheduled at 2026-01-30 09:45:01.013912+01:00)\n", + "2026-01-30 09:45:01,018 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:45:09,715 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:19,739 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:29,761 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:39,787 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:49,812 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:45:54,102 - INFO - Running job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:54 CET)\" (scheduled at 2026-01-30 09:45:54.085516+01:00)\n", + "2026-01-30 09:45:54,104 - INFO - Job \"PositionMonitor.check_open_positions (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:54 CET)\" executed successfully\n", + "2026-01-30 09:45:58,258 - INFO - Running job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:58 CET)\" (scheduled at 2026-01-30 09:45:58.257297+01:00)\n", + "2026-01-30 09:45:58,260 - INFO - Job \"create_enhanced_position_monitor..enhanced_position_monitor (trigger: interval[0:01:00], next run at: 2026-01-30 09:46:58 CET)\" executed successfully\n", + "2026-01-30 09:45:59,836 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:46:01,016 - INFO - Running job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:47:01 CET)\" (scheduled at 2026-01-30 09:46:01.013912+01:00)\n", + "2026-01-30 09:46:01,019 - INFO - Job \"Enhanced Adaptive Trading Check (trigger: interval[0:01:00], next run at: 2026-01-30 09:47:01 CET)\" executed successfully\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⛔ SESSION BLOCKED: LONDON\n", + " Reason: London blocked: 12.5% win-rate, -$10/trade\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-01-30 09:46:09,859 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:46:19,888 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n", + "2026-01-30 09:46:29,914 - INFO - HTTP Request: POST https://api.telegram.org/bot7783303065:AAHVVvwWGqmhJ2BVq8LqkLRSsicKy1CUsD8/getUpdates \"HTTP/1.1 200 OK\"\n" + ] + } + ], + "source": [ + "# ==========================================\n", + "# 🧪 REVERSAL DETECTOR TEST\n", + "# ==========================================\n", + "\n", + "print(\"🧪 Testing Reversal Detector...\")\n", + "print(\"=\" * 60)\n", + "\n", + "# Test 1: Import prüfen\n", + "try:\n", + " from reversal_integration import check_reversal_risk, get_reversal_status, REVERSAL_CONFIG\n", + " print(\"✅ Import erfolgreich\")\n", + "except Exception as e:\n", + " print(f\"❌ Import fehlgeschlagen: {e}\")\n", + "\n", + "# Test 2: Status anzeigen\n", + "print(\"\\n\" + get_reversal_status())\n", + "\n", + "# Test 3: Mit echten Marktdaten testen\n", + "print(\"\\n🔍 Testing with live market data...\")\n", + "\n", + "signal_info = extended_top_down_v2_adaptive(\"XAUUSD\")\n", + "\n", + "if signal_info:\n", + " print(f\"\\n📊 Signal Info:\")\n", + " print(f\" Entry Signal: {signal_info['entry_signal']}\")\n", + " print(f\" Standard Trend: {signal_info.get('standard_trend', 'N/A')}\")\n", + " print(f\" Confidence: {signal_info['confidence']}%\")\n", + " \n", + " # Reversal Check durchführen\n", + " print(\"\\n🔄 Running Reversal Check...\")\n", + " result = check_reversal_risk(signal_info, \"XAUUSD\")\n", + " \n", + " print(f\"\\n📊 Reversal Check Result:\")\n", + " print(f\" Should Trade: {result['should_trade']}\")\n", + " print(f\" Reversal Score: {result['reversal_score']}%\")\n", + " print(f\" Action: {result['action']}\")\n", + " print(f\" Lot Multiplier: {result['lot_multiplier']:.0%}\")\n", + " print(f\" Reason: {result['reason']}\")\n", + " \n", + " if 'signals' in result and result['signals']:\n", + " print(f\"\\n🔍 Signal Details:\")\n", + " for signal_name, signal_data in result['signals'].items():\n", + " status = \"⚠️\" if signal_data.get('detected', False) else \"✅\"\n", + " print(f\" {signal_name}: {status} {signal_data.get('description', 'N/A')}\")\n", + "else:\n", + " print(\"❌ Could not get signal info\")\n", + "\n", + "print(\"\\n\" + \"=\" * 60)\n", + "print(\"✅ Reversal Detector Test Complete\")" + ] }, { "cell_type": "code", diff --git a/reversal_detector.py b/reversal_detector.py new file mode 100644 index 0000000..2ab26e5 --- /dev/null +++ b/reversal_detector.py @@ -0,0 +1,633 @@ +#!/usr/bin/env python3 +""" +🔄 TREND REVERSAL DETECTOR +Erkennt potenzielle Trendumkehrungen durch Multi-Signal-Analyse + +SIGNALE: +1. RSI Divergenz (Bullish/Bearish) +2. EMA Slope Change +3. Volume Spike +4. Candlestick Patterns +5. Break of Structure + +VERWENDUNG: + from reversal_detector import ReversalDetector + + detector = ReversalDetector() + result = detector.analyze(df_m15, df_h1, current_trend='uptrend') + + if result['reversal_score'] >= 60: + print("Reversal-Warnung! Trade blockieren.") +""" + +import numpy as np +import pandas as pd +from typing import Dict, Tuple, Optional, List +import logging + +logger = logging.getLogger(__name__) + + +class ReversalDetector: + """ + Multi-Signal Trend Reversal Detector + + Kombiniert mehrere Indikatoren um Trendumkehrungen zu erkennen: + - RSI Divergenz + - EMA Slope Änderung + - Volume Spikes + - Candlestick Patterns + - Break of Structure + """ + + def __init__(self, + rsi_period: int = 14, + ema_fast: int = 9, + ema_slow: int = 21, + volume_spike_mult: float = 2.0, + divergence_lookback: int = 10, + mode: str = "defensive"): + """ + Args: + rsi_period: RSI Berechnungsperiode + ema_fast: Schneller EMA für Slope + ema_slow: Langsamer EMA für Slope + volume_spike_mult: Multiplikator für Volume-Spike-Erkennung + divergence_lookback: Bars für Divergenz-Suche + mode: "defensive" (blockiert Trades) oder "info" (nur Logging) + """ + self.rsi_period = rsi_period + self.ema_fast = ema_fast + self.ema_slow = ema_slow + self.volume_spike_mult = volume_spike_mult + self.divergence_lookback = divergence_lookback + self.mode = mode + + # Gewichtung der Signale + self.weights = { + 'rsi_divergence': 30, # Sehr zuverlässig + 'ema_slope_change': 20, # Früher Indikator + 'volume_spike': 15, # Bestätigung + 'candlestick': 15, # Pattern-basiert + 'break_of_structure': 20 # Strukturbruch + } + + logger.info("=" * 60) + logger.info("🔄 REVERSAL DETECTOR INITIALIZED") + logger.info("=" * 60) + logger.info(f" Mode: {mode.upper()}") + logger.info(f" RSI Period: {rsi_period}") + logger.info(f" EMA Fast/Slow: {ema_fast}/{ema_slow}") + logger.info(f" Volume Spike Mult: {volume_spike_mult}x") + logger.info(f" Divergence Lookback: {divergence_lookback} bars") + logger.info("=" * 60) + + # ========================================== + # MAIN ANALYSIS METHOD + # ========================================== + + def analyze(self, + df: pd.DataFrame, + current_trend: str, + df_higher_tf: Optional[pd.DataFrame] = None) -> Dict: + """ + Führt vollständige Reversal-Analyse durch + + Args: + df: DataFrame mit OHLCV Daten (primärer Timeframe, z.B. M15) + current_trend: 'uptrend' oder 'downtrend' + df_higher_tf: Optional höherer Timeframe für Bestätigung (z.B. H1) + + Returns: + Dict mit Reversal-Score und Details + """ + if df is None or len(df) < 50: + return self._empty_result("Insufficient data") + + # Stelle sicher dass nötige Indikatoren berechnet sind + df = self._ensure_indicators(df) + + signals = {} + + # 1. RSI Divergenz + signals['rsi_divergence'] = self._detect_rsi_divergence(df, current_trend) + + # 2. EMA Slope Change + signals['ema_slope_change'] = self._detect_ema_slope_change(df, current_trend) + + # 3. Volume Spike + signals['volume_spike'] = self._detect_volume_spike(df) + + # 4. Candlestick Patterns + signals['candlestick'] = self._detect_candlestick_patterns(df, current_trend) + + # 5. Break of Structure + signals['break_of_structure'] = self._detect_break_of_structure(df, current_trend) + + # Berechne Gesamt-Score + reversal_score = self._calculate_reversal_score(signals) + + # Bestimme Reversal-Typ + if current_trend == 'uptrend': + reversal_type = 'BEARISH' if reversal_score >= 30 else 'NONE' + else: + reversal_type = 'BULLISH' if reversal_score >= 30 else 'NONE' + + # Bestimme Aktion + action, lot_multiplier = self._determine_action(reversal_score) + + result = { + 'reversal_score': reversal_score, + 'reversal_type': reversal_type, + 'current_trend': current_trend, + 'signals': signals, + 'action': action, + 'lot_multiplier': lot_multiplier, + 'should_trade': action != 'BLOCK', + 'mode': self.mode + } + + # Logging + self._log_analysis(result) + + return result + + # ========================================== + # SIGNAL DETECTION METHODS + # ========================================== + + def _detect_rsi_divergence(self, df: pd.DataFrame, trend: str) -> Dict: + """ + Erkennt RSI Divergenz + + Bearish Divergenz: Preis Higher High, RSI Lower High + Bullish Divergenz: Preis Lower Low, RSI Higher Low + """ + if 'rsi' not in df.columns: + return {'detected': False, 'strength': 0, 'type': 'none', 'description': 'RSI not available'} + + lookback = self.divergence_lookback + recent = df.tail(lookback) + + if len(recent) < lookback: + return {'detected': False, 'strength': 0, 'type': 'none', 'description': 'Not enough data'} + + prices = recent['close'].values + rsi = recent['rsi'].values + + # Finde lokale Extrema + price_highs_idx = self._find_local_extrema(prices, 'high') + price_lows_idx = self._find_local_extrema(prices, 'low') + rsi_highs_idx = self._find_local_extrema(rsi, 'high') + rsi_lows_idx = self._find_local_extrema(rsi, 'low') + + detected = False + div_type = 'none' + strength = 0 + description = 'No divergence' + + # Bearish Divergenz prüfen (für Uptrend) + if trend == 'uptrend' and len(price_highs_idx) >= 2 and len(rsi_highs_idx) >= 2: + # Preis macht Higher High + if prices[price_highs_idx[-1]] > prices[price_highs_idx[-2]]: + # RSI macht Lower High + if rsi[rsi_highs_idx[-1]] < rsi[rsi_highs_idx[-2]]: + detected = True + div_type = 'bearish' + # Stärke basierend auf Differenz + price_diff = (prices[price_highs_idx[-1]] - prices[price_highs_idx[-2]]) / prices[price_highs_idx[-2]] + rsi_diff = rsi[rsi_highs_idx[-2]] - rsi[rsi_highs_idx[-1]] + strength = min(100, int((price_diff * 1000 + rsi_diff) * 2)) + description = f"Bearish Divergence: Price HH, RSI LH (RSI diff: {rsi_diff:.1f})" + + # Bullish Divergenz prüfen (für Downtrend) + if trend == 'downtrend' and len(price_lows_idx) >= 2 and len(rsi_lows_idx) >= 2: + # Preis macht Lower Low + if prices[price_lows_idx[-1]] < prices[price_lows_idx[-2]]: + # RSI macht Higher Low + if rsi[rsi_lows_idx[-1]] > rsi[rsi_lows_idx[-2]]: + detected = True + div_type = 'bullish' + price_diff = (prices[price_lows_idx[-2]] - prices[price_lows_idx[-1]]) / prices[price_lows_idx[-2]] + rsi_diff = rsi[rsi_lows_idx[-1]] - rsi[rsi_lows_idx[-2]] + strength = min(100, int((price_diff * 1000 + rsi_diff) * 2)) + description = f"Bullish Divergence: Price LL, RSI HL (RSI diff: {rsi_diff:.1f})" + + return { + 'detected': detected, + 'strength': strength, + 'type': div_type, + 'description': description + } + + def _detect_ema_slope_change(self, df: pd.DataFrame, trend: str) -> Dict: + """ + Erkennt Änderung der EMA-Steigung + + Warnsignal wenn Slope sich dem Nullpunkt nähert oder Vorzeichen wechselt + """ + if f'ema_{self.ema_fast}' not in df.columns: + # Berechne EMA falls nicht vorhanden + df[f'ema_{self.ema_fast}'] = df['close'].ewm(span=self.ema_fast).mean() + + ema = df[f'ema_{self.ema_fast}'].values + + if len(ema) < 5: + return {'detected': False, 'strength': 0, 'slope': 0, 'description': 'Not enough data'} + + # Berechne Slopes + current_slope = (ema[-1] - ema[-3]) / ema[-3] * 100 # Letzte 3 Bars + prev_slope = (ema[-4] - ema[-6]) / ema[-6] * 100 if len(ema) >= 6 else current_slope + + detected = False + strength = 0 + description = f"Slope: {current_slope:.4f}%" + + # Slope-Wechsel erkennen + if trend == 'uptrend': + # Warnung wenn positiver Slope abflacht oder negativ wird + if current_slope < prev_slope * 0.5: # Slope halbiert sich + detected = True + strength = min(100, int(abs(prev_slope - current_slope) * 500)) + description = f"Slope weakening: {prev_slope:.4f}% -> {current_slope:.4f}%" + if current_slope < 0 and prev_slope > 0: # Vorzeichenwechsel + detected = True + strength = 80 + description = f"Slope turned negative: {current_slope:.4f}%" + + elif trend == 'downtrend': + # Warnung wenn negativer Slope abflacht oder positiv wird + if current_slope > prev_slope * 0.5: # Slope halbiert sich + detected = True + strength = min(100, int(abs(prev_slope - current_slope) * 500)) + description = f"Slope weakening: {prev_slope:.4f}% -> {current_slope:.4f}%" + if current_slope > 0 and prev_slope < 0: # Vorzeichenwechsel + detected = True + strength = 80 + description = f"Slope turned positive: {current_slope:.4f}%" + + return { + 'detected': detected, + 'strength': strength, + 'slope': current_slope, + 'prev_slope': prev_slope, + 'description': description + } + + def _detect_volume_spike(self, df: pd.DataFrame) -> Dict: + """ + Erkennt Volume-Spikes bei potenziellen Wendepunkten + """ + if 'tick_volume' not in df.columns and 'volume' not in df.columns: + return {'detected': False, 'strength': 0, 'ratio': 1.0, 'description': 'Volume not available'} + + vol_col = 'tick_volume' if 'tick_volume' in df.columns else 'volume' + + # Durchschnittsvolumen der letzten 20 Bars + avg_volume = df[vol_col].tail(20).mean() + current_volume = df[vol_col].iloc[-1] + + if avg_volume == 0: + return {'detected': False, 'strength': 0, 'ratio': 1.0, 'description': 'No volume data'} + + ratio = current_volume / avg_volume + + detected = ratio >= self.volume_spike_mult + strength = min(100, int((ratio - 1) * 50)) if detected else 0 + + return { + 'detected': detected, + 'strength': strength, + 'ratio': ratio, + 'current_volume': current_volume, + 'avg_volume': avg_volume, + 'description': f"Volume: {ratio:.1f}x average" + (" (SPIKE!)" if detected else "") + } + + def _detect_candlestick_patterns(self, df: pd.DataFrame, trend: str) -> Dict: + """ + Erkennt Reversal-Candlestick-Patterns + + - Doji (Unentschlossenheit) + - Engulfing (Umkehr) + - Hammer/Shooting Star + - Morning/Evening Star + """ + if len(df) < 3: + return {'detected': False, 'strength': 0, 'pattern': 'none', 'description': 'Not enough data'} + + # Letzte Kerzen + current = df.iloc[-1] + prev = df.iloc[-2] + prev2 = df.iloc[-3] if len(df) >= 3 else None + + o, h, l, c = current['open'], current['high'], current['low'], current['close'] + body = abs(c - o) + upper_wick = h - max(o, c) + lower_wick = min(o, c) - l + total_range = h - l if h != l else 0.0001 + + detected = False + strength = 0 + pattern = 'none' + description = 'No reversal pattern' + + # 1. Doji (Body < 10% der Range) + if body / total_range < 0.1: + detected = True + strength = 40 + pattern = 'doji' + description = "Doji: Market indecision" + + # 2. Engulfing Pattern + prev_body = abs(prev['close'] - prev['open']) + if body > prev_body * 1.5: # Aktuelle Kerze größer + if trend == 'uptrend' and c < o and prev['close'] > prev['open']: + # Bearish Engulfing + detected = True + strength = 70 + pattern = 'bearish_engulfing' + description = "Bearish Engulfing: Strong reversal signal" + elif trend == 'downtrend' and c > o and prev['close'] < prev['open']: + # Bullish Engulfing + detected = True + strength = 70 + pattern = 'bullish_engulfing' + description = "Bullish Engulfing: Strong reversal signal" + + # 3. Hammer (Bullish) / Shooting Star (Bearish) + if lower_wick > body * 2 and upper_wick < body * 0.5: + # Hammer-Form + if trend == 'downtrend': + detected = True + strength = 60 + pattern = 'hammer' + description = "Hammer: Potential bullish reversal" + + if upper_wick > body * 2 and lower_wick < body * 0.5: + # Shooting Star-Form + if trend == 'uptrend': + detected = True + strength = 60 + pattern = 'shooting_star' + description = "Shooting Star: Potential bearish reversal" + + # 4. Pin Bar (Long Wick Rejection) + if upper_wick > total_range * 0.6 or lower_wick > total_range * 0.6: + if trend == 'uptrend' and upper_wick > lower_wick: + detected = True + strength = max(strength, 55) + pattern = 'pin_bar_bearish' if pattern == 'none' else pattern + description = "Pin Bar: Upper wick rejection" + elif trend == 'downtrend' and lower_wick > upper_wick: + detected = True + strength = max(strength, 55) + pattern = 'pin_bar_bullish' if pattern == 'none' else pattern + description = "Pin Bar: Lower wick rejection" + + return { + 'detected': detected, + 'strength': strength, + 'pattern': pattern, + 'description': description + } + + def _detect_break_of_structure(self, df: pd.DataFrame, trend: str) -> Dict: + """ + Erkennt Break of Structure (BOS) + + Uptrend BOS: Erstes Lower Low nach Higher Highs + Downtrend BOS: Erstes Higher High nach Lower Lows + """ + lookback = 20 + if len(df) < lookback: + return {'detected': False, 'strength': 0, 'description': 'Not enough data'} + + recent = df.tail(lookback) + highs = recent['high'].values + lows = recent['low'].values + + detected = False + strength = 0 + description = 'Structure intact' + + # Finde Swing Points + swing_highs = [] + swing_lows = [] + + for i in range(2, len(highs) - 2): + # Swing High: Höher als 2 Bars links und rechts + if highs[i] > highs[i-1] and highs[i] > highs[i-2] and highs[i] > highs[i+1] and highs[i] > highs[i+2]: + swing_highs.append((i, highs[i])) + # Swing Low: Niedriger als 2 Bars links und rechts + if lows[i] < lows[i-1] and lows[i] < lows[i-2] and lows[i] < lows[i+1] and lows[i] < lows[i+2]: + swing_lows.append((i, lows[i])) + + if len(swing_highs) >= 2 and len(swing_lows) >= 2: + if trend == 'uptrend': + # Check for Lower Low (BOS) + if swing_lows[-1][1] < swing_lows[-2][1]: + detected = True + diff_pct = (swing_lows[-2][1] - swing_lows[-1][1]) / swing_lows[-2][1] * 100 + strength = min(100, int(diff_pct * 20)) + description = f"BOS: Lower Low detected ({diff_pct:.2f}% below prev swing)" + + elif trend == 'downtrend': + # Check for Higher High (BOS) + if swing_highs[-1][1] > swing_highs[-2][1]: + detected = True + diff_pct = (swing_highs[-1][1] - swing_highs[-2][1]) / swing_highs[-2][1] * 100 + strength = min(100, int(diff_pct * 20)) + description = f"BOS: Higher High detected ({diff_pct:.2f}% above prev swing)" + + return { + 'detected': detected, + 'strength': strength, + 'swing_highs': len(swing_highs), + 'swing_lows': len(swing_lows), + 'description': description + } + + # ========================================== + # HELPER METHODS + # ========================================== + + def _ensure_indicators(self, df: pd.DataFrame) -> pd.DataFrame: + """Stellt sicher dass alle nötigen Indikatoren berechnet sind""" + df = df.copy() + + # RSI + if 'rsi' not in df.columns: + delta = df['close'].diff() + gain = (delta.where(delta > 0, 0)).rolling(window=self.rsi_period).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=self.rsi_period).mean() + rs = gain / loss + df['rsi'] = 100 - (100 / (1 + rs)) + + # EMAs + if f'ema_{self.ema_fast}' not in df.columns: + df[f'ema_{self.ema_fast}'] = df['close'].ewm(span=self.ema_fast).mean() + + if f'ema_{self.ema_slow}' not in df.columns: + df[f'ema_{self.ema_slow}'] = df['close'].ewm(span=self.ema_slow).mean() + + return df + + def _find_local_extrema(self, data: np.ndarray, extrema_type: str, window: int = 3) -> List[int]: + """Findet lokale Hochs/Tiefs in einem Array""" + extrema = [] + for i in range(window, len(data) - window): + if extrema_type == 'high': + if all(data[i] >= data[i-j] for j in range(1, window+1)) and \ + all(data[i] >= data[i+j] for j in range(1, window+1)): + extrema.append(i) + else: # low + if all(data[i] <= data[i-j] for j in range(1, window+1)) and \ + all(data[i] <= data[i+j] for j in range(1, window+1)): + extrema.append(i) + return extrema + + def _calculate_reversal_score(self, signals: Dict) -> int: + """Berechnet gewichteten Reversal-Score""" + score = 0 + + for signal_name, signal_data in signals.items(): + if signal_data.get('detected', False): + weight = self.weights.get(signal_name, 10) + signal_strength = signal_data.get('strength', 50) / 100 + score += weight * signal_strength + + return min(100, int(score)) + + def _determine_action(self, score: int) -> Tuple[str, float]: + """ + Bestimmt Aktion basierend auf Reversal-Score + + Returns: + (action, lot_multiplier) + """ + if self.mode == "info": + # Info-Mode: Nur Logging, keine Änderungen + return "ALLOW", 1.0 + + # Defensive Mode + if score < 30: + return "ALLOW", 1.0 + elif score < 50: + return "CAUTION", 0.75 + elif score < 70: + return "REDUCE", 0.5 + else: + return "BLOCK", 0.0 + + def _empty_result(self, reason: str) -> Dict: + """Gibt leeres Ergebnis zurück""" + return { + 'reversal_score': 0, + 'reversal_type': 'NONE', + 'current_trend': 'unknown', + 'signals': {}, + 'action': 'ALLOW', + 'lot_multiplier': 1.0, + 'should_trade': True, + 'error': reason, + 'mode': self.mode + } + + def _log_analysis(self, result: Dict): + """Loggt Analyse-Ergebnis""" + score = result['reversal_score'] + + # Emoji basierend auf Score + if score < 30: + emoji = "✅" + level = "LOW" + elif score < 50: + emoji = "⚠️" + level = "MODERATE" + elif score < 70: + emoji = "🔶" + level = "HIGH" + else: + emoji = "🔴" + level = "CRITICAL" + + print(f"\n🔄 REVERSAL CHECK ({result['current_trend'].upper()}):") + print("-" * 50) + + for signal_name, signal_data in result['signals'].items(): + status = "⚠️" if signal_data.get('detected', False) else "✅" + desc = signal_data.get('description', 'N/A') + strength = signal_data.get('strength', 0) + print(f" {signal_name.replace('_', ' ').title():20s}: {status} {desc}") + if signal_data.get('detected'): + print(f" {'':20s} Strength: {strength}%") + + print("-" * 50) + print(f" {emoji} Reversal Score: {score}% ({level})") + print(f" Action: {result['action']} | Lot Mult: {result['lot_multiplier']:.0%}") + + if result['action'] == 'BLOCK': + print(f" ⛔ TRADE BLOCKED due to high reversal risk!") + elif result['action'] == 'REDUCE': + print(f" 📉 Lot size reduced to {result['lot_multiplier']:.0%}") + + # ========================================== + # QUICK CHECK METHOD + # ========================================== + + def quick_check(self, df: pd.DataFrame, trend: str) -> Tuple[bool, int, str]: + """ + Schnelle Reversal-Prüfung + + Returns: + (should_trade, reversal_score, reason) + """ + result = self.analyze(df, trend) + return result['should_trade'], result['reversal_score'], result['action'] + + +# ========================================== +# STANDALONE TESTING +# ========================================== + +if __name__ == "__main__": + print("=" * 60) + print("🔄 REVERSAL DETECTOR TEST") + print("=" * 60) + + # Simuliere Test-Daten + import numpy as np + + np.random.seed(42) + + # Erzeuge einen Uptrend mit Reversal-Anzeichen + n = 100 + trend_base = np.linspace(100, 120, n) # Uptrend + noise = np.random.normal(0, 1, n) + + # Füge Reversal-Anzeichen am Ende hinzu + trend_base[-10:] = trend_base[-10] - np.linspace(0, 3, 10) # Abflachung + + prices = trend_base + noise + + df = pd.DataFrame({ + 'open': prices - np.random.uniform(0, 0.5, n), + 'high': prices + np.random.uniform(0.5, 1.5, n), + 'low': prices - np.random.uniform(0.5, 1.5, n), + 'close': prices, + 'tick_volume': np.random.randint(100, 1000, n) + }) + + # Volume Spike am Ende + df.loc[df.index[-1], 'tick_volume'] = 5000 + + # Test + detector = ReversalDetector(mode="defensive") + result = detector.analyze(df, current_trend='uptrend') + + print(f"\n📊 Test Result:") + print(f" Reversal Score: {result['reversal_score']}%") + print(f" Should Trade: {result['should_trade']}") + print(f" Action: {result['action']}") + print(f" Lot Multiplier: {result['lot_multiplier']}") diff --git a/reversal_integration.py b/reversal_integration.py new file mode 100644 index 0000000..80faa48 --- /dev/null +++ b/reversal_integration.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +""" +🔄 REVERSAL DETECTOR INTEGRATION +Integriert den Reversal Detector in den Trading Bot + +VERWENDUNG IM NOTEBOOK: + # Am Anfang importieren (nach den anderen Imports): + from reversal_integration import reversal_detector, check_reversal_risk + + # In enhanced_trading_check_wrapper nach Signal Analysis: + reversal_result = check_reversal_risk(signal_info, symbol) + if not reversal_result['should_trade']: + print(f"⛔ TRADE BLOCKIERT durch Reversal Detector") + return None + + # Lot Multiplier anpassen: + lot_multiplier *= reversal_result['lot_multiplier'] +""" + +import logging +from typing import Dict, Optional +import pandas as pd + +# Import the reversal detector +from reversal_detector import ReversalDetector + +logger = logging.getLogger(__name__) + +# ========================================== +# GLOBAL REVERSAL DETECTOR INSTANCE +# ========================================== + +# Initialize with defensive mode (blocks/reduces trades at high reversal risk) +reversal_detector = ReversalDetector( + rsi_period=14, + ema_fast=9, + ema_slow=21, + volume_spike_mult=2.0, + divergence_lookback=10, + mode="defensive" # "defensive" or "info" +) + +# ========================================== +# CONFIGURATION +# ========================================== + +REVERSAL_CONFIG = { + 'enabled': True, # Reversal Check aktiviert + 'block_threshold': 70, # Score >= 70 = Trade blockieren + 'reduce_threshold': 50, # Score >= 50 = Lot reduzieren + 'caution_threshold': 30, # Score >= 30 = Warnung + 'use_m15_data': True, # M15 für Analyse verwenden + 'use_h1_confirmation': True, # H1 für Bestätigung +} + + +# ========================================== +# INTEGRATION FUNCTION +# ========================================== + +def check_reversal_risk(signal_info: Dict, symbol: str = "XAUUSD") -> Dict: + """ + Prüft Reversal-Risiko basierend auf Signal-Info + + Args: + signal_info: Dict von extended_top_down_v2_adaptive() + symbol: Trading Symbol + + Returns: + Dict mit: + - should_trade: bool + - reversal_score: int (0-100) + - lot_multiplier: float (1.0, 0.75, 0.5, 0.0) + - action: str (ALLOW, CAUTION, REDUCE, BLOCK) + - reason: str + """ + if not REVERSAL_CONFIG['enabled']: + return { + 'should_trade': True, + 'reversal_score': 0, + 'lot_multiplier': 1.0, + 'action': 'ALLOW', + 'reason': 'Reversal check disabled' + } + + if signal_info is None: + return { + 'should_trade': True, + 'reversal_score': 0, + 'lot_multiplier': 1.0, + 'action': 'ALLOW', + 'reason': 'No signal info available' + } + + try: + # Bestimme aktuellen Trend + entry_signal = signal_info.get('entry_signal', 0) + standard_trend = signal_info.get('standard_trend', 'sideways') + + # Trend aus entry_signal ableiten falls standard_trend nicht verfügbar + if standard_trend == 'sideways' and entry_signal != 0: + current_trend = 'uptrend' if entry_signal == 1 else 'downtrend' + else: + current_trend = standard_trend + + # Hole M15 DataFrame aus trend_info + trend_info = signal_info.get('trend_info', {}) + + df_m15 = None + df_h1 = None + + # Versuche M15 Daten zu holen + if REVERSAL_CONFIG['use_m15_data'] and 'M15' in trend_info: + m15_info = trend_info['M15'] + if isinstance(m15_info, dict) and 'df' in m15_info: + df_m15 = m15_info['df'] + elif hasattr(m15_info, 'df'): + df_m15 = m15_info.df + + # Versuche H1 Daten zu holen + if REVERSAL_CONFIG['use_h1_confirmation'] and 'H1' in trend_info: + h1_info = trend_info['H1'] + if isinstance(h1_info, dict) and 'df' in h1_info: + df_h1 = h1_info['df'] + elif hasattr(h1_info, 'df'): + df_h1 = h1_info.df + + # Falls keine DataFrame verfügbar, versuche get_rates + if df_m15 is None: + try: + # Import get_rates falls verfügbar + import sys + if 'get_rates' in dir(sys.modules.get('__main__', {})): + from __main__ import get_rates + df_m15 = get_rates('m15', 100, symbol) + except Exception as e: + logger.debug(f"Could not get M15 data: {e}") + + if df_m15 is None or len(df_m15) < 50: + print(f"⚠️ Reversal Check: Not enough M15 data, skipping") + return { + 'should_trade': True, + 'reversal_score': 0, + 'lot_multiplier': 1.0, + 'action': 'ALLOW', + 'reason': 'Insufficient data for reversal check' + } + + # Führe Reversal-Analyse durch + result = reversal_detector.analyze( + df=df_m15, + current_trend=current_trend, + df_higher_tf=df_h1 + ) + + reversal_score = result['reversal_score'] + + # Bestimme Aktion basierend auf Config-Thresholds + if reversal_score >= REVERSAL_CONFIG['block_threshold']: + action = 'BLOCK' + lot_multiplier = 0.0 + should_trade = False + reason = f"High reversal risk ({reversal_score}% >= {REVERSAL_CONFIG['block_threshold']}%)" + elif reversal_score >= REVERSAL_CONFIG['reduce_threshold']: + action = 'REDUCE' + lot_multiplier = 0.5 + should_trade = True + reason = f"Moderate reversal risk ({reversal_score}%), lot reduced to 50%" + elif reversal_score >= REVERSAL_CONFIG['caution_threshold']: + action = 'CAUTION' + lot_multiplier = 0.75 + should_trade = True + reason = f"Low reversal risk ({reversal_score}%), lot reduced to 75%" + else: + action = 'ALLOW' + lot_multiplier = 1.0 + should_trade = True + reason = f"No significant reversal risk ({reversal_score}%)" + + return { + 'should_trade': should_trade, + 'reversal_score': reversal_score, + 'lot_multiplier': lot_multiplier, + 'action': action, + 'reason': reason, + 'reversal_type': result.get('reversal_type', 'NONE'), + 'signals': result.get('signals', {}) + } + + except Exception as e: + logger.error(f"Reversal check error: {e}") + print(f"⚠️ Reversal Check Error: {e}") + return { + 'should_trade': True, + 'reversal_score': 0, + 'lot_multiplier': 1.0, + 'action': 'ALLOW', + 'reason': f'Error: {e}' + } + + +def get_reversal_status() -> str: + """Gibt aktuellen Reversal Detector Status zurück""" + status = [] + status.append("=" * 60) + status.append("🔄 REVERSAL DETECTOR STATUS") + status.append("=" * 60) + status.append(f" Enabled: {REVERSAL_CONFIG['enabled']}") + status.append(f" Mode: {reversal_detector.mode}") + status.append(f" Block Threshold: {REVERSAL_CONFIG['block_threshold']}%") + status.append(f" Reduce Threshold: {REVERSAL_CONFIG['reduce_threshold']}%") + status.append(f" Caution Threshold: {REVERSAL_CONFIG['caution_threshold']}%") + status.append("=" * 60) + return "\n".join(status) + + +def enable_reversal_check(): + """Aktiviert den Reversal Check""" + REVERSAL_CONFIG['enabled'] = True + print("✅ Reversal Check ENABLED") + + +def disable_reversal_check(): + """Deaktiviert den Reversal Check""" + REVERSAL_CONFIG['enabled'] = False + print("⚠️ Reversal Check DISABLED") + + +def set_reversal_mode(mode: str): + """ + Setzt den Reversal Detector Mode + + Args: + mode: "defensive" (blockiert Trades) oder "info" (nur Logging) + """ + global reversal_detector + reversal_detector = ReversalDetector( + rsi_period=14, + ema_fast=9, + ema_slow=21, + volume_spike_mult=2.0, + divergence_lookback=10, + mode=mode + ) + print(f"✅ Reversal Detector mode set to: {mode.upper()}") + + +# ========================================== +# STANDALONE TEST +# ========================================== + +if __name__ == "__main__": + print(get_reversal_status()) + + # Test mit simulierten Daten + import numpy as np + + np.random.seed(42) + n = 100 + prices = np.linspace(100, 110, n) + np.random.normal(0, 0.5, n) + + df = pd.DataFrame({ + 'open': prices - np.random.uniform(0, 0.3, n), + 'high': prices + np.random.uniform(0.3, 0.8, n), + 'low': prices - np.random.uniform(0.3, 0.8, n), + 'close': prices, + 'tick_volume': np.random.randint(100, 500, n) + }) + + # Simuliere signal_info + mock_signal_info = { + 'entry_signal': 1, + 'standard_trend': 'uptrend', + 'trend_info': { + 'M15': {'df': df} + } + } + + print("\n🧪 Testing Reversal Check...") + result = check_reversal_risk(mock_signal_info, "XAUUSD") + + print(f"\n📊 Result:") + print(f" Should Trade: {result['should_trade']}") + print(f" Reversal Score: {result['reversal_score']}%") + print(f" Action: {result['action']}") + print(f" Lot Multiplier: {result['lot_multiplier']}") + print(f" Reason: {result['reason']}") diff --git a/session_filter_patch.py b/session_filter_patch.py index 5618645..a09e88c 100644 --- a/session_filter_patch.py +++ b/session_filter_patch.py @@ -20,10 +20,10 @@ PERFORMANCE-IMPACT: SESSION_WHITELIST_CONFIG = { # Welche Sessions erlauben? 'enabled_sessions': { - 'asian': True, # ✅ BESTE SESSION: 97.8% Win-Rate, $151/Trade - 'london': False, # ❌ BLOCKIERT: 12.5% Win-Rate, -$10/Trade - 'overlap': False, # ❌ BLOCKIERT: 14.3% Win-Rate, -$7/Trade - 'ny': True, # ✅ AKTIV: 43.3% Win-Rate, aber profitabel ($48/Trade) + 'asian': True, # ✅ BESTE SESSION: 54.2% Win-Rate, +$21/Trade + 'london': False, # ❌ BLOCKIERT: 46.9% Win-Rate, +$8/Trade + 'overlap': True, # ✅ TEST: Aktiviert 29.01.2026 mit V1.6 Adaptive + 'ny': True, # ✅ AKTIV: 49.1% Win-Rate, +$6/Trade }, # Session-spezifische Confidence Thresholds (NEU 26.12.2025)