#![allow(missing_docs)]
use crate::backtesting::strategy::StrategyContext;
use crate::indicators::Indicator;
use super::IndicatorRef;
#[derive(Debug, Clone)]
pub struct SmaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for SmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Sma(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn sma(period: usize) -> SmaRef {
SmaRef {
period,
key: format!("sma_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct EmaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for EmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Ema(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn ema(period: usize) -> EmaRef {
EmaRef {
period,
key: format!("ema_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct WmaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for WmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Wma(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn wma(period: usize) -> WmaRef {
WmaRef {
period,
key: format!("wma_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct DemaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for DemaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Dema(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn dema(period: usize) -> DemaRef {
DemaRef {
period,
key: format!("dema_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct TemaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for TemaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Tema(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn tema(period: usize) -> TemaRef {
TemaRef {
period,
key: format!("tema_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct HmaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for HmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Hma(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn hma(period: usize) -> HmaRef {
HmaRef {
period,
key: format!("hma_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct VwmaRef {
pub period: usize,
key: String,
}
impl IndicatorRef for VwmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Vwma(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn vwma(period: usize) -> VwmaRef {
VwmaRef {
period,
key: format!("vwma_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct McginleyDynamicRef {
pub period: usize,
key: String,
}
impl IndicatorRef for McginleyDynamicRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::McginleyDynamic(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn mcginley(period: usize) -> McginleyDynamicRef {
McginleyDynamicRef {
period,
key: format!("mcginley_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct RsiRef {
pub period: usize,
key: String,
}
impl IndicatorRef for RsiRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Rsi(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn rsi(period: usize) -> RsiRef {
RsiRef {
period,
key: format!("rsi_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct CciRef {
pub period: usize,
key: String,
}
impl IndicatorRef for CciRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Cci(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn cci(period: usize) -> CciRef {
CciRef {
period,
key: format!("cci_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct WilliamsRRef {
pub period: usize,
key: String,
}
impl IndicatorRef for WilliamsRRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::WilliamsR(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn williams_r(period: usize) -> WilliamsRRef {
WilliamsRRef {
period,
key: format!("williams_r_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct CmoRef {
pub period: usize,
key: String,
}
impl IndicatorRef for CmoRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Cmo(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn cmo(period: usize) -> CmoRef {
CmoRef {
period,
key: format!("cmo_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct MomentumRef {
pub period: usize,
key: String,
}
impl IndicatorRef for MomentumRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Momentum(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn momentum(period: usize) -> MomentumRef {
MomentumRef {
period,
key: format!("momentum_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct RocRef {
pub period: usize,
key: String,
}
impl IndicatorRef for RocRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Roc(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn roc(period: usize) -> RocRef {
RocRef {
period,
key: format!("roc_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct AdxRef {
pub period: usize,
key: String,
}
impl IndicatorRef for AdxRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Adx(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn adx(period: usize) -> AdxRef {
AdxRef {
period,
key: format!("adx_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct AtrRef {
pub period: usize,
key: String,
}
impl IndicatorRef for AtrRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Atr(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn atr(period: usize) -> AtrRef {
AtrRef {
period,
key: format!("atr_{period}"),
}
}
#[derive(Debug, Clone, Copy)]
pub struct ObvRef;
impl IndicatorRef for ObvRef {
fn key(&self) -> &str {
"obv"
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![("obv".to_string(), Indicator::Obv)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn obv() -> ObvRef {
ObvRef
}
#[derive(Debug, Clone, Copy)]
pub struct VwapRef;
impl IndicatorRef for VwapRef {
fn key(&self) -> &str {
"vwap"
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![("vwap".to_string(), Indicator::Vwap)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn vwap() -> VwapRef {
VwapRef
}
#[derive(Debug, Clone)]
pub struct MfiRef {
pub period: usize,
key: String,
}
impl IndicatorRef for MfiRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Mfi(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn mfi(period: usize) -> MfiRef {
MfiRef {
period,
key: format!("mfi_{period}"),
}
}
#[derive(Debug, Clone)]
pub struct CmfRef {
pub period: usize,
key: String,
}
impl IndicatorRef for CmfRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Cmf(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[inline]
pub fn cmf(period: usize) -> CmfRef {
CmfRef {
period,
key: format!("cmf_{period}"),
}
}
#[derive(Debug, Clone, Copy)]
pub struct MacdConfig {
pub fast: usize,
pub slow: usize,
pub signal: usize,
}
impl MacdConfig {
pub fn line(&self) -> MacdLineRef {
MacdLineRef::new(self.fast, self.slow, self.signal)
}
pub fn signal_line(&self) -> MacdSignalRef {
MacdSignalRef::new(self.fast, self.slow, self.signal)
}
pub fn histogram(&self) -> MacdHistogramRef {
MacdHistogramRef::new(self.fast, self.slow, self.signal)
}
}
#[inline]
pub fn macd(fast: usize, slow: usize, signal: usize) -> MacdConfig {
MacdConfig { fast, slow, signal }
}
#[derive(Debug, Clone)]
pub struct MacdLineRef {
pub fast: usize,
pub slow: usize,
pub signal: usize,
key: String,
}
impl MacdLineRef {
fn new(fast: usize, slow: usize, signal: usize) -> Self {
Self {
fast,
slow,
signal,
key: format!("macd_line_{fast}_{slow}_{signal}"),
}
}
}
impl IndicatorRef for MacdLineRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Macd {
fast: self.fast,
slow: self.slow,
signal: self.signal,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct MacdSignalRef {
pub fast: usize,
pub slow: usize,
pub signal: usize,
key: String,
}
impl MacdSignalRef {
fn new(fast: usize, slow: usize, signal: usize) -> Self {
Self {
fast,
slow,
signal,
key: format!("macd_signal_{fast}_{slow}_{signal}"),
}
}
}
impl IndicatorRef for MacdSignalRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Macd {
fast: self.fast,
slow: self.slow,
signal: self.signal,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct MacdHistogramRef {
pub fast: usize,
pub slow: usize,
pub signal: usize,
key: String,
}
impl MacdHistogramRef {
fn new(fast: usize, slow: usize, signal: usize) -> Self {
Self {
fast,
slow,
signal,
key: format!("macd_histogram_{fast}_{slow}_{signal}"),
}
}
}
impl IndicatorRef for MacdHistogramRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Macd {
fast: self.fast,
slow: self.slow,
signal: self.signal,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct BollingerConfig {
pub period: usize,
pub std_dev: f64,
}
impl BollingerConfig {
pub fn upper(&self) -> BollingerUpperRef {
BollingerUpperRef::new(self.period, self.std_dev)
}
pub fn middle(&self) -> BollingerMiddleRef {
BollingerMiddleRef::new(self.period, self.std_dev)
}
pub fn lower(&self) -> BollingerLowerRef {
BollingerLowerRef::new(self.period, self.std_dev)
}
}
#[inline]
pub fn bollinger(period: usize, std_dev: f64) -> BollingerConfig {
BollingerConfig { period, std_dev }
}
#[derive(Debug, Clone)]
pub struct BollingerUpperRef {
pub period: usize,
pub std_dev: f64,
key: String,
}
impl BollingerUpperRef {
fn new(period: usize, std_dev: f64) -> Self {
Self {
period,
std_dev,
key: format!("bollinger_upper_{period}_{std_dev}"),
}
}
}
impl IndicatorRef for BollingerUpperRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Bollinger {
period: self.period,
std_dev: self.std_dev,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct BollingerMiddleRef {
pub period: usize,
pub std_dev: f64,
key: String,
}
impl BollingerMiddleRef {
fn new(period: usize, std_dev: f64) -> Self {
Self {
period,
std_dev,
key: format!("bollinger_middle_{period}_{std_dev}"),
}
}
}
impl IndicatorRef for BollingerMiddleRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Bollinger {
period: self.period,
std_dev: self.std_dev,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct BollingerLowerRef {
pub period: usize,
pub std_dev: f64,
key: String,
}
impl BollingerLowerRef {
fn new(period: usize, std_dev: f64) -> Self {
Self {
period,
std_dev,
key: format!("bollinger_lower_{period}_{std_dev}"),
}
}
}
impl IndicatorRef for BollingerLowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Bollinger {
period: self.period,
std_dev: self.std_dev,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct DonchianConfig {
pub period: usize,
}
impl DonchianConfig {
pub fn upper(&self) -> DonchianUpperRef {
DonchianUpperRef::new(self.period)
}
pub fn middle(&self) -> DonchianMiddleRef {
DonchianMiddleRef::new(self.period)
}
pub fn lower(&self) -> DonchianLowerRef {
DonchianLowerRef::new(self.period)
}
}
#[inline]
pub fn donchian(period: usize) -> DonchianConfig {
DonchianConfig { period }
}
#[derive(Debug, Clone)]
pub struct DonchianUpperRef {
pub period: usize,
key: String,
}
impl DonchianUpperRef {
fn new(period: usize) -> Self {
Self {
period,
key: format!("donchian_upper_{period}"),
}
}
}
impl IndicatorRef for DonchianUpperRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct DonchianMiddleRef {
pub period: usize,
key: String,
}
impl DonchianMiddleRef {
fn new(period: usize) -> Self {
Self {
period,
key: format!("donchian_middle_{period}"),
}
}
}
impl IndicatorRef for DonchianMiddleRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct DonchianLowerRef {
pub period: usize,
key: String,
}
impl DonchianLowerRef {
fn new(period: usize) -> Self {
Self {
period,
key: format!("donchian_lower_{period}"),
}
}
}
impl IndicatorRef for DonchianLowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct SupertrendConfig {
pub period: usize,
pub multiplier: f64,
}
impl SupertrendConfig {
pub fn value(&self) -> SupertrendValueRef {
SupertrendValueRef::new(self.period, self.multiplier)
}
pub fn uptrend(&self) -> SupertrendUptrendRef {
SupertrendUptrendRef::new(self.period, self.multiplier)
}
}
#[inline]
pub fn supertrend(period: usize, multiplier: f64) -> SupertrendConfig {
SupertrendConfig { period, multiplier }
}
#[derive(Debug, Clone)]
pub struct SupertrendValueRef {
pub period: usize,
pub multiplier: f64,
key: String,
}
impl SupertrendValueRef {
fn new(period: usize, multiplier: f64) -> Self {
Self {
period,
multiplier,
key: format!("supertrend_value_{period}_{multiplier}"),
}
}
}
impl IndicatorRef for SupertrendValueRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Supertrend {
period: self.period,
multiplier: self.multiplier,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct SupertrendUptrendRef {
pub period: usize,
pub multiplier: f64,
key: String,
}
impl SupertrendUptrendRef {
fn new(period: usize, multiplier: f64) -> Self {
Self {
period,
multiplier,
key: format!("supertrend_uptrend_{period}_{multiplier}"),
}
}
}
impl IndicatorRef for SupertrendUptrendRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Supertrend {
period: self.period,
multiplier: self.multiplier,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct StochasticConfig {
pub k_period: usize,
pub k_slow: usize,
pub d_period: usize,
}
impl StochasticConfig {
pub fn k(&self) -> StochasticKRef {
StochasticKRef::new(self.k_period, self.k_slow, self.d_period)
}
pub fn d(&self) -> StochasticDRef {
StochasticDRef::new(self.k_period, self.k_slow, self.d_period)
}
}
#[inline]
pub fn stochastic(k_period: usize, k_slow: usize, d_period: usize) -> StochasticConfig {
StochasticConfig {
k_period,
k_slow,
d_period,
}
}
#[derive(Debug, Clone)]
pub struct StochasticKRef {
pub k_period: usize,
pub k_slow: usize,
pub d_period: usize,
key: String,
}
impl StochasticKRef {
fn new(k_period: usize, k_slow: usize, d_period: usize) -> Self {
Self {
k_period,
k_slow,
d_period,
key: format!("stochastic_k_{k_period}_{k_slow}_{d_period}"),
}
}
}
impl IndicatorRef for StochasticKRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Stochastic {
k_period: self.k_period,
k_slow: self.k_slow,
d_period: self.d_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct StochasticDRef {
pub k_period: usize,
pub k_slow: usize,
pub d_period: usize,
key: String,
}
impl StochasticDRef {
fn new(k_period: usize, k_slow: usize, d_period: usize) -> Self {
Self {
k_period,
k_slow,
d_period,
key: format!("stochastic_d_{k_period}_{k_slow}_{d_period}"),
}
}
}
impl IndicatorRef for StochasticDRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Stochastic {
k_period: self.k_period,
k_slow: self.k_slow,
d_period: self.d_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct AroonConfig {
pub period: usize,
}
impl AroonConfig {
pub fn up(&self) -> AroonUpRef {
AroonUpRef::new(self.period)
}
pub fn down(&self) -> AroonDownRef {
AroonDownRef::new(self.period)
}
}
#[inline]
pub fn aroon(period: usize) -> AroonConfig {
AroonConfig { period }
}
#[derive(Debug, Clone)]
pub struct AroonUpRef {
pub period: usize,
key: String,
}
impl AroonUpRef {
fn new(period: usize) -> Self {
Self {
period,
key: format!("aroon_up_{period}"),
}
}
}
impl IndicatorRef for AroonUpRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Aroon(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct AroonDownRef {
pub period: usize,
key: String,
}
impl AroonDownRef {
fn new(period: usize) -> Self {
Self {
period,
key: format!("aroon_down_{period}"),
}
}
}
impl IndicatorRef for AroonDownRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::Aroon(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct IchimokuConfig {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
}
impl IchimokuConfig {
pub fn conversion_line(&self) -> IchimokuConversionRef {
IchimokuConversionRef::new(self.conversion, self.base, self.lagging, self.displacement)
}
pub fn base_line(&self) -> IchimokuBaseRef {
IchimokuBaseRef::new(self.conversion, self.base, self.lagging, self.displacement)
}
pub fn leading_span_a(&self) -> IchimokuLeadingARef {
IchimokuLeadingARef::new(self.conversion, self.base, self.lagging, self.displacement)
}
pub fn leading_span_b(&self) -> IchimokuLeadingBRef {
IchimokuLeadingBRef::new(self.conversion, self.base, self.lagging, self.displacement)
}
pub fn lagging_span(&self) -> IchimokuLaggingRef {
IchimokuLaggingRef::new(self.conversion, self.base, self.lagging, self.displacement)
}
}
#[inline]
pub fn ichimoku() -> IchimokuConfig {
IchimokuConfig {
conversion: 9,
base: 26,
lagging: 52,
displacement: 26,
}
}
#[inline]
pub fn ichimoku_custom(
conversion: usize,
base: usize,
lagging: usize,
displacement: usize,
) -> IchimokuConfig {
IchimokuConfig {
conversion,
base,
lagging,
displacement,
}
}
#[derive(Debug, Clone)]
pub struct IchimokuConversionRef {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
key: String,
}
impl IchimokuConversionRef {
fn new(conversion: usize, base: usize, lagging: usize, displacement: usize) -> Self {
Self {
conversion,
base,
lagging,
displacement,
key: format!("ichimoku_conversion_{conversion}_{base}_{lagging}_{displacement}"),
}
}
}
impl IndicatorRef for IchimokuConversionRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Ichimoku {
conversion: self.conversion,
base: self.base,
lagging: self.lagging,
displacement: self.displacement,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct IchimokuBaseRef {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
key: String,
}
impl IchimokuBaseRef {
fn new(conversion: usize, base: usize, lagging: usize, displacement: usize) -> Self {
Self {
conversion,
base,
lagging,
displacement,
key: format!("ichimoku_base_{conversion}_{base}_{lagging}_{displacement}"),
}
}
}
impl IndicatorRef for IchimokuBaseRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Ichimoku {
conversion: self.conversion,
base: self.base,
lagging: self.lagging,
displacement: self.displacement,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct IchimokuLeadingARef {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
key: String,
}
impl IchimokuLeadingARef {
fn new(conversion: usize, base: usize, lagging: usize, displacement: usize) -> Self {
Self {
conversion,
base,
lagging,
displacement,
key: format!("ichimoku_leading_a_{conversion}_{base}_{lagging}_{displacement}"),
}
}
}
impl IndicatorRef for IchimokuLeadingARef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Ichimoku {
conversion: self.conversion,
base: self.base,
lagging: self.lagging,
displacement: self.displacement,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct IchimokuLeadingBRef {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
key: String,
}
impl IchimokuLeadingBRef {
fn new(conversion: usize, base: usize, lagging: usize, displacement: usize) -> Self {
Self {
conversion,
base,
lagging,
displacement,
key: format!("ichimoku_leading_b_{conversion}_{base}_{lagging}_{displacement}"),
}
}
}
impl IndicatorRef for IchimokuLeadingBRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Ichimoku {
conversion: self.conversion,
base: self.base,
lagging: self.lagging,
displacement: self.displacement,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct IchimokuLaggingRef {
pub conversion: usize,
pub base: usize,
pub lagging: usize,
pub displacement: usize,
key: String,
}
impl IchimokuLaggingRef {
fn new(conversion: usize, base: usize, lagging: usize, displacement: usize) -> Self {
Self {
conversion,
base,
lagging,
displacement,
key: format!("ichimoku_lagging_{conversion}_{base}_{lagging}_{displacement}"),
}
}
}
impl IndicatorRef for IchimokuLaggingRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Ichimoku {
conversion: self.conversion,
base: self.base,
lagging: self.lagging,
displacement: self.displacement,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct KeltnerConfig {
pub period: usize,
pub multiplier: f64,
pub atr_period: usize,
}
impl KeltnerConfig {
pub fn upper(&self) -> KeltnerUpperRef {
KeltnerUpperRef::new(self.period, self.multiplier, self.atr_period)
}
pub fn middle(&self) -> KeltnerMiddleRef {
KeltnerMiddleRef::new(self.period, self.multiplier, self.atr_period)
}
pub fn lower(&self) -> KeltnerLowerRef {
KeltnerLowerRef::new(self.period, self.multiplier, self.atr_period)
}
}
#[inline]
pub fn keltner(period: usize, multiplier: f64, atr_period: usize) -> KeltnerConfig {
KeltnerConfig {
period,
multiplier,
atr_period,
}
}
#[derive(Debug, Clone)]
pub struct KeltnerUpperRef {
pub period: usize,
pub multiplier: f64,
pub atr_period: usize,
key: String,
}
impl KeltnerUpperRef {
fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
Self {
period,
multiplier,
atr_period,
key: format!("keltner_upper_{period}_{multiplier}_{atr_period}"),
}
}
}
impl IndicatorRef for KeltnerUpperRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::KeltnerChannels {
period: self.period,
multiplier: self.multiplier,
atr_period: self.atr_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct KeltnerMiddleRef {
pub period: usize,
pub multiplier: f64,
pub atr_period: usize,
key: String,
}
impl KeltnerMiddleRef {
fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
Self {
period,
multiplier,
atr_period,
key: format!("keltner_middle_{period}_{multiplier}_{atr_period}"),
}
}
}
impl IndicatorRef for KeltnerMiddleRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::KeltnerChannels {
period: self.period,
multiplier: self.multiplier,
atr_period: self.atr_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct KeltnerLowerRef {
pub period: usize,
pub multiplier: f64,
pub atr_period: usize,
key: String,
}
impl KeltnerLowerRef {
fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
Self {
period,
multiplier,
atr_period,
key: format!("keltner_lower_{period}_{multiplier}_{atr_period}"),
}
}
}
impl IndicatorRef for KeltnerLowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::KeltnerChannels {
period: self.period,
multiplier: self.multiplier,
atr_period: self.atr_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParabolicSarConfig {
pub step: f64,
pub max: f64,
}
#[inline]
pub fn parabolic_sar(step: f64, max: f64) -> ParabolicSarRef {
ParabolicSarRef::new(step, max)
}
#[derive(Debug, Clone)]
pub struct ParabolicSarRef {
pub step: f64,
pub max: f64,
key: String,
}
impl ParabolicSarRef {
fn new(step: f64, max: f64) -> Self {
Self {
step,
max,
key: format!("psar_{step}_{max}"),
}
}
}
impl IndicatorRef for ParabolicSarRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::ParabolicSar {
step: self.step,
max: self.max,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct AlmaConfig {
pub period: usize,
pub offset: f64,
pub sigma: f64,
}
#[inline]
pub fn alma(period: usize, offset: f64, sigma: f64) -> AlmaRef {
AlmaRef::new(period, offset, sigma)
}
#[derive(Debug, Clone)]
pub struct AlmaRef {
pub period: usize,
pub offset: f64,
pub sigma: f64,
key: String,
}
impl AlmaRef {
fn new(period: usize, offset: f64, sigma: f64) -> Self {
Self {
period,
offset,
sigma,
key: format!("alma_{period}_{offset}_{sigma}"),
}
}
}
impl IndicatorRef for AlmaRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::Alma {
period: self.period,
offset: self.offset,
sigma: self.sigma,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct StochasticRsiConfig {
pub rsi_period: usize,
pub stoch_period: usize,
pub k_period: usize,
pub d_period: usize,
}
impl StochasticRsiConfig {
pub fn k(&self) -> StochasticRsiRef {
StochasticRsiRef::new(
self.rsi_period,
self.stoch_period,
self.k_period,
self.d_period,
)
}
pub fn d(&self) -> StochasticRsiDRef {
StochasticRsiDRef::new(
self.rsi_period,
self.stoch_period,
self.k_period,
self.d_period,
)
}
}
#[inline]
pub fn stochastic_rsi(
rsi_period: usize,
stoch_period: usize,
k_period: usize,
d_period: usize,
) -> StochasticRsiConfig {
StochasticRsiConfig {
rsi_period,
stoch_period,
k_period,
d_period,
}
}
#[derive(Debug, Clone)]
pub struct StochasticRsiRef {
pub rsi_period: usize,
pub stoch_period: usize,
pub k_period: usize,
pub d_period: usize,
key: String,
}
impl StochasticRsiRef {
fn new(rsi_period: usize, stoch_period: usize, k_period: usize, d_period: usize) -> Self {
Self {
rsi_period,
stoch_period,
k_period,
d_period,
key: format!("stoch_rsi_k_{rsi_period}_{stoch_period}_{k_period}_{d_period}"),
}
}
}
impl IndicatorRef for StochasticRsiRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::StochasticRsi {
rsi_period: self.rsi_period,
stoch_period: self.stoch_period,
k_period: self.k_period,
d_period: self.d_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct StochasticRsiDRef {
pub rsi_period: usize,
pub stoch_period: usize,
pub k_period: usize,
pub d_period: usize,
key: String,
}
impl StochasticRsiDRef {
fn new(rsi_period: usize, stoch_period: usize, k_period: usize, d_period: usize) -> Self {
Self {
rsi_period,
stoch_period,
k_period,
d_period,
key: format!("stoch_rsi_d_{rsi_period}_{stoch_period}_{k_period}_{d_period}"),
}
}
}
impl IndicatorRef for StochasticRsiDRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
let k_key = format!(
"stoch_rsi_k_{}_{}_{}_{}",
self.rsi_period, self.stoch_period, self.k_period, self.d_period
);
vec![(
k_key,
Indicator::StochasticRsi {
rsi_period: self.rsi_period,
stoch_period: self.stoch_period,
k_period: self.k_period,
d_period: self.d_period,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct AwesomeOscillatorRef {
pub fast: usize,
pub slow: usize,
key: String,
}
#[inline]
pub fn awesome_oscillator(fast: usize, slow: usize) -> AwesomeOscillatorRef {
AwesomeOscillatorRef {
fast,
slow,
key: format!("ao_{fast}_{slow}"),
}
}
impl IndicatorRef for AwesomeOscillatorRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::AwesomeOscillator {
fast: self.fast,
slow: self.slow,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct CoppockCurveRef {
pub wma_period: usize,
pub long_roc: usize,
pub short_roc: usize,
key: String,
}
#[inline]
pub fn coppock_curve(wma_period: usize, long_roc: usize, short_roc: usize) -> CoppockCurveRef {
CoppockCurveRef {
wma_period,
long_roc,
short_roc,
key: format!("coppock_{wma_period}_{long_roc}_{short_roc}"),
}
}
impl IndicatorRef for CoppockCurveRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(
self.key.clone(),
Indicator::CoppockCurve {
wma_period: self.wma_period,
long_roc: self.long_roc,
short_roc: self.short_roc,
},
)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct ChoppinessIndexRef {
pub period: usize,
key: String,
}
#[inline]
pub fn choppiness_index(period: usize) -> ChoppinessIndexRef {
ChoppinessIndexRef {
period,
key: format!("chop_{period}"),
}
}
impl IndicatorRef for ChoppinessIndexRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::ChoppinessIndex(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct TrueRangeRef;
#[inline]
pub fn true_range() -> TrueRangeRef {
TrueRangeRef
}
impl IndicatorRef for TrueRangeRef {
fn key(&self) -> &str {
"true_range"
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![("true_range".to_string(), Indicator::TrueRange)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct ChaikinOscillatorRef;
#[inline]
pub fn chaikin_oscillator() -> ChaikinOscillatorRef {
ChaikinOscillatorRef
}
impl IndicatorRef for ChaikinOscillatorRef {
fn key(&self) -> &str {
"chaikin_osc"
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![("chaikin_osc".to_string(), Indicator::ChaikinOscillator)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone, Copy)]
pub struct AccumulationDistributionRef;
#[inline]
pub fn accumulation_distribution() -> AccumulationDistributionRef {
AccumulationDistributionRef
}
impl IndicatorRef for AccumulationDistributionRef {
fn key(&self) -> &str {
"ad"
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![("ad".to_string(), Indicator::AccumulationDistribution)]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct BalanceOfPowerRef {
pub period: Option<usize>,
key: String,
}
#[inline]
pub fn balance_of_power(period: Option<usize>) -> BalanceOfPowerRef {
let key = match period {
Some(p) => format!("bop_{p}"),
None => "bop".to_string(),
};
BalanceOfPowerRef { period, key }
}
impl IndicatorRef for BalanceOfPowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::BalanceOfPower(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct BullPowerRef {
pub period: usize,
key: String,
}
#[inline]
pub fn bull_power(period: usize) -> BullPowerRef {
BullPowerRef {
period,
key: format!("bull_power_{period}"),
}
}
impl IndicatorRef for BullPowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::BullBearPower(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct BearPowerRef {
pub period: usize,
key: String,
}
#[inline]
pub fn bear_power(period: usize) -> BearPowerRef {
BearPowerRef {
period,
key: format!("bear_power_{period}"),
}
}
impl IndicatorRef for BearPowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::BullBearPower(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct ElderBullPowerRef {
pub period: usize,
key: String,
}
#[inline]
pub fn elder_bull_power(period: usize) -> ElderBullPowerRef {
ElderBullPowerRef {
period,
key: format!("elder_bull_{period}"),
}
}
impl IndicatorRef for ElderBullPowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::ElderRay(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[derive(Debug, Clone)]
pub struct ElderBearPowerRef {
pub period: usize,
key: String,
}
#[inline]
pub fn elder_bear_power(period: usize) -> ElderBearPowerRef {
ElderBearPowerRef {
period,
key: format!("elder_bear_{period}"),
}
}
impl IndicatorRef for ElderBearPowerRef {
fn key(&self) -> &str {
&self.key
}
fn required_indicators(&self) -> Vec<(String, Indicator)> {
vec![(self.key.clone(), Indicator::ElderRay(self.period))]
}
fn value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator(self.key())
}
fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
ctx.indicator_prev(self.key())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_moving_average_keys() {
assert_eq!(sma(20).key(), "sma_20");
assert_eq!(ema(12).key(), "ema_12");
assert_eq!(wma(14).key(), "wma_14");
assert_eq!(dema(21).key(), "dema_21");
assert_eq!(tema(21).key(), "tema_21");
assert_eq!(hma(9).key(), "hma_9");
assert_eq!(vwma(20).key(), "vwma_20");
assert_eq!(mcginley(14).key(), "mcginley_14");
assert_eq!(alma(9, 0.85, 6.0).key(), "alma_9_0.85_6");
}
#[test]
fn test_oscillator_keys() {
assert_eq!(rsi(14).key(), "rsi_14");
assert_eq!(cci(20).key(), "cci_20");
assert_eq!(williams_r(14).key(), "williams_r_14");
assert_eq!(cmo(14).key(), "cmo_14");
assert_eq!(
stochastic_rsi(14, 14, 3, 3).k().key(),
"stoch_rsi_k_14_14_3_3"
);
assert_eq!(
stochastic_rsi(14, 14, 3, 3).d().key(),
"stoch_rsi_d_14_14_3_3"
);
assert_eq!(awesome_oscillator(5, 34).key(), "ao_5_34");
assert_eq!(choppiness_index(14).key(), "chop_14");
}
#[test]
fn test_macd_keys() {
let m = macd(12, 26, 9);
assert_eq!(m.line().key(), "macd_line_12_26_9");
assert_eq!(m.signal_line().key(), "macd_signal_12_26_9");
assert_eq!(m.histogram().key(), "macd_histogram_12_26_9");
}
#[test]
fn test_bollinger_keys() {
let bb = bollinger(20, 2.0);
assert_eq!(bb.upper().key(), "bollinger_upper_20_2");
assert_eq!(bb.middle().key(), "bollinger_middle_20_2");
assert_eq!(bb.lower().key(), "bollinger_lower_20_2");
}
#[test]
fn test_donchian_keys() {
let dc = donchian(20);
assert_eq!(dc.upper().key(), "donchian_upper_20");
assert_eq!(dc.middle().key(), "donchian_middle_20");
assert_eq!(dc.lower().key(), "donchian_lower_20");
}
#[test]
fn test_supertrend_keys() {
let st = supertrend(10, 3.0);
assert_eq!(st.value().key(), "supertrend_value_10_3");
assert_eq!(st.uptrend().key(), "supertrend_uptrend_10_3");
}
#[test]
fn test_stochastic_keys() {
let stoch = stochastic(14, 3, 3);
assert_eq!(stoch.k().key(), "stochastic_k_14_3_3");
assert_eq!(stoch.d().key(), "stochastic_d_14_3_3");
}
#[test]
fn test_aroon_keys() {
let ar = aroon(25);
assert_eq!(ar.up().key(), "aroon_up_25");
assert_eq!(ar.down().key(), "aroon_down_25");
}
#[test]
fn test_ichimoku_keys() {
let ich = ichimoku();
assert_eq!(
ich.conversion_line().key(),
"ichimoku_conversion_9_26_52_26"
);
assert_eq!(ich.base_line().key(), "ichimoku_base_9_26_52_26");
assert_eq!(ich.leading_span_a().key(), "ichimoku_leading_a_9_26_52_26");
assert_eq!(ich.leading_span_b().key(), "ichimoku_leading_b_9_26_52_26");
assert_eq!(ich.lagging_span().key(), "ichimoku_lagging_9_26_52_26");
}
#[test]
fn test_keltner_keys() {
let kc = keltner(20, 2.0, 10);
assert_eq!(kc.upper().key(), "keltner_upper_20_2_10");
assert_eq!(kc.middle().key(), "keltner_middle_20_2_10");
assert_eq!(kc.lower().key(), "keltner_lower_20_2_10");
}
#[test]
fn test_volume_keys() {
assert_eq!(obv().key(), "obv");
assert_eq!(vwap().key(), "vwap");
assert_eq!(mfi(14).key(), "mfi_14");
assert_eq!(cmf(20).key(), "cmf_20");
assert_eq!(chaikin_oscillator().key(), "chaikin_osc");
assert_eq!(accumulation_distribution().key(), "ad");
assert_eq!(balance_of_power(Some(14)).key(), "bop_14");
assert_eq!(balance_of_power(None).key(), "bop");
}
#[test]
fn test_power_keys() {
assert_eq!(bull_power(13).key(), "bull_power_13");
assert_eq!(bear_power(13).key(), "bear_power_13");
assert_eq!(elder_bull_power(13).key(), "elder_bull_13");
assert_eq!(elder_bear_power(13).key(), "elder_bear_13");
}
#[test]
fn test_other_keys() {
assert_eq!(parabolic_sar(0.02, 0.2).key(), "psar_0.02_0.2");
assert_eq!(true_range().key(), "true_range");
assert_eq!(coppock_curve(10, 14, 11).key(), "coppock_10_14_11");
}
#[test]
fn test_required_indicators() {
let sma_ref = sma(20);
let indicators = sma_ref.required_indicators();
assert_eq!(indicators.len(), 1);
assert_eq!(indicators[0].0, "sma_20");
assert!(matches!(indicators[0].1, Indicator::Sma(20)));
}
}