mod indicators;
mod internals;
mod indicator;
mod ohlcv;
mod price_source;
pub use crate::indicator::{Indicator, IndicatorConfig, IndicatorConfigBuilder};
pub use crate::ohlcv::{Ohlcv, Price, Timestamp};
pub use crate::price_source::PriceSource;
pub use crate::indicators::*;
macro_rules! impl_inherent_methods {
($indicator:ty, $config:ty, $builder:ty) => {
impl $indicator {
#[must_use]
pub fn new(config: <Self as Indicator>::Config) -> Self {
<Self as Indicator>::new(config)
}
pub fn compute(&mut self, ohlcv: &impl Ohlcv) -> Option<<Self as Indicator>::Output> {
<Self as Indicator>::compute(self, ohlcv)
}
#[must_use]
#[inline]
pub fn value(&self) -> Option<<Self as Indicator>::Output> {
<Self as Indicator>::value(self)
}
}
impl $config {
#[must_use]
pub fn builder() -> <Self as IndicatorConfig>::Builder {
<Self as IndicatorConfig>::builder()
}
#[must_use]
pub fn source(&self) -> PriceSource {
<Self as IndicatorConfig>::source(self)
}
#[must_use]
pub fn convergence(&self) -> usize {
<Self as IndicatorConfig>::convergence(self)
}
#[must_use]
pub fn to_builder(&self) -> <Self as IndicatorConfig>::Builder {
<Self as IndicatorConfig>::to_builder(self)
}
}
impl $builder {
#[must_use]
pub fn source(self, source: PriceSource) -> Self {
<Self as IndicatorConfigBuilder<$config>>::source(self, source)
}
#[must_use]
pub fn build(self) -> $config {
<Self as IndicatorConfigBuilder<$config>>::build(self)
}
}
};
}
impl_inherent_methods!(Adx, AdxConfig, AdxConfigBuilder);
impl_inherent_methods!(Atr, AtrConfig, AtrConfigBuilder);
impl_inherent_methods!(Cci, CciConfig, CciConfigBuilder);
impl_inherent_methods!(Chop, ChopConfig, ChopConfigBuilder);
impl_inherent_methods!(Dc, DcConfig, DcConfigBuilder);
impl_inherent_methods!(Sma, SmaConfig, SmaConfigBuilder);
impl_inherent_methods!(Rsi, RsiConfig, RsiConfigBuilder);
impl_inherent_methods!(Ema, EmaConfig, EmaConfigBuilder);
impl_inherent_methods!(Kc, KcConfig, KcConfigBuilder);
impl_inherent_methods!(Bb, BbConfig, BbConfigBuilder);
impl_inherent_methods!(Ichimoku, IchimokuConfig, IchimokuBuilder);
impl_inherent_methods!(Macd, MacdConfig, MacdConfigBuilder);
impl_inherent_methods!(Obv, ObvConfig, ObvConfigBuilder);
impl_inherent_methods!(Stoch, StochConfig, StochConfigBuilder);
impl_inherent_methods!(StochRsi, StochRsiConfig, StochRsiConfigBuilder);
impl_inherent_methods!(Vwap, VwapConfig, VwapConfigBuilder);
impl_inherent_methods!(WillR, WillRConfig, WillRConfigBuilder);
#[cfg(test)]
mod test_util;
#[cfg(test)]
mod inherent_methods {
use super::test_util::nz;
use super::{Bb, BbConfig, BbValue, Ema, EmaConfig, Ohlcv, Price, Sma, SmaConfig, Timestamp};
struct Bar(f64, u64);
impl Ohlcv for Bar {
fn open(&self) -> Price {
self.0
}
fn high(&self) -> Price {
self.0
}
fn low(&self) -> Price {
self.0
}
fn close(&self) -> Price {
self.0
}
fn open_time(&self) -> Timestamp {
self.1
}
}
#[test]
fn sma_without_indicator_import() {
let mut sma = Sma::new(SmaConfig::close(nz(2)));
assert_eq!(sma.compute(&Bar(10.0, 1)), None);
assert_eq!(sma.compute(&Bar(20.0, 2)), Some(15.0));
assert_eq!(sma.value(), Some(15.0));
}
#[test]
fn ema_without_indicator_import() {
let mut ema = Ema::new(EmaConfig::close(nz(2)));
assert_eq!(ema.compute(&Bar(10.0, 1)), None);
assert!(ema.compute(&Bar(20.0, 2)).is_some());
assert!(ema.value().is_some());
}
#[test]
fn bb_without_indicator_import() {
let mut bb = Bb::new(BbConfig::close(nz(2)));
assert!(bb.compute(&Bar(10.0, 1)).is_none());
let v: Option<BbValue> = bb.compute(&Bar(20.0, 2));
assert!(v.is_some());
assert!(bb.value().is_some());
}
#[test]
fn config_methods_without_trait_import() {
let config = SmaConfig::close(nz(20));
assert_eq!(config.length(), 20);
assert_eq!(config.source(), super::PriceSource::Close);
let config = EmaConfig::close(nz(10));
assert_eq!(config.length(), 10);
let config = BbConfig::close(nz(5));
assert_eq!(config.length(), 5);
}
#[test]
fn builder_methods_without_trait_import() {
let config = SmaConfig::builder()
.length(nz(14))
.source(super::PriceSource::HL2)
.build();
assert_eq!(config.length(), 14);
assert_eq!(config.source(), super::PriceSource::HL2);
let config = EmaConfig::builder().length(nz(20)).build();
assert_eq!(config.length(), 20);
let config = BbConfig::builder().length(nz(20)).build();
assert_eq!(config.length(), 20);
}
}