# source: https://raw.githubusercontent.com/ikonclast/bob_der_botmeister/da05d31149b2f7577580f600e6bb591310274fe0/scripts/safe_guard_smoke.py
#!/usr/bin/env python3
"""
SAFE GUARD IMPLEMENTATION
- entry_signal_rate tracking
- FAILED_ZERO_SIGNAL marking
- HIGH_CHURN flag (not prohibition, just marking)
"""

import json
import subprocess
import zipfile
from pathlib import Path
from datetime import datetime

FREQTRADE_BASE = Path("/opt/docker/freqtrade/shared_data/user_data")
STRATEGIES_DIR = FREQTRADE_BASE / "strategies"
CONFIGS_DIR = FREQTRADE_BASE / "configs"
BACKTEST_BASE = FREQTRADE_BASE / "backtest_results"
DOCKER_ENV = {"DOCKER_HOST": "tcp://socket-proxy:2375"}


def create_breakout_fixed() -> str:
    """Fixed breakout_vol with relaxed gates + debug logging."""
    return '''from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta

class Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920(IStrategy):
    """
    Breakout Volatility - FIXED VERSION
    - Relaxed gates to allow trades
    - Debug logging for gate pass rates
    - Safety guards for monitoring
    """
    
    timeframe = '4h'
    stoploss = -0.045
    trailing_stop = True
    trailing_stop_positive = 0.02
    minimal_roi = {"0": 0.035, "60": 0.02}
    max_open_trades = 2
    
    # Safety tracking
    entry_signals_total = 0
    candles_total = 0

    def populate_indicators(self, dataframe: DataFrame, metadata: dict):
        # BBANDS with error handling
        try:
            bb = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2, nbdevdn=2)
            dataframe['bb_upper'] = bb['upperband']
            dataframe['bb_middle'] = bb['middleband']
            dataframe['bb_lower'] = bb['lowerband']
        except Exception as e:
            print(f"[SAFEGUARD] BBANDS error: {e}")
            dataframe['bb_upper'] = dataframe['close'] * 1.02
            dataframe['bb_middle'] = dataframe['close']
            dataframe['bb_lower'] = dataframe['close'] * 0.98
        
        dataframe['bb_width'] = (dataframe['bb_upper'] - dataframe['bb_lower']) / dataframe['bb_middle']
        dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['volume_ma'] = ta.SMA(dataframe['volume'], timeperiod=20)
        dataframe['volume_spike'] = dataframe['volume'] / dataframe['volume_ma']
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
        dataframe['atr_pct'] = dataframe['atr'] / dataframe['close'] * 100
        
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict):
        dataframe.loc[:, 'buy'] = 0
        
        # FIXED GATES - much more relaxed
        # 1. Volume condition - RELAXED (was 0.015-0.035, now 0.005-)
        vol_ok = dataframe['bb_width'] > 0.005
        vol_rate = (vol_ok).sum() / len(dataframe)
        
        # 2. Breakout - RELAXED (was 0.994-0.999, now allow at upper)
        breakout = dataframe['close'] > dataframe['bb_upper'] * 0.998
        breakout_rate = (breakout).sum() / len(dataframe)
        
        # 3. Trend - RELAXED (was 0.98, now 0.95)
        trend_ok = dataframe['close'] > dataframe['ema_50'] * 0.95
        
        # 4. Volume spike - RELAXED (was 1.0-1.25, now 0.8)
        volume_ok = dataframe['volume_spike'] > 0.8
        
        # 5. ATR - RELAXED (was 0.3-0.5, now 0.15)
        atr_ok = dataframe['atr_pct'] > 0.15
        
        # DEBUG: Log gate rates (once per backtest)
        if not hasattr(self, '_debugged'):
            print(f"[SAFEGUARD] Gate pass rates:")
            print(f"  Vol >0.5%: {vol_rate:.1%}")
            print(f"  Breakout: {breakout_rate:.1%}")
            print(f"  Volume >0.8x: {(volume_ok).sum()/len(dataframe):.1%}")
            
            # WARN if gates too strict
            if vol_rate < 0.1:
                print("[WARN] Vol gate too strict! <10% pass rate")
            if breakout_rate < 0.01:
                print("[WARN] Breakout gate too strict! <1% pass rate")
            
            self._debugged = True
        
        buy = vol_ok & breakout & trend_ok & volume_ok & atr_ok
        
        # Track signals
        self.entry_signals_total += buy.sum()
        self.candles_total += len(dataframe)
        
        dataframe.loc[buy, 'buy'] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict):
        dataframe.loc[:, 'sell'] = 0
        
        # Exit to middle or trailing stop
        to_middle = dataframe['close'] < dataframe['bb_middle']
        trend_broken = dataframe['close'] < dataframe['ema_50'] * 0.97
        
        sell = to_middle | trend_broken
        dataframe.loc[sell, 'sell'] = 1
        return dataframe
'''


