How symbols are ranked — and what to expect
One list, four 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 3 slots in. A symbol opens a bot only if all four pass; it is then ranked purely on funding.
- 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 at all (per-position APY 6.9% → 7.0% → 7.4% going 0 → 1.0 → 2.0pp) while slot utilisation collapsed 100% → 86% → 48%. It looks backward, and mostly re-measures what the score already sorts on. A floor of 0 keeps only the useful part: the symbol must have paid something net positive.
- Funding still alive today (latest ≥ 0.02%/8h) — the real funding gate now, so a symbol that paid well then died cannot
coast in on history. 0.01 is Gate's baseline rate — the house default when the market is balanced, which 65% of candidates sit at exactly — so a floor
above it is what separates genuine demand from "not zero". It also matches the bot's own live open gate (
CARRY_MIN_FUNDING_OPEN): below it the bot refuses to open, so anything qualified between 0.01 and 0.02 was a launched bot that could never take a position. - The spot leg lends ≥ 0.005 pp/day, measured on rates actually PAID, not advertised.
- The entry is reachable —
openP95 ≥ 0.05%. The bot only opens above that bar, so if the symbol's basis never gets there the entry simply never prints and the slot idles. This is an upper-tail question, not a typical-day one: measured on 54 real fills, the bot's actual entries sit above openP75 on 93% of positions (mean gap +0.388) — it waits for the good print, so the tail is what decides reachability.
Score = realized funding × persistence. Lending is not in the score — it only gates.
Why lending is a gate and not a score
A coin lends richly because a crowd wants to borrow it — to short it. That same crowd shorts the perp,
which pushes funding against us. Measured corr(lending, funding) = −0.759. Ranking on net income therefore
selects precisely the symbols where the two cancel: over 27 backtested dates those picks earned
+0.2675 pp/d lending and paid −0.2617 funding — a wash. That was the RLC trade.
The gate is mostly a junk filter, not an income source
It lifts income from −1.608 to +0.406pp. A coin nobody will lend against has no borrow market, which usually means thin or newly listed: its trailing funding spike is noise that reverts, and its book is wide. Filtering on book width alone does not work (−2.159pp), so lendability carries information the book does not.
Why a rejected symbol can show HIGHER income than a ranked one
It can, and that is the gate doing its job. Today AI shows the highest total income of any candidate (0.194 pp/d) and is rejected because it lends 0.0% — no borrow market. The bet is that such a symbol's funding is a spike that reverts, not a rate you will still be collecting in two weeks. Over 27 backtested dates that bet paid: unfiltered picks realized −1.608pp of income, filtered picks +0.406pp. The Total income column is trailing history; the gate is a forecast about which of it survives.
What to expect — median P&L per position, 4 slots, basis and fees priced in:
| rank funding, require lending (this rule) | +0.930pp | win 59% |
| rank net income (the old second door) | −0.183pp | win 48% |
| rank funding, no lending gate | −2.062pp | win 33% |
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%). Expect few trades held long — churn is the main way this loses money.
Caveats: 27 decision dates over May–Jul 2026, one regime. The backtest holds blind — no death clock,
funding-collapse stop or time stop — so its mean is worse than the live system; the median is the honest figure.
Harnesses: earn_ranking_backtest_pnl.js (P&L) and earn_ranking_backtest.js (income only).
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.
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.
botScheduler.js. Safe to use — the scheduler will resume its normal 15-min tick cycle.dashboard_audit.jsonl.
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.