fig, axes = plt.subplots(2, 2, figsize=(16, 10))
# H1: Lookback
ax = axes[0, 0]
for lb_m, lb_d in [(6, 126), (9, 189), (12, 252), (18, 378)]:
ret = backtest_dual_momentum(closes, ['SPY', 'EFA'], 'BND', lookback=lb_d)
cum = (1 + ret).cumprod()
ax.plot(cum.index, cum, label=f'{lb_m}m', linewidth=1.5)
ax.set_title('H1: Lookback period', fontweight='bold')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
# H2: Threshold
ax = axes[0, 1]
for thresh in [-0.05, 0.0, 0.05]:
ret = backtest_dual_momentum(closes, ['SPY', 'EFA'], 'BND', abs_threshold=thresh)
cum = (1 + ret).cumprod()
ax.plot(cum.index, cum, label=f'Seuil {thresh:+.0%}', linewidth=1.5)
ax.set_title('H2: Abs. momentum threshold', fontweight='bold')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
# H3: Refuge
ax = axes[1, 0]
for refuge in ['BND', 'IEF', 'SHY', 'GLD']:
ret = backtest_dual_momentum(closes, ['SPY', 'EFA'], refuge)
cum = (1 + ret).cumprod()
ax.plot(cum.index, cum, label=f'Refuge: {refuge}', linewidth=1.5)
ax.set_title('H3: Refuge alternatives', fontweight='bold')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
# H4: Universe
ax = axes[1, 1]
for name, risky in universes.items():
ret = backtest_dual_momentum(closes, risky, 'BND')
cum = (1 + ret).cumprod()
ax.plot(cum.index, cum, label=name, linewidth=1.5)
spy_cum = (1 + spy_ret).cumprod()
ax.plot(spy_cum.index, spy_cum, label='SPY B&H', linestyle='--', alpha=0.5)
ax.set_title('H4: Univers elargi', fontweight='bold')
ax.legend(fontsize=7)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('dualmomentum_quantbook_analysis.png', dpi=150, bbox_inches='tight')
plt.show()