def run_smoke_test():
    """Run smoke test with fixed breakout."""
    
    print("="*70)
    print("🧪 SAFE GUARD + FIXED BREAKOUT SMOKE TEST")
    print("="*70)
    
    # Write strategy
    strat_code = create_breakout_fixed()
    strat_file = STRATEGIES_DIR / "Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920.py"
    strat_file.write_text(strat_code)
    print(f"✓ Strategy written: {strat_file}")
    
    # Config
    config = {
        "max_open_trades": 2,
        "stake_currency": "USDT",
        "stake_amount": 100,
        "dry_run": True,
        "dry_run_wallet": 1000,
        "timeframe": "4h",
        "fee": 0.0015,
        "trading_mode": "spot",
        "exchange": {"name": "binance", "pair_whitelist": ["BTC/USDT","ETH/USDT"]},
        "pairlists": [{"method": "StaticPairList"}],
        "entry_pricing": {"price_side": "other", "use_order_book": False},
        "exit_pricing": {"price_side": "other", "use_order_book": False},
        "telegram": {"enabled": False, "token": "x", "chat_id": "1"},
        "api_server": {"enabled": False, "listen_ip_address": "127.0.0.1", "listen_port": 8080, "username": "a", "password": "a"},
    }
    
    cfg_file = CONFIGS_DIR / "cfg_Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920.json"
    cfg_file.write_text(json.dumps(config, indent=2))
    print(f"✓ Config written: {cfg_file}")
    
    # Run
    docker_backtest_dir = "/freqtrade/user_data/backtest_results/smoke_breakout_fixed"
    cmd = [
        "docker", "run", "--rm", "--network", "host",
        "-v", f"{FREQTRADE_BASE}:/freqtrade/user_data:rw",
        "freqtradeorg/freqtrade:stable",
        "backtesting",
        "--strategy", "Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920",
        "--config", "/freqtrade/user_data/configs/cfg_Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920.json",
        "--timeframe", "4h",
        "--timerange", "20230601-20231231",
        "--fee", "0.0015",
        "--export", "trades",
        "--backtest-directory", docker_backtest_dir,
        "--notes", "breakout_fixed_smoke",
        "--cache", "none",
        "--no-color"
    ]
    
    print(f"\nRunning smoke test...")
    print(f"  Strategy: Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920")
    print(f"  Pairs: BTC/USDT, ETH/USDT")
    print(f"  Period: 2023-06 to 2023-12")
    print(f"  Fee: 0.15%")
    
    try:
        import subprocess
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180, env=DOCKER_ENV)
        
        # Parse result
        import time
        time.sleep(0.5)
        
        zip_files = list(BACKTEST_BASE.glob("smoke_breakout_fixed-*.zip"))
        if not zip_files:
            print("❌ No ZIP generated - smoke test FAILED")
            return {"status": "FAILED", "trades": 0, "error": "No output"}
        
        zip_file = max(zip_files, key=lambda p: p.stat().st_mtime)
        
        with zipfile.ZipFile(zip_file, 'r') as zf:
            json_files = [f for f in zf.namelist() if f.endswith('.json') and '_config' not in f]
            with zf.open(json_files[0]) as f:
                data = json.load(f)
            
            strat_key = list(data['strategy'].keys())[0]
            s = data['strategy'][strat_key]
            
            trades = s.get('total_trades', 0)
            profit = s.get('profit_total', 0) * 100 if s.get('profit_total') else 0
            
            # Calculate TPPPD
            pairs = 2
            days = 214
            tpppd = trades / pairs / days if pairs > 0 and days > 0 else 0
            
            result = {
                "status": "SUCCESS",
                "trades": trades,
                "profit": round(profit, 2),
                "pf": round(s.get('profit_factor', 0), 2),
                "winrate": round((s.get('wins', 0) / trades * 100) if trades > 0 else 0, 1),
                "tpppd": round(tpppd, 3),
                "high_churn": tpppd > 0.5
            }
            
            return result
            
    except Exception as e:
        print(f"❌ Error: {e}")
        return {"status": "FAILED", "error": str(e)}


