Files
DOLPHIN/prod/nautilus_native_gold_repro.py

180 lines
6.9 KiB
Python
Raw Normal View History

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()