#!/usr/bin/env python3
"""
CONSISTENT MONTHLY STRATEGY - Gagner TOUS les mois

Philosophie inverse :
- Pas chercher ROI max → Chercher CONSISTANCE max
- Pas gros trades rares → Beaucoup de petits trades
- Pas volatility expansion → Mean reversion (plus prévisible)
- Timeframe 1h (plus d'opportunités)
- Win rate >70% (petits gains mais réguliers)
"""

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

class ConsistentMonthlyStrategy:
    """Stratégie pour gagner tous les mois"""

    def __init__(self, initial_capital=1000):
        self.capital = initial_capital
        self.initial_capital = initial_capital
        self.position = None
        self.trades = []
        self.consecutive_losses = 0

    def detect_entry_signal(self, df, i):
        """Mean reversion + Range trading"""

        if i < 50:
            return None

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

        # ===== SIGNAL 1: RSI MEAN REVERSION (principal) =====
        deltas = recent['close'].diff()
        gains = deltas.clip(lower=0).rolling(14).mean()
        losses = -deltas.clip(upper=0).rolling(14).mean()

        if losses.iloc[-1] == 0:
            return None

        rs = gains.iloc[-1] / losses.iloc[-1]
        rsi = 100 - (100 / (1 + rs))

        # RSI extremes
        if rsi < 35:  # Oversold → LONG (mean reversion)
            side = 'LONG'
            confidence = 0.8
        elif rsi > 65:  # Overbought → SHORT (mean reversion)
            side = 'SHORT'
            confidence = 0.8
        else:
            return None  # Pas de signal si RSI neutre

        # ===== SIGNAL 2: BOLLINGER BANDS =====
        ma20 = recent['close'].tail(20).mean()
        std20 = recent['close'].tail(20).std()
        bb_upper = ma20 + (2 * std20)
        bb_lower = ma20 - (2 * std20)

        # Bonus si touche les bandes
        if side == 'LONG' and current['close'] < bb_lower:
            confidence += 0.1
        elif side == 'SHORT' and current['close'] > bb_upper:
            confidence += 0.1

        # ===== SIGNAL 3: VOLUME (confirmation) =====
        vol_ma = recent['volume'].tail(20).mean()
        if current['volume'] > vol_ma * 1.2:  # Volume spike
            confidence += 0.1

        # Minimum confidence
        if confidence < 0.8:
            return None

        return {
            'side': side,
            'confidence': confidence,
            'rsi': rsi
        }

    def calculate_params(self, df, i, signal):
        """Paramètres pour high win rate"""

        recent = df.iloc[max(0, i-50):i]

        # ATR pour sizing
        high_low = recent['high'] - recent['low']
        atr = high_low.mean()
        atr_pct = (atr / recent['close'].mean()) * 100

        # LEVERAGE: Modéré (on veut consistance, pas gros gains)
        leverage = 20  # Fixe à 20x (ni trop ni pas assez)

        # TP/SL: SERRÉS pour high win rate
        # Mean reversion = petits mouvements, il faut prendre profits vite
        tp_pct = atr_pct * 0.8  # RÉDUIT (prendre profits rapidement)
        sl_pct = atr_pct * 1.2  # Plus large que TP (laisser respirer)

        # Limites
        tp_pct = max(0.3, min(tp_pct, 1.5))  # Max 1.5% TP (petits gains)
        sl_pct = max(0.4, min(sl_pct, 2.0))  # Max 2% SL

        # POSITION SIZE: Petit pour sécurité
        risk_pct = 0.015  # 1.5% risk par trade (conservateur)

        if self.consecutive_losses >= 2:
            risk_pct = 0.01  # 1% après pertes

        risk_amount = self.capital * risk_pct
        position_size = risk_amount / (sl_pct/100 * leverage)
        position_size = min(position_size, self.capital * 0.25)

        return {
            'leverage': leverage,
            'tp_pct': tp_pct,
            'sl_pct': sl_pct,
            'position_size': position_size
        }

    def should_exit(self, df, i, position, params):
        """Exit rapide pour lock profits"""

        current = df.iloc[i]

        # TP/SL
        if position['side'] == 'LONG':
            tp = position['entry'] * (1 + params['tp_pct']/100)
            sl = position['entry'] * (1 - params['sl_pct']/100)

            if current['close'] >= tp:
                return True, 'TP'
            if current['close'] <= sl:
                return True, 'SL'

            # QUICK PROFIT LOCK: Dès 60% du TP atteint
            profit_pct = (current['close'] - position['entry']) / position['entry'] * 100
            if profit_pct >= params['tp_pct'] * 0.6:
                return True, 'QUICK_PROFIT'

        else:  # SHORT
            tp = position['entry'] * (1 - params['tp_pct']/100)
            sl = position['entry'] * (1 + params['sl_pct']/100)

            if current['close'] <= tp:
                return True, 'TP'
            if current['close'] >= sl:
                return True, 'SL'

            profit_pct = (position['entry'] - current['close']) / position['entry'] * 100
            if profit_pct >= params['tp_pct'] * 0.6:
                return True, 'QUICK_PROFIT'

        return False, None

    def close_trade(self, exit_price, exit_type):
        """Close trade"""

        if not self.position:
            return

        params = self.position['params']

        # PnL
        if self.position['side'] == 'LONG':
            pnl_pct = (exit_price - self.position['entry']) / self.position['entry']
        else:
            pnl_pct = (self.position['entry'] - exit_price) / self.position['entry']

        pnl_pct *= params['leverage']
        pnl_pct -= 0.001

        pnl_usd = params['position_size'] * pnl_pct
        self.capital += pnl_usd

        won = pnl_usd > 0

        if won:
            self.consecutive_losses = 0
        else:
            self.consecutive_losses += 1

        self.trades.append({
            'pnl_usd': pnl_usd,
            'pnl_pct': pnl_pct * 100,
            'won': won,
            'exit_type': exit_type
        })

        self.position = None

    def backtest(self, df):
        """Backtest"""

        for i in range(50, len(df)):
            # Gérer position
            if self.position:
                should_exit, exit_type = self.should_exit(df, i, self.position, self.position['params'])
                if should_exit:
                    self.close_trade(df.iloc[i]['close'], exit_type)
                continue

            # Stop après 3 pertes (au lieu de 4)
            if self.consecutive_losses >= 3:
                continue

            # Signal mean reversion
            signal = self.detect_entry_signal(df, i)
            if signal:
                params = self.calculate_params(df, i, signal)
                self.position = {
                    'entry': df.iloc[i]['close'],
                    'side': signal['side'],
                    'params': params
                }

        # Stats
        if not self.trades:
            return None

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

        total_return = ((self.capital - self.initial_capital) / self.initial_capital) * 100
        win_rate = len(wins) / len(self.trades)
        profit_factor = abs(sum([t['pnl_usd'] for t in wins]) / sum([t['pnl_usd'] for t in losses])) if losses else 999

        return {
            'roi': total_return,
            'capital': self.capital,
            'trades': len(self.trades),
            'win_rate': win_rate,
            'profit_factor': profit_factor
        }


