Turin LT: the curve matches, the live signal does not

This is the cleanest possible answer to a messy replication request: historical fidelity passes; strategy admission fails. The notebook reruns everything from committed offline fixtures. It never fetches TradingView.

In [1]:
from pathlib import Path
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import HTML, display
from backtest.turin_lt_claudified import run_fidelity_backtest, fidelity_comparison

ROOT = Path.cwd()
result, events = run_fidelity_backtest()
curves, metrics = fidelity_comparison(result, events)
pd.Series(metrics, name='frozen 80% replay').to_frame()
Out[1]:
frozen 80% replay
correlation 0.999982
coverage 1.000000
normalized_rmse 0.027824
change_sign_agreement 1.000000
final_normalized_ratio 1.013028

1. What is known — and what is not

Part Publicly documented Still protected
Entry breadth washout + A/D thrust + realized-vol gate exact breadth horizon/EMA/threshold, A/D formula, vol window/floor
Exit breadth repair exact repair threshold
Position long only, 80% of equity, pyramiding one SPY chart vs SPXL metadata conflict
Costs 0% commission, 0 ticks slippage no hidden exceptions observed
Timing process_orders_on_close=false Pine text is unavailable, so no source hash exists

Unavailable values stay unavailable. Nothing below estimates them.

In [2]:
rule_table = pd.DataFrame([
 {'rule':'Entry','implementation':'Replay exact published entry event at 80% SPY','divergence':'Cannot generate a new entry'},
 {'rule':'Exit','implementation':'Replay exact published exit event to 0% SPY','divergence':'Hidden repair threshold'},
 {'rule':'Lag','implementation':'run_backtest(... execution=next_open)','divergence':'Event replay, not live causality'},
 {'rule':'Cash','implementation':'Residual zero-yield cash','divergence':'Source cash yield undisclosed'},
])
rule_table
Out[2]:
rule implementation divergence
0 Entry Replay exact published entry event at 80% SPY Cannot generate a new entry
1 Exit Replay exact published exit event to 0% SPY Hidden repair threshold
2 Lag run_backtest(... execution=next_open) Event replay, not live causality
3 Cash Residual zero-yield cash Source cash yield undisclosed

2. The visual result

Both lines start at $1. The solid line is the published report reconstructed from cumulative profit; the dashed line is QuantModel's canonical engine. The match is about the whole path, not just the endpoint.

In [3]:
fig, ax = plt.subplots(figsize=(11, 5.5))
ax.plot(curves.index, curves['tradingview_equity'], lw=2.4, label='Published report')
ax.plot(curves.index, curves['replay_equity'], '--', lw=1.8, label='QuantModel replay')
ax.set(title=f"Normalized event equity · corr {metrics['correlation']:.6f}", xlabel='Event date', ylabel='Growth of $1')
ax.grid(alpha=.25); ax.legend(frameon=False); plt.show()
No description has been provided for this image

3. Stress the result without tuning it

The frozen robustness matrix includes costs, a 100% sizing ablation, the final open mark, a daily adjusted-SPY path, and one extra event lag. The extra-lag failure is important: it proves timing is doing real work and was not massaged away.

In [4]:
robust = json.loads((ROOT/'research/findings/turin-lt-robustness-qm-wpx5.json').read_text())
rows=[]
for name, item in robust['matrix'].items():
    metric=item.get('metrics', {})
    rows.append({'variant':name, 'status':item.get('status'), 'correlation':metric.get('correlation', item.get('event_equity_correlation')), 'terminal ratio':metric.get('final_normalized_ratio')})
pd.DataFrame(rows)
Out[4]:
variant status correlation terminal ratio
0 source_zero_cost_80pct evaluated 0.999982 1.013028
1 base_cost_10bps evaluated 0.999985 0.972446
2 double_cost_20bps evaluated 0.999944 0.933474
3 published_weight_ablation_100pct evaluated 0.998783 1.572871
4 terminal_open_mark_included evaluated 0.999980 1.013149
5 one_extra_event_lag evaluated -0.767979 0.081205
6 daily_adjusted_spy_path evaluated_as_path_ablation 0.999474 NaN

4. Try the predeclared cost range

Move the slider from 0 to 20 basis points. Every position was precomputed by the real backtest engine; the browser redraws annual derived summaries and recomputes correlation and the terminal ratio. This is a sensitivity viewer, not an optimizer.

In [5]:
source_annual = curves['tradingview_equity'].resample('YE').last()
cost_payload = {'labels':[d.date().isoformat() for d in source_annual.index], 'source':source_annual.tolist(), 'curves':{}}
for bps in range(21):
    r, e = run_fidelity_backtest(fee_bps=float(bps))
    c, _ = fidelity_comparison(r, e)
    annual = c['replay_equity'].resample('YE').last().reindex(source_annual.index)
    cost_payload['curves'][str(bps)] = annual.tolist()
DATA = json.dumps(cost_payload, separators=(',', ':'))
display(HTML('''<div id="turin-cost-playground" style="border:1px solid #ddd;padding:16px;border-radius:10px">
<label for="turin-cost-slider"><b>One-way cost:</b> <span id="turin-cost-value">0</span> bps</label>
<input id="turin-cost-slider" type="range" min="0" max="20" value="0" step="1" style="width:100%">
<p id="turin-cost-metrics"></p><canvas id="turin-cost-canvas" width="900" height="360" style="max-width:100%;height:auto"></canvas></div>
<script>(function(){const D=''' + DATA + ''';const s=document.getElementById('turin-cost-slider'),v=document.getElementById('turin-cost-value'),m=document.getElementById('turin-cost-metrics'),cv=document.getElementById('turin-cost-canvas'),x=cv.getContext('2d');
function corr(a,b){let n=a.length,ma=a.reduce((q,z)=>q+z,0)/n,mb=b.reduce((q,z)=>q+z,0)/n,xy=0,xx=0,yy=0;for(let i=0;i<n;i++){let da=a[i]-ma,db=b[i]-mb;xy+=da*db;xx+=da*da;yy+=db*db}return xy/Math.sqrt(xx*yy)}
function line(a,color,dash){x.strokeStyle=color;x.lineWidth=3;x.setLineDash(dash);x.beginPath();let all=D.source.concat(a),lo=Math.min(...all),hi=Math.max(...all);a.forEach((z,i)=>{let px=45+i*(cv.width-70)/(a.length-1),py=cv.height-35-(z-lo)*(cv.height-65)/(hi-lo);i?x.lineTo(px,py):x.moveTo(px,py)});x.stroke()}
function draw(){let b=s.value,a=D.curves[b];v.textContent=b;m.textContent='Correlation '+corr(a,D.source).toFixed(6)+' · terminal ratio '+(a[a.length-1]/D.source[D.source.length-1]).toFixed(4);x.clearRect(0,0,cv.width,cv.height);x.fillStyle='#666';x.fillText('Annual normalized equity (blue: report, orange: replay)',45,18);line(D.source,'#4c72b0',[]);line(a,'#dd8452',[8,5])}s.addEventListener('input',draw);draw()})();</script>'''))

5. Decision

Fidelity only. Correlation and visual shape pass, but a strategy catalog entry must produce future allocations from point-in-time inputs. This replay consumes the historical orders themselves. The Pine source, exact signal defaults, and an untouched economic window are unavailable.

Raw TradingView HTML, the publisher screenshot, fill prices, and individual trade observations are intentionally absent from this public notebook output.

In [6]:
pd.DataFrame([
 {'artifact':'public page archive', 'sha256':'eba7a280…f364', 'public output':'hash and rule summary only'},
 {'artifact':'equity fixture', 'sha256':'564e1af6…e4dd', 'public output':'annual normalized summaries + generated chart'},
 {'artifact':'frozen protocol', 'sha256':'3229e940…f898', 'public output':'full protocol summary'},
 {'artifact':'strategy code', 'sha256':'0a4515c6…e1d', 'public output':'repository source'},
])
Out[6]:
artifact sha256 public output
0 public page archive eba7a280…f364 hash and rule summary only
1 equity fixture 564e1af6…e4dd annual normalized summaries + generated chart
2 frozen protocol 3229e940…f898 full protocol summary
3 strategy code 0a4515c6…e1d repository source