""" 多策略组合回测 — 目标: 1000 USDT/月 思路: 同时运行多个不同参数的 EMA 策略,它们在不同时间段产生信号, 彼此信号不重叠时各自独立开仓,等于"多个策略并行跑"。 条件: - 每笔: 100 USDT 保证金, 100x 杠杆, 名义 10,000 USDT - 90% 返佣 - 最低持仓 > 3 分钟 - ETH 合约, 2025 全年 测试方案: A) 单策略加大仓位 (500U/1000U) B) 多策略组合 (3-5个不同参数策略并行) C) 降低 ATR 门槛 + 更宽止损 D) 综合最优方案 """ import sys, time, datetime, sqlite3 from pathlib import Path class EMA: __slots__ = ('k', 'v') def __init__(self, p): self.k = 2.0 / (p + 1); self.v = None def update(self, x): self.v = x if self.v is None else x * self.k + self.v * (1 - self.k) return self.v def load(): db = Path(__file__).parent.parent / 'models' / 'database.db' s = int(datetime.datetime(2025,1,1).timestamp()) * 1000 e = int(datetime.datetime(2026,1,1).timestamp()) * 1000 conn = sqlite3.connect(str(db)) rows = conn.cursor().execute( "SELECT id,open,high,low,close FROM bitmart_eth_1m WHERE id>=? AND idAP+1: s=0.0 for i in range(-AP,0): tr=H[i]-L[i]; d1=abs(H[i]-C[i-1]); d2=abs(L[i]-C[i-1]) if d1>tr: tr=d1 if d2>tr: tr=d2 s+=tr atr_pct=s/(AP*p) if p>0 else 0 cu=pf_ is not None and pf_<=ps_ and fast>slow cd=pf_ is not None and pf_>=ps_ and fast=hsl: pnl=notional*pp; fee=notional*FEE_RATE*2; reb=fee*REB_RATE trades.append((pos, op, p, pnl, fee, reb, hsec, ot, dt)) pos=0; op=0; ot=None; pend=None; continue if hsec>=MIN_H: dc=False if -pp>=sl_pct: dc=True elif hsec>=mh: dc=True elif pos==1 and cd: dc=True elif pos==-1 and cu: dc=True elif pend=='cl' and pos==1: dc=True elif pend=='cs' and pos==-1: dc=True if dc: pnl=notional*pp; fee=notional*FEE_RATE*2; reb=fee*REB_RATE trades.append((pos, op, p, pnl, fee, reb, hsec, ot, dt)) pos=0; op=0; ot=None; pend=None if atr_pct>=atr_min: if (cd or fastslow) and p>big: pos=1; op=p; ot=dt continue else: if pos==1 and cd: pend='cl' elif pos==-1 and cu: pend='cs' if pos==0 and atr_pct>=atr_min: if cu and p>big: pos=1; op=p; ot=dt elif cd and p peak: peak = cum if peak - cum > dd: dd = peak - cum # 月度 monthly = {} for t in trades: k = t[8].strftime('%Y-%m') if k not in monthly: monthly[k] = {'n': 0, 'net': 0} monthly[k]['n'] += 1 monthly[k]['net'] += t[3] - (t[4] - t[5]) wr = len([t for t in trades if t[3]>0]) / n * 100 return {'label': label, 'n': n, 'net': net, 'pnl': total_pnl, 'reb': total_reb, 'fee': total_fee, 'dd': dd, 'wr': wr, 'monthly': monthly} def merge_trades(all_trade_lists): """合并多个策略的交易(检查时间冲突:同一时间只能有一个持仓)""" # 简单合并:按开仓时间排序,跳过与已有持仓重叠的交易 all_trades = [] for trades in all_trade_lists: for t in trades: all_trades.append(t) all_trades.sort(key=lambda x: x[7]) # 按开仓时间排序 merged = [] last_close = None for t in all_trades: open_time = t[7] close_time = t[8] if last_close is None or open_time >= last_close: merged.append(t) last_close = close_time return merged def print_comparison(results): """打印对比表""" print(f"\n{'='*110}", flush=True) print(f" COMPARISON: Target = 1000 USDT/month = 12,000 USDT/year", flush=True) print(f"{'='*110}", flush=True) print(f" {'方案':<40} {'交易数':>6} {'年净利':>10} {'月均':>8} {'胜率':>6} {'返佣':>10} {'最大回撤':>10} {'达标':>4}", flush=True) print(f" {'-'*104}", flush=True) for r in results: monthly_avg = r['net'] / 12 ok = "Yes" if monthly_avg >= 1000 else "No" print(f" {r['label']:<40} {r['n']:>6} {r['net']:>+10.0f} {monthly_avg:>+8.0f} {r.get('wr',0):>5.1f}% {r['reb']:>10.0f} {r['dd']:>10.0f} {ok:>4}", flush=True) print(f"{'='*110}", flush=True) # 打印最佳方案的月度明细 best = max(results, key=lambda x: x['net']) print(f"\n 最佳方案: {best['label']}", flush=True) print(f" 年净利: {best['net']:+.0f} USDT | 月均: {best['net']/12:+.0f} USDT\n", flush=True) if best['monthly']: print(f" {'月份':<8} {'笔数':>5} {'净利润':>10}", flush=True) print(f" {'-'*28}", flush=True) for m in sorted(best['monthly'].keys()): d = best['monthly'][m] print(f" {m:<8} {d['n']:>5} {d['net']:>+10.0f}", flush=True) print(f" {'-'*28}", flush=True) print(f" {'合计':<8} {best['n']:>5} {best['net']:>+10.0f}", flush=True) def main(): print("Loading data...", flush=True) data = load() print(f"{len(data)} bars loaded\n", flush=True) NOTIONAL = 10000.0 # 100U * 100x results = [] # ============================ # 方案 1: 原始策略(基线) # ============================ t1 = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, NOTIONAL) results.append(analyze(t1, "A1: EMA(8/21) ATR>0.3% [基线]", NOTIONAL)) print(f" A1 done: {len(t1)} trades", flush=True) # ============================ # 方案 2: 加大仓位 - 500U (5倍) # ============================ t2 = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, 50000.0) results.append(analyze(t2, "A2: 基线 x5 (500U保证金)", 50000.0)) print(f" A2 done: {len(t2)} trades", flush=True) # ============================ # 方案 3: 加大仓位 - 1000U (10倍) # ============================ t3 = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, 100000.0) results.append(analyze(t3, "A3: 基线 x10 (1000U保证金)", 100000.0)) print(f" A3 done: {len(t3)} trades", flush=True) # ============================ # 方案 4: 降低ATR到0.15%(更多交易) # ============================ t4 = run_strategy(data, 8, 21, 120, 0.0015, 0.004, 1800, NOTIONAL) results.append(analyze(t4, "B1: ATR>0.15% (更频繁)", NOTIONAL)) print(f" B1 done: {len(t4)} trades", flush=True) # ============================ # 方案 5: ATR>0.1% + 宽止损0.8% # ============================ t5 = run_strategy(data, 8, 21, 120, 0.001, 0.008, 1800, NOTIONAL) results.append(analyze(t5, "B2: ATR>0.1% SL=0.8%", NOTIONAL)) print(f" B2 done: {len(t5)} trades", flush=True) # ============================ # 方案 6: ATR>0.2% + SL=0.8% + 更长持仓3600s # ============================ t6 = run_strategy(data, 8, 21, 120, 0.002, 0.008, 3600, NOTIONAL) results.append(analyze(t6, "B3: ATR>0.2% SL=0.8% MH=3600", NOTIONAL)) print(f" B3 done: {len(t6)} trades", flush=True) # ============================ # 方案 7: 多策略组合(3个不同EMA参数并行,无时间重叠) # ============================ s1 = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, NOTIONAL) s2 = run_strategy(data, 13, 55, 200, 0.002, 0.005, 1800, NOTIONAL) s3 = run_strategy(data, 30, 80, 200, 0.002, 0.008, 3600, NOTIONAL) merged3 = merge_trades([s1, s2, s3]) results.append(analyze(merged3, "C1: 3策略组合 (不重叠)", NOTIONAL)) print(f" C1 done: {len(s1)}+{len(s2)}+{len(s3)} -> {len(merged3)} merged", flush=True) # ============================ # 方案 8: 5策略组合 # ============================ s4 = run_strategy(data, 20, 55, 120, 0.002, 0.006, 1800, NOTIONAL) s5 = run_strategy(data, 8, 34, 200, 0.002, 0.005, 1800, NOTIONAL) merged5 = merge_trades([s1, s2, s3, s4, s5]) results.append(analyze(merged5, "C2: 5策略组合 (不重叠)", NOTIONAL)) print(f" C2 done: -> {len(merged5)} merged", flush=True) # ============================ # 方案 9: 3策略组合 + 加大仓位到 300U # ============================ s1b = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, 30000.0) s2b = run_strategy(data, 13, 55, 200, 0.002, 0.005, 1800, 30000.0) s3b = run_strategy(data, 30, 80, 200, 0.002, 0.008, 3600, 30000.0) merged3b = merge_trades([s1b, s2b, s3b]) results.append(analyze(merged3b, "D1: 3策略+300U仓位", 30000.0)) print(f" D1 done: -> {len(merged3b)} merged", flush=True) # ============================ # 方案 10: 3策略组合 + 500U仓位 # ============================ s1c = run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, 50000.0) s2c = run_strategy(data, 13, 55, 200, 0.002, 0.005, 1800, 50000.0) s3c = run_strategy(data, 30, 80, 200, 0.002, 0.008, 3600, 50000.0) merged3c = merge_trades([s1c, s2c, s3c]) results.append(analyze(merged3c, "D2: 3策略+500U仓位", 50000.0)) print(f" D2 done: -> {len(merged3c)} merged", flush=True) # ============================ # 方案 11: 多策略并行(允许同时持仓,各策略独立运行) # ============================ # 如果账户允许同时持有多个仓位(不同策略各自独立) s1_r = analyze(s1, "sub1") s2_r = analyze(run_strategy(data, 13, 55, 200, 0.002, 0.005, 1800, NOTIONAL), "sub2") s3_r = analyze(run_strategy(data, 30, 80, 200, 0.002, 0.008, 3600, NOTIONAL), "sub3") s4_r = analyze(run_strategy(data, 20, 55, 120, 0.002, 0.006, 1800, NOTIONAL), "sub4") s5_r = analyze(run_strategy(data, 8, 34, 200, 0.002, 0.005, 1800, NOTIONAL), "sub5") # 合并月度(允许重叠 = 各自独立计算再加总) parallel_net = s1_r['net'] + s2_r['net'] + s3_r['net'] + s4_r['net'] + s5_r['net'] parallel_reb = s1_r['reb'] + s2_r['reb'] + s3_r['reb'] + s4_r['reb'] + s5_r['reb'] parallel_fee = s1_r['fee'] + s2_r['fee'] + s3_r['fee'] + s4_r['fee'] + s5_r['fee'] parallel_pnl = s1_r['pnl'] + s2_r['pnl'] + s3_r['pnl'] + s4_r['pnl'] + s5_r['pnl'] parallel_n = s1_r['n'] + s2_r['n'] + s3_r['n'] + s4_r['n'] + s5_r['n'] parallel_dd = max(s1_r['dd'], s2_r['dd'], s3_r['dd'], s4_r['dd'], s5_r['dd']) * 2 # 保守估计 # 合并月度 all_months = set() for sr in [s1_r, s2_r, s3_r, s4_r, s5_r]: all_months.update(sr['monthly'].keys()) parallel_monthly = {} for m in all_months: n_m = 0; net_m = 0 for sr in [s1_r, s2_r, s3_r, s4_r, s5_r]: if m in sr['monthly']: n_m += sr['monthly'][m]['n'] net_m += sr['monthly'][m]['net'] parallel_monthly[m] = {'n': n_m, 'net': net_m} results.append({ 'label': "E1: 5策略并行(允许同时持仓) 100U each", 'n': parallel_n, 'net': parallel_net, 'pnl': parallel_pnl, 'reb': parallel_reb, 'fee': parallel_fee, 'dd': parallel_dd, 'wr': 0, 'monthly': parallel_monthly }) print(f" E1 done: {parallel_n} total trades (parallel)", flush=True) # ============================ # 方案 12: 5策略并行 + 200U仓位 # ============================ N2 = 20000.0 ps1 = analyze(run_strategy(data, 8, 21, 120, 0.003, 0.004, 1800, N2), "p1") ps2 = analyze(run_strategy(data, 13, 55, 200, 0.002, 0.005, 1800, N2), "p2") ps3 = analyze(run_strategy(data, 30, 80, 200, 0.002, 0.008, 3600, N2), "p3") ps4 = analyze(run_strategy(data, 20, 55, 120, 0.002, 0.006, 1800, N2), "p4") ps5 = analyze(run_strategy(data, 8, 34, 200, 0.002, 0.005, 1800, N2), "p5") p_net = ps1['net']+ps2['net']+ps3['net']+ps4['net']+ps5['net'] p_reb = ps1['reb']+ps2['reb']+ps3['reb']+ps4['reb']+ps5['reb'] p_fee = ps1['fee']+ps2['fee']+ps3['fee']+ps4['fee']+ps5['fee'] p_pnl = ps1['pnl']+ps2['pnl']+ps3['pnl']+ps4['pnl']+ps5['pnl'] p_n = ps1['n']+ps2['n']+ps3['n']+ps4['n']+ps5['n'] p_dd = max(ps1['dd'],ps2['dd'],ps3['dd'],ps4['dd'],ps5['dd'])*2 p_monthly = {} for m in all_months: n_m=0; net_m=0 for sr in [ps1,ps2,ps3,ps4,ps5]: if m in sr['monthly']: n_m+=sr['monthly'][m]['n']; net_m+=sr['monthly'][m]['net'] p_monthly[m] = {'n': n_m, 'net': net_m} results.append({ 'label': "E2: 5策略并行 200U each", 'n': p_n, 'net': p_net, 'pnl': p_pnl, 'reb': p_reb, 'fee': p_fee, 'dd': p_dd, 'wr': 0, 'monthly': p_monthly }) print(f" E2 done: {p_n} total trades (parallel 200U)", flush=True) # ============================ # 打印对比 # ============================ print_comparison(results) # 保存 csv = Path(__file__).parent.parent / 'multi_strategy_results.csv' with open(csv, 'w', encoding='utf-8-sig') as f: f.write("方案,交易数,年净利,月均,返佣,最大回撤\n") for r in results: f.write(f"{r['label']},{r['n']},{r['net']:.0f},{r['net']/12:.0f},{r['reb']:.0f},{r['dd']:.0f}\n") print(f"\nSaved: {csv}", flush=True) if __name__ == '__main__': main()