volHarvester — Status & roadmap
Where this strategy is today
ENGINEERING COMPLETE — the code is correct, uniform and shippable. That is a statement about engineering, not about profitability; the performance verdict is separate and sits below it.
| Dimension | State |
|---|---|
| Correctness | 5 / 5 invariants pass |
| Console output | 15 tagged calls, 0 off-format |
| Side panel | 20 rows, padded to the 3-column grid |
| Chart marks | reference-levels |
| Palette | 8 / 8 canonical |
| GUI settings | 20 exposed · 0 read at runtime · 0 untunable · 0 inert |
| Deployed to a live install | Not yet — audited and staged, not yet shipped |
Performance verdict. Over three years on 7 markets it returns a median -10.5% against buy-and-hold's 49.6% — an edge of -66.4% — and is profitable on 1 of 7. On this window it is not a replacement for simply holding the asset, and nothing in these reports claims it is.
What it actually does
SUPERSEDED — use volRegimeMM instead. This strategy was renamed volRegimeMM at v2.0 and both files ship in this pack. They were measured against each other here on 3 years × 7 markets at 15m and are behaviourally identical: same trades, same returns, same final cash. There is no behavioural reason to choose this file over its successor, and both appear as separate selectable entries in the Gunbot GUI.
What it does: spot accumulation conditioned on the realized-volatility regime, not on price direction.
Four volatility estimators are computed each cycle and averaged into one σ — Parkinson (high-low range), a return-based rolling standard deviation, an ATR-normalised estimate, and an EWMA with λ = 0.97. That average is then z-scored against its own rolling history, and every decision reads the z-score rather than the raw σ:
- Accumulate when
volZ ≤ VH_BUY_Z (−0.5)— calm relative to this market's own norm — one rung of aVH_MAX_DCA(6) ladder, each rungVH_DCA_DECAY(0.8) × the last. - Scale out when
volZ ≥ VH_SELL_Z (1.2)and the position is at leastVH_GAIN(1%) up, selling 30–80% depending on how extreme the spike is. - Take profit separately at 2× the gain target, selling half.
- Emergency stop when the position is
VH_MAX_DD(15%) under break-even — sells the entire position at market. - Halt after 3 consecutive losses, or a daily loss beyond 2% of allocation.
The whole result is one trade per market
Over three years and 111,044 bars of 15m data the strategy takes roughly eleven positions per market. Of the 88 exits, the ladder accounts for them like this:
- 49 take-profits, mean +2.54%, summed +125%
- 8 emergency stops, mean −19.40%, worst −32.00%, summed −155%
That is one stop per market — two on SOL — and it is the entire difference between the strategy and a profitable one. The median win rate is 91% and the median profit factor is 0.15. Those two numbers together are the whole diagnosis: it wins nine times out of ten and loses anyway, because a +2.54% win needs to happen 7.6 times to pay for one −19.40% loss and it gets about six.
Median fee drag is 0.3% of the account. This is not a cost problem — unlike most of the pack, the trading is far too infrequent for fees to matter. It is a risk-shape problem, and it sits entirely in the exit.
The stop overshoots its own limit. It triggers at −15% and realises a mean of −19.40%, worst −32.00%. The trigger is evaluated on a closed bar, the whole position is then sold at market on the next bar's open, and on a 15m bar in a fast market that gap is several points wide.
The one profitable market is DOGE (+3.5%, profit factor 3.41), and it is also the market with the lowest exposure (54% against a 70–100% range elsewhere). Less time holding, fewer chances to be caught 15% under water.
Correction, 2026-09-15: this page previously stated "There is no stop-loss sell. Every sell path requires a profit." That is false and was the first thing an operator would read when sizing a position. The emergency stop sells the entire holding at market. It fired zero times in the earlier 60-minute measurement, which is how the claim survived — the earlier pass described the sell paths it had seen fire rather than the ones in the file. At 15m it fires once per market and decides the result.
Correction, earlier: an earlier version described the strategy as capturing a variance risk premium and credited a Yang-Zhang estimator, following the file's own header. Both were wrong and the header has been corrected — see the fixes report. Capturing a variance risk premium needs options or variance swaps, which Gunbot does not access; the strategy takes outright long spot exposure. Yang-Zhang was declared in the persisted store and never computed.
Read from the shipped strategy source, not from its documentation.
The measured constraint
Time in market is 81.4%, over 88 round trips across all 7 markets and three years. Everything in the performance report rests on that fraction of the bars.
Settings, measured
This strategy does not use the engine config surface.
What to build next
Ordered by expected effect on the result, not by effort.
1. Use volRegimeMM and retire this file
Highest priority
volRegimeMM is this strategy renamed, and the two are identical on every market at 15m as they were at 60m. Both are selectable in the GUI, so an operator can pick the retired one without knowing it is retired. Nothing here argues for choosing this file.
Everything below applies to both, because they are the same code.
2. The exit is the strategy — fix the stop before touching the signal
Highest priority
Median return is −10.5% over three years against a buy-and-hold of +49.6%, an edge of −66.4%. The median win rate is 91% and the median profit factor is 0.15.
Eight trades out of 88 produce that. Take-profits realise +2.54% on average across 49 exits; the eight emergency stops realise −19.40% on average, worst −32.00%. Summed, the wins are +125% and the stops are −155%.
So the shape to change is the ratio, and there are two independent ways in:
Stop overshoot. The stop is set at VH_MAX_DD = 15% and realises −19.40%. It is checked on a closed bar and then dumps the whole position at market on the next open. A staged exit — half at the trigger, the rest on the following bar — or a stop that also rests as a limit would recover several points of that gap without changing when the decision is made.
Win size. VH_GAIN is 1% and the take-profit path fires at 2× that. A +2.54% mean win against a −19.40% mean loss needs a 88.4% win rate merely to break even, and the strategy achieves 91% — which is why it is close to water rather than catastrophic. Raising VH_GAIN trades win rate for win size, and the measurement to run is the pair together, not either alone.
Median fee drag is 0.3%, so unlike most of this pack there is no cost argument for trading less. The trading is already rare.
3. Measure exposure against outcome — DOGE is the tell
High priority
DOGE is the only profitable market (+3.5%, profit factor 3.41) and also the one with the lowest exposure at 54%, against 70–100% everywhere else. ETH sits at 100% exposure and loses 10.5%.
That is one market and not a result, but it is the cheapest hypothesis available and it is directly testable: the accumulate gate is volZ ≤ −0.5 with no ceiling on how much of the account the ladder may commit, so in a market whose volatility stays below its own norm for a long stretch the strategy simply ends up fully invested and stays there. A maxExposure cap of the kind already applied to the Directional engine in this pack would bound that, and the pack has the tool for it.
Run the ladder at 60%, 80% and no cap across all seven markets and read the profit factor, not the return.
4. Re-tune the ladder, which has never been tuned
High priority
VH_MAX_DCA (6) and VH_DCA_DECAY (0.8) were dead until this pack's ladder repair — a bare return above the accumulate path made it unreachable while a position was held, and this strategy holds one on most bars, so the ladder never advanced past its first rung and DCA_DECAY ^ 0 was always 1.
They work now, which means their shipped values have never been measured doing anything. Six rungs decaying at 0.8 puts 26% of the ladder's total into the first rung and 7% into the last; whether that is the right distribution for a strategy whose losses come from being too far in is an open question with a cheap answer.
5. Check whether four estimators beat one
Worth testing
The ensemble averages Parkinson, return-standard-deviation, an ATR-normalised estimate and an EWMA, then z-scores the average. Four estimators of the same quantity on the same bars are highly correlated, and averaging them mostly removes the differences that would make any one of them informative.
The experiment is one line: run the strategy on each estimator alone and on the ensemble, same seven markets, same window, and compare. If the ensemble does not beat its best single member, three quarters of the computation is decoration — and the header has already been wrong once about what is in this array.
6. The settings measurement does not yet cover this lineage
Read before acting on the others
the presentation audit measures which settings a strategy actually reads by wrapping the shared settings accessor with a recording proxy. The 348 Gunbot Quant files route through the shared settings accessor; the Quantroduction files — this one included — build a plain P: { ... } from the GUI settings directly, so nothing is measured for them and the untunable and inert counts on this page are blank rather than zero.
Every dead setting found in this lineage so far was found by hand. Until the proxy covers P the same way, treat a blank knob section here as unmeasured, not clean — the distinction that has already hidden a defect class in this pack for months.
Operator output, measured
Everything below was read out of the strategy file by the presentation audit, not taken from its documentation. These are the surfaces an operator actually watches: the terminal log, the side panel, the chart, and the settings the GUI offers.
- Tagged, aligned, coloured
- 15
- Raw and off-format
- 0
- Exempt (object and error dumps)
- 10
Every non-exempt line carries the strategy name, an event tag and the palette colour for that tag, so one terminal running many pairs stays readable.
- Data rows
- 20
- Section headers
- 4
- Rows with no tooltip
- 1
- Padded to the 3-column grid
- yes
- Model
- reference-levels
draws price levels into customChartTargets and no per-trade marks, so there is no intent-vs-fill distinction to get wrong
- Non-canonical colours
- 0
One colour per meaning, identical in the log, the panel and the chart — the eight canonical roles.
Settings the GUI exposes
20 settings appear in the Gunbot strategy editor for this strategy. Which of them the code reads has not yet been measured for this lineage: it does not use the shared config surface, so there is nothing to wrap with a recording proxy.
LOG_LEVELWARMUP_CYCLESVH_VOL_LBVH_EWMAVH_HIGH_ZVH_EXT_ZVH_LOW_ZVH_SELL_ZVH_BUY_ZVH_MAX_EXPVH_MAX_DCAVH_DCA_DECAYVH_COMPOUNDVH_SPMIN_ORDER_QUOTEVH_TLVH_CAPITAL_ALLOCVH_GAINVH_MAX_DDVH_FEE
Open presentation findings
- WARN · sidebar — 1 of 20 data row(s) carry no tooltip, so the value has no explanation in the GUI: Holding