FIL_Grid_Engine — Fixes
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 | The published return measures how fast the grid's floor was breached, not how the grid performed | DEFECT | measurement |
| 2 | Nothing said the grid had been left behind — on BTC it reported Active for three years and placed no orders | DEFECT | side panel |
| 3 | The console audit said this strategy could not emit the tagged format, while it was emitting it twelve times | DEFECT | measurement |
| 4 | Every exchange rejection was logged without a strategy tag | WARNING | console |
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 published return measures how fast the grid's floor was breached, not how the grid performed
Severity DEFECT · Surface measurement · Sites 1
When the price falls through the bottom of the grid by more than 3%, the strategy sells the basket and stops. Every cycle after that does nothing but print "halted — re-arm by resetting the pair". Nothing in the file ever clears that state.
That is a sensible thing for a live grid to do; it should not restart itself into a falling market while nobody is watching. But across a three-year test it means the strategy trades for a while, stops, and the rest of the window is a flat line. The figure that gets reported is the result up to the moment it stopped, on a page that says three years.
The symptom was there in the record and I nearly read past it: time in market was 0% on every market, with 15 to 61 trades across 111,044 bars.
Why it matters. The number on the performance page was being read as a statement about a grid strategy. It is a statement about how quickly each market broke 3% below its own starting range. Those are different things, and only one of them is about this strategy.
The same strategy with the halting stop disabled, 3 years x 7 markets at 15m
| Market | as shipped | stop disabled | ||
|---|---|---|---|---|
| trades | return | trades | return | |
| ADA | 36 | −2.4% | 1,102 | −32.49% |
| BTC | 25 | −0.2% | 88 | +26.48% |
| DOGE | 15 | −0.2% | 1,710 | −5.95% |
| ETH | 49 | −2.8% | 1,502 | −5.90% |
| LINK | 61 | −3.8% | 748 | +25.57% |
| SOL | 52 | −4.3% | 961 | +57.40% |
| XRP | 40 | −4.2% | 2,546 | −2.22% |
| median | −2.80% | −2.22% | ||
| range across markets | 4.1 pts | 89.9 pts | ||
| profitable on | 0 of 7 | 3 of 7 |
The median barely moves. The distribution is a different object entirely. As shipped, seven markets over three years land in a 4.1-point band of small losses, none of them profitable — because none of them ran long enough for anything to happen. With the halt removed the same seven spread over 89.9 points, three are profitable and one returns +57%. A strategy that cannot lose much and cannot win at all is not a conservative strategy; it is one that stopped.
The fix. Nothing in the strategy changes, and that is deliberate — whether the halt should clear itself is a design question discussed on the status page, not something to settle on the strength of a backtest.
What changes is the claim. The performance page now says the figure is cut short by the halt, and reports the comparison without it alongside, so the strategy's own behaviour can be told apart from the halt's. The reading of 0% time in market is called out directly rather than left sitting in a column, because it is the thing that gives it away.
Effect on live behaviour. None — the strategy is untouched. The shipped figures remain correct for a run in which the halt fires early; they are no longer presented as a three-year measurement of the grid.
Scope beyond this strategy. All 15 fil-grid strategies carry the same permanent halt, so the same truncation applies to every one of their pages. The halt itself is defensible in a live install and is discussed on the status page; what this entry is about is that the measurement cannot be read as a three-year result while it is in force.
Nothing said the grid had been left behind — on BTC it reported Active for three years and placed no orders
Severity DEFECT · Surface side panel · Sites 2
The grid bounds are computed once at initialisation and never rebuilt — hi and lo are assigned on one line in the whole file, inside if (!isInitialized). When price leaves the range, no buy level can fill and the strategy can do nothing at all. The side panel went on reporting Grid: Active (N) with the original range, the log went on printing ok. buys=36 sells=0, and the chart showed nothing, because this strategy drew no chart annotations of any kind.
Why it matters. This is not a rare edge. Measured over three years and seven markets, the share of bars price spent above the frozen grid predicts the trade count almost mechanically:
| market | grid (frozen at init) | price afterwards | bars above grid | buys |
|---|---|---|---|---|
| BTC | 26,808 – 35,280 | 33,596 – 126,011 | 99% | 0 |
| SOL | 21.66 – 33.90 | 31.50 – 286 | 100% | 4 |
| DOGE | 0.0574 – 0.0752 | 0.0661 – 0.4751 | 94% | 17 |
| ETH | 1,542 – 1,866 | 1,419 – 4,935 | 91% | 18 |
| ADA | 0.2394 – 0.2980 | 0.1389 – 1.30 | 79% | 580 |
| XRP | 0.4769 – 0.5866 | 0.3979 – 3.65 | 77% | 85 |
| LINK | 7.21 – 11.79 | 7.03 – 30.36 | 70% | 445 |
On BTC the strategy ran for three years, evaluated every bar, and never placed a single order — and every surface an operator can see said it was working. A strategy that cannot act should say so; this one looked identical whether it was trading 580 times or not at all.
The fix. Three additions, all display. A side-panel row that states where price sits relative to the grid — inside, or ABOVE +N% / BELOW −N% in amber — with a tooltip saying the grid is never rebuilt. A log warning on any cycle where price is outside the range, naming the distance and what it means. And chart annotations: Grid top, Grid floor and the stop level, drawn through customChartTargets in the same shape the generated FILGrid_* variants use, so both halves of the family look alike in the GUI.
The warning firing, counted from the strategy's own output over the 3-year run
| market | "above grid" warnings | "below grid" | of tagged lines | orders placed |
|---|---|---|---|---|
| BTC | 24,903 | 0 | 50,063 | 0 |
| LINK | 17,701 | 37 | 43,934 | 445 |
Effect on live behaviour. None. Re-running the full 3-year backtest on all 7 markets and diffing the result record against the pre-fix baseline gives an identical record — trade counts, fills, rejects and every metric. These are display and logging only.
Scope beyond this strategy. This file. The 14 generated
FILGrid_*strategies freeze their grid the same way but already drawGrid topandGrid flooron the chart, so an operator there can at least see the gap. None of the 15 names the condition in words.
The console audit said this strategy could not emit the tagged format, while it was emitting it twelve times
Severity DEFECT · Surface measurement · Sites 1
The audit decides how a strategy logs by looking for one of two emitters:
The code behind this is in the engineering record, which this site does not publish.
and reports unknown as a DEFECT: "no logLine() and no rt. emitter — strategy cannot emit the standard tagged format"*. There is a third style. This file has no emitter function and writes the format inline at each call site:
The code behind this is in the engineering record, which this site does not publish.
That is the house format, with the name, the padded tag and the separator.
Why it matters. The report claimed a strategy could not do something it was visibly doing. A second consequence was quieter and worse: the raw-console scan classified those twelve inline calls as exempt — its isEmitterDef test matches a quoted [ plus a ▸, which is what an inline call looks like — so they vanished from the tagged total too. The summary line read 0 tagged call(s) via the tagged log emitter, 4 off-format, 18 exempt for a file with twelve correctly formatted log lines and four wrong ones.
Console surface on FIL_Grid_Engine, same file, same scan
| before | after | |
|---|---|---|
| Tagged calls counted | 0 | 12 |
| Counted as exempt | 18 | 6 |
| Off-format | 4 | 4 |
| Defects reported | 1 | 0 |
The four off-format calls were real and are fixed separately below; after both, the file reports 18 tagged and 0 off-format.
The fix. The check now looks for the inline shape before concluding anything. A strategy that emits the format inline is reported as a NOTE — one shared emitter is still better than twelve copies of a format string — and the DEFECT is kept for a strategy that genuinely cannot produce the format. Inline calls are counted as tagged output rather than exempted, so the summary numbers describe the file.
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 defect was withdrawn and this strategy is uniform on every surface.
Scope beyond this strategy. 6 strategies were being reported:
FIL_Grid_Engine,GQ_Indicator_Engine,moonPhases_FUTURES,priceactionpro,quantroduction-mixer-futures,quantroduction-mixer-spot. Measured across the pack: 348 strategies usethe tagged log emitter, 75 usert.*, 6 emit inline, and zero have no tagged format anywhere — so this defect was wrong every time it fired.
Every exchange rejection was logged without a strategy tag
Severity WARNING · Surface console · Sites 4
The four order helpers caught their exchange errors and logged them bare:
The code behind this is in the engineering record, which this site does not publish.
No strategy name, no tag, no alignment — the only untagged output in a file that otherwise emits the house format everywhere.
Why it matters. These are the lines an operator reads when an order did not go through, and in a terminal running many pairs at once they do not say which pair or which strategy produced them. On a grid placing a limit at every level, a rejection at one rate is the difference between a working ladder and a ladder with a hole in it.
The fix. Routed through the same inline format the rest of the file uses, tagged WARN and naming the operation and rate. The helpers are defined above decideTrade(), where STRATEGY_NAME does not exist yet, so they carry their own copy of the tag.
Effect on live behaviour. None. Verified against the pre-fix baseline: the result record is identical.
Scope beyond this strategy. This file's four order helpers.