btcRegimeScaler — Fixes
Every defect the audit found and how it was repaired — the same measurements as the engineering record, without the code.
5 issues found and repaired — 4 defects, 1 warning.
| # | Issue | Severity | Surface |
|---|---|---|---|
| 1 | The daily reset read the wall clock, so in a backtest the day never changed and the circuit breaker latched forever | DEFECT | behaviour |
| 2 | The strategy allowed itself to trade on half an order's cash, then demanded a whole one | DEFECT | behaviour |
| 3 | The console audit reported a silent logger on 29 files whose logging was fine | DEFECT | measurement |
| 4 | Any setting typed as 0 was silently ignored | DEFECT | user inputs |
| 5 | Nine side-panel rows with no explanation | WARNING | side panel |
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.
The daily reset read the wall clock, so in a backtest the day never changed and the circuit breaker latched forever
Severity DEFECT · Surface behaviour · Sites 2
The backtest engine pins the clock to candle time so a run is deterministic:
The code behind this is in the engineering record, which this site does not publish.
That pins the millisecond clock function. It does not pin the bare date constructor, which reads the host clock directly and ignores any override of it. The strategy opens every cycle with
The code behind this is in the engineering record, which this site does not publish.
so a three-year run sees exactly one calendar day and the reset never fires.
Why it matters. On this strategy the daily reset is the only thing that can clear a latch which sits above the trading logic:
The code behind this is in the engineering record, which this site does not publish.
The counter is incremented by a losing sell and zeroed by either a winning sell or the daily reset. With the reset dead and the guard returning before execute() is ever called, the strategy cannot sell — so it cannot book the winning trade that is now its only way out. Three losing trades killed it permanently.
It is not a marginal effect. Across all seven markets the breaker first tripped between cycle 1,446 and cycle 5,507 — inside the first few months of a three-year window — and the strategy then sat switched off for 155,049 of 176,120 decision cycles, 88.0% of the run.
Everything the pre-fix backtest reported was therefore a measurement of a strategy that had stopped. A median +7.4% return, profitable on 5 of 7 markets, a 15.4% drawdown and 3.3% time in market: those are the numbers of an account sitting in cash. This is the defect that matters most on this file, because it was not making the result worse — it was manufacturing it.
It also breaks the determinism the engine override was written for. Start the same backtest either side of local midnight and the reset fires in one run and not the other.
3 years × 7 markets, 0.10% taker fee + 2 bps slippage, each version at its own calibrated capital
| wall clock | candle time | |
|---|---|---|
| Cycles switched off by the breaker | 155,049 of 176,120 (88.0%) | 0 |
| First trip, earliest market | cycle 1,446 of 25,160 | never |
| Total buys, all markets | 213 | 1,029 |
| Median time in market | 3.3% | 16.5% |
| Median return | +7.4% | −37.5% |
| Median max drawdown | 15.4% | 49.5% |
| Profitable markets | 5 / 7 | 0 / 7 |
The capital used moves from 126 to 157 between the columns because the audit funds each version so its own peak position is ~95% of the account, and a strategy that is no longer switched off deploys more. The two return figures are therefore not measuring the same account — but the direction is not in doubt, and the 88% figure does not depend on capital at all.
The fix. The bare date constructor becomes the explicit form that reads the overridable clock. Identical on a live bot, where nothing overrides it; candle time under the harness. Only the zero-argument constructor is rewritten — a date built from an explicit timestamp already takes its time from its argument and is left alone, and there were 185 of those in the pack.
Effect on live behaviour. None on a live bot — the explicit form that reads the overridable clock and the bare date constructor are the same call there. It changes what the backtest measures, which is the point: the pre-fix numbers described a strategy that had switched itself off, and the post-fix numbers describe the strategy as it would actually run.
Scope beyond this strategy. 76 files, 138 clock reads, fixed pack-wide. 65 use the clock for a daily reset and 52 of those clear a flag that gates trading with an early return — 24 on
consecutiveLosseslike this one, 28 ondailyLossLimitalone. The six strategies already published were re-measured against their published records and every measured value is identical: their latch isdailyLossLimit, which needs a daily loss of 2% ofCAPITAL_ALLOCto arm, and none of them ever had one. Nothing already reported needs restating. The fix also repairsmoonPhases_FUTURESandmoonPhases_SPOT, which computed the lunar phase for the real date rather than the bar's.
The strategy allowed itself to trade on half an order's cash, then demanded a whole one
Severity DEFECT · Surface behaviour · Sites 1
Two gates decide whether the strategy may buy, and they disagree:
The code behind this is in the engineering record, which this site does not publish.
canBuy says half an order's worth of cash is enough. The buy then demands a full order and never sizes down. The whole band between half an order and a full one passes the first gate and fails the second.
Why it matters. The order size is fixed, so an account that drifts into that band stays in it: the strategy is switched off for the rest of the run, and because fees decide when the account gets there, trading activity becomes a function of the fee rate. That is precisely what the pack's "fees change P&L, not the ability to act" invariant exists to catch — and it was catching it, masked behind the circuit-breaker defect above.
The half-order allowance is the evidence this is a defect rather than a design decision to sit out. The author wrote a floor at half an order in one gate and then ignored it in the other.
Buys with costs ÷ buys with fees and slippage set to zero — worst of the 7 markets. The invariant needs ≥ 0.50
| Capital (order size 100) | after the clock fix only | after both fixes |
|---|---|---|
| 126 | 0.47 FAIL | 0.59 PASS |
| 157 — the calibrated figure | 0.40 FAIL | 0.44 FAIL |
| 200 | 0.43 FAIL | 0.78 PASS |
| 300 | 0.98 PASS | 0.98 PASS |
| 500 | 0.98 PASS | 0.98 PASS |
The coupling weakens but does not vanish, and 157 is worse than either 126 or 200 — the ratio is chaotic this close to the boundary rather than crossing a clean threshold. What is left is not the contradiction repaired here: it is that the strategy loses 69% of a 157-quote account, which takes it below its own half-order floor, and fees decide when it gets there. That floor is the author's own and is honoured, so the residual is a consequence of a losing strategy at tight capital, not a code defect. At 300 and above the strategy never reaches the floor and the invariant passes outright.
The fix. Size the order to the cash actually available, and keep the half-order floor canBuy already sets — which is the behaviour those two lines together already describe.
Effect on live behaviour. This changes behaviour at the shipped defaults. The strategy now keeps trading, in smaller size, where it used to stop: total buys rise from 1,029 to 1,612 and the median return falls from −37.5% to −68.9%. The result gets worse because the strategy is losing and was previously being stopped by an accident rather than by a rule — the repair removes the accident, not the losses.
Scope beyond this strategy. Three files in the pack carry the full-size gate: this one,
apexEngineandcashFlowEngine. Only this one andapexEnginealso carry the half-order allowance that makes it self-contradictory. Both of the others recorded against each strategy and deliberately left unfixed — a change to live behaviour belongs in the audit that measures it, andcashFlowEnginehas no half-order floor of its own, so what it should do instead is a judgement its own audit has to make.
The console audit reported a silent logger on 29 files whose logging was fine
Severity DEFECT · Surface measurement · Sites 1
Each of these strategies wraps its runtime require in a try/catch, and the catch defines a fallback rt that keeps the output format when the shared module is absent. The audit checked it with
The code behind this is in the engineering record, which this site does not publish.
Two things went wrong on this file. The pattern matched one of the two spellings only, and 29 files write the same fallback with an arrow — an arrow-function form. Having missed the real one, the search then found the first log: anywhere in the file, which is the _qBacktestRtSafeV1 defensive stub further down: log:function(){}, a deliberate no-op whose job is to keep rt callable, not to define output format.
Why it matters. The audit reported that this strategy would go silent if the runtime module were missing. It would not — its fallback logs correctly, in the house format, with the strategy name. The warning pointed at a real no-op in the file and drew the wrong conclusion from it, which is the worst shape a false positive can take: it looks specific and checkable.
The fix. Read the fallback where it is actually defined — inside the catch of the runtime require — and accept either function or arrow form. If no fallback defines log at all, that is now reported as its own finding rather than being confused with one that does.
Effect on live behaviour. None to any strategy. It changes what the audit measures, and is recorded because it changes what this report says: the warning was withdrawn and this strategy is uniform on every surface.
Scope beyond this strategy. 29 of the 67 quantroduction strategies were being warned about. After the fix all 67 are measured as emitting the house format, and 0 warnings remain.
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. Zero is falsy in JavaScript, so a setting of zero was replaced by the baked default with no warning.
Why it matters. Zero is the only way to turn several of these off, and on this strategy the list is consequential: BR_FEE (the assumed fee used in its own P&L accounting), BR_MAX_DD (the hard stop), BR_TP_PCT (the profit target), BR_CALM_VOL and BR_PANIC_VOL (the regime boundaries). An operator disabling the stop by typing 0 would have got the 10% stop back instead. The same bug was also discarding the backtest harness's WARMUP_CYCLES: 0.
The fix. Replaced the idiom with a reader that separates "not set" from "set to zero", returning the default only for undefined, null, "" and a non-numeric value.
Effect on live behaviour. None at the tested settings — verified by re-running the full 3-year backtest on all 7 markets and diffing the result record against the pre-fix baseline: identical, including trade counts, fills, rejects and every metric. The harness already passes WARMUP_CYCLES: 0, and this strategy's baked warmup is also 0, so nothing moved.
Scope beyond this strategy. Pack-wide: 1,743 sites across 70 files.
Nine side-panel rows with no explanation
Severity WARNING · Surface side panel · Sites 9
Nine of thirteen data rows carried an empty tooltip or none at all.
Why it matters. The side panel is where an operator reads what a strategy is doing without opening the code, and on this strategy several of the unexplained rows are the ones that matter. BTC Samples reading 14/100 is the difference between "warming up" and "broken", because below 20 samples the regime is UNKNOWN and the strategy will not enter at all. Size Multiplier is the regime's only visible effect on sizing.
The fix. Five were filled from the shared side-panel label glossary. The remaining four are labels the glossary does not know — three are unique to this strategy (BTC Price, Size Multiplier, BTC Samples) and one, Hold, is deliberately excluded from the glossary because across the pack it is used both for a yes/no and for a quantity, so no single wording is true everywhere. All four were written against this file, where Hold is unambiguously holdCycles/MAX_HOLD_CY.
Effect on live behaviour. None. Tooltips are display text.
Scope beyond this strategy. Pack-wide: 1,433 rows over 392 distinct labels.