From 19badff677233ee9d63d7a39ca065c230b3a550e Mon Sep 17 00:00:00 2001 From: DBarr3 <143002219+DBarr3@users.noreply.github.com> Date: Thu, 6 Aug 2026 10:59:55 -0400 Subject: [PATCH] feat(library): application context for strategy selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each library strategy carried a two- or three-line header restating the condition its IR already encodes. That is zero selection value: it says what the strategy does, never when it applies or when it must not fire. ATS reads this block verbatim (llmre/nano_catalog.py reads the leading // comment block and renders it beside the compiled intent) and it is the only place a rejection can be expressed, because the proposal engine retargets a published rule to the live instrument but carries its thresholds unchanged. Each header now states the regime it belongs to and the regimes where it must NOT fire, the conditions that must hold first, what invalidates it, its shape on the chart, the near-neighbour it gets confused with, and the instrument class its thresholds were calibrated on. That last field is the one that prevents silent damage. Several thresholds do not travel: ROC > 5 is an ordinary hour for BTC and a limit move for an index future, and BB_WIDTH < 4 is an absolute percentage that stops discriminating on a quieter instrument. ATR_PCT > 5 is the worst case — carried across unchanged it does not misfire, it never fires, and the volatility brake silently disappears. Comments only. No IR changes, so the source/IR conformance guard is unaffected. --- .../mean_reversion/bollinger_band_touch.nano | 12 ++++++++++++ nano/library/mean_reversion/cci_extreme.nano | 12 ++++++++++++ .../mean_reversion/zscore_reversion.nano | 12 ++++++++++++ nano/library/momentum/roc_momentum.nano | 11 +++++++++++ .../library/momentum/rsi_oversold_reversal.nano | 14 ++++++++++++++ nano/library/momentum/stochastic_oversold.nano | 13 +++++++++++++ nano/library/momentum/williams_r_reversal.nano | 12 ++++++++++++ nano/library/risk/max_drawdown_breaker.nano | 13 +++++++++++++ nano/library/trend/donchian_breakout.nano | 14 ++++++++++++++ nano/library/trend/golden_cross.nano | 15 +++++++++++++++ nano/library/trend/macd_histogram_flip.nano | 14 ++++++++++++++ .../library/volatility/atr_volatility_halt.nano | 17 +++++++++++++++++ .../library/volatility/bb_squeeze_breakout.nano | 16 ++++++++++++++++ nano/library/volume/obv_trend.nano | 15 +++++++++++++++ .../volume/volume_spike_confirmation.nano | 16 ++++++++++++++++ 15 files changed, 206 insertions(+) diff --git a/nano/library/mean_reversion/bollinger_band_touch.nano b/nano/library/mean_reversion/bollinger_band_touch.nano index 64c45b0..02ccfa7 100644 --- a/nano/library/mean_reversion/bollinger_band_touch.nano +++ b/nano/library/mean_reversion/bollinger_band_touch.nano @@ -1,6 +1,18 @@ // Bollinger lower-band touch. BB_PCT_B = (close - lower) / (upper - lower), // Pine's ta.bb %B, provided by the host data feed. Below 0 = close under // the lower band. +// REGIME: range-bound with stable band width. Do NOT fire in a downtrend or a +// volatility expansion - %B sits below 0 for long runs in a trend, and every +// touch there is a knife-catch. +// CONDITIONS: band width flat or contracting, and the prior swing low still +// holding on the timeframe above. +// INVALIDATION: a second consecutive close below the lower band, or band width +// expanding while price falls. Both mean continuation, not reversion. +// SHAPE: 1h; a wick piercing the lower band that closes back inside it. +// NOT bb_squeeze_breakout: same indicator family, opposite intent. That one +// enters on expansion out of compression; this one needs the range to hold. +// CALIBRATED ON: US large-cap equity ETF, 1h. %B itself is scale-free, but +// "band width is stable" is not - re-derive it for a new instrument class. strategy BollingerBandTouch { every 1h { diff --git a/nano/library/mean_reversion/cci_extreme.nano b/nano/library/mean_reversion/cci_extreme.nano index 74072dc..5f431bb 100644 --- a/nano/library/mean_reversion/cci_extreme.nano +++ b/nano/library/mean_reversion/cci_extreme.nano @@ -1,6 +1,18 @@ // CCI oversold extreme. Pine's ta.cci goes deeply negative when oversold; // the feed provides the negated series: CCI_NEG = -CCI. // CCI_NEG >= 100 is the classic CCI < -100 oversold zone. +// REGIME: range, or a pullback inside a standing uptrend. Do NOT fire in a +// sustained downtrend - CCI pins beyond -100 and stays there for many bars. +// CONDITIONS: a definable range floor, and the higher timeframe not printing +// new lows. +// INVALIDATION: CCI_NEG continuing past roughly 200 (the move is accelerating, +// not exhausting), or a close beneath the range floor. +// SHAPE: 1h; a sharp excursion below recent congestion that snaps back. +// NOT zscore_reversion: both measure distance from a mean, but CCI normalises +// by mean absolute deviation rather than standard deviation, so it reacts +// sooner and fires considerably more often in chop. +// CALIBRATED ON: US tech equity ETF, 1h. The +/-100 convention is standard; +// how often it is actually reached is entirely instrument-dependent. strategy CciExtreme { every 1h { diff --git a/nano/library/mean_reversion/zscore_reversion.nano b/nano/library/mean_reversion/zscore_reversion.nano index 5487345..8a24a6c 100644 --- a/nano/library/mean_reversion/zscore_reversion.nano +++ b/nano/library/mean_reversion/zscore_reversion.nano @@ -1,6 +1,18 @@ // Mean-reversion z-score entry. Nano numbers are non-negative, so the feed // provides the negated series: ZSCORE_NEG = -((close - sma) / stdev). // ZSCORE_NEG >= 2 means price is 2+ standard deviations BELOW the mean. +// REGIME: statistically stationary - a range whose mean is flat. Do NOT fire +// during a trend or a repricing event: once the mean itself moves, distance +// from it stops being information. +// CONDITIONS: the 20-period mean roughly flat, and stdev not expanding. +// INVALIDATION: ZSCORE_NEG holding at or above 2 across several bars, or the +// mean turning down. Both say the distribution moved rather than the price. +// SHAPE: 4h; a visible stretch away from a horizontal mean. +// NOT cci_extreme: the same idea measured more strictly and more slowly, so it +// produces far fewer signals. If both fire, that is one setup, not two. +// CALIBRATED ON: crypto, 4h - continuous trading, no session boundaries, and a +// higher baseline volatility than an index future. On a session-bound +// instrument the 20-period window straddles the overnight gap. strategy ZscoreReversion { every 4h { diff --git a/nano/library/momentum/roc_momentum.nano b/nano/library/momentum/roc_momentum.nano index c95071f..6218b13 100644 --- a/nano/library/momentum/roc_momentum.nano +++ b/nano/library/momentum/roc_momentum.nano @@ -1,5 +1,16 @@ // Rate-of-change momentum (Pine: ta.roc(close, 10) > 5). // ROC = percent change of close over the lookback window. +// REGIME: trend or expansion. Do NOT fire in chop - in a range a 5 percent +// 10-bar move marks the top of the range, so this becomes buy-the-high. +// CONDITIONS: range expanding, higher highs on the timeframe above. +// INVALIDATION: ROC decaying back under the threshold while price stalls +// (momentum exhaustion), or the whole move coming from one spike bar. +// SHAPE: 1h; a sustained directional push, not a single candle. +// NOT macd_histogram_flip: that signals a change of trend, this one signals +// continuation of a trend already running. +// CALIBRATED ON: crypto, 1h. The threshold is the danger here - a 5 percent +// move over 10 bars is an ordinary afternoon for BTC and a limit-move event +// for an index future. Do not carry the number across instrument classes. strategy RocMomentum { every 1h { diff --git a/nano/library/momentum/rsi_oversold_reversal.nano b/nano/library/momentum/rsi_oversold_reversal.nano index c5e2af7..aacc958 100644 --- a/nano/library/momentum/rsi_oversold_reversal.nano +++ b/nano/library/momentum/rsi_oversold_reversal.nano @@ -1,5 +1,19 @@ // Classic RSI oversold reversal (Pine: ta.rsi(close, 14) < 30). // Buy when the 14-period RSI dips below 30. +// REGIME: a pullback inside an uptrend, or a range. Do NOT fire in a sustained +// downtrend - RSI can hold under 30 for dozens of bars while price keeps +// falling, and this is the single most common way the strategy loses. +// CONDITIONS: the higher timeframe trending up or neutral, and a prior support +// level within reach. +// INVALIDATION: RSI making a lower low together with price. Oversold that gets +// more oversold is trend, not exhaustion. +// SHAPE: 15m; a flush into support that turns within a few bars. +// NOT stochastic_oversold: that measures position inside the recent range and +// fires earlier and far more often. NOT volume_spike_confirmation: that is +// this exact RSI condition plus a volume gate, so it is a strict subset - when +// both fire it is one setup, not two. +// CALIBRATED ON: crypto, 15m. RSI is bounded 0-100 so the threshold travels, +// but how long an instrument stays sub-30 does not. strategy RsiOversoldReversal { every 15m { diff --git a/nano/library/momentum/stochastic_oversold.nano b/nano/library/momentum/stochastic_oversold.nano index f2152ff..1661ca5 100644 --- a/nano/library/momentum/stochastic_oversold.nano +++ b/nano/library/momentum/stochastic_oversold.nano @@ -1,6 +1,19 @@ // Stochastic oversold entry (Pine: ta.stoch(close, high, low, 14) < 20). // STOCH_K = %K line of the 14-period stochastic oscillator, provided by // the host data feed. +// REGIME: range. Do NOT fire in a trend - %K pins under 20 for the length of a +// downtrend, and this is the fastest of the oscillators, so it pins first. +// CONDITIONS: a defined support level, and a range wide enough that the low of +// the lookback window is meaningful. +// INVALIDATION: %K flat under 20 across several bars rather than turning up. +// SHAPE: 30m; price probing the bottom of an established range. +// NOT rsi_oversold_reversal: RSI measures average gain against average loss, +// %K measures position within the recent high-low range. %K fires earlier and +// more often, so it is the noisier of the pair. +// NOT williams_r_reversal: that is the same construction inverted. Firing both +// is one idea counted twice. +// CALIBRATED ON: crypto, 30m. The 0-100 bound travels; the dwell time below 20 +// is a property of the instrument. strategy StochasticOversold { every 30m { diff --git a/nano/library/momentum/williams_r_reversal.nano b/nano/library/momentum/williams_r_reversal.nano index a0db3fe..00bd083 100644 --- a/nano/library/momentum/williams_r_reversal.nano +++ b/nano/library/momentum/williams_r_reversal.nano @@ -1,6 +1,18 @@ // Williams %R reversal. Pine's ta.wpr ranges -100..0; Nano numbers are // non-negative, so the feed provides the shifted series: // WILLR_POS = Williams %R + 100 (range 0..100; < 20 means oversold). +// REGIME: range, or a pullback within an uptrend. Do NOT fire in a sustained +// downtrend - like every position-in-range oscillator it pins at the bottom +// and stays there. +// CONDITIONS: a defined range with a floor that has held at least once. +// INVALIDATION: WILLR_POS remaining under 20 while the range floor gives way. +// SHAPE: 1h; a probe of the low of the 14-period range that recovers. +// NOT stochastic_oversold: Williams %R is the inverted stochastic - the same +// measurement of position within the recent range. These two agreeing is a +// single idea counted twice, not confirmation. +// CALIBRATED ON: high-beta crypto, 1h. The 0-100 bound travels; on a slower +// instrument the oscillator reaches 20 far less often, so this will simply go +// quiet rather than misfire. strategy WilliamsRReversal { every 1h { diff --git a/nano/library/risk/max_drawdown_breaker.nano b/nano/library/risk/max_drawdown_breaker.nano index 930ae8e..a4bceef 100644 --- a/nano/library/risk/max_drawdown_breaker.nano +++ b/nano/library/risk/max_drawdown_breaker.nano @@ -1,5 +1,18 @@ // Max-drawdown circuit breaker: when portfolio drawdown reaches 5 percent, // pause all proposals and hand control to the named risk agent. +// REGIME: all of them. This is a control, not a directional hypothesis, and it +// is always applicable. It must never be promoted into an execution slot or +// counted as a setup - it emits PAUSE, never BUY or SELL. +// CONDITIONS: none. It is armed whenever the book is open. +// INVALIDATION: none. A breaker is not a trade and does not get invalidated; +// it is reset by the risk agent, deliberately and outside this strategy. +// SHAPE: 1m, so it reacts within a bar rather than after one. +// NOT atr_volatility_halt: that one halts on market volatility, this one halts +// on realised portfolio loss. They are not redundant - the tape can be calm +// while the book bleeds, and violent while the book is flat. Both should be +// armed, and neither substitutes for the other. +// CALIBRATED ON: nothing instrument-specific. 5 percent is a portfolio-level +// figure and is the one threshold in this library that travels unchanged. strategy MaxDrawdownBreaker { agent RiskDesk diff --git a/nano/library/trend/donchian_breakout.nano b/nano/library/trend/donchian_breakout.nano index b974680..9757e92 100644 --- a/nano/library/trend/donchian_breakout.nano +++ b/nano/library/trend/donchian_breakout.nano @@ -1,6 +1,20 @@ // Donchian channel breakout. DONCHIAN_POS = (close - lower) / (upper - lower) // over the 20-period channel, provided by the host data feed. // A value at or above 1 means close broke the prior 20-period high. +// REGIME: expansion. Do NOT fire in a range - inside a range the 20-period +// high IS the range ceiling, so every touch mean-reverts and this becomes a +// systematic top-buyer. Range versus expansion is the whole decision here. +// CONDITIONS: a prior contraction to break out of, and participation behind +// the break (rising volume or range). +// INVALIDATION: a close back inside the channel. A breakout that does not hold +// is a failed breakout and usually resolves the other way. +// SHAPE: 1d; a clean push through a flat multi-week ceiling. +// NOT bb_squeeze_breakout: that anticipates expansion while still compressed; +// this confirms expansion once it has begun. Sequence, not synonym - if both +// fire, the squeeze fired first and this is its confirmation. +// CALIBRATED ON: crypto, daily. DONCHIAN_POS is scale-free, so the threshold +// travels cleanly; what does not travel is the gap behaviour of a +// session-bound instrument, where the open can clear the channel outright. strategy DonchianBreakout { every 1d { diff --git a/nano/library/trend/golden_cross.nano b/nano/library/trend/golden_cross.nano index 84c3f85..440a451 100644 --- a/nano/library/trend/golden_cross.nano +++ b/nano/library/trend/golden_cross.nano @@ -1,6 +1,21 @@ // Golden cross as a spread signal. Nano cannot compute crosses in-language; // the feed provides SMA_SPREAD = SMA(50) - SMA(200). Positive spread means // the fast average is above the slow one (post-golden-cross regime). +// REGIME: established uptrend. Read this as a REGIME FILTER, not an entry. +// The distinction matters: a positive spread is a persistent state that stays +// true for months, so treating it as a trigger fires it on every single bar of +// a bull market. Use it to permit or veto other setups, not to open a trade. +// CONDITIONS: none beyond the spread itself - that is precisely the problem +// with using it alone. +// INVALIDATION: the spread crossing back through zero, which is a death cross +// and a regime change rather than a stop on a position. +// SHAPE: 1d; the slow pair of averages fanned apart and holding. +// NOT macd_histogram_flip: that is an event on a fast pair and marks a moment; +// this is a state on a slow pair and marks a season. If both are true, only +// the MACD flip carries timing information. +// CALIBRATED ON: US large-cap equity ETF, daily, where the 50/200 pair is the +// convention. On a 24/7 instrument "200 days" spans a different amount of +// price action than it does on a session-bound one. strategy GoldenCross { every 1d { diff --git a/nano/library/trend/macd_histogram_flip.nano b/nano/library/trend/macd_histogram_flip.nano index 63af90f..8310466 100644 --- a/nano/library/trend/macd_histogram_flip.nano +++ b/nano/library/trend/macd_histogram_flip.nano @@ -1,5 +1,19 @@ // MACD histogram flip to positive (Pine: ta.macd histogram > 0). // MACD_HIST = MACD line - signal line, provided by the host data feed. +// REGIME: trend initiation, or resumption after a pullback. Do NOT fire in +// chop - the histogram oscillates around zero in a range, so it flips +// constantly and produces a stream of one-bar signals that mean nothing. +// CONDITIONS: a directional context on the timeframe above; the flip is a +// timing input and needs a trend to be timing into. +// INVALIDATION: the histogram dropping back below zero within a bar or two. +// A flip that does not persist was noise around the zero line. +// SHAPE: 4h; histogram bars crossing from below zero to above and staying. +// NOT golden_cross: that is a persistent state on a slow average pair, this is +// a discrete event on a fast one. NOT roc_momentum: that measures the size of +// a move already underway, this measures a change in its direction. +// CALIBRATED ON: crypto, 4h. The zero crossing is scale-free and travels, but +// flip frequency scales with noise, so a choppier instrument will produce many +// more of these for the same amount of real trend. strategy MacdHistogramFlip { every 4h { diff --git a/nano/library/volatility/atr_volatility_halt.nano b/nano/library/volatility/atr_volatility_halt.nano index 4454d7d..7b35edd 100644 --- a/nano/library/volatility/atr_volatility_halt.nano +++ b/nano/library/volatility/atr_volatility_halt.nano @@ -1,6 +1,23 @@ // ATR circuit breaker. ATR_PCT = ATR(14) / close * 100, provided by the // host data feed. When volatility exceeds 5 percent of price, stop // proposing entries until the regime calms down. +// REGIME: all of them. This is a control, not a directional hypothesis. It is +// always applicable, emits PAUSE rather than BUY or SELL, and must never be +// promoted into an execution slot or counted as a setup. +// CONDITIONS: none. It is armed whenever the feed is live. +// INVALIDATION: none - a breaker is not a trade. It releases when ATR_PCT +// falls back under the threshold. +// SHAPE: 5m, so a volatility spike is caught inside the move rather than after +// it. +// NOT max_drawdown_breaker: that halts on realised portfolio loss, this halts +// on market volatility. Both should be armed; neither substitutes for the +// other, because the tape can be violent while the book is flat. +// CALIBRATED ON: crypto, 5m - and this is the most dangerous threshold in the +// library to transplant. A 5 percent ATR is an ordinary volatile session in +// crypto and a once-in-years event on an index future, whose ATR_PCT normally +// sits well under 1 percent. Carried across unchanged this breaker does not +// misfire, it does something worse: it never fires at all, and the volatility +// brake silently disappears. Re-derive the threshold per instrument class. strategy AtrVolatilityHalt { every 5m { diff --git a/nano/library/volatility/bb_squeeze_breakout.nano b/nano/library/volatility/bb_squeeze_breakout.nano index b77f12a..eeef687 100644 --- a/nano/library/volatility/bb_squeeze_breakout.nano +++ b/nano/library/volatility/bb_squeeze_breakout.nano @@ -1,6 +1,22 @@ // Bollinger squeeze breakout. BB_WIDTH = (upper - lower) / middle * 100 // (band width percent); MOM = close - close[10] momentum. A tight squeeze // with positive momentum anticipates an upside expansion. +// REGIME: contraction, on the edge of expansion. Do NOT fire once expansion is +// already underway - by then the bands are wide, the edge is gone, and the +// entry is late. +// CONDITIONS: band width at the low end of its own recent range, and momentum +// already leaning positive. The squeeze alone is directionless; MOM is what +// picks the side, and it is the weaker half of the pair. +// INVALIDATION: width expanding while price resolves downward. A squeeze +// resolves in some direction, and being early is not the same as being right. +// SHAPE: 1h; bands pinched to a narrow ribbon, price coiled against the top. +// NOT bollinger_band_touch: same indicator, opposite regime - that one needs +// the range to hold, this one is betting it breaks. NOT donchian_breakout: +// this anticipates the expansion, that confirms it after the fact. +// CALIBRATED ON: crypto, 1h. BB_WIDTH < 4 is an absolute percentage and does +// NOT travel - band width percent scales with the instrument's own +// volatility, so on a quieter instrument 4 percent is permanently satisfied +// and the squeeze condition stops discriminating at all. strategy BbSqueezeBreakout { every 1h { diff --git a/nano/library/volume/obv_trend.nano b/nano/library/volume/obv_trend.nano index 9e3cc0a..d5f7860 100644 --- a/nano/library/volume/obv_trend.nano +++ b/nano/library/volume/obv_trend.nano @@ -1,6 +1,21 @@ // On-balance-volume trend confirmation. OBV_SLOPE = linear-regression slope // of OBV over the lookback window, provided by the host data feed. // A positive slope confirms accumulation. +// REGIME: any directional regime. This is a CONFIRMATION input and is weak on +// its own - a positive OBV slope is true through most of any advance, so +// firing it standalone is close to firing on "the market went up". +// CONDITIONS: compose it with a directional trigger and let this gate the +// trigger. It answers "is there participation behind the move", nothing else. +// INVALIDATION: slope flattening or turning negative while price still rises - +// the classic distribution divergence, and the one case where this input is +// genuinely informative on its own. +// SHAPE: 4h; OBV grinding upward underneath a rising price. +// NOT volume_spike_confirmation: that is a single-bar capitulation event, this +// is sustained accumulation across a window. Opposite time scales. +// CALIBRATED ON: crypto, 4h - and volume is the least portable series in this +// library. Crypto volume is per-venue and unaudited; futures volume is +// exchange-consolidated; equity volume fragments across lit and dark venues. +// An OBV slope computed on one is not comparable to the other. strategy ObvTrend { every 4h { diff --git a/nano/library/volume/volume_spike_confirmation.nano b/nano/library/volume/volume_spike_confirmation.nano index d4fb4ed..fc0ea4f 100644 --- a/nano/library/volume/volume_spike_confirmation.nano +++ b/nano/library/volume/volume_spike_confirmation.nano @@ -1,6 +1,22 @@ // Volume-confirmed capitulation buy. VOL_RATIO = volume / SMA(volume, 20), // provided by the host data feed. A 3x volume spike while RSI is oversold // marks a high-conviction reversal candidate. +// REGIME: capitulation or climax, inside a larger range or an uptrend +// pullback. Do NOT fire in an orderly downtrend - steady selling produces +// oversold RSI without the volume climax, and the volume gate is the only +// thing separating this from catching a falling knife. +// CONDITIONS: both halves must hold in the same bar. The volume spike is the +// evidence of exhaustion; the RSI reading alone is not. +// INVALIDATION: the next bar making a new low on equal or greater volume. +// That is continuation on participation, which is the opposite of exhaustion. +// SHAPE: 15m; a high-volume flush candle with a long lower wick. +// NOT rsi_oversold_reversal: this is that exact condition plus a volume gate, +// so it is a strict subset of it. When both fire it is one setup with two +// names, and treating them as two independent confirmations double-counts the +// same evidence. +// CALIBRATED ON: crypto, 15m. RSI 30 travels; the 3x volume ratio does not - +// it depends entirely on the venue's volume profile and on how much of the +// instrument's real volume the feed actually sees. strategy VolumeSpikeConfirmation { every 15m {