← apexEngine

apexEngine — Fixes

BLOCKEDAudited 2026-09-13· hand-written (no shared engine) engine· quantroduction· either

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

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

# Issue Severity Surface
1 It never noticed its own resting-order fills, so it sat dormant for three years DEFECT state machine
2 The buy gate contradicted itself — allow at half an order, demand a whole one DEFECT order sizing
3 The settings surface could not be measured, and still cannot NOTE inputs

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.


It never noticed its own resting-order fills, so it sat dormant for three years

Severity DEFECT · Surface state machine · Sites 7

At the bottom of every cycle this file publishes ledger.customSellTarget = effectiveBE + atr × GRID_GAIN_ATR — a resting limit order. Gunbot fills it the moment price trades through, and does not call back into the strategy. None of the code that maintains the strategy's own state ever ran for those fills.

So after a resting fill the strategy still believed it held the position it had just sold: dcaEntries still listed the rungs, dcaLevel was still non-zero, avgCost still held the old cost basis. And recordSell — which maintains totalRealisedPnL, tradeCount, wins, losses, harvestedCash, reinvestedProfit and fillLog — never ran either.

Why it matters. This is not a reporting problem. A grid engine that believes its rungs are still open does not open new ones, so the stale state switched the strategy off.

Measured over three years on seven markets, apexEngine held a position 0.7% of the time and placed 29 buys per market — roughly one trade every 40 days, from a file whose header promises four adaptive modes and calls the grid mode "the bread and butter". It was not being selective. It was stuck.

The published +1.3% return, profitable on 7 of 7 markets, was the result of not playing. This is the pack's own rule — a good result on very low exposure usually means the strategy stopped trading — in its clearest form so far.

Which half of the repair did what — same capital (180), 3 years × 7 markets

buys sells median return time in market
Before (no reconcile) 209 231 +1.27% 0.7%
Book the P&L only, leave the state stale 228 258 +1.34% 0.8%
Reset the state only, book nothing 2,390 2,208 −17.84% 93.6%
Both — the repair as shipped 1,166 1,403 −11.56% 95.1%

The stale state is the whole effect: booking the P&L alone changes almost nothing, while resetting the state alone moves time-in-market from 0.7% to 93.6%. Booking it still matters — it is what lets the circuit breaker see the losses, which is why the full repair trades less than the state reset alone. The identity was confirmed rather than inferred: before the repair, 199 unexplained exits matched the engine's restingFills counter exactly.

The fix. A RECONCILE block after the recordSell / recordBuy helpers. It detects a drop in the holding the strategy did not itself ask for, books it through the existing recordSell helper at the resting target published on the previous cycle (lastTarget), and clears the position state when the holding is gone.

Detection is by quantity rather than by order feed, so it does not depend on what a venue reports. expectQty, recorded at each of the five method.sellMarket sites, is what the strategy expects to be left after its own sale, so its own exits are not counted twice.

Effect on live behaviour. Changes behaviour completely, and makes the measured result far worse. Median return goes from +1.3% to −20.2%, drawdown from 0.7% to 67.4%, time in market from 0.7% to 92.4%, and the strategy now fails the cost-independence invariant.

It was applied anyway, because the previous numbers described a strategy that was not running. A state machine that believes it holds a position it has already sold is a defect whether or not the resulting paralysis happens to look profitable. What the repair produced is this strategy's actual behaviour, and that behaviour is not viable at the shipped defaults — see the roadmap.

Scope beyond this strategy. Second confirmed instance of the silent-resting-exit class, after dipHunter. 373 of the pack's 429 strategies publish a customSellTarget, so every one has to be checked; the audit tooling now reports unexplained exits as a share on every audit.


The buy gate contradicted itself — allow at half an order, demand a whole one

Severity DEFECT · Surface order sizing · Sites 1

The strategy checked twice whether it could afford to buy, and the two checks disagreed. The first let a cycle through while the account still held half an order's worth of cash; the second, further down, refused to place anything unless a whole order's worth was there. Every balance between those two levels passed the first and failed the second, and the order was never scaled down to fit what was actually available.

The order size itself can only grow: it starts at the configured trading limit and is raised by a share of realised profit, never lowered. So losses cannot shrink the requirement to meet a shrinking account — the gap only widens.

Why it matters. An account that drifts below one order size stops trading for the rest of the run, and because fees decide when it gets there, trading activity becomes a function of the fee rate. That is precisely what the pack's cost-independence invariant exists to catch. On btcRegimeScaler the worst buys-with-costs / buys-free ratio was 0.47 at capital 126 and 0.43 at 200 — both failures against a 0.50 threshold — rising to 0.98 at 500 where the account never dips below one order.

This strategy, before and after, across four capital levels

capital buys before → after cost-independence ratio median return
110 205 → 205 1.000 → 1.000 +1.90% → +1.90%
130 205 → 205 1.000 → 1.000 +1.61% → +1.61%
180 209 → 209 0.995 → 0.995 +1.27% → +1.27%
400 209 → 209 0.995 → 0.995 +0.57% → +0.57%

On this strategy the defect is latent — the repair is a no-op at every capital tested. Measured before the state-machine repair above, while the strategy was still dormant: at 0.7% time in market it simply never reached a cycle where it wanted to buy and held between half and one order of cash. The self-contradiction in the source is real and was repaired; the claim that it changes this strategy's behaviour would not have been true.

The fix. Size the order to the cash actually available, and apply the same half-order threshold the first check already used, so the two agree.

Effect on live behaviour. None measurable on this strategy, at any capital tested. Verified by diffing the full 3-year run on all seven markets before and after: identical buys, sells, return and drawdown.

Scope beyond this strategy. Found while auditing btcRegimeScaler, which carried the identical gate and where it caused a live invariant failure. Recorded against this strategy at the time and deliberately left for this audit to measure.


The settings surface could not be measured, and still cannot

Severity NOTE · Surface inputs

The audit measures which GUI settings a strategy actually reads by watching it run and recording every setting it asks for. That works for the 348 strategies built on the shared engine, because they all read their settings through one shared accessor the audit can watch. The 79 hand-written strategies — this one included — read the settings object directly instead, so there is nothing to watch, and the counts of dead and hidden settings on this page come back blank.

Why it matters. Every dead setting found in this family so far was found by reading the file by hand, which does not scale to 79 of them. It is recorded here so that the blank on this page reads as a known gap rather than as a clean bill of health.

The fix. Not fixed. Watching the hand-written settings object the same way is the highest-value piece of tooling still outstanding.

Effect on live behaviour. None — nothing was changed.

Scope beyond this strategy. All 79 hand-written strategies. The largest outstanding gap in the audit's own tooling.