Files
DOLPHIN/prod/diag_day1_trades.py

282 lines
10 KiB
Python
Raw Normal View History

"""
Day-1 trade-level comparison: process_day vs actor-style step_bar loop.
Prints every trade entry/exit with bar_idx, gidx, bars_held, exit_type, pnl.
Focus: identify which trade(s) differ between the two paths on 2025-12-31.
"""
import sys, math, pathlib
import numpy as np
import pandas as pd
sys.path.insert(0, '/mnt/dolphinng5_predict')
sys.path.insert(0, '/mnt/dolphinng5_predict/nautilus_dolphin')
print("Importing...", flush=True)
from nautilus_dolphin.nautilus.proxy_boost_engine import create_boost_engine
print("Import done.", flush=True)
PARQUET_DIR = pathlib.Path('/mnt/dolphinng5_predict/vbt_cache')
VOL_P60_INWINDOW = 0.00009868
ENG_KWARGS = dict(
max_hold_bars=120,
min_irp_alignment=0.45,
max_leverage=8.0,
vel_div_threshold=-0.02, vel_div_extreme=-0.05,
min_leverage=0.5, leverage_convexity=3.0,
fraction=0.20, fixed_tp_pct=0.0095, stop_pct=1.0,
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,
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,
)
def make_engine(initial_capital=25000.0):
return create_boost_engine(mode='d_liq', initial_capital=initial_capital, **ENG_KWARGS)
def load_day(date_str):
p = PARQUET_DIR / f"{date_str}.parquet"
return pd.read_parquet(p)
def compute_vol_ok(df):
"""Actor method: 49-ret window, static threshold, stored at j."""
btc_f = df['BTCUSDT'].values.astype('float64')
n = len(btc_f)
vol_ok = np.zeros(n, dtype=bool)
for j in range(50, n):
seg = btc_f[max(0, j-50):j]
diffs = np.diff(seg)
denom = seg[:-1]
if np.any(denom == 0):
continue
v = float(np.std(diffs / denom))
if math.isfinite(v) and v > 0:
vol_ok[j] = v > VOL_P60_INWINDOW
return vol_ok
def build_prices(row, assets):
prices = {}
for sym in assets:
try:
v = float(row[sym])
if math.isfinite(v):
prices[sym] = v
except:
pass
return prices
ASSET_COLS = [c for c in ['BTCUSDT','ETHUSDT','BNBUSDT','LTCUSDT','XRPUSDT','ADAUSDT',
'LINKUSDT','ATOMUSDT','DOGEUSDT','XLMUSDT','TRXUSDT','ALGOUSDT'] ]
def run_pd(df, initial_capital=25000.0):
"""Process_day path: NaN vel_div increments _global_bar_idx."""
eng = make_engine(initial_capital)
eng.begin_day('2025-12-31')
btc_f = df['BTCUSDT'].values.astype('float64')
vol_ok = compute_vol_ok(df)
trades = []
for i in range(len(df)):
row = df.iloc[i]
vd_raw = row['vel_div']
vd = None if (vd_raw is None or not math.isfinite(float(vd_raw))) else float(vd_raw)
if vd is None:
eng._global_bar_idx += 1
continue
v750 = float(row.get('v750_lambda_max_velocity', 0.0))
inst50 = float(row.get('instability_50', 0.0))
v50 = float(row.get('v50_lambda_max_velocity', 0.0))
prices = build_prices(row, [c for c in df.columns if c.endswith('USDT')])
prev_cap = eng.capital
prev_pos = eng.position
gidx_before = eng._global_bar_idx
if hasattr(eng, 'pre_bar_proxy_update'):
eng.pre_bar_proxy_update(inst50, v750)
result = eng.step_bar(
bar_idx=i,
vel_div=vd,
prices=prices,
v50_vel=v50,
v750_vel=v750,
vol_regime_ok=bool(vol_ok[i]),
)
new_pos = eng.position
new_cap = eng.capital
if prev_pos is None and new_pos is not None:
trades.append({'ev':'ENTRY','row':i,'gidx':gidx_before,'cap':new_cap,'price':btc_f[i]})
elif prev_pos is not None and new_pos is None:
trades.append({'ev':'EXIT','row':i,'gidx':gidx_before,'cap':new_cap,'pnl':new_cap-prev_cap})
eng.end_day()
return eng, trades
def run_fixed(df, initial_capital=25000.0):
"""Fixed actor path: NaN vel_div DOES increment _global_bar_idx (matches process_day)."""
eng = make_engine(initial_capital)
eng.begin_day('2025-12-31')
btc_f = df['BTCUSDT'].values.astype('float64')
vol_ok = compute_vol_ok(df)
trades = []
for i in range(len(df)):
row = df.iloc[i]
vd_raw = row['vel_div']
vd = None if (vd_raw is None or not math.isfinite(float(vd_raw))) else float(vd_raw)
if vd is None:
# FIXED: increment _global_bar_idx to match process_day
eng._global_bar_idx += 1
continue
v750 = float(row.get('v750_lambda_max_velocity', 0.0))
inst50 = float(row.get('instability_50', 0.0))
v50 = float(row.get('v50_lambda_max_velocity', 0.0))
prices = build_prices(row, [c for c in df.columns if c.endswith('USDT')])
prev_cap = eng.capital
prev_pos = eng.position
gidx_before = eng._global_bar_idx
if hasattr(eng, 'pre_bar_proxy_update'):
eng.pre_bar_proxy_update(inst50, v750)
result = eng.step_bar(
bar_idx=i,
vel_div=vd,
prices=prices,
v50_vel=v50,
v750_vel=v750,
vol_regime_ok=bool(vol_ok[i]),
)
new_pos = eng.position
new_cap = eng.capital
if prev_pos is None and new_pos is not None:
trades.append({'ev':'ENTRY','row':i,'gidx':gidx_before,'cap':new_cap,'price':btc_f[i]})
elif prev_pos is not None and new_pos is None:
trades.append({'ev':'EXIT','row':i,'gidx':gidx_before,'cap':new_cap,'pnl':new_cap-prev_cap})
eng.end_day()
return eng, trades
def run_act(df, initial_capital=25000.0):
"""Actor path: NaN vel_div does NOT increment _global_bar_idx."""
eng = make_engine(initial_capital)
eng.begin_day('2025-12-31')
btc_f = df['BTCUSDT'].values.astype('float64')
vol_ok = compute_vol_ok(df)
trades = []
for i in range(len(df)):
row = df.iloc[i]
vd_raw = row['vel_div']
vd = None if (vd_raw is None or not math.isfinite(float(vd_raw))) else float(vd_raw)
if vd is None:
# ACT path: skip entirely — _global_bar_idx NOT incremented
continue
v750 = float(row.get('v750_lambda_max_velocity', 0.0))
inst50 = float(row.get('instability_50', 0.0))
v50 = float(row.get('v50_lambda_max_velocity', 0.0))
prices = build_prices(row, [c for c in df.columns if c.endswith('USDT')])
prev_cap = eng.capital
prev_pos = eng.position
gidx_before = eng._global_bar_idx
if hasattr(eng, 'pre_bar_proxy_update'):
eng.pre_bar_proxy_update(inst50, v750)
result = eng.step_bar(
bar_idx=i,
vel_div=vd,
prices=prices,
v50_vel=v50,
v750_vel=v750,
vol_regime_ok=bool(vol_ok[i]),
)
new_pos = eng.position
new_cap = eng.capital
if prev_pos is None and new_pos is not None:
trades.append({'ev':'ENTRY','row':i,'gidx':gidx_before,'cap':new_cap,'price':btc_f[i]})
elif prev_pos is not None and new_pos is None:
trades.append({'ev':'EXIT','row':i,'gidx':gidx_before,'cap':new_cap,'pnl':new_cap-prev_cap})
eng.end_day()
return eng, trades
def main():
print("\n=== DAY 1 TRADE COMPARISON: 2025-12-31 ===", flush=True)
df = load_day('2025-12-31')
nan_count = df['vel_div'].isna().sum()
print(f"Rows: {len(df)}, NaN vel_div: {nan_count}", flush=True)
# Show where NaN rows cluster
nan_rows = df.index[df['vel_div'].isna()].tolist()
print(f"NaN rows (first 10): {nan_rows[:10]}", flush=True)
pd_eng, pd_trades = run_pd(df)
act_eng, act_trades = run_act(df)
fix_eng, fix_trades = run_fixed(df)
pd_exits = [t for t in pd_trades if t['ev']=='EXIT']
act_exits = [t for t in act_trades if t['ev']=='EXIT']
fix_exits = [t for t in fix_trades if t['ev']=='EXIT']
print(f"\nPD: T={len(pd_exits)}, cap=${pd_eng.capital:.2f}, pnl=${pd_eng.capital-25000:.2f}", flush=True)
print(f"ACT: T={len(act_exits)}, cap=${act_eng.capital:.2f}, pnl=${act_eng.capital-25000:.2f}", flush=True)
print(f"FIX: T={len(fix_exits)}, cap=${fix_eng.capital:.2f}, pnl=${fix_eng.capital-25000:.2f}", flush=True)
print("\n--- PD TRADES (entry+exit pairs) ---", flush=True)
entries = {t['row']: t for t in pd_trades if t['ev']=='ENTRY'}
for t in pd_trades:
if t['ev'] == 'ENTRY':
print(f" E row={t['row']:4d} gidx={t['gidx']:4d} btc={t['price']:.2f}", flush=True)
else:
# Find matching entry
e = next((x for x in reversed(pd_trades[:pd_trades.index(t)]) if x['ev']=='ENTRY'), None)
held = t['gidx'] - (e['gidx'] if e else 0)
print(f" X row={t['row']:4d} gidx={t['gidx']:4d} held={held:3d} pnl={t['pnl']:+8.2f} cap=${t['cap']:.2f}", flush=True)
print("\n--- ACT TRADES (entry+exit pairs) ---", flush=True)
for t in act_trades:
if t['ev'] == 'ENTRY':
print(f" E row={t['row']:4d} gidx={t['gidx']:4d} btc={t['price']:.2f}", flush=True)
else:
e = next((x for x in reversed(act_trades[:act_trades.index(t)]) if x['ev']=='ENTRY'), None)
held = t['gidx'] - (e['gidx'] if e else 0)
print(f" X row={t['row']:4d} gidx={t['gidx']:4d} held={held:3d} pnl={t['pnl']:+8.2f} cap=${t['cap']:.2f}", flush=True)
# Diff: find first divergence
print("\n--- DIVERGENCE ANALYSIS ---", flush=True)
for i, (p, a) in enumerate(zip(pd_trades, act_trades)):
if p['ev'] != a['ev'] or p['row'] != a['row'] or p['gidx'] != a['gidx']:
print(f" First divergence at trade event #{i}:", flush=True)
print(f" PD: {p}", flush=True)
print(f" ACT: {a}", flush=True)
break
else:
if len(pd_trades) != len(act_trades):
print(f" Paths agree up to min length, but PD has {len(pd_trades)} events vs ACT {len(act_trades)}", flush=True)
else:
print(" Paths are identical in trade events!", flush=True)
if __name__ == '__main__':
main()