WaveTrend_LB

WaveTrend_LB — Fixes

ENGINEERING COMPLETEAudited 2026-09-12· directional engine· gunbot-quant· 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 It went all-in on one order; it now scales in and never exceeds 85% of the account DEFECT behaviour
2 The pyramiding knob shrank the position and could never rebuild it DEFECT behaviour
3 Three settings the engine reads were invisible in the Gunbot GUI DEFECT user inputs
4 The most diagnostic messages in the file bypassed the log format 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.


It went all-in on one order; it now scales in and never exceeds 85% of the account

Severity DEFECT · Surface behaviour · Sites 2

The engine sized an entry as the entire available balance, in one order: it took the smaller of the wanted limit and the whole free balance, with maxAdds shipped at 1. One signal, one order, the whole account.

Why it matters. Two separate problems, and fixing only one does not work.

Slicing alone does not cap exposure. allocBase is total equity, so splitting an entry into three still reaches ~100% once the ladder fills. Raising maxAdds changes the path in, not the destination — measured peak deployment stayed at 100%.

Capping alone loses the benefit of scaling in. A single order at 85% is still one all-or-nothing entry at one price.

So both were applied: entries arrive in four slices, and a headroom check caps total held value at maxExposure of equity on the first entry and on every top-up, so it holds however many adds fire.

3 years x 7 markets, measured on four Directional strategies spanning the pack's best and worst

