#!/usr/bin/env python3
"""
MEGA SCANNER - Trouver une VRAIE espérance positive

On teste TOUT:
- Timeframes: 1m, 5m, 15m, 1h
- Symbols: BTC, ETH, SOL, BNB
- Stratégies: Grid, DCA, Breakout, Momentum, Mean Reversion
- Patterns: Horaires, Volume, Volatilité
- Combos

OBJECTIF: Trouver quelque chose qui marche VRAIMENT
"""

import pandas as pd
import numpy as np
from martingale_backtester import MartingaleBacktester
import requests
from datetime import datetime
import json

print("=" * 80)
print("🔍 MEGA SCANNER - RECHERCHE ESPÉRANCE POSITIVE")
print("=" * 80)

# ============ FETCH MULTI-TIMEFRAME DATA ============

def fetch_multi_data():
    """Fetch data pour plusieurs timeframes et symbols"""

    backtester = MartingaleBacktester(
        initial_capital=1000.0,
        trading_fee_pct=0.0005,
        timeout_minutes=60
    )

    data = {}

    symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT']
    timeframes = ['1m', '5m', '15m', '1h']

    print("\n📥 TÉLÉCHARGEMENT DONNÉES MULTI-TIMEFRAME/SYMBOL\n")

    for symbol in symbols:
        data[symbol] = {}
        for tf in timeframes:
            print(f"   Fetching {symbol} {tf}...", end=" ")

            # Adapter le nombre de bougies selon timeframe
            if tf == '1m':
                limit = 1000
            elif tf == '5m':
                limit = 500
            elif tf == '15m':
                limit = 300
            else:  # 1h
                limit = 200

            df = backtester.fetch_binance_data(symbol, tf, limit)

            if df is not None:
                data[symbol][tf] = df
                print(f"✅ {len(df)} bougies")
            else:
                print("❌")

    return data

data = fetch_multi_data()

# ============ STRATÉGIES À TESTER ============

def backtest_simple(df, strategy_name, entry_logic, exit_logic, position_size=10):
    """Backtest simple sans martingale"""

    capital = 1000.0
    position = None
    trades = []

    for i in range(len(df)):
        current = df.iloc[i]

        # Sortie de position
        if position is not None:
            exit_signal = exit_logic(df, i, position)

            if exit_signal:
                # Calculer PnL
                if position['side'] == 'LONG':
                    pnl_pct = (current['close'] - position['entry']) / position['entry']
                else:
                    pnl_pct = (position['entry'] - current['close']) / position['entry']

                # Leverage
                pnl_pct *= position['leverage']

                # Frais
                pnl_pct -= 0.001  # 0.05% entrée + 0.05% sortie

                pnl_usd = position['size'] * pnl_pct
                capital += pnl_usd

                trades.append({
                    'entry': position['entry'],
                    'exit': current['close'],
                    'side': position['side'],
                    'pnl_pct': pnl_pct * 100,
                    'pnl_usd': pnl_usd,
                    'won': pnl_usd > 0
                })

                position = None

        # Entrée de position
        if position is None and i > 50:  # Besoin d'historique
            entry_signal = entry_logic(df, i)

            if entry_signal:
                side, leverage = entry_signal
                position = {
                    'entry': current['close'],
                    'side': side,
                    'leverage': leverage,
                    'size': position_size
                }

    # Stats
    if not trades:
        return None

    wins = [t for t in trades if t['won']]
    losses = [t for t in trades if not t['won']]

    total_return = ((capital - 1000) / 1000) * 100
    win_rate = len(wins) / len(trades) if trades else 0

    avg_win = np.mean([t['pnl_pct'] for t in wins]) if wins else 0
    avg_loss = np.mean([t['pnl_pct'] for t in losses]) if losses else 0

    profit_factor = abs(sum([t['pnl_usd'] for t in wins]) / sum([t['pnl_usd'] for t in losses])) if losses else 999

    return {
        'strategy': strategy_name,
        'roi': total_return,
        'capital': capital,
        'trades': len(trades),
        'win_rate': win_rate,
        'avg_win': avg_win,
        'avg_loss': avg_loss,
        'profit_factor': profit_factor
    }

