← rangeRider

rangeRider — Fixes

BLOCKEDAudited 2026-09-15· hand-written (no shared engine) engine· quantroduction· spot

Every defect the audit found and how it was repaired — the same measurements as the engineering record, without the code.

4 issues found and repaired — 3 defects, 1 warning.

# Issue Severity Surface
1 Any setting typed as 0 was silently ignored DEFECT user inputs
2 Eleven numbers on the side panel had no explanation WARNING side panel
3 The GUI offers a maximum-drawdown slider on a strategy that has no way to sell at a loss DEFECT user inputs
4 It could buy on a third of an order and refused to place one below a whole order DEFECT behaviour

Every fix was verified by re-running the full backtest across all 7 markets and comparing the result record against the pre-fix baseline. Where a fix is stated to change no behaviour, the two records are identical to the byte.


Any setting typed as 0 was silently ignored

Severity DEFECT · Surface user inputs · Sites 14

Every numeric setting was read through a fallback idiom meaning use the operator's value, or the baked default. In JavaScript zero is falsy, so the idiom could not tell zero from unset — a setting of zero was replaced by the baked default, with no warning and no log line.

Why it matters. Zero is a meaningful value for most of these settings, and in several cases it is the only way to turn a feature off: no minimum gain percentage, no DCA layers, a zero-fee venue, no exposure cap. The single input an operator could not express was the one that disables a behaviour. Worse, the side panel then displayed the default as though it were the operator's own setting, so there was nothing on screen to reveal that the instruction had been discarded.

RR_MAX_DCA on BTCUSDT 1h — before the fix, 0 and unset were indistinguishable

RR_MAX_DCA buys peak deployed meaning
unset 11 95.6% default of 10 DCA layers
0 — before the fix 11 95.6% ignored, silently became 10
0 — after the fix 3 16.0% DCA disabled, as typed
3 — after the fix 8 58.7% three layers

The fix. Replaced the idiom with a reader that separates "not set" from "set to zero". It returns the default for undefined, null, "" and a non-numeric value — exactly what the old idiom returned in those cases — and the operator's number for everything else, including 0. This also closes the second hole in the old idiom: a non-numeric setting parses to NaN, and only the short-circuit stopped NaN reaching the arithmetic.

Effect on live behaviour. None at any setting that previously worked. The 3-year run across all 7 markets is byte-identical before and after. The change is only visible to an operator who types 0, which previously did nothing.

Scope beyond this strategy. Pack-wide: 1,743 sites across 70 files use this idiom. This audit built the fixer and applied it to this strategy only; the tool refuses any file where an affected setting reaches a divisor, so the rest can be done safely one at a time.


Eleven numbers on the side panel had no explanation

Severity WARNING · Surface side panel · Sites 11

The Gunbot side panel showed values such as RSI, Gain, DCA Level, Round Trips and Max DD with either no tooltip property or an empty one. Hovering told the operator nothing.

Why it matters. The side panel is where an operator checks what a strategy is doing without reading its code. A number with no label explanation is not information — it is something to guess at, and guessing about Break Even or Daily loss limit while a position is open is exactly when a wrong guess costs money.

Side-panel rows on this strategy

before after
data rows 22 22
with a tooltip 11 21
with no tooltip 11 1
section headers (need none) 5 5

The one remaining row is Holding. It is left deliberately unexplained: across the pack that label is used both for a yes/no and for a quantity held, so no single wording is true everywhere. A wrong tooltip is worse than a missing one, because the operator believes it.

The fix. Filled the missing tooltips from a new shared glossary of side-panel labels, keyed on the label text. The glossary says what each number is, and where it helps, how to read it — Round Trips, for instance, becomes "Completed buy-then-sell cycles. The unit a strategy's performance is actually made of." A label absent from the glossary is reported rather than filled.

Effect on live behaviour. None. Tooltips are display text. Verified by re-running the full 3-year backtest on all 7 markets and diffing the result record — identical to the byte.

Scope beyond this strategy. Pack-wide: 1,433 side-panel rows across the pack put a number on screen with no tooltip, spread over 392 distinct labels. The distribution is heavily skewed — Anchor alone appears 101 times — so a shared glossary repairs most of it once. This audit built that glossary.


The GUI offers a maximum-drawdown slider on a strategy that has no way to sell at a loss

Severity DEFECT · Surface user inputs · Sites 1

The Gunbot settings panel offers this strategy a maximum-drawdown slider, running from 0 to 60 and set to 15 out of the box. The strategy reads that number and then never looks at it again.

