diff --git a/backtesting/engine.py b/backtesting/engine.py index 075f03f..44dfaa9 100644 --- a/backtesting/engine.py +++ b/backtesting/engine.py @@ -361,11 +361,13 @@ def run_backtest(): if abs(d["score"] - current_score) <= margin and d["forward_returns"]: comparable.append(d) - avg_1yr = None + avg_returns = {} if comparable: - yr_returns = [d["forward_returns"]["365d"] for d in comparable if "365d" in d["forward_returns"]] - if yr_returns: - avg_1yr = round(sum(yr_returns) / len(yr_returns), 2) + for period in ["30d", "90d", "180d", "365d"]: + vals = [d["forward_returns"][period] for d in comparable if period in d["forward_returns"]] + if vals: + avg_returns[period] = round(sum(vals) / len(vals), 2) + avg_1yr = avg_returns.get("365d") # Best comparable examples (most recent 5) examples = [] @@ -383,6 +385,9 @@ def run_backtest(): "percentile": percentile, "comparable_days": len(comparable), "avg_1yr_return": avg_1yr, + "avg_30d_return": avg_returns.get("30d"), + "avg_90d_return": avg_returns.get("90d"), + "avg_180d_return": avg_returns.get("180d"), "examples": examples, } diff --git a/config/llm_settings.json b/config/llm_settings.json index 2e532c5..f15bbb2 100644 --- a/config/llm_settings.json +++ b/config/llm_settings.json @@ -1,6 +1,6 @@ { - "provider": "ollama", - "model": "qwen3.5:27b", + "provider": "openrouter", + "model": "minimax/minimax-m2.5", "providers": { "ollama": { "base_url": "http://100.100.242.21:11434" @@ -15,7 +15,7 @@ "api_key": "" }, "openrouter": { - "api_key": "" + "api_key": "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" } } -} +} \ No newline at end of file diff --git a/dashboard/server.py b/dashboard/server.py index d72a42b..df35c62 100644 --- a/dashboard/server.py +++ b/dashboard/server.py @@ -1121,7 +1121,7 @@ tr:hover td{background:var(--card-hover)} Score RangeLabelDays - Avg 30dAvg 90dAvg 1yr + Avg 30dAvg 90dAvg 180dAvg 1yr Win Rate (1yr)Max Gain (1yr)Max Loss (1yr) Avg Max DD @@ -1228,7 +1228,7 @@ function renderAll() { document.getElementById('mainContent').innerHTML = `

Current Signal Context

--

Historical Score vs BTC Price

-

Score Bracket Performance

Score RangeLabelDaysAvg 30dAvg 90dAvg 1yrWin Rate (1yr)Max GainMax LossAvg Max DD
+

Score Bracket Performance

Score RangeLabelDaysAvg 30dAvg 90dAvg 180dAvg 1yrWin Rate (1yr)Max GainMax LossAvg Max DD

Major Signal Events (Score Crossed 70/80/90+)

`; renderContext(); @@ -1246,9 +1246,12 @@ function renderContext() { document.getElementById('ctxPercentile').textContent = 'Historical percentile: top ' + (100 - ctx.percentile).toFixed(1) + '% of all days (' + ctx.comparable_days + ' comparable days found)'; if (ctx.avg_1yr_return != null) { - document.getElementById('ctxReturn').textContent = - 'Average 1-year return from this score level: ' + fmtPct(ctx.avg_1yr_return); - document.getElementById('ctxReturn').className = 'context-return ' + retClass(ctx.avg_1yr_return); + let retHtml = 'Average returns from this score level: '; + if (ctx.avg_30d_return != null) retHtml += '30d: ' + fmtPct(ctx.avg_30d_return) + ' · '; + if (ctx.avg_90d_return != null) retHtml += '90d: ' + fmtPct(ctx.avg_90d_return) + ' · '; + if (ctx.avg_180d_return != null) retHtml += '180d: ' + fmtPct(ctx.avg_180d_return) + ' · '; + retHtml += '1yr: ' + fmtPct(ctx.avg_1yr_return) + ''; + document.getElementById('ctxReturn').innerHTML = retHtml; } // Examples const list = document.getElementById('ctxComparables'); @@ -1259,6 +1262,8 @@ function renderContext() { html += '
' + ex.date + ' — Score ' + ex.score + ' — ' + fmtPrice(ex.price) + ''; html += ''; if (fr['30d'] != null) html += '30d: ' + fmtPct(fr['30d']) + ' '; + if (fr['90d'] != null) html += '90d: ' + fmtPct(fr['90d']) + ' '; + if (fr['180d'] != null) html += '180d: ' + fmtPct(fr['180d']) + ' '; if (fr['365d'] != null) html += '1yr: ' + fmtPct(fr['365d']) + ''; html += '
'; } @@ -1362,6 +1367,7 @@ function renderBracketTable() { html += '' + b.days + ''; html += '' + fmtPct(b.avg_30d) + ''; html += '' + fmtPct(b.avg_90d) + ''; + html += '' + fmtPct(b.avg_180d) + ''; html += '' + fmtPct(b.avg_365d) + ''; html += '' + (b.win_rate_365d != null ? b.win_rate_365d + '%' : '--') + ''; html += '' + fmtPct(b.max_gain_365d) + ''; @@ -1390,6 +1396,7 @@ function renderSignalEvents() { const fr = ev.forward_returns || {}; if (fr['30d'] != null) html += '30d: ' + fmtPct(fr['30d']) + ''; if (fr['90d'] != null) html += '90d: ' + fmtPct(fr['90d']) + ''; + if (fr['180d'] != null) html += '180d: ' + fmtPct(fr['180d']) + ''; if (fr['365d'] != null) html += '1yr: ' + fmtPct(fr['365d']) + ''; if (ev.price_365d) html += 'Price 1yr: ' + fmtPrice(ev.price_365d) + ''; html += ''; diff --git a/data/score_history.jsonl b/data/score_history.jsonl index d93e414..57f906c 100644 --- a/data/score_history.jsonl +++ b/data/score_history.jsonl @@ -2,3 +2,4 @@ {"timestamp": "2026-03-20T22:30:13.547149+00:00", "composite_score": 51.0, "scored_count": 10, "metrics": {"fear_greed": {"score": 7, "value": 11}, "puell_multiple": {"score": 5, "value": 0.6602699608966011}, "mvrv_zscore": {"score": 5, "value": 0.5211180167687892}, "drawdown": {"score": 6, "value": 43.910215736040605}, "price_vs_200w_sma": {"score": 3, "value": 58895.78086828114}, "reserve_risk": {"score": 10, "value": 0.0012985709697654493}, "rhodl_ratio": {"score": 4, "value": 1230.6243545314708}, "nupl": {"score": 7, "value": 0.22243290955405431}, "lth_realized_price": {"score": 1, "value": 43346.58756410873}, "hash_ribbons": {"score": 3, "value": null}}} {"timestamp": "2026-03-20T22:46:34.952569+00:00", "composite_score": 51.0, "scored_count": 10, "metrics": {"fear_greed": {"score": 7, "value": 11}, "puell_multiple": {"score": 5, "value": 0.6602699608966011}, "mvrv_zscore": {"score": 5, "value": 0.5211180167687892}, "drawdown": {"score": 6, "value": 43.931630710659896}, "price_vs_200w_sma": {"score": 3, "value": 58895.78086828114}, "reserve_risk": {"score": 10, "value": 0.0012985709697654493}, "rhodl_ratio": {"score": 4, "value": 1230.6243545314708}, "nupl": {"score": 7, "value": 0.22243290955405431}, "lth_realized_price": {"score": 1, "value": 43346.58756410873}, "hash_ribbons": {"score": 3, "value": null}}} {"timestamp": "2026-03-20T22:51:27.724327+00:00", "composite_score": 54.0, "scored_count": 10, "metrics": {"fear_greed": {"score": 7, "value": 11}, "puell_multiple": {"score": 5, "value": 0.6602699608966011}, "mvrv_zscore": {"score": 5, "value": 0.5211180167687892}, "drawdown": {"score": 6, "value": 43.94907994923858}, "price_vs_200w_sma": {"score": 6, "value": 58895.78086828114}, "reserve_risk": {"score": 10, "value": 0.0012985709697654493}, "rhodl_ratio": {"score": 4, "value": 1230.6243545314708}, "nupl": {"score": 7, "value": 0.22243290955405431}, "lth_realized_price": {"score": 1, "value": 43346.58756410873}, "hash_ribbons": {"score": 3, "value": null}}} +{"timestamp": "2026-03-20T23:07:48.303808+00:00", "composite_score": 51.0, "scored_count": 10, "metrics": {"fear_greed": {"score": 7, "value": 11}, "puell_multiple": {"score": 5, "value": 0.6602699608966011}, "mvrv_zscore": {"score": 5, "value": 0.5211180167687892}, "drawdown": {"score": 6, "value": 43.942734771573605}, "price_vs_200w_sma": {"score": 3, "value": 58895.78086828114}, "reserve_risk": {"score": 10, "value": 0.0012985709697654493}, "rhodl_ratio": {"score": 4, "value": 1230.6243545314708}, "nupl": {"score": 7, "value": 0.22243290955405431}, "lth_realized_price": {"score": 1, "value": 43346.58756410873}, "hash_ribbons": {"score": 3, "value": null}}} diff --git a/screenshots/dashboard-backtest.png b/screenshots/dashboard-backtest.png index bd7bfd1..df22290 100644 Binary files a/screenshots/dashboard-backtest.png and b/screenshots/dashboard-backtest.png differ