def generate_report(result: dict):
    """Generate smoke test report."""
    
    print("\n" + "="*70)
    print("📊 SMOKE TEST RESULT")
    print("="*70)
    
    if result['status'] == 'SUCCESS':
        print(f"\n✅ Smoke test PASSED")
        print(f"\nMetrics:")
        print(f"  Trades: {result['trades']}")
        print(f"  Profit: {result['profit']:.2f}%")
        print(f"  PF: {result['pf']}")
        print(f"  Winrate: {result['winrate']}%")
        print(f"  TPPPD: {result['tpppd']}")
        print(f"  High Churn: {'⚠️ YES' if result['high_churn'] else '✅ NO'}")
        
        if result['trades'] == 0:
            print(f"\n❌ FAILED_ZERO_SIGNAL - 0 trades generated")
            print("   - Gates still too strict")
            print("   - Requires further relaxation")
        elif result['trades'] < 50:
            print(f"\n⚠️ LOW_SAMPLE - {result['trades']} trades")
            print("   - Working but few opportunities")
        else:
            print(f"\n🎯 VALID - {result['trades']} trades")
            print("   - Ready for Anchor Sprint #002")
            
            if result['profit'] >= -5 and result['pf'] > 0.8:
                print("   - Candidate for POSITIVE_WEAK!")
    else:
        print(f"\n❌ Smoke test FAILED: {result.get('error', 'Unknown')}")
    
    # Write report
    report_path = Path("/home/node/.openclaw/workspace/bob_quant/debug_analysis/smoke_test_breakout_fixed.md")
    with open(report_path, 'w') as f:
        f.write("# Safe Guard + Fixed Breakout Smoke Test\n\n")
        f.write(f"**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M')}\n")
        f.write(f"**Strategy:** Github_ikonclast_bob_der_botmeister__safe_guard_smoke__20260716_095920\n\n")
        f.write("## Changes Made\n\n")
        f.write("1. **BB_WIDTH_MIN:** 0.005 (was 0.015-0.035)\n")
        f.write("2. **BREAKOUT_MULT:** 0.998 (was 0.994-0.999)\n")
        f.write("3. **TREND_MULT:** 0.95 (was 0.98)\n")
        f.write("4. **VOLUME_MULT:** 0.8 (was 1.0-1.25)\n")
        f.write("5. **ATR_MIN:** 0.15 (was 0.3-0.5)\n\n")
        f.write("## Result\n\n")
        
        if result['status'] == 'SUCCESS':
            f.write(f"| Metric | Value |\n")
            f.write(f"|--------|-------|\n")
            f.write(f"| Status | {result['status']} |\n")
            f.write(f"| Trades | {result['trades']} |\n")
            f.write(f"| Profit | {result['profit']:.2f}% |\n")
            f.write(f"| PF | {result['pf']} |\n")
            f.write(f"| Winrate | {result['winrate']}% |\n")
            f.write(f"| TPPPD | {result['tpppd']} |\n")
            f.write(f"| High Churn | {result['high_churn']} |\n")
            
            if result['trades'] == 0:
                f.write(f"\n**Verdict:** ❌ FAILED_ZERO_SIGNAL\n")
            elif result['trades'] < 50:
                f.write(f"\n**Verdict:** ⚠️ LOW_SAMPLE\n")
            else:
                f.write(f"\n**Verdict:** ✅ PASSED - Ready for Anchor Sprint #002\n")
        else:
            f.write(f"**Error:** {result.get('error', 'Unknown')}\n")
    
    print(f"\n✅ Report written: {report_path}")


def main():
    result = run_smoke_test()
    generate_report(result)


if __name__ == "__main__":
    main()