# ============ STRATÉGIE 1: GRID TRADING ============

def grid_entry(df, i):
    """Grid: acheter bas, vendre haut dans un range"""
    current = df.iloc[i]
    recent = df.iloc[max(0, i-50):i]

    if len(recent) < 20:
        return None

    # Range detection
    support = recent['low'].min()
    resistance = recent['high'].max()
    range_size = resistance - support

    # Si proche du support → LONG
    if current['close'] <= support + range_size * 0.1:
        return ('LONG', 5)  # 5x leverage

    # Si proche de la résistance → SHORT
    elif current['close'] >= resistance - range_size * 0.1:
        return ('SHORT', 5)

    return None

def grid_exit(df, i, position):
    """Exit grid: prendre profit rapide"""
    current = df.iloc[i]

    if position['side'] == 'LONG':
        profit_target = position['entry'] * 1.005  # 0.5% profit
        return current['close'] >= profit_target
    else:
        profit_target = position['entry'] * 0.995
        return current['close'] <= profit_target

# ============ STRATÉGIE 2: MOMENTUM BREAKOUT ============

def breakout_entry(df, i):
    """Trade les breakouts avec volume"""
    if i < 100:
        return None

    current = df.iloc[i]
    recent = df.iloc[i-100:i]

    # ATH/ATL des 100 dernières bougies
    ath = recent['high'].max()
    atl = recent['low'].min()

    # Volume spike
    avg_vol = recent['volume'].mean()
    vol_spike = current['volume'] > avg_vol * 2

    # Breakout haut avec volume
    if current['close'] > ath and vol_spike:
        return ('LONG', 10)

    # Breakdown bas avec volume
    elif current['close'] < atl and vol_spike:
        return ('SHORT', 10)

    return None

def breakout_exit(df, i, position):
    """Exit breakout: trailing stop ou reversal"""
    current = df.iloc[i]

    # Stop loss 2%
    if position['side'] == 'LONG':
        stop = position['entry'] * 0.98
        if current['close'] <= stop:
            return True
        # Take profit 3%
        target = position['entry'] * 1.03
        return current['close'] >= target
    else:
        stop = position['entry'] * 1.02
        if current['close'] >= stop:
            return True
        target = position['entry'] * 0.97
        return current['close'] <= target

# ============ STRATÉGIE 3: MEAN REVERSION ============

def meanrev_entry(df, i):
    """Acheter les oversold, vendre les overbought"""
    if i < 50:
        return None

    current = df.iloc[i]
    recent = df.iloc[i-50:i]

    # Bollinger Bands
    ma = recent['close'].mean()
    std = recent['close'].std()

    lower_band = ma - 2 * std
    upper_band = ma + 2 * std

    # Oversold
    if current['close'] < lower_band:
        return ('LONG', 8)

    # Overbought
    elif current['close'] > upper_band:
        return ('SHORT', 8)

    return None

def meanrev_exit(df, i, position):
    """Exit: retour à la moyenne"""
    if i < 50:
        return False

    current = df.iloc[i]
    recent = df.iloc[i-50:i]
    ma = recent['close'].mean()

    # Retour à la moyenne
    if position['side'] == 'LONG':
        return current['close'] >= ma
    else:
        return current['close'] <= ma

# ============ STRATÉGIE 4: PATTERN HORAIRE ============

def hourly_entry(df, i):
    """Trader seulement aux heures volatiles"""
    current = df.iloc[i]
    hour = current['timestamp'].hour

    # Heures volatiles: 14h-16h UTC (US open) et 22h-00h (Asia)
    if hour in [14, 15, 22, 23]:
        # Simple momentum
        if i < 10:
            return None
        prev = df.iloc[i-10:i]
        trend = (current['close'] - prev['close'].iloc[0]) / prev['close'].iloc[0]

        if trend > 0.001:
            return ('LONG', 15)
        elif trend < -0.001:
            return ('SHORT', 15)

    return None

