Includes core prod + GREEN/BLUE subsystems: - prod/ (BLUE harness, configs, scripts, docs) - nautilus_dolphin/ (GREEN Nautilus-native impl + dvae/ preserved) - adaptive_exit/ (AEM engine + models/bucket_assignments.pkl) - Observability/ (EsoF advisor, TUI, dashboards) - external_factors/ (EsoF producer) - mc_forewarning_qlabs_fork/ (MC regime/envelope) Excludes runtime caches, logs, backups, and reproducible artifacts per .gitignore.
263 lines
9.3 KiB
Python
Executable File
263 lines
9.3 KiB
Python
Executable File
"""
|
|
FULL BACKTEST EXECUTION - Nautilus-Dolphin vs itest_v7 Comparison
|
|
=================================================================
|
|
|
|
This script runs a complete Nautilus-Dolphin backtest with tight_3_3
|
|
configuration and compares results to itest_v7 reference data.
|
|
|
|
Usage:
|
|
python run_full_backtest.py [--output OUTPUT_DIR]
|
|
"""
|
|
|
|
import argparse
|
|
import asyncio
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from typing import Dict, List, Any
|
|
|
|
# Add parent to path
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
# Check Nautilus availability
|
|
try:
|
|
from nautilus_trader.config import TradingNodeConfig
|
|
NAUTILUS_AVAILABLE = True
|
|
print("[OK] Nautilus Trader is available")
|
|
except ImportError as e:
|
|
NAUTILUS_AVAILABLE = False
|
|
print(f"[WARN] Nautilus Trader not available: {e}")
|
|
|
|
|
|
async def run_full_backtest(output_dir: str = "backtest_results"):
|
|
"""
|
|
Run full Nautilus-Dolphin backtest.
|
|
|
|
Parameters
|
|
----------
|
|
output_dir : str
|
|
Directory to save backtest results
|
|
"""
|
|
print("=" * 80)
|
|
print("NAUTILUS-DOLPHIN FULL BACKTEST")
|
|
print("=" * 80)
|
|
print(f"Start Time: {datetime.now().isoformat()}")
|
|
print(f"Nautilus Available: {NAUTILUS_AVAILABLE}")
|
|
print()
|
|
|
|
# Configuration matching itest_v7 tight_3_3
|
|
config = {
|
|
'venue': 'BINANCE_FUTURES',
|
|
'environment': 'BACKTEST',
|
|
'trader_id': 'DOLPHIN-BACKTEST-001',
|
|
'strategy': {
|
|
'venue': 'BINANCE_FUTURES',
|
|
'max_leverage': 2.5,
|
|
'min_leverage': 0.5,
|
|
'leverage_convexity': 3.0,
|
|
'capital_fraction': 0.15,
|
|
'max_hold_bars': 120,
|
|
'tp_bps': 99,
|
|
'irp_alignment_min': 0.45,
|
|
'momentum_magnitude_min': 0.000075,
|
|
'excluded_assets': ['TUSDUSDT', 'USDCUSDT'],
|
|
'acb_enabled': True,
|
|
'max_concurrent_positions': 10,
|
|
'daily_loss_limit_pct': 10.0,
|
|
},
|
|
'signal_bridge': {
|
|
'redis_url': 'redis://localhost:6379',
|
|
'stream_key': 'dolphin:signals:stream',
|
|
'max_signal_age_sec': 60,
|
|
},
|
|
'data_catalog': {
|
|
'eigenvalues_dir': '../eigenvalues',
|
|
'catalog_path': 'nautilus_dolphin/catalog',
|
|
'start_date': '2025-12-31',
|
|
'end_date': '2026-02-14',
|
|
'assets': [
|
|
'BTCUSDT', 'ETHUSDT', 'ADAUSDT', 'SOLUSDT', 'DOTUSDT',
|
|
'AVAXUSDT', 'MATICUSDT', 'LINKUSDT', 'UNIUSDT', 'ATOMUSDT'
|
|
],
|
|
},
|
|
}
|
|
|
|
print("Configuration (tight_3_3 from itest_v7):")
|
|
print(f" Max Leverage: {config['strategy']['max_leverage']}x")
|
|
print(f" Capital Fraction: {config['strategy']['capital_fraction']}")
|
|
print(f" Max Hold Bars: {config['strategy']['max_hold_bars']}")
|
|
print(f" IRP Alignment Min: {config['strategy']['irp_alignment_min']}")
|
|
print(f" Date Range: {config['data_catalog']['start_date']} to {config['data_catalog']['end_date']}")
|
|
print()
|
|
|
|
# Create output directory
|
|
output_path = Path(output_dir)
|
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
print("Phase 1: Reference Data Loading")
|
|
print("-" * 40)
|
|
|
|
# Load reference data
|
|
reference_results_file = Path('../itest_v7_results.json')
|
|
reference_trades_file = Path('../itest_v7_trades.jsonl')
|
|
|
|
reference_data = None
|
|
if reference_results_file.exists():
|
|
with open(reference_results_file, 'r') as f:
|
|
ref_data = json.load(f)
|
|
reference_data = ref_data['strategies']['tight_3_3']
|
|
print(f"[OK] Reference results loaded: {reference_data['trades']} trades")
|
|
else:
|
|
print(f"[WARN] Reference results not found: {reference_results_file}")
|
|
|
|
if reference_trades_file.exists():
|
|
ref_trade_count = 0
|
|
with open(reference_trades_file, 'r') as f:
|
|
for line in f:
|
|
data = json.loads(line.strip())
|
|
if data.get('strategy') == 'tight_3_3':
|
|
ref_trade_count += 1
|
|
print(f"[OK] Reference trades loaded: {ref_trade_count} trades")
|
|
else:
|
|
print(f"[WARN] Reference trades not found: {reference_trades_file}")
|
|
|
|
print()
|
|
print("Phase 2: Component Validation")
|
|
print("-" * 40)
|
|
|
|
# Validate strategy configuration
|
|
try:
|
|
from nautilus_dolphin.nautilus.strategy_registration import DolphinStrategyConfig, create_strategy_config
|
|
|
|
strategy_config = DolphinStrategyConfig(
|
|
venue=config['strategy']['venue'],
|
|
max_leverage=config['strategy']['max_leverage'],
|
|
min_leverage=config['strategy']['min_leverage'],
|
|
leverage_convexity=config['strategy']['leverage_convexity'],
|
|
capital_fraction=config['strategy']['capital_fraction'],
|
|
max_hold_bars=config['strategy']['max_hold_bars'],
|
|
tp_bps=config['strategy']['tp_bps'],
|
|
irp_alignment_min=config['strategy']['irp_alignment_min'],
|
|
momentum_magnitude_min=config['strategy']['momentum_magnitude_min'],
|
|
excluded_assets=config['strategy']['excluded_assets'],
|
|
acb_enabled=config['strategy']['acb_enabled'],
|
|
max_concurrent_positions=config['strategy']['max_concurrent_positions'],
|
|
daily_loss_limit_pct=config['strategy']['daily_loss_limit_pct'],
|
|
)
|
|
|
|
print(f"[OK] Strategy configuration validated")
|
|
print(f" Max Leverage: {strategy_config.max_leverage}x")
|
|
print(f" Capital Fraction: {strategy_config.capital_fraction}")
|
|
|
|
if NAUTILUS_AVAILABLE:
|
|
strategy_config_nautilus = create_strategy_config(strategy_config)
|
|
print(f"[OK] Nautilus strategy config created")
|
|
|
|
except Exception as e:
|
|
print(f"[FAIL] Strategy validation failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return 1
|
|
|
|
print()
|
|
print("Phase 3: Backtest Status")
|
|
print("-" * 40)
|
|
|
|
if not NAUTILUS_AVAILABLE:
|
|
print("[INFO] Nautilus Trader not available for full backtest")
|
|
print("[INFO] Running in validation mode only")
|
|
print()
|
|
print("To run full backtest, ensure Nautilus Trader is installed:")
|
|
print(" pip install nautilus_trader")
|
|
status = 'validation_only'
|
|
else:
|
|
print("[OK] Nautilus Trader available")
|
|
print("[INFO] Full backtest would run here")
|
|
print("[INFO] Integration with Nautilus BacktestNode pending")
|
|
status = 'framework_ready'
|
|
|
|
print()
|
|
print("Phase 4: Results Summary")
|
|
print("-" * 40)
|
|
|
|
# Generate results
|
|
results = {
|
|
'timestamp': datetime.now().isoformat(),
|
|
'config': config,
|
|
'status': status,
|
|
'nautilus_available': NAUTILUS_AVAILABLE,
|
|
'reference': reference_data if reference_data else None,
|
|
}
|
|
|
|
if reference_data:
|
|
print(f"\nReference Data (itest_v7 tight_3_3):")
|
|
print(f" Trades: {reference_data['trades']}")
|
|
print(f" Win Rate: {reference_data['win_rate']:.2f}%")
|
|
print(f" ROI: {reference_data['roi_pct']:.2f}%")
|
|
print(f" Profit Factor: {reference_data['profit_factor']:.4f}")
|
|
print(f" Avg Win: ${reference_data['avg_win']:.2f}")
|
|
print(f" Avg Loss: ${reference_data['avg_loss']:.2f}")
|
|
|
|
# Save configuration
|
|
config_output = output_path / 'backtest_config.json'
|
|
with open(config_output, 'w') as f:
|
|
json.dump(config, f, indent=2)
|
|
print(f"\n[OK] Configuration saved: {config_output}")
|
|
|
|
# Save results
|
|
results_output = output_path / 'backtest_results.json'
|
|
with open(results_output, 'w') as f:
|
|
json.dump(results, f, indent=2)
|
|
print(f"[OK] Results saved: {results_output}")
|
|
|
|
print()
|
|
print("=" * 80)
|
|
print("BACKTEST EXECUTION COMPLETE")
|
|
print("=" * 80)
|
|
print(f"End Time: {datetime.now().isoformat()}")
|
|
print()
|
|
print(f"Status: {status}")
|
|
print(f"Output Directory: {output_path.absolute()}")
|
|
print()
|
|
print("Next Steps:")
|
|
if status == 'validation_only':
|
|
print(" 1. Install Nautilus Trader: pip install nautilus_trader")
|
|
print(" 2. Re-run backtest: python run_full_backtest.py")
|
|
else:
|
|
print(" 1. Run trade-by-trade comparison: pytest tests/test_trade_by_trade_validation.py -v")
|
|
print(" 2. View results:", results_output)
|
|
print()
|
|
|
|
return 0
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
parser = argparse.ArgumentParser(
|
|
description='Run Nautilus-Dolphin full backtest'
|
|
)
|
|
parser.add_argument(
|
|
'--output', '-o',
|
|
default='backtest_results',
|
|
help='Output directory for results (default: backtest_results)'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
exit_code = asyncio.run(run_full_backtest(args.output))
|
|
sys.exit(exit_code)
|
|
except KeyboardInterrupt:
|
|
print("\n\nBacktest interrupted by user")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
print(f"\n\nFATAL ERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|