On most strategies that would be a wasted control. Here it is worse, because there was no other way out of a losing position either — the only sell this strategy makes is at a profit target above what the position cost. No stop, no time limit, no drawdown exit. Anyone who set a maximum drawdown got no protection at all, and nothing told them.

Over three years the drawdown went past that 15% setting on six of the seven markets tested.

Why it matters. A risk control that does nothing is worse than no risk control, because the operator sizes their position believing it is there. This one sat on a strategy that, by design, never sells at a loss — so the setting was the only thing standing between the account and an unbounded hold, and it was not standing anywhere.

Measured drawdown against the 15% the slider showed, 3 years x 7 markets at 15m

Market max drawdown vs the 15% setting
ETH 44.0% exceeded by 29.0 points
XRP 27.8% exceeded by 12.8 points
SOL 26.0% exceeded by 11.0 points
DOGE 23.8% exceeded by 8.8 points
LINK 20.5% exceeded by 5.5 points
ADA 17.1% exceeded by 2.1 points
BTC 13.1% within

Six of seven markets past the limit the GUI implied was in force, the worst of them at nearly three times it.

The fix. The setting is now connected to a real exit: when a position falls the configured percentage below what it cost, the whole holding is sold and the grid resets.

It ships switched off, rather than at the 15 the dead slider used to show. That 15 was never actually in force, so switching it on by default would silently change the behaviour of every existing installation — on a strategy whose whole character is that it never sells at a loss. Anyone who wants the protection now gets it by setting the number.

The repair also refuses to fail quietly in one particular case. This strategy ships an optional break-even guard that blocks any sale below cost — which is every sale this stop would ever make. Two optional safety features cancelling each other without saying so is worse than either alone, so when both are switched on the strategy now says so in the log and names the setting that resolves it.

Re-measured after the change, 3 years x 7 markets at 15m

Setting result
RR_MAX_DD = 0 (as shipped) every market byte-identical — same buys, same sells, same return
RR_MAX_DD > 0 arms the stop; not the default, and an operator opting in should measure it on their own pair

Effect on live behaviour. None at the shipped default, and that is verified rather than asserted — the knob ships at 0 and the re-measurement returned identical trades and returns on all seven markets. Setting it to any positive value arms a real stop that did not previously exist.

Scope beyond this strategy. Found by a new scan of the whole Quantroduction lineage, which the audit's existing knob measurement could not see — it wraps the shared shared config accessor, and these files read whatstrat directly. That scan found 162 dead settings across 62 files, of which 5 are risk controls: this one, both of cashFlowEngine's (a stop loss and a bag-drawdown limit), phantomEngine's exposure cap, and fundingRateFarmer's trade cooldown.


It could buy on a third of an order and refused to place one below a whole order

Severity DEFECT · Surface behaviour · Sites 2

The strategy asks two questions before buying and they disagree. The first, "may I trade this cycle?", is satisfied by holding a third of an order's worth of cash. The second, "may I place this order?", refuses anything less than a whole order — and never sizes the order down to fit what is actually available.

Every balance between those two levels passes the first and fails the second. Because the order size only ever grows, an account that drifts into that band stays there for good, silently.

Why it matters. A strategy that stops trading and does not say so reports its floor as its performance. This one is calibrated to a capital at which it never reaches the band, so the published numbers are unaffected — but an operator on a smaller account would be running a strategy that had switched itself off.

The fix. Size the order to the cash that is actually there, and use the same threshold for placing an order that the strategy already used for deciding whether to trade at all. The two tests now agree, and the figure is the strategy's own rather than one chosen for it.

Re-measured after the change, 3 years x 7 markets at 15m

Market buys sells return
ADA 14 → 14 3 → 3 1.17% → 1.17%
BTC 257 → 257 63 → 63 21.76% → 21.76%
DOGE 78 → 78 25 → 25 6.80% → 6.80%
ETH 590 → 590 142 → 142 5.53% → 5.53%
LINK 80 → 80 20 → 20 6.71% → 6.71%
SOL 156 → 156 41 → 41 13.36% → 13.36%
XRP 188 → 188 49 → 49 15.85% → 15.85%

Effect on live behaviour. None at the calibrated capital: every market returned identical trades and returns. The repair binds on a smaller account, which is the case it exists for.

Scope beyond this strategy. 24 strategies in the pack carry this, found by the audit tooling. On this one it is latent at the capital the audit calibrates to, and active on a smaller account.