# ============ TEST MENSUEL ============

print("=" * 80)
print("🎯 CONSISTENT MONTHLY STRATEGY - Gagner TOUS les mois")
print("=" * 80)
print("\nPhilosophie:")
print("  - Mean reversion (RSI extremes)")
print("  - 1h timeframe (plus d'opportunités)")
print("  - Small TP (0.3-1.5%) pour high win rate")
print("  - Quick profit lock (60% TP)")
print("  - Target: >70% win rate, profit tous les mois")

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

print("\n📥 Téléchargement BTC 1h (1000 bougies)...")
df_full = backtester.fetch_binance_data('BTCUSDT', '1h', 1000)

if df_full is None:
    exit(1)

# Créer timestamp si absent
if 'timestamp' not in df_full.columns:
    from datetime import datetime
    df_full['timestamp'] = pd.date_range(end=datetime.now(), periods=len(df_full), freq='1H')

df_full['year_month'] = pd.to_datetime(df_full['timestamp']).dt.to_period('M')
months = df_full['year_month'].unique()

print(f"\n📊 Test mensuel ({len(months)} mois):\n")

monthly_results = []

for month in months:
    month_data = df_full[df_full['year_month'] == month].copy()

    if len(month_data) < 50:
        continue

    month_str = str(month)
    print(f"🧪 {month_str}...", end=" ")

    system = ConsistentMonthlyStrategy(initial_capital=1000)
    result = system.backtest(month_data)

    if result:
        result['month'] = month_str
        monthly_results.append(result)

        status = "✅" if result['roi'] > 0 else "❌"
        wr_status = "✅" if result['win_rate'] > 0.7 else "⚠️" if result['win_rate'] > 0.6 else "❌"

        print(f"{status} ROI: {result['roi']:+6.2f}% | WR: {wr_status} {result['win_rate']*100:5.1f}% | Trades: {result['trades']:3d} | PF: {result['profit_factor']:.2f}")
    else:
        print(f"⚠️  Aucun trade")

# ============ RÉSULTATS ============

print("\n" + "=" * 80)
print("📊 RÉSULTATS CONSISTANCE")
print("=" * 80)

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

profitable_months = [r for r in monthly_results if r['roi'] > 0]
losing_months = [r for r in monthly_results if r['roi'] <= 0]

rois = [r['roi'] for r in monthly_results]
wrs = [r['win_rate'] for r in monthly_results]
trades_counts = [r['trades'] for r in monthly_results]

print(f"\n🎯 CONSISTANCE:")
print(f"   Mois profitables:      {len(profitable_months)}/{len(monthly_results)} ({len(profitable_months)/len(monthly_results)*100:.1f}%)")
print(f"   Mois perdants:         {len(losing_months)}/{len(monthly_results)} ({len(losing_months)/len(monthly_results)*100:.1f}%)")

if len(profitable_months) / len(monthly_results) >= 0.9:
    print(f"   ✅ OBJECTIF ATTEINT: >90% mois profitables!")
elif len(profitable_months) / len(monthly_results) >= 0.8:
    print(f"   ✅ EXCELLENT: >80% mois profitables")
elif len(profitable_months) / len(monthly_results) >= 0.7:
    print(f"   ⚠️  BON: >70% mois profitables")
else:
    print(f"   ❌ Insuffisant: <70% mois profitables")

print(f"\n💰 PERFORMANCE:")
print(f"   ROI moyen mensuel:     {np.mean(rois):+.2f}%")
print(f"   ROI médian:            {np.median(rois):+.2f}%")
print(f"   ROI écart-type:        {np.std(rois):.2f}%")

print(f"\n🎯 QUALITÉ:")
print(f"   Win rate moyen:        {np.mean(wrs)*100:.1f}%")
print(f"   Trades moyen/mois:     {np.mean(trades_counts):.1f}")

# Projection compound
capital = 1000
for r in monthly_results:
    capital *= (1 + r['roi']/100)

roi_total = ((capital - 1000) / 1000) * 100

print(f"\n💵 PROJECTION CAPITAL:")
print(f"   ROI total ({len(monthly_results)} mois): {roi_total:+.2f}%")
print(f"   Capital final:         ${capital:,.2f}")

# Comparaison
print(f"\n📊 VS BASELINE (4h):")
print(f"   Baseline 4h:           +17.14% par ~2 mois")
print(f"   Consistent 1h:         {np.mean(rois):+.2f}% par mois")
print(f"   Consistance baseline:  60% (3/5 mois)")
print(f"   Consistance 1h:        {len(profitable_months)/len(monthly_results)*100:.0f}% ({len(profitable_months)}/{len(monthly_results)} mois)")

# Verdict
print(f"\n{'=' * 80}")
print("🎯 VERDICT")
print("=" * 80)

consistance_rate = len(profitable_months) / len(monthly_results)

if consistance_rate >= 0.9 and np.mean(wrs) > 0.7:
    print("\n🎉 OBJECTIF ATTEINT!")
    print(f"   ✅ {consistance_rate*100:.0f}% mois profitables")
    print(f"   ✅ {np.mean(wrs)*100:.1f}% win rate")
    print(f"   ✅ ROI moyen: {np.mean(rois):+.2f}%/mois")
    print(f"\n   🚀 STRATÉGIE CONSISTANTE TROUVÉE!")
elif consistance_rate >= 0.75:
    print("\n✅ TRÈS BON RÉSULTAT")
    print(f"   ✅ {consistance_rate*100:.0f}% mois profitables")
    print(f"   Win rate: {np.mean(wrs)*100:.1f}%")
elif consistance_rate >= 0.6:
    print("\n⚠️  BON MAIS PEUT MIEUX FAIRE")
    print(f"   {consistance_rate*100:.0f}% mois profitables (target: >90%)")
else:
    print("\n❌ OBJECTIF NON ATTEINT")
    print(f"   {consistance_rate*100:.0f}% mois profitables (target: >90%)")

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

# Sauvegarder
with open('consistent_monthly_results.json', 'w') as f:
    json.dump({
        'months': monthly_results,
        'summary': {
            'total_months': len(monthly_results),
            'profitable_months': len(profitable_months),
            'consistance_rate': consistance_rate,
            'avg_roi': np.mean(rois),
            'avg_win_rate': np.mean(wrs),
            'avg_trades_per_month': np.mean(trades_counts),
            'total_roi': roi_total
        }
    }, f, indent=2, default=str)

print(f"\n💾 Résultats: consistent_monthly_results.json")
print("=" * 80)