def hourly_exit(df, i, position):
    """Exit après 1h ou SL/TP"""
    current = df.iloc[i]

    # SL 1%, TP 2%
    if position['side'] == 'LONG':
        sl = position['entry'] * 0.99
        tp = position['entry'] * 1.02
        return current['close'] <= sl or current['close'] >= tp
    else:
        sl = position['entry'] * 1.01
        tp = position['entry'] * 0.98
        return current['close'] >= sl or current['close'] <= tp

# ============ STRATÉGIE 5: VOLATILITY EXPANSION ============

def volexp_entry(df, i):
    """Trade expansion de volatilité"""
    if i < 50:
        return None

    current = df.iloc[i]
    recent = df.iloc[i-50:i]

    # ATR
    high_low = recent['high'] - recent['low']
    atr = high_low.mean()
    current_range = current['high'] - current['low']

    # Range actuel > 2x ATR moyen
    if current_range > atr * 2:
        # Direction du mouvement
        if current['close'] > current['open']:
            return ('LONG', 12)
        else:
            return ('SHORT', 12)

    return None

def volexp_exit(df, i, position):
    """Exit volatility"""
    current = df.iloc[i]

    # Quick exit 1.5% profit ou 1% loss
    if position['side'] == 'LONG':
        tp = position['entry'] * 1.015
        sl = position['entry'] * 0.99
        return current['close'] >= tp or current['close'] <= sl
    else:
        tp = position['entry'] * 0.985
        sl = position['entry'] * 1.01
        return current['close'] <= tp or current['close'] >= sl

# ============ TESTS MASSIFS ============

strategies = [
    ('Grid Trading', grid_entry, grid_exit),
    ('Momentum Breakout', breakout_entry, breakout_exit),
    ('Mean Reversion', meanrev_entry, meanrev_exit),
    ('Hourly Pattern', hourly_entry, hourly_exit),
    ('Volatility Expansion', volexp_entry, volexp_exit),
]

print("\n\n🔬 SCANNING...")
print("=" * 80)

all_results = []
test_num = 0
total_tests = len(strategies) * len(data) * 4  # symbols * timeframes

for symbol, timeframes in data.items():
    for tf, df in timeframes.items():
        for strat_name, entry_fn, exit_fn in strategies:
            test_num += 1

            print(f"\r🧪 Test {test_num}/{total_tests} | {symbol} {tf} {strat_name}",
                  end="", flush=True)

            try:
                result = backtest_simple(df, strat_name, entry_fn, exit_fn)

                if result:
                    result['symbol'] = symbol
                    result['timeframe'] = tf
                    all_results.append(result)
            except:
                pass

print("\n\n" + "=" * 80)
print("🏆 TOP 30 STRATÉGIES - TOUTES COMBINAISONS")
print("=" * 80)

if not all_results:
    print("\n❌ Aucun résultat!")
    exit(1)

all_results.sort(key=lambda x: x['roi'], reverse=True)
top_30 = all_results[:30]

print(f"\n{'#':<3} {'Symbol':<8} {'TF':<5} {'Stratégie':<25} "
      f"{'ROI%':>7} {'WR%':>5} {'PF':>6} {'Tr':>4} {'Avg+':>6} {'Avg-':>6}")
print("-" * 95)

for rank, res in enumerate(top_30, 1):
    emoji = "🥇" if rank == 1 else "🥈" if rank == 2 else "🥉" if rank == 3 else f"{rank:2}"
    status = "✅" if res['roi'] > 5 else "⚠️" if res['roi'] > 0 else "❌"

    print(f"{emoji:<3} {res['symbol']:<8} {res['timeframe']:<5} {res['strategy']:<25} "
          f"{res['roi']:>6.2f}% {res['win_rate']*100:>4.1f}% {res['profit_factor']:>6.2f} "
          f"{res['trades']:>4} {res['avg_win']:>5.2f}% {res['avg_loss']:>5.2f}% {status}")

# Meilleure
best = top_30[0]

