From bdcef09057f58c3258861ee723edc1b3f7d5c660 Mon Sep 17 00:00:00 2001 From: AdrianoDev Date: Thu, 28 May 2026 09:46:24 +0200 Subject: [PATCH] chore: untrack paper_trades runtime data + report per anno/mercato MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - data/paper_trades/ rimosso dal tracking (dati runtime, gitignored) - scripts/analysis/yearly_market_report.py: accuracy/trades/PnL per anno×mercato Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 + .../ML01_squeeze_gbm__ETH__15m/status.json | 13 -- .../ML01_squeeze_gbm__ETH__15m/trades.jsonl | 1 - .../SQ01_squeeze_base__BTC__15m/status.json | 13 -- .../SQ01_squeeze_base__BTC__15m/trades.jsonl | 1 - .../SQ02_antifake_vol__BTC__15m/status.json | 13 -- .../SQ02_antifake_vol__BTC__15m/trades.jsonl | 1 - .../SQ02_antifake_vol__ETH__15m/status.json | 13 -- .../SQ02_antifake_vol__ETH__15m/trades.jsonl | 1 - data/paper_trades/status.json | 8 - .../paper_trades/trades_20260527_093510.jsonl | 2 - .../paper_trades/trades_20260527_093602.jsonl | 3 - .../paper_trades/trades_20260527_100441.jsonl | 6 - scripts/analysis/yearly_market_report.py | 169 ++++++++++++++++++ 14 files changed, 170 insertions(+), 75 deletions(-) delete mode 100644 data/paper_trades/ML01_squeeze_gbm__ETH__15m/status.json delete mode 100644 data/paper_trades/ML01_squeeze_gbm__ETH__15m/trades.jsonl delete mode 100644 data/paper_trades/SQ01_squeeze_base__BTC__15m/status.json delete mode 100644 data/paper_trades/SQ01_squeeze_base__BTC__15m/trades.jsonl delete mode 100644 data/paper_trades/SQ02_antifake_vol__BTC__15m/status.json delete mode 100644 data/paper_trades/SQ02_antifake_vol__BTC__15m/trades.jsonl delete mode 100644 data/paper_trades/SQ02_antifake_vol__ETH__15m/status.json delete mode 100644 data/paper_trades/SQ02_antifake_vol__ETH__15m/trades.jsonl delete mode 100644 data/paper_trades/status.json delete mode 100644 data/paper_trades/trades_20260527_093510.jsonl delete mode 100644 data/paper_trades/trades_20260527_093602.jsonl delete mode 100644 data/paper_trades/trades_20260527_100441.jsonl create mode 100644 scripts/analysis/yearly_market_report.py diff --git a/.gitignore b/.gitignore index 9ce00ec..ff2ffd8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ data/processed/ *.pt *.pth notebooks/.ipynb_checkpoints/ +data/paper_trades/ diff --git a/data/paper_trades/ML01_squeeze_gbm__ETH__15m/status.json b/data/paper_trades/ML01_squeeze_gbm__ETH__15m/status.json deleted file mode 100644 index ee26b70..0000000 --- a/data/paper_trades/ML01_squeeze_gbm__ETH__15m/status.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "capital": 1000, - "in_position": false, - "direction": 0, - "entry_price": 0, - "entry_time": "", - "bars_held": 0, - "total_trades": 0, - "total_wins": 0, - "started_at": "2026-05-27T21:16:02.087963+00:00", - "last_bar_ts": 0, - "last_update": "2026-05-27T21:16:04.705726+00:00" -} \ No newline at end of file diff --git a/data/paper_trades/ML01_squeeze_gbm__ETH__15m/trades.jsonl b/data/paper_trades/ML01_squeeze_gbm__ETH__15m/trades.jsonl deleted file mode 100644 index 5a8a89c..0000000 --- a/data/paper_trades/ML01_squeeze_gbm__ETH__15m/trades.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"ts": "2026-05-27T21:16:02.087975+00:00", "worker": "ML01_squeeze_gbm__ETH__15m", "event": "INIT", "capital": 1000, "strategy": "ML01_squeeze_gbm", "asset": "ETH", "tf": "15m"} diff --git a/data/paper_trades/SQ01_squeeze_base__BTC__15m/status.json b/data/paper_trades/SQ01_squeeze_base__BTC__15m/status.json deleted file mode 100644 index df84190..0000000 --- a/data/paper_trades/SQ01_squeeze_base__BTC__15m/status.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "capital": 1000, - "in_position": false, - "direction": 0, - "entry_price": 0, - "entry_time": "", - "bars_held": 0, - "total_trades": 0, - "total_wins": 0, - "started_at": "2026-05-27T21:16:02.087646+00:00", - "last_bar_ts": 0, - "last_update": "2026-05-27T21:16:04.584685+00:00" -} \ No newline at end of file diff --git a/data/paper_trades/SQ01_squeeze_base__BTC__15m/trades.jsonl b/data/paper_trades/SQ01_squeeze_base__BTC__15m/trades.jsonl deleted file mode 100644 index 38adef4..0000000 --- a/data/paper_trades/SQ01_squeeze_base__BTC__15m/trades.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"ts": "2026-05-27T21:16:02.087660+00:00", "worker": "SQ01_squeeze_base__BTC__15m", "event": "INIT", "capital": 1000, "strategy": "SQ01_squeeze_base", "asset": "BTC", "tf": "15m"} diff --git a/data/paper_trades/SQ02_antifake_vol__BTC__15m/status.json b/data/paper_trades/SQ02_antifake_vol__BTC__15m/status.json deleted file mode 100644 index 0ecde13..0000000 --- a/data/paper_trades/SQ02_antifake_vol__BTC__15m/status.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "capital": 1000, - "in_position": false, - "direction": 0, - "entry_price": 0, - "entry_time": "", - "bars_held": 0, - "total_trades": 0, - "total_wins": 0, - "started_at": "2026-05-27T21:16:02.087214+00:00", - "last_bar_ts": 0, - "last_update": "2026-05-27T21:16:04.339917+00:00" -} \ No newline at end of file diff --git a/data/paper_trades/SQ02_antifake_vol__BTC__15m/trades.jsonl b/data/paper_trades/SQ02_antifake_vol__BTC__15m/trades.jsonl deleted file mode 100644 index 738ca27..0000000 --- a/data/paper_trades/SQ02_antifake_vol__BTC__15m/trades.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"ts": "2026-05-27T21:16:02.087241+00:00", "worker": "SQ02_antifake_vol__BTC__15m", "event": "INIT", "capital": 1000, "strategy": "SQ02_antifake_vol", "asset": "BTC", "tf": "15m"} diff --git a/data/paper_trades/SQ02_antifake_vol__ETH__15m/status.json b/data/paper_trades/SQ02_antifake_vol__ETH__15m/status.json deleted file mode 100644 index 4bbb6a3..0000000 --- a/data/paper_trades/SQ02_antifake_vol__ETH__15m/status.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "capital": 1000, - "in_position": false, - "direction": 0, - "entry_price": 0, - "entry_time": "", - "bars_held": 0, - "total_trades": 0, - "total_wins": 0, - "started_at": "2026-05-27T21:16:02.087438+00:00", - "last_bar_ts": 0, - "last_update": "2026-05-27T21:16:04.463602+00:00" -} \ No newline at end of file diff --git a/data/paper_trades/SQ02_antifake_vol__ETH__15m/trades.jsonl b/data/paper_trades/SQ02_antifake_vol__ETH__15m/trades.jsonl deleted file mode 100644 index 61eb950..0000000 --- a/data/paper_trades/SQ02_antifake_vol__ETH__15m/trades.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"ts": "2026-05-27T21:16:02.087448+00:00", "worker": "SQ02_antifake_vol__ETH__15m", "event": "INIT", "capital": 1000, "strategy": "SQ02_antifake_vol", "asset": "ETH", "tf": "15m"} diff --git a/data/paper_trades/status.json b/data/paper_trades/status.json deleted file mode 100644 index 9687499..0000000 --- a/data/paper_trades/status.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "in_position": false, - "direction": null, - "entry_price": 0, - "entry_time": null, - "bars_held": 0, - "last_update": "2026-05-27T07:40:09.196718+00:00" -} \ No newline at end of file diff --git a/data/paper_trades/trades_20260527_093510.jsonl b/data/paper_trades/trades_20260527_093510.jsonl deleted file mode 100644 index dde44fe..0000000 --- a/data/paper_trades/trades_20260527_093510.jsonl +++ /dev/null @@ -1,2 +0,0 @@ -{"timestamp": "2026-05-27T07:35:10.715321+00:00", "event": "TRAINING", "lookback_days": 365} -{"timestamp": "2026-05-27T07:35:11.967644+00:00", "event": "TRAINING_DONE", "samples": 90, "up_ratio": 48.888888888888886, "train_accuracy": 100.0} diff --git a/data/paper_trades/trades_20260527_093602.jsonl b/data/paper_trades/trades_20260527_093602.jsonl deleted file mode 100644 index 7fe329b..0000000 --- a/data/paper_trades/trades_20260527_093602.jsonl +++ /dev/null @@ -1,3 +0,0 @@ -{"timestamp": "2026-05-27T07:36:03.120802+00:00", "event": "STARTUP", "equity": 101459.276155, "testnet": true} -{"timestamp": "2026-05-27T07:36:03.121518+00:00", "event": "TRAINING", "lookback_days": 365} -{"timestamp": "2026-05-27T07:36:04.249123+00:00", "event": "TRAINING_DONE", "samples": 90, "up_ratio": 48.888888888888886, "train_accuracy": 100.0} diff --git a/data/paper_trades/trades_20260527_100441.jsonl b/data/paper_trades/trades_20260527_100441.jsonl deleted file mode 100644 index 819b710..0000000 --- a/data/paper_trades/trades_20260527_100441.jsonl +++ /dev/null @@ -1,6 +0,0 @@ -{"timestamp": "2026-05-27T08:04:41.544464+00:00", "event": "TRAINING", "lookback_days": 365, "instrument": "ETH-PERPETUAL"} -{"timestamp": "2026-05-27T08:04:42.704464+00:00", "event": "TRAINING_DONE", "samples": 90, "up_ratio": 48.888888888888886, "train_accuracy": 100.0} -{"timestamp": "2026-05-27T08:04:42.918237+00:00", "event": "OPENING", "side": "buy", "amount": 0.216, "price": 2083.75, "virtual_capital": 1000.0, "notional": 450.0, "signal": {"direction": "buy", "probability": 0.75, "squeeze_duration": 10}} -{"timestamp": "2026-05-27T08:04:43.143718+00:00", "event": "OPENED", "order_result": {"order": {"label": "pythagoras-squeeze", "price": 2292.25, "order_id": "USDC-209283595178", "user_id": 81070, "amount": 0.216, "instrument_name": "ETH_USDC-PERPETUAL", "direction": "buy", "time_in_force": "good_til_cancelled", "web": false, "api": true, "creation_timestamp": 1779869083116, "mmp": false, "replaced": false, "post_only": false, "reduce_only": false, "filled_amount": 0.216, "last_update_timestamp": 1779869083116, "average_price": 2083.9, "contracts": 216.0, "order_state": "filled", "order_type": "market", "is_liquidation": false, "risk_reducing": false}, "trades": [{"label": "pythagoras-squeeze", "timestamp": 1779869083116, "state": "filled", "price": 2083.9, "order_id": "USDC-209283595178", "user_id": 81070, "amount": 0.216, "instrument_name": "ETH_USDC-PERPETUAL", "direction": "buy", "index_price": 2083.37, "trade_seq": 6674514, "api": true, "mark_price": 2083.86, "matching_id": null, "tick_direction": 0, "profit_loss": 0.0, "mmp": false, "post_only": false, "reduce_only": false, "self_trade": false, "contracts": 216.0, "trade_id": "USDC-32731729", "fee_currency": "USDC", "order_type": "market", "fee": 0.2250612, "liquidity": "T", "risk_reducing": false}], "data_timestamp": "2026-05-27T08:04:43.126155+00:00"}} -{"timestamp": "2026-05-27T08:04:46.361078+00:00", "event": "CLOSING", "reason": "test", "entry_price": 2083.75, "exit_price": 2083.95, "size": 0.216, "trade_pnl": 0.04, "fee": 0.9, "net_pnl": -0.86, "pnl_pct": -0.086, "bars_held": 0, "capital_before": 1000.0} -{"timestamp": "2026-05-27T08:04:46.574322+00:00", "event": "CLOSED", "result": {"order_id": "USDC-209283608601", "state": "filled", "data_timestamp": "2026-05-27T08:04:46.555823+00:00"}, "net_pnl": -0.86, "pnl_pct": -0.086, "virtual_capital": 999.14} diff --git a/scripts/analysis/yearly_market_report.py b/scripts/analysis/yearly_market_report.py new file mode 100644 index 0000000..20e343c --- /dev/null +++ b/scripts/analysis/yearly_market_report.py @@ -0,0 +1,169 @@ +"""Report accuracy per ANNO × MERCATO delle strategie migliori. + +Esegue ogni strategia vincente su BTC e ETH e produce tabella +accuracy/trades per ogni anno. Permette di vedere robustezza temporale +e differenze tra mercati. +""" +from __future__ import annotations +import sys +sys.path.insert(0, ".") + +import importlib.util +from pathlib import Path + +STRATEGIES_DIR = Path("scripts/strategies") + + +def load_class(module_file, class_name): + path = STRATEGIES_DIR / f"{module_file}.py" + spec = importlib.util.spec_from_file_location(module_file, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return getattr(mod, class_name) + + +# (label, module, class, params, hold) +STRATEGIES = [ + ("SQ02 antifake+vol", "SQ02_squeeze_antifake_vol", "SqueezeAntifakeVol", {}, 3), + ("MT01 ema20+vol", "MT01_squeeze_mtf_momentum", "SqueezeMTFMomentum", + {"ema_period": 20, "min_slope": 0.001, "vol_filter": True}, 3), + ("PD01 vtb3 vm1.3", "PD01_price_volume_divergence", "PriceVolumeDivergence", + {}, 3), + ("CM01 cb6+vol", "CM01_cross_market_momentum", "CrossMarketMomentum", + {"cross_bars": 6, "mom_min": 0.001, "use_vol": True}, 3), + ("AD01 lt.65 ht.95", "AD01_adaptive_squeeze", "AdaptiveSqueeze", + {"low_thr": 0.65, "high_thr": 0.95, "use_vol": True}, 3), +] + +ASSETS = ["BTC", "ETH"] +TF = "15m" +ALL_YEARS = list(range(2018, 2027)) + + +def run(): + results = {} # (label, asset) -> BacktestResult + + for label, module, cls_name, params, hold in STRATEGIES: + try: + cls = load_class(module, cls_name) + except Exception as e: + print(f"SKIP {label}: {e}") + continue + strat = cls() + for asset in ASSETS: + try: + r = strat.backtest(asset, TF, hold=hold, **params) + if r: + results[(label, asset)] = r + except Exception as e: + print(f" errore {label} {asset}: {e}") + + # ── Tabella ACCURACY per anno × mercato ────────────────────────── + print(f"\n{'=' * 140}") + print(f" ACCURACY PER ANNO × MERCATO — {TF} (fee 0.2% RT, leva 3x, pos 15%)") + print(f"{'=' * 140}") + + header = f" {'Strategia':<22s} {'Mkt':>3s}" + for y in ALL_YEARS: + header += f" {y:>7d}" + header += f" │ {'TOT':>6s} {'DD%':>5s} {'Worst':>10s}" + print(header) + print(f" {'─' * 136}") + + for label, module, cls_name, params, hold in STRATEGIES: + for asset in ASSETS: + r = results.get((label, asset)) + if not r: + continue + yd = {ys.year: ys for ys in r.yearly} + line = f" {label:<22s} {asset:>3s}" + for y in ALL_YEARS: + if y in yd: + line += f" {yd[y].accuracy:>5.0f}%↑" if yd[y].accuracy >= 80 else f" {yd[y].accuracy:>5.0f}% " + else: + line += f" {'—':>7s}" + worst = r.worst_year + worst_str = f"{worst.year}({worst.accuracy:.0f}%)" if worst else "N/A" + line += f" │ {r.accuracy:>5.1f}% {r.max_dd:>4.1f}% {worst_str:>10s}" + print(line) + print(f" {'·' * 136}") + + # ── Tabella TRADES per anno × mercato ──────────────────────────── + print(f"\n{'=' * 140}") + print(f" NUMERO TRADES PER ANNO × MERCATO") + print(f"{'=' * 140}") + + header = f" {'Strategia':<22s} {'Mkt':>3s}" + for y in ALL_YEARS: + header += f" {y:>7d}" + header += f" │ {'TOT':>6s} {'€/day':>6s}" + print(header) + print(f" {'─' * 130}") + + for label, module, cls_name, params, hold in STRATEGIES: + for asset in ASSETS: + r = results.get((label, asset)) + if not r: + continue + yd = {ys.year: ys for ys in r.yearly} + line = f" {label:<22s} {asset:>3s}" + for y in ALL_YEARS: + if y in yd: + line += f" {yd[y].trades:>7d}" + else: + line += f" {'—':>7s}" + line += f" │ {r.trades:>6d} {r.daily_pnl:>+6.2f}" + print(line) + print(f" {'·' * 130}") + + # ── Tabella PnL per anno × mercato ────────────────────────────── + print(f"\n{'=' * 140}") + print(f" PnL € PER ANNO × MERCATO (su €1000, no compounding tra anni)") + print(f"{'=' * 140}") + + header = f" {'Strategia':<22s} {'Mkt':>3s}" + for y in ALL_YEARS: + header += f" {y:>7d}" + header += f" │ {'TOT€':>8s}" + print(header) + print(f" {'─' * 132}") + + for label, module, cls_name, params, hold in STRATEGIES: + for asset in ASSETS: + r = results.get((label, asset)) + if not r: + continue + yd = {ys.year: ys for ys in r.yearly} + line = f" {label:<22s} {asset:>3s}" + for y in ALL_YEARS: + if y in yd: + line += f" {yd[y].pnl:>+7.0f}" + else: + line += f" {'—':>7s}" + line += f" │ {r.pnl:>+8.0f}" + print(line) + print(f" {'·' * 132}") + + # ── Sintesi: media per anno (tutte le strategie) ──────────────── + print(f"\n{'=' * 140}") + print(f" SINTESI — Accuracy media per anno (tutte le strategie, BTC+ETH)") + print(f"{'=' * 140}") + year_acc = {y: [] for y in ALL_YEARS} + for (label, asset), r in results.items(): + for ys in r.yearly: + if ys.trades >= 10: + year_acc[ys.year].append(ys.accuracy) + + line_y = f" {'Anno':<22s} " + line_a = f" {'Acc media':<22s} " + for y in ALL_YEARS: + accs = year_acc[y] + avg = sum(accs) / len(accs) if accs else 0 + line_y += f" {y:>7d}" + line_a += f" {avg:>6.1f}%" + print(line_y) + print(line_a) + + +if __name__ == "__main__": + run()