-
Notifications
You must be signed in to change notification settings - Fork 0
Cookbook
Practical strategy recipes built on Wickra's streaming indicators. Each recipe is a small, runnable snippet you can drop into a backtest loop or a live trading bot. Both paths share the same indicator state, so the same recipe works in either mode — see Streaming vs Batch.
Enter when RSI crosses out of an extreme; flatten when it returns to neutral.
import wickra as ta
rsi = ta.RSI(14)
position = 0 # 0 flat, +1 long, −1 short
for price in price_feed:
v = rsi.update(price)
if v is None:
continue
if position == 0 and v < 30:
position = 1
print(f"BUY at {price:.2f}")
elif position == 1 and v > 50:
position = 0
print(f"EXIT long at {price:.2f}")
elif position == 0 and v > 70:
position = -1
print(f"SHORT at {price:.2f}")
elif position == -1 and v < 50:
position = 0
print(f"COVER short at {price:.2f}")Trade in the direction of a MACD-histogram sign change. Zero-crossings of
the histogram (MACD − signal) are the canonical trigger and lead the
slower MACD-vs-signal line cross.
use wickra::{Indicator, MacdIndicator};
let mut macd = MacdIndicator::classic(); // (12, 26, 9)
let mut last_hist: Option<f64> = None;
for &price in &prices {
if let Some(v) = macd.update(price) {
if let Some(prev) = last_hist {
if prev <= 0.0 && v.histogram > 0.0 {
println!("BUY: MACD histogram turned positive at {price:.2}");
} else if prev >= 0.0 && v.histogram < 0.0 {
println!("SELL: MACD histogram turned negative at {price:.2}");
}
}
last_hist = Some(v.histogram);
}
}Trade in the direction of a band-piercing close, taking the bands as a dynamic support / resistance.
import wickra as ta
bb = ta.BollingerBands(20, 2.0)
for price in price_feed:
out = bb.update(price)
if out is None:
continue
upper, _middle, lower, _stddev = out
if price > upper:
print(f"BREAKOUT (long): {price:.2f} > upper {upper:.2f}")
elif price < lower:
print(f"BREAKOUT (short): {price:.2f} < lower {lower:.2f}")Take EMA-crossover signals only when ADX confirms a trend is in place. This is a textbook way to silence whipsaws in a ranging market.
import wickra as ta
ema_fast = ta.EMA(20)
ema_slow = ta.EMA(50)
adx = ta.ADX(14)
for high, low, close in candle_feed:
f = ema_fast.update(close)
s = ema_slow.update(close)
a = adx.update(high, low, close) # (plus_di, minus_di, adx) or None
if f is None or s is None or a is None:
continue
_, _, adx_v = a
if adx_v < 25:
continue # ranging market — skip
if f > s:
print(f"LONG: EMA20 > EMA50, ADX={adx_v:.1f}")
elif f < s:
print(f"SHORT: EMA20 < EMA50, ADX={adx_v:.1f}")Only take a 1-minute entry when the 1-hour trend agrees. With Wickra you
keep one streaming indicator per timeframe and feed each only the candles
that belong to it. wickra-data's Resampler rolls one
candle stream up into a coarser one; the canonical example is
examples/rust/src/bin/multi_timeframe.rs.
use wickra::{Indicator, Rsi};
let mut rsi_1m = Rsi::new(14)?;
let mut rsi_1h = Rsi::new(14)?;
for candle in one_min_candles {
let fast = rsi_1m.update(candle.close);
if candle.is_hour_close {
let slow = rsi_1h.update(candle.close);
if let (Some(f), Some(s)) = (fast, slow) {
if f > 70.0 && s > 50.0 {
println!("strong overbought (1m {f:.1} / 1h {s:.1})");
} else if f < 30.0 && s < 50.0 {
println!("strong oversold (1m {f:.1} / 1h {s:.1})");
}
}
}
}SuperTrend is a single-line ATR-banded trailing stop with explicit flip
logic — drop it into a long-only loop to manage exits:
import wickra as ta
st = ta.SuperTrend(10, 3.0)
position = 0 # 0 flat, +1 long
for high, low, close in candle_feed:
out = st.update(high, low, close)
if out is None:
continue
value, direction = out
if direction > 0 and position == 0:
position = 1
print(f"BUY at {close:.2f}, stop={value:.2f}")
elif direction < 0 and position == 1:
position = 0
print(f"EXIT at {close:.2f} (SuperTrend flipped)")When you want an indicator computed over the output of another, use the
Rust Chain combinator. The chain itself implements Indicator, so you
can nest, stack, and feed it into anything that takes an indicator.
use wickra::{BatchExt, Chain, Ema, Rsi};
// RSI(7) of EMA(14)-smoothed closes.
let mut chain = Chain::new(Ema::new(14)?, Rsi::new(7)?);
let out: Vec<Option<f64>> = chain.batch(&prices);See Indicator Chaining for the chained-warmup rule and three-stage examples.
- Indicators Overview — pick the right indicator for the question you are asking.
- Streaming vs Batch — why these recipes work bit-identically in both modes.
-
Data Layer —
Resamplerand the bundled BTCUSDT datasets for live multi-timeframe work.
Wickra on GitHub · crates.io · PyPI · npm · License: PolyForm-Noncommercial-1.0.0
- Alligator
- Alma
- Dema
- Ema
- Evwma
- Frama
- Hma
- Jma
- Kama
- McGinleyDynamic
- Sma
- Smma
- T3
- Tema
- Trima
- Vidya
- Vwma
- Wma
- Zlema
- AwesomeOscillator
- Cci
- Cmo
- ConnorsRSI
- Inertia
- Kst
- LaguerreRSI
- Mfi
- Mom
- Pgo
- Pmo
- Roc
- Rsi
- Rvi
- Smi
- Stochastic
- StochRsi
- Tsi
- UltimateOscillator
- WilliamsR
- Adx
- Adxr
- Aroon
- AroonOscillator
- ChoppinessIndex
- MacdIndicator
- MassIndex
- Rwi
- Tii
- Trix
- VerticalHorizontalFilter
- Vortex
- WaveTrend
- Atr
- BollingerBands
- BollingerBandwidth
- ChaikinVolatility
- Donchian
- GarmanKlassVolatility
- HistoricalVolatility
- Keltner
- Natr
- ParkinsonVolatility
- PercentB
- RogersSatchellVolatility
- RviVolatility
- StdDev
- TrueRange
- UlcerIndex
- YangZhangVolatility