—
Capital
Loading…
System Processes
Active Positions 0
Open Positions 0
Running Bots 0
Selection funnel 0
Bands are proportional to symbol count, with a minimum width so single-symbol flows stay visible — always read the number, not the thickness. Rows counted here are symbol/venue verdicts: stale_samples is evaluated outside the ranked universe, so the skipped total can exceed the universe count. The alive door above is a separate population (a top-N diagnostic list), never summed with these.
Ranking funnel 0
How symbols are ranked — and what to expect

One list, three conditions, one score. This table is the whole decision: every symbol the optimizer considered, the stage it failed at, and — for the survivors — the order the scheduler fills its 8 bot slots in. A symbol opens a bot only if all three pass; it is then ranked purely on funding. Carry only — spread-mean-reversion ranking was removed on 2026-08-17: it was never simulated, and on these books the executable close spread (VWAP at leg size) runs ~1% against a −0.20 target, so a basis round trip cannot pay for itself.

  1. Funding paid ≥ 0pp over 14 days — the thesis, and the income we are actually buying. v16.4 retired the old 1.0pp bar: tested alone it did not improve pick quality (per-position APY 6.9% → 7.0% → 7.4% going 0 → 1.0 → 2.0pp) while slot utilisation collapsed 100% → 86% → 48%. A floor of 0 keeps only the useful part: the symbol must have paid something net positive.
  2. Funding still alive today (latest ≥ 0.02%/8h), so a symbol that paid well then died cannot coast in on history. Read as an EMA (α=0.05), not a spot value — changed 2026-08-17. Gate's quoted rate is a FORECAST of the next settlement and it resets at every boundary, rebuilding from the premium index over the interval. Measured over 3,644 settlements on 287 symbols, predicting the rate actually paid: EMA r=0.984 · interval mean r=0.953 · single sample r=0.878 · last settlement r=0.850. A single sample's own accuracy swings 0.84→0.98 depending where in the interval it lands, and it disagreed with the settled rate on 14% of 916k samples across 77% of symbols — which flipped marginal names in and out every settlement and cycled their bots.
  3. Expected value must be positive — realized funding × persistence, minus the 0.30pp round trip amortised over the hold. A negative score literally means "expected to lose at these thresholds". Added 2026-08-17 after two symbols ranked at −0.029 and −0.041/day (breakeven 6.9d and 27.8d, one with negative mean funding and persistence 0.20) — both qualified on sporadic spikes rather than steady carry.

Score = realized funding × persistence, net of amortised fees. Lending is not in it, and no longer gates either.

THREE EXIT RULES REMOVED on 2026-08-23 — min-hold, dead-thesis, RULE 7

Measured on research/bot_sim_v16.js, Jan–Jul 2026 (212d, 30s books, 4 slots, 340 capital, entry bar 0.30, 2×). The three rules were tested together, because they interact:

confignet USDT APY totaltrades basisfees utilwin
all three OFF (now live)65.40 33.12%87 +27.43−14.54 92.8%95%
+ dead-thesis only60.23 30.50%149 +27.90−25.26 78.4%75%
+ RULE 7 only57.44 29.09%109 +15.47−18.41 88.0%70%
+ min-hold only50.72 25.68%53 +11.85−8.97 93.5%92%
all three ON (previous live)47.20 23.90%132 +8.85−22.30 77.9%61%

+18.20 USDT (+38.6%) on the same capital, with 87 trades instead of 132 — fewer, more profitable, higher occupancy. Min-hold was the most expensive single rule (−14.68), almost entirely basis (+27.43 → +11.85): it forbids a spread_target exit for 75–120h, so positions that reach their basis target are held through the compression and give it back. It was also what made the dead-thesis exit look necessary — with min-hold on, the dead exit is the only way out of a locked position, so removing only the dead exit is worse than removing neither. They had to go together. RULE 7 (−7.96) recycles into fresher payers but pays the round trip twice. Restore with MIN_HOLD=1, CARRY_DEAD_EXIT=1, RECYCLE_ENABLED=1.

⚠ REGIME CAVEAT — WITHDRAWN 2026-08-24. It was a DATA ARTEFACT, not a regime. The original caveat said the gain was concentrated in Jan–May and the sign flipped late (Jan01–Mar15 +10.54, Mar15–May22 +8.38, May22–Jul31 −1.84, Apr15–Jul31 −4.89), and warned the change “optimises for a regime that may have passed”. That split was measuring the data source. The simulator's runtime funding gates read FundingHistoryDaily, which changes schema mid-window — true daily (dailySum) through April, 3-day smoothed (mean) from May — so the two halves ran on different data, and the flip sits exactly on that boundary. Re-measured with --true-daily (gates rebuilt from the settlement CSVs, one method across the whole window):