Strategy shipped: 1 order, uncapped 4 slices, capped at 85%
WaveTrend_LB (ranked #1 in the pack) -8.3% return, 24.6% max DD +1.1% return, 12.2% max DD
ConnorsRSI_Composite -6.7% return, 12.3% max DD -1.4% return, 3.2% max DD
OU_MeanReversion -98.9% return, 99.0% max DD -66.9% return, 67.9% max DD
Confluence_Vote -99.9% return, 99.9% max DD -80.4% return, 80.9% max DD

Every strategy improved on both return and drawdown, and the effect was monotonic in the number of slices. The two worst strategies in the pack were destroying essentially the whole account over three years; the cap does not make them good, but it stops them being total. This is risk reduction, not alpha — the gains shrink too, which is visible per market: on WaveTrend_LB, XRP falls from +59.9% to +35.9% while BTC improves from -19.8% to -7.8%.

The fix. SIG_maxAdds default 1 -> 4, and a new SIG_maxExposure knob defaulting to 0.85. The cap is computed as remaining headroom against equity rather than by shrinking the slice, so it holds regardless of how many adds fire or what the operator sets maxAdds to. Both knobs are exposed in the Gunbot GUI with labels, tooltips and ranges, and every SIG_ default in the editor was resynced to the baked value — which also caught one unrelated pre-existing drift.

Effect on live behaviour. This changes behaviour at the shipped defaults, deliberately and on request. The strategy now places roughly twice as many orders — 51 buys on ADA became 103 — builds its position in four steps instead of one, and never holds more than about 86% of the account. Measured peak deployment on WaveTrend_LB fell from 100.0% to 85.9%.

Scope beyond this strategy. Pack-wide. 112 of 429 strategies put 95% or more of equity into a single position. 81 of the 84 Directional strategies did, and all 83 that could be matched are now capped and pyramiding, along with the the Directional engine template so regeneration keeps it. A further 21 grid and maker strategies had their inventory ceiling lowered to the same 85%.


The pyramiding knob shrank the position and could never rebuild it

Severity DEFECT · Surface behaviour · Sites 1

The Directional engine lets you split an entry into SIG_maxAdds slices and top the position up as it works. The division always happened; the top-up was gated on the entry signal still being true.

Why it matters. WaveTrend enters when WT1 crosses above WT2 out of oversold. A cross is true for exactly one bar — and on that bar the strategy is not yet in a position, it is opening one. By the next bar the cross has passed, so the top-up condition was false for the entire life of every position. The entry kept being divided; nothing ever added to it. Raising the knob therefore only ever reduced how much capital the strategy committed, with no way back up.

WaveTrend_LB on BTCUSDT 1h, before the fix — trade count identical, deployment collapsing

SIG_maxAdds buys peak deployed total return
1 (default) 18 100.0% -10.6%
2 18 53.1% -5.3%
3 18 36.2% -3.5%
10 18 11.2% -1.1%

The return appears to improve as the knob rises. It is not improving — the strategy is progressively not participating. This is the same illusion the flat-capital sweep produced for SuperTrend_MM: a number that looks like capital preservation but is actually absence.

The fix. Drop the entry-signal condition from the top-up gate. The block's own comment already named the intended evidence — price advancing at least addSpacing ATRs since the last entry — and that advance, with the exit signal absent, is what shows the position is working. The entry-signal condition was the redundant one and the one that made the feature dead.

After the fix — the top-up fires, deployment is restored

SIG_maxAdds buys peak deployed total return
1 (default) 18 100.0% -10.6%
2 27 100.0% -7.8%
3 31 100.0% -5.8%
10 34 61.3% -2.3%

Effect on live behaviour. None at the shipped default. maxAdds = 1 skips the block entirely, and the full 3-year run across all 7 markets is byte-identical before and after — same trade counts, same returns, same drawdowns. This repairs an opt-in feature nobody was using rather than changing live behaviour.

Scope beyond this strategy. Engine-wide. The same gate is in all 84 Directional strategies; every one whose entry is a cross rather than a level has the same dead branch.


Three settings the engine reads were invisible in the Gunbot GUI

Severity DEFECT · Surface user inputs · Sites 3

SIG_maxAdds, SIG_addSpacing and SIG_addScale are read by the strategy at runtime but had no entry in the GUI editor definition. An operator had no way to set them.

Why it matters. This was drift, not an oversight in any one file: the pyramiding patch added the knobs to the engine templates after the shared settings glossary and the editor definitions had been generated. The engine read three settings that nothing else in the system knew about.

Measured by running the strategy with a recording config proxy

before after
knobs exposed in the GUI 5 8
knobs read at runtime 6 8
read but not exposed (untunable) 1 0
exposed but never read (inert) 0 0

Which knobs a Directional strategy reads cannot be determined by reading the source: the file bakes 76 of them and the active mode branch reads eight. The strategy is run with its settings accessor replaced by a proxy that records every key access, so the read-set is measured rather than inferred.

The fix. Added the three knobs to the shared settings glossary with labels, tooltips and effect descriptions, then generated editor entries from the strategy's own baked defaults. addSpacing and addScale are only read once maxAdds > 1, so the tooltips say so.

Effect on live behaviour. None. Editor definitions describe the GUI; they do not run. The three knobs keep their existing baked defaults, so an operator who changes nothing sees no difference.

Scope beyond this strategy. The knob glossary was written before pyramiding was added to the engine, so the editor generator never knew these three existed. Every Directional strategy is affected.


The most diagnostic messages in the file bypassed the log format

Severity WARNING · Surface console · Sites 15

Order rejections, blocked orders and reconcile events were emitted as bare strings: Buy blocked: qty rounds to zero. No strategy name, no tag, no colour.

Why it matters. In a terminal running many pairs at once that line does not say which pair or which strategy produced it, and it is exactly the class of event the palette reserves amber for — the strategy wanted to act and could not. These are the lines an operator scans for when something looks wrong, and they were the least legible in the file.

Call sites by format

before after
tagged, aligned, coloured 10 25
raw and off-format 15 0
exempt (object/error dumps, pre-scope sanity waits) 7 7

The fix. Routed the string-literal sites through the tagged log emitter that already existed in the same scope, with the tag and palette colour the event calls for. Object dumps and the two top-of-file sanity waits are left alone — the waits run before that emitter is in scope, and a dump has no message to tag.

Effect on live behaviour. None. Verified by re-running the full 3-year backtest on all 7 markets and diffing the result record: identical to the byte, including trade counts, fills, rejects and every metric.

Scope beyond this strategy. The same call sites exist across the 348 Gunbot Quant strategies — they predate the tagged format rather than deviating from it.