print(f"\n\n{'=' * 80}")
print(f"🏆 MEILLEURE COMBINAISON TROUVÉE")
print(f"{'=' * 80}")

print(f"\n📊 PERFORMANCE:")
print(f"   Symbol:            {best['symbol']}")
print(f"   Timeframe:         {best['timeframe']}")
print(f"   Stratégie:         {best['strategy']}")
print(f"   ROI:               {best['roi']:+.2f}% {'✅ EXCELLENT!' if best['roi'] > 10 else '✅ BON' if best['roi'] > 5 else '⚠️'}")
print(f"   Capital final:     ${best['capital']:.2f}")
print(f"   Gain:              ${best['capital'] - 1000:.2f}")
print(f"   Trades:            {best['trades']}")
print(f"   Win Rate:          {best['win_rate']*100:.1f}%")
print(f"   Profit Factor:     {best['profit_factor']:.2f}")
print(f"   Gain moyen:        +{best['avg_win']:.2f}%")
print(f"   Perte moyenne:     {best['avg_loss']:.2f}%")

print(f"\n💡 INSIGHTS:")
profitable = [r for r in all_results if r['roi'] > 0]
print(f"   Total configs testées:  {len(all_results)}")
print(f"   Configs profitables:    {len(profitable)} ({len(profitable)/len(all_results)*100:.1f}%)")

if profitable:
    avg_roi_profitable = np.mean([r['roi'] for r in profitable])
    print(f"   ROI moyen profitable:   +{avg_roi_profitable:.2f}%")

    # Best symbol
    by_symbol = {}
    for r in profitable:
        if r['symbol'] not in by_symbol:
            by_symbol[r['symbol']] = []
        by_symbol[r['symbol']].append(r['roi'])

    print(f"\n   📈 MEILLEURS SYMBOLS:")
    for sym in sorted(by_symbol.keys(), key=lambda x: np.mean(by_symbol[x]), reverse=True):
        avg = np.mean(by_symbol[sym])
        print(f"      {sym}: {avg:+.2f}% avg ({len(by_symbol[sym])} configs)")

    # Best timeframe
    by_tf = {}
    for r in profitable:
        if r['timeframe'] not in by_tf:
            by_tf[r['timeframe']] = []
        by_tf[r['timeframe']].append(r['roi'])

    print(f"\n   ⏰ MEILLEURS TIMEFRAMES:")
    for tf in sorted(by_tf.keys(), key=lambda x: np.mean(by_tf[x]), reverse=True):
        avg = np.mean(by_tf[tf])
        print(f"      {tf}: {avg:+.2f}% avg ({len(by_tf[tf])} configs)")

    # Best strategy
    by_strat = {}
    for r in profitable:
        if r['strategy'] not in by_strat:
            by_strat[r['strategy']] = []
        by_strat[r['strategy']].append(r['roi'])

    print(f"\n   🎯 MEILLEURES STRATÉGIES:")
    for strat in sorted(by_strat.keys(), key=lambda x: np.mean(by_strat[x]), reverse=True):
        avg = np.mean(by_strat[strat])
        print(f"      {strat}: {avg:+.2f}% avg ({len(by_strat[strat])} configs)")

print(f"{'=' * 80}")

# Sauvegarder
with open('mega_scan_results.json', 'w') as f:
    json.dump({
        'best': best,
        'top_30': top_30,
        'all_results': all_results
    }, f, indent=2, default=str)

print(f"\n💾 Résultats: mega_scan_results.json")

if best['roi'] > 10:
    print(f"\n🎉 ESPÉRANCE POSITIVE TROUVÉE! +{best['roi']:.2f}%")
elif best['roi'] > 5:
    print(f"\n✨ Bonne espérance trouvée: +{best['roi']:.2f}%")
elif best['roi'] > 0:
    print(f"\n⚠️  Légèrement profitable: +{best['roi']:.2f}%")
else:
    print(f"\n❌ Toutes les stratégies sont perdantes. Faut creuser ailleurs.")

print(f"{'=' * 80}")
