#!/usr/bin/env python3
"""
Backtest trailing stop unificato 2° account.
Regole: trigger +1.5%, step 0.5%, high water mark.
NON tocca Bybit. Solo simulazione su closed-pnl.
Limite: senza serie intrabar minuto, il risultato e' approssimativo.
"""
import sys, os
sys.path.insert(0, '/opt/charter-live/live_deploy_v2')
os.chdir('/opt/charter-live/live_deploy_v2')
from bybit_demo_client import BybitDemoClient
import statistics

c = BybitDemoClient()

# Scarica TUTTI i closed-pnl (senza cursor, solo prima pagina)
all_closed = []
r = c._request('GET', '/v5/position/closed-pnl', {'category': 'linear', 'settleCoin': 'USDT', 'limit': '200'}, signed=True)
all_closed = r.get('result', {}).get('list', [])

print(f'TOTAL closed trades: {len(all_closed)}')

# Regole trailing
TRIGGER_PCT = 0.015  # +1.5%
STEP_PCT = 0.005      # 0.5%

def simulate_trade(tr):
    """Simula trailing stop su un singolo trade.
    Restituisce (pnl_ideale, locked_profit_applied)."""
    symbol = tr['symbol']
    side = tr['side']  # 'Buy' o 'Sell'
    qty = float(tr['qty'])
    entry = float(tr['avgEntryPrice'])
    exit_price = float(tr['avgExitPrice'])
    pnl_real = float(tr['closedPnl'])

    if entry <= 0:
        return None

    # Calcola PnL% reale
    if side == 'Buy':
        pnl_pct_real = (exit_price - entry) / entry
    else:  # Sell
        pnl_pct_real = (entry - exit_price) / entry

    # Stima PnL% raggiunto durante la vita del trade
    # Euristica: se trade chiuso in profitto, PnL ha raggiunto almeno il pnl_pct_real
    # Per i trade in loss, ipotizziamo che sia sceso linearmente (PESSIMA euristica)
    if pnl_pct_real > 0:
        # trade in profitto: il max PnL raggiunto è almeno pnl_pct_real
        max_pnl_pct = pnl_pct_real
    else:
        # trade in loss: euristica conservativa
        # ipotizziamo che il PnL abbia raggiunto un massimo di max(0, 2 * pnl_pct_real)
        max_pnl_pct = max(0, pnl_pct_real * 2)

    # Applica trailing
    if max_pnl_pct < TRIGGER_PCT:
        # trailing mai attivato, PnL ideale = reale
        return (pnl_real, False)

    # trailing attivato: lock-in a max_pnl_pct - STEP_PCT
    locked_pct = max(TRIGGER_PCT, max_pnl_pct - STEP_PCT)
    pnl_ideale = locked_pct * qty * entry

    return (pnl_ideale, True)


results = []
for tr in all_closed:
    res = simulate_trade(tr)
    if res is None:
        continue
    pnl_ideale, applied = res
    results.append({
        'symbol': tr['symbol'],
        'side': tr['side'],
        'qty': float(tr['qty']),
        'entry': float(tr['avgEntryPrice']),
        'exit': float(tr['avgExitPrice']),
        'pnl_real': float(tr['closedPnl']),
        'pnl_ideale': pnl_ideale,
        'applied': applied,
    })

# Stats
n = len(results)
total_real = sum(r['pnl_real'] for r in results)
total_ideale = sum(r['pnl_ideale'] for r in results)
diff = total_ideale - total_real

applied_count = sum(1 for r in results if r['applied'])
applied_diff = sum(r['pnl_ideale'] - r['pnl_real'] for r in results if r['applied'])
not_applied_diff = sum(r['pnl_ideale'] - r['pnl_real'] for r in results if not r['applied'])

# Per strategia (euristica basata su symbol noto)
SYMBOL_STRATEGY = {
    'ARUSDT': 'rettangolo_simple', 'WIFUSDT': 'rsi_swing', 'AEROUSDT': 'rsi_swing',
    'VIRTUALUSDT': 'vptr3', 'BTCUSDT': 'vptr3', 'ZECUSDT': 'vptr3', 'AXSUSDT': 'vptr3',
    'NEARUSDT': 'ma_trailing', 'BEATUSDT': 'ma_trailing',
    'UNIUSDT': 'rettangolo', 'DASHUSDT': 'vptr3', 'SOLUSDT': 'vptr3',
    '1000BONKUSDT': 'sqw', '1000PEPEUSDT': 'rettangolo', 'SUIUSDT': 'rettangolo',
    'RENDERUSDT': 'rettangolo',
}

by_strat = {}
for r in results:
    s = SYMBOL_STRATEGY.get(r['symbol'], '?')
    if s not in by_strat:
        by_strat[s] = {'n': 0, 'pnl_real': 0, 'pnl_ideale': 0, 'applied': 0}
    by_strat[s]['n'] += 1
    by_strat[s]['pnl_real'] += r['pnl_real']
    by_strat[s]['pnl_ideale'] += r['pnl_ideale']
    if r['applied']:
        by_strat[s]['applied'] += 1

print(f'\n=== RISULTATI BACKTEST ===')
print(f'Trade analizzati: {n}')
print(f'Trade con trailing attivato: {applied_count} ({100*applied_count/n:.1f}%)')
print()
print(f'PnL reale totale:       {total_real:+.2f} USDT')
print(f'PnL ideale (con trail): {total_ideale:+.2f} USDT')
print(f'Differenza:             {diff:+.2f} USDT')
print(f'  di cui trailing attivato: {applied_diff:+.2f}')
print(f'  di cui trailing non attivato: {not_applied_diff:+.2f}')
print()
print(f'Verdetto: {"PEGGO" if diff < 0 else "MEGLIO"} con il nuovo trailing stop')

print(f'\n=== Per strategia ===')
for s in sorted(by_strat.keys(), key=lambda k: -by_strat[k]['pnl_real']):
    info = by_strat[s]
    diff = info['pnl_ideale'] - info['pnl_real']
    print(f'  {s:25} n={info["n"]:>3} applied={info["applied"]:>3} pnl_real={info["pnl_real"]:+8.2f} pnl_ideale={info["pnl_ideale"]:+8.2f} diff={diff:+7.2f}')

# Top 10 trade che avrebbero perso di più
print(f'\n=== TOP 10 trade con MAGGIOR PERDITA da trailing (ideal < real) ===')
loss_trades = sorted([r for r in results if r['pnl_ideale'] < r['pnl_real']], key=lambda r: r['pnl_real'] - r['pnl_ideale'], reverse=True)[:10]
for r in loss_trades:
    diff = r['pnl_ideale'] - r['pnl_real']
    print(f"  {r['symbol']:12} {r['side']:5} real={r['pnl_real']:+7.2f} ideal={r['pnl_ideale']:+7.2f} diff={diff:+7.2f}")

print(f'\n=== TOP 10 trade con MAGGIOR GUADAGNO da trailing (ideal > real) ===')
gain_trades = sorted([r for r in results if r['pnl_ideale'] > r['pnl_real']], key=lambda r: r['pnl_ideale'] - r['pnl_real'], reverse=True)[:10]
for r in gain_trades:
    diff = r['pnl_ideale'] - r['pnl_real']
    print(f"  {r['symbol']:12} {r['side']:5} real={r['pnl_real']:+7.2f} ideal={r['pnl_ideale']:+7.2f} diff={diff:+7.2f}")
