"""
v4.2 真实微观数据策略 - 反向思维版
核心逻辑：大跌后 Taker 占比低 (<50%) = 散户恐慌抛售，主力悄悄接盘
"""
import pandas as pd
import numpy as np

print("🚀 加载数据...")
df = pd.read_parquet('/root/quant_pipeline/data/btc_15m_binance_full.parquet')
print(f"数据量: {len(df):,} 根 K 线")

# 计算指标
df['ret'] = df['c'].pct_change() * 100
df['ema21'] = df['c'].ewm(span=21).mean()
df['ema50'] = df['c'].ewm(span=50).mean()
df['vol_ma20'] = df['v'].rolling(20).mean()
df['ema21_1h'] = df['c'].ewm(span=84).mean()  # 21*4

# ──────────────────────────────────────────────────────
# 策略逻辑：大跌 + Taker 低 (主力吸筹) + 止跌信号
# ──────────────────────────────────────────────────────
print("\n📊 v4.2 反向思维策略回测")
print("   逻辑：大跌后 Taker<50% = 散户恐慌，主力吸筹")
print("="*80)

trades = []

for i in range(50, len(df) - 30):
    # 1. 检测过去 12 根内是否有单次大跌 > 2%
    drop_found = False
    drop_idx = -1
    for j in range(i-12, i+1):
        if df['ret'].iloc[j] < -2.0:
            drop_found = True
            drop_idx = j
            break
    
    if not drop_found:
        continue
    
    # 2. 在大跌后 1-6 根 K 线内寻找入场信号
    entered = False
    for offset in range(1, 7):
        ci = drop_idx + offset
        if ci >= len(df) - 30 or ci < 0 or entered:
            continue
        
        taker_ratio = df['taker_buy_ratio'].iloc[ci]
        
        # 【反向逻辑】Taker 买入占比 < 50% (散户恐慌抛售)
        if taker_ratio >= 0.50:
            continue
        
        # 趋势过滤：1H 趋势向上或走平 (不做逆势)
        trend_ok = df['ema21_1h'].iloc[ci] >= df['ema50'].iloc[ci] * 0.995
        
        # 成交量萎缩 (抛压耗尽)
        vol_shrink = df['v'].iloc[ci] < df['vol_ma20'].iloc[ci] * 0.9
        
        # 止跌信号：阳线 或 下影线
        is_bull = df['c'].iloc[ci] > df['o'].iloc[ci]
        lower_shadow = (df['l'].iloc[ci] < df['o'].iloc[ci] * 0.998) and \
                       (df['c'].iloc[ci] > df['o'].iloc[ci] * 0.995)
        stop_loss_signal = is_bull or lower_shadow
        
        # 入场条件
        if trend_ok and vol_shrink and stop_loss_signal:
            entry_price = df['c'].iloc[ci]
            
            # 出场：固定止盈止损
            atr = df['c'].iloc[ci-20:ci+1].std() * 0.01
            sl_mult = 1.2
            tp_mult = 2.5
            
            sl_price = entry_price * (1 - atr/entry_price * sl_mult)
            tp_price = entry_price * (1 + atr/entry_price * tp_mult)
            
            # 模拟持仓最多 24 根 K 线
            exit_price = None
            exit_idx = None
            hit_sl = hit_tp = False
            
            for j in range(ci+1, min(ci+24, len(df))):
                high_j = df['h'].iloc[j]
                low_j = df['l'].iloc[j]
                
                if high_j >= tp_price:
                    exit_price = tp_price
                    hit_tp = True
                    exit_idx = j
                    break
                elif low_j <= sl_price:
                    exit_price = sl_price
                    hit_sl = True
                    exit_idx = j
                    break
            
            if exit_price is None:
                exit_price = df['c'].iloc[min(ci+24, len(df)-1)]
                exit_idx = min(ci+24, len(df)-1)
            
            ret_pct = (exit_price / entry_price - 1) * 100 - 0.06
            
            trades.append({
                'entry_time': df.index[ci],
                'exit_time': df.index[exit_idx],
                'entry_price': entry_price,
                'exit_price': exit_price,
                'taker_ratio': taker_ratio,
                'vol_ratio': df['v'].iloc[ci] / (df['vol_ma20'].iloc[ci] + 1e-9),
                'return_pct': ret_pct,
                'hit_tp': hit_tp,
                'hit_sl': hit_sl,
                'bars_held': exit_idx - ci,
            })
            entered = True

# ──────────────────────────────────────────────────────
# 分析结果
# ──────────────────────────────────────────────────────
if len(trades) == 0:
    print("❌ 没有产生任何信号！需要放宽条件。")
else:
    df_trades = pd.DataFrame(trades)
    
    total = len(df_trades)
    wins = (df_trades['return_pct'] > 0).sum()
    win_rate = wins / total * 100
    avg_ret = df_trades['return_pct'].mean()
    total_ret = df_trades['return_pct'].sum()
    
    # 复利
    cum = (1 + df_trades['return_pct']/100).prod()
    
    # 回撤
    equity = (1 + df_trades['return_pct']/100).cumprod()
    peak = equity.expanding().max()
    max_dd = ((equity - peak) / peak).min() * 100
    
    # Sharpe
    sharpe = df_trades['return_pct'].mean() / df_trades['return_pct'].std() * np.sqrt(365*4) if df_trades['return_pct'].std() > 0 else 0
    
    print(f"\n{'='*80}")
    print(f"📊 v4.2 反向思维策略回测结果")
    print(f"{'='*80}")
    print(f"总交易次数: {total}")
    print(f"盈利次数: {wins} | 亏损次数: {total - wins}")
    print(f"✅ 胜率: {win_rate:.1f}%")
    print(f"平均单笔收益: {avg_ret:+.2f}%")
    print(f"总收益: {total_ret:+.1f}%")
    print(f"复利倍数: {cum:.2f}x")
    print(f"年化收益: {(cum ** (1/3.5) - 1) * 100:.1f}%")  # 3.5 年数据
    print(f"最大回撤: {max_dd:.1f}%")
    print(f"Sharpe 比率: {sharpe:.2f}")
    print(f"{'='*80}")
    
    # 按 Taker 占比分组
    print(f"\n📈 按 Taker 买入占比分组:")
    df_trades['bucket'] = pd.cut(df_trades['taker_ratio'], bins=[0, 0.40, 0.45, 0.50], 
                                  labels=['<40%', '40-45%', '45-50%'])
    grouped = df_trades.groupby('bucket', observed=True).agg({
        'return_pct': ['count', 'mean', 'sum'],
        'hit_tp': 'mean'
    }).round(3)
    print(grouped)
    
    # 展示前 10 笔
    print(f"\n📋 前 10 笔交易详情:")
    cols = ['entry_time', 'exit_time', 'entry_price', 'exit_price', 'taker_ratio', 'return_pct', 'hit_tp']
    print(df_trades[cols].head(10).to_string())
    
    # 按月统计
    print(f"\n📅 月度收益分布 (前 12 个月):")
    df_trades['month'] = df_trades['entry_time'].dt.strftime('%Y-%m')
    monthly = df_trades.groupby('month', observed=True)['return_pct'].agg(['count', 'sum', 'mean']).round(2)
    print(monthly.head(12).to_string())
