import os import sys import json import logging import gc import math import uuid from pathlib import Path from datetime import datetime, timezone import numpy as np import pandas as pd from tqdm import tqdm # --- Project Paths --- BASE_DIR = Path(r"C:\Users\Lenovo\Documents\- DOLPHIN NG HD HCM TSF Predict") sys.path.insert(0, str(BASE_DIR)) sys.path.insert(0, str(BASE_DIR / 'nautilus_dolphin')) from nautilus_trader.backtest.engine import BacktestEngine, BacktestEngineConfig from nautilus_trader.model.identifiers import Venue, InstrumentId from nautilus_trader.model.currencies import USDT from nautilus_trader.model.objects import Money from nautilus_trader.model.data import BarType, Bar from nautilus_trader.model.enums import AccountType, OmsType from nautilus_trader.model.instruments import Instrument from nautilus_dolphin.nautilus.dolphin_actor import DolphinActor from nautilus_dolphin.nautilus.proxy_boost_engine import create_boost_engine # --- [GOLD STANDARD REPRO CONFIGURATION] --- NATIVE_GOLD_CFG = dict( initial_capital=25000.0, vel_div_threshold=-0.02, vel_div_extreme=-0.05, min_leverage=0.5, max_leverage=8.0, leverage_convexity=3.0, fraction=0.20, fixed_tp_pct=0.0095, stop_pct=1.0, max_hold_bars=250, use_direction_confirm=True, dc_lookback_bars=7, dc_min_magnitude_bps=0.75, dc_skip_contradicts=True, dc_leverage_boost=1.0, dc_leverage_reduce=0.5, use_asset_selection=True, min_irp_alignment=0.0, use_sp_fees=True, use_sp_slippage=True, sp_maker_entry_rate=0.62, sp_maker_exit_rate=0.50, use_ob_edge=True, ob_edge_bps=5.0, ob_confirm_rate=0.40, lookback=100, use_alpha_layers=True, use_dynamic_leverage=True, seed=42, boost_mode='d_liq', ) # --- Helpers --- from prod.nautilus_native_backtest import _make_instrument, _make_bar, _FEATURE_STORE def run_gold_repro(): print(f"\n[!] LAUNCHING GOLD REPRO V12 (THE FORTRESS): T=2155 | ROI=181.81% (Target)") data_dir = BASE_DIR / "vbt_cache" # Process exactly 56 days as per Gold Standard parquet_files = sorted(data_dir.glob("202*.parquet"))[0:56] if not parquet_files: print(f"ERROR: No parquet files found in {data_dir}") return venue = Venue("BINANCE") config = BacktestEngineConfig(trader_id="GOLD-REPRO-012") engine = BacktestEngine(config=config) # Starting capital engine.add_venue(venue, OmsType.NETTING, AccountType.MARGIN, [Money(25000.0, USDT)]) actor_cfg = { 'initial_capital': 25000.0, 'paper_trade': {'initial_capital': 25000.0}, 'native_mode': True, 'registered_assets': [], 'engine_cfg': NATIVE_GOLD_CFG } _FEATURE_STORE.clear() all_bars = [] df0 = pd.read_parquet(parquet_files[0]) excluded = {'timestamp', 'scan_number', 'v50_lambda_max_velocity', 'v150_lambda_max_velocity', 'v300_lambda_max_velocity', 'v750_lambda_max_velocity', 'vel_div', 'instability_50', 'instability_150'} assets = [c for c in df0.columns if c not in excluded] actor_cfg['registered_assets'] = assets bar_type_map = {} for sym in assets: inst = _make_instrument(sym, venue) if inst: engine.add_instrument(inst) bt_str = f"{sym}.BINANCE-5-SECOND-LAST-EXTERNAL" bar_type_map[sym] = BarType.from_str(bt_str) print(f"[*] Pre-loading {len(parquet_files)} days ({len(assets)} assets)...") global_row_idx = 0 for pf in tqdm(parquet_files): df = pd.read_parquet(pf) columns = df.columns.tolist() day_str = pf.stem day_dt = datetime.strptime(day_str, '%Y-%m-%d').replace(tzinfo=timezone.utc) day_start_ns = int(day_dt.timestamp() * 1e9) vd_idx = columns.index('vel_div') if 'vel_div' in columns else -1 v50_idx = columns.index('v50_lambda_max_velocity') if 'v50_lambda_max_velocity' in columns else -1 v750_idx = columns.index('v750_lambda_max_velocity') if 'v750_lambda_max_velocity' in columns else -1 inst50_idx = columns.index('instability_50') if 'instability_50' in columns else -1 asset_indices = {sym: columns.index(sym) for sym in assets if sym in columns} data = df.values.tolist() for i, row in enumerate(data): ts_ns = day_start_ns + i * 5 * 1_000_000_000 vol_ok = (global_row_idx >= 100) # FORTRESS FIX: Sanitize features. Replace NaNs with reasonable defaults. def _safe_float(val, default=0.0): if val is None: return default try: f = float(val) return f if math.isfinite(f) else default except: return default _FEATURE_STORE[ts_ns] = { 'vel_div': _safe_float(row[vd_idx], 0.0) if vd_idx != -1 else 0.0, 'v50': _safe_float(row[v50_idx], 0.0) if v50_idx != -1 else 0.0, 'v750': _safe_float(row[v750_idx], 0.0) if v750_idx != -1 else 0.0, 'inst50': _safe_float(row[inst50_idx], 0.0) if inst50_idx != -1 else 0.0, 'vol_ok': vol_ok, 'row_i': i, } # Non-BTC assets first for sym in assets: if sym == 'BTCUSDT': continue idx = asset_indices.get(sym) if idx is not None: p = row[idx] if p is not None and p > 0 and math.isfinite(p): bar = _make_bar(bar_type_map[sym], float(p), ts_ns) if bar: all_bars.append(bar) # BTC last (The "Heartbeat" of DolphinActor) if 'BTCUSDT' in asset_indices: p = row[asset_indices['BTCUSDT']] if p is not None and p > 0 and math.isfinite(p): bar = _make_bar(bar_type_map['BTCUSDT'], float(p), ts_ns) if bar: all_bars.append(bar) global_row_idx += 1 del df, data gc.collect() print(f"[RAM] Pre-load complete. {len(all_bars):,} bars synthesized.") actor = DolphinActor(actor_cfg) engine.add_strategy(actor) # Inject all bars into the engine queue engine.add_data(all_bars) print(f"[NATIVE] Executing Gold-Repro V12 ({len(all_bars):,} bars)...") t0 = datetime.now() engine.run() dur = (datetime.now() - t0).total_seconds() stats = actor.engine.get_performance_summary() print("\n" + "="*72) print(f" GOLD REPRO RESULTS (V12 - FORTRESS)") print(f" ROI : {stats['total_return']*100:+.2f}%") print(f" Trades : {stats['total_trades']}") print(f" Final Capital : ${stats['final_capital']:,.2f}") print(f" Elapsed : {dur/60:.1f} min") print("="*72) if __name__ == "__main__": os.environ['PYTHONIOENCODING'] = 'utf-8' run_gold_repro()