#![warn(missing_docs, missing_debug_implementations)]
mod history;
mod methods;
use crate::core::{Candle, ValueType};
pub use history::{Buffered, Peekable, WithHistory, WithLastValue};
pub use methods::{MAInstance, MA};
#[inline]
#[must_use]
pub fn sign(value: ValueType) -> ValueType {
signi(value) as ValueType
}
#[inline]
#[must_use]
pub fn signi(value: ValueType) -> i8 {
(value > 0.) as i8 - (value < 0.) as i8
}
pub fn assert_eq_float(original: ValueType, calculated: ValueType) {
const SIGMA: ValueType = if cfg!(feature = "value_type_f32") {
4e-3
} else {
1e-10
};
assert!(
calculated.is_finite(),
"Calculated value is not a regular number: {}",
calculated
);
let diff = original - calculated;
let mid = (original.abs() + calculated.abs()) / 2.0;
if mid != 0. {
assert!(
(diff / mid).abs() <= SIGMA || diff < SIGMA,
"orignial={}, calculated={}, diff={}, relative diff={}",
original,
calculated,
diff,
(diff / original).abs(),
);
}
}
pub fn assert_neq_float(value1: ValueType, value2: ValueType) {
const SIGMA: ValueType = if cfg!(feature = "value_type_f32") {
1e-10
} else {
1e-20
};
let mid = (value1 + value2) / 2.0;
let diff = value1 - value2;
assert!(
(diff / mid).abs() > SIGMA,
"value#1={}, value#2={}",
value1,
value2
);
}
#[derive(Debug, Clone, Default)]
#[allow(missing_copy_implementations)]
pub struct RandomCandles(u16);
impl RandomCandles {
const DEFAULT_PRICE: ValueType = 1.0;
const DEFAULT_VOLUME: ValueType = 10.0;
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[allow(clippy::missing_panics_doc)]
pub fn first(&mut self) -> Candle {
let position = self.0;
self.0 = 0;
let candle = self.next().unwrap();
self.0 = position;
candle
}
}
impl Iterator for RandomCandles {
type Item = Candle;
#[allow(clippy::suboptimal_flops)]
fn next(&mut self) -> Option<Self::Item> {
let prev_position = self.0.wrapping_sub(1) as ValueType;
let position = self.0 as ValueType;
let close = Self::DEFAULT_PRICE + position.sin() / 2.;
let open = Self::DEFAULT_PRICE + prev_position.sin() / 2.;
let high = close.max(open) + (position * 1.4).tan().abs();
let low = close.min(open) - (position * 0.8).cos().abs() / 3.;
let volume = Self::DEFAULT_VOLUME * (position / 2.).sin() + Self::DEFAULT_VOLUME / 2.;
let candle = Self::Item {
open,
high,
low,
close,
volume,
};
self.0 = self.0.wrapping_sub(1);
Some(candle)
}
#[allow(clippy::cast_possible_truncation)]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0 = n as u16;
self.0 = self.0.wrapping_sub(1);
self.next()
}
}