"""Independent standard-library signal, fill and accounting replay of three frames.""" import csv import gzip import json import math import sys from collections import defaultdict from datetime import datetime, timezone from pathlib import Path base = Path(sys.argv[1]) if len(sys.argv)>1 else Path(__file__).resolve().parent report = json.loads((base/"research.json").read_text()) with (base/"trades.csv").open(newline="") as f: trades = list(csv.DictReader(f)) with (base/"monthly.csv").open(newline="") as f: months = list(csv.DictReader(f)) for item in report["summary"]: frame = item["timeframe"] ts = [r for r in trades if r["timeframe"] == frame] assert len(ts) == item["trades"] assert sum(float(r["pnl"])>0 for r in ts) == item["winning_trades"] assert sum(float(r["pnl"])<0 for r in ts) == item["losing_trades"] assert abs(sum(float(r["fees"]) for r in ts)-item["fee_usdt"]) < 1e-6 assert abs(sum(float(r["pnl"]) for r in ts)-(item["final_balance"]-10000)) < 1e-6 grouped = defaultdict(list) for r in ts: month = datetime.fromtimestamp(float(r["opened"]),timezone.utc).strftime("%Y-%m") grouped[month].append(float(r["pnl"])) for row in [r for r in months if r["timeframe"] == frame]: assert len(grouped[row["utc_month"]]) == int(row["trades"]) assert abs(sum(grouped[row["utc_month"]])-float(row["net_trade_pnl"])) < 1e-6 assert item["missing_bars"] == 0 with gzip.open(base/f"btc-{frame}-candles.csv.gz", "rt", newline="") as handle: bars = [{k: int(float(v)) if k == "opened" else float(v) for k,v in row.items()} for row in csv.DictReader(handle)] seconds = {"5m":300,"15m":900,"1h":3600}[frame] start = datetime.fromisoformat(report["period_start_utc"].replace("Z","+00:00")).timestamp() # This implementation is intentionally separate from the production indicator and replay code. closes = [bar["c"] for bar in bars] def ema(period): out = [None]*len(closes) seed = sum(closes[:period])/period out[period-1] = seed alpha = 2/(period+1) for n in range(period,len(closes)): out[n] = alpha*closes[n]+(1-alpha)*out[n-1] return out e9,e21 = ema(9),ema(21) def replay(cost): fee,slip = .0005*cost,.0002*cost cash=10000.0; pos=None; output=[] def exit_at(price,ts,reason): nonlocal cash,pos fill=price*(1-slip) gross=(fill-pos["entry"])*pos["quantity"] exit_fee=fill*pos["quantity"]*fee pnl=gross-pos["entry_fee"]-exit_fee cash += gross-exit_fee output.append(dict(opened=pos["opened"],closed=ts,entry=pos["entry"],exit=fill,fees=pos["entry_fee"]+exit_fee,pnl=pnl,reason=reason)) pos=None for n in range(22,len(bars)): bar=bars[n] if bar["opened"] < start: continue up=e9[n-1]>e21[n-1] and e9[n-2]<=e21[n-2] down=e9[n-1]=e21[n-2] if pos and (down or bar["opened"]-pos["opened"]>=48*3600): exit_at(bar["o"],bar["opened"],"Opposite signal" if down else "Time exit") if pos is None and up and cash>0: margin=min(500,max(0,cash*.1)) if margin>=10: fill=bar["o"]*(1+slip) qty=margin/fill entry_fee=qty*fill*fee cash-=entry_fee pos=dict(opened=bar["opened"],entry=fill,quantity=qty,entry_fee=entry_fee,stop=fill*.98,target=fill*1.04) if pos: hit_stop=bar["l"]<=pos["stop"] hit_target=bar["h"]>=pos["target"] if hit_stop: exit_at(min(bar["o"],pos["stop"]),bar["opened"],"Stop first (OHLC)") elif hit_target: exit_at(pos["target"],bar["opened"],"Target (OHLC)") if pos: exit_at(bars[-1]["c"],bars[-1]["opened"]+seconds,"End of sample") return cash,output cash,reproduced=replay(1) assert len(reproduced)==len(ts) checks=0 for observed, expected in zip(reproduced,ts): for key in ("opened","closed","entry","exit","fees","pnl","reason"): a=observed[key];b=expected[key] if key=="reason" else float(expected[key]) assert a==b if key=="reason" else math.isclose(a,b,rel_tol=0,abs_tol=1e-7), (frame,key,a,b) checks+=1 assert math.isclose(cash,item["final_balance"],rel_tol=0,abs_tol=1e-7) double_cash,double_trades=replay(2) assert len(double_trades)==len(ts) assert math.isclose((double_cash/10000-1)*100,item["double_cost_return_pct"],rel_tol=0,abs_tol=1e-7) print(f"{frame}: {len(ts)} trades, {checks} trade fields, ordinary and double-cost end balance PASS") print(f"PASS: {len(trades)} independent closed-bar trade replays; historical paper fills remain a model, not exchange execution.")