period delta, smoothed delta, TRUE daily
Jan01–Mar15+10.54+11.78
Mar15–May22+8.38+10.64
May22–Jul31−1.84−0.23
Apr15–Jul31−4.89+19.52 ← sign flips

Removing the three rules wins in every period once the data is honest. Mechanism: the dead-exit floor is 0.0110 and Gate's house minimum is a point mass at 0.0100. The smoothed mean sat above 0.0110 far more often than the truth did, so it MASKED how constantly the dead clock fires — with true rates the all-rules-on arm churns down to 12.24 on Apr15–Jul31 where the smoothed run flattered it to 31.74. Do not re-derive a regime conclusion from any run without --true-daily.

⚠ The published 38.91% baseline overstates the live system. research/bot_sim_v16_result.json was generated with --no-rule7 --no-minhold, i.e. without two rules that were live. Live-faithful before this change was 30.68% deployed / 23.90% total, not 38.91%. Regenerate via research/export_sim_result.js at the live config.

Two gates were REMOVED on 2026-08-17 — and why

The lending gate (spot leg must lend ≥ 0.005 pp/day) is gone. Its evidence was real but unrepeatable: EarnRateDaily spans 21 days and EarnAprHistory stops at 2026-08-04, so it could not be re-tested on the 7-month set the rest of the strategy was validated on. Against it: PTB lends 0.59% APR — far under the floor — and is the best-paying position in the book at 109%/yr; and the reading itself was broken, forcing ppDay to 0 when history was thin, so AIO reported "5.7% APR = 0.0000pp/d" and was rejected as a non-lender on stale data. Restore with EARN_GATE=1 if live trades show it earning its keep.

The reachability gate (openP95 ≥ 0.05) is gone — it was costing money. Backtested Jan–Jul on 30s order-book data, 4 slots / 300 capital: no gate 34.28% APY vs p95≥0.05 21.62%, removing only 7 of 128 trades. The mechanism: p95 measures the body of the basis distribution, but entries happen in the tail — the last 10 live entries were 0.309–0.319 against a 0.30 bar. So it discarded symbols that sit flat and spike occasionally, which is exactly the profitable carry entry. Restore with CARRY_REACH_GATE=1.

Why a rejected symbol can show HIGHER income than a ranked one

Trailing income is history; the ranking is a forecast about which of it survives. A symbol can show strong 14-day funding and still be rejected because its EV is negative once fees are amortised, or because its funding is already dead today. The Total income column looks backward; the score does not.

Hold length dominates. Friction is ~0.5–0.6pp fixed per round trip while income scales with time: median P&L is +0.165pp at 7d, +0.930pp at 14d, +1.339pp at 21d, +2.372pp at 28d (win 92%). Churn is the main way this loses money — which is also why the alive gate reads a smoothed rate rather than a spot one.

Caveats: the removals above rest on a Jan–Jul 30s backtest (4 slots, 300 capital, entry bar 0.30) and on live evidence; the lending gate could not be re-tested at all for want of data. Reachability magnitude is fragile — 12.7pp rests on a 7-trade difference — though its direction held across every setting tried. Harnesses: research/bot_sim_v16.js, carry_backtest_v15.js.

Loading…
Validation — is live doing what the simulation said?
Loading…
Current strategy — live configuration, simulated on 2025 and 2026
Archived — August 2026 portfolio simulation (older harness: Jan–Jul, 4 slots / 300 USDT, no clip execution — superseded by the section above)
Continuous portfolio simulation
What this is — and why it disagrees with the older numbers

The earlier harness asked “if I opened on day X, what happened over the next N days?” for every X independently. Two problems: starting Monday and starting Tuesday share N−1 of their N days, so 64 dates were really about 5 independent periods; and every date re-picked the top N from scratch, so a held position never actually occupied a slot a better symbol then couldn’t use.

This walks the period once, holding real positions in real slots until a real exit fires. Hold length is an outcome, not an input. The honest sample is therefore the trade count below — not the number of dates.

Max rise per trade is the worst upward price excursion during the hold. For a cash-and-carry the pair is delta-neutral in P&L, but the SHORT leg’s margin is eaten by a price rise with no offset — Gate gives these symbols a 0 collateral discount — so that column is what a liquidation would have come from. “Liq at” lists the leverages that excursion would have blown, before safeguard RULE 5 deleveraging.

Which close statistic the exit uses — and why it changed

The bot watches continuously and fires the instant the close spread prints below its threshold (sustained ~120 ms). So the right daily question is “did it ever GET there?”, not “where did it sit?”. With 2398 samples/day from the 30-second order-book archive, closeP25 is a level the spread holds for a quarter of the day — far too conservative. Using it forced windowLevel down to an artificial −0.750 just to make exits fire at a realistic rate. Switching to a deep statistic lets the level be the bot’s real −0.20 threshold. The difference is not small — see the sweep below.

Why leverage does not add value here

It is not RULE 5 over-reacting: most trades take zero or one shed of ~10%, and only a symbol that ran +41.85% needed four. Leverage fails because one position in seven moves so violently that no amount of deleveraging saves it (LAB ran +127%, IN +265%). The extra notional is worth ~50%; a single liquidation in six-to-eight trades costs more than that. Every exit model tested gives the same ordering.

Loading…
Effective leverage through the period · a 3× run, so RULE 5 can be seen working
Each line is one position's notional ÷ equity as its own price moved. It starts at 3×, rises when price runs against the short, and drops each time RULE 5 sheds. The dashed line is the trip level (3 × 1.35 = 4.05×); the red line is where the short dies.
Loading…
Threshold-crossing durations — how long spreads sit beyond the open / close bar
Loading…
Side: Group: Window:
Loading…
“% ≥ floor” = share of crossings that outlast the bot’s sustain floor (open 100 ms / close 200 ms) — i.e. actionable opportunities. “fired” = episodes that triggered a real order.
Burst confirmation — does a fresh crossing PERSIST? (cross_sampler re-fetches ~0.6 s; phantom vs durable)
Loading…
Side: Group: Window:
Loading…
“confirm %” = share of bursts that persisted (≥50 % of samples still over threshold). On the Open side, a row highlighted 🚫 is phantom-gated by the scheduler: ≥4 bursts of evidence and confirm-rate < 25 % → its bot launch is suppressed. Depegs confirm high (they persist) and are filtered separately.

Research loop

checking…
Offline simulation only, running outside the live fleet. It is propose-only — nothing it finds is ever applied automatically. A result is promotable only if it wins 2 of 3 periods, wins on the shared-symbol subset, clears a bar that rises with the experiment count, and then also wins on sealed August, which the loop never optimises against.
Loading…
WORKER LOG
…
Entry unwinds — aborted one-leg entries (fees you paid without a trade)
Loading…
Closed Positions (last 50)
Scheduler
Start or restart botScheduler.js. Safe to use — the scheduler will resume its normal 15-min tick cycle.
Spread Thresholds — edit spreadThresholds.json
Search for a symbol, adjust the open/close thresholds, then type the confirmation phrase. The file is written atomically with rolling backups (last 5 kept as .bak.N). Changes are picked up by bots on their next hot-reload cycle (hourly).
—
Stop a Single Bot
SIGINT + delete from PM2 and RunningBot collection. Refused if the bot has an open position — use Force Close Position below for that case.
⚠ Force Close Position
Stops the bot, then places market orders to close the position (spot sell + futures close). Use when a position is stuck (thresholds unreachable, bot unresponsive). Review the preview carefully — the estimate is rough; actual P&L is computed from fill prices.
Recent Actions (audit log)
Last 50 destructive actions. Stored in dashboard_audit.jsonl.
⏸ Pause new entries — let open positions finish
Writes halt.flag with mode:"no-new". The scheduler keeps open-position bots running, so they still take their basis exit, time stop, patient time stop and safeguard rules — it simply launches nothing new.

This is the switch for a wind-down or a capital change. HALT below is not: it stops every bot, which leaves an open position with no bot at all and only safeguard's 5-minute margin tick watching it. Nothing is closed here — use force-close for that.
⛔ HALT — stop everything and keep it stopped
Stops every bot and writes a halt flag the scheduler honours on every tick, so nothing comes back — not after pm2 start botScheduler.js, not after pm2 resurrect, not after a reboot. This is the difference from “Stop All” below, which the scheduler undoes on its next tick.

The scheduler is deliberately left running so safeguard.js keeps protecting open positions — halting stops trading, it does not abandon your money. Open positions are not closed; use force-close for that.

Type HALT to confirm.
Scheduler process ⚠️ Stopping the scheduler also stops safeguard — nothing will watch margin, liquidations or the death clock on open positions. HALT alone is the safer stop; use this only when you need the process itself down.
⚠ Danger Zone — Stop All Bots (does NOT stay stopped — prefer HALT above)
This will gracefully SIGINT every running bot (waits 8s each for order cancellation), then stop the scheduler. ⚠️ It leaves no flag: anything that starts the scheduler again relaunches the whole fleet. Type STOP ALL BOTS to confirm.
RAM Usage —
CPU Usage —
Bot Count —
Event Loop Lag —
Bot Health —
Per-Bot Memory