pub mod single {
use crate::candle_indicators::single::moving_constant_bands;
use crate::momentum_indicators::single::{macd_line, relative_strength_index, signal_line};
use crate::moving_average::single::moving_average;
use crate::{ConstantModelType, DeviationModel, MovingAverageType};
#[inline]
pub fn simple_moving_average(prices: &[f64]) -> f64 {
if prices.is_empty() {
panic!("Prices cannot be empty")
};
moving_average(prices, MovingAverageType::Simple)
}
#[inline]
pub fn smoothed_moving_average(prices: &[f64]) -> f64 {
if prices.is_empty() {
panic!("Prices cannot be empty")
};
moving_average(prices, MovingAverageType::Smoothed)
}
#[inline]
pub fn exponential_moving_average(prices: &[f64]) -> f64 {
if prices.is_empty() {
panic!("Prices cannot be empty")
};
moving_average(prices, MovingAverageType::Exponential)
}
#[inline]
pub fn bollinger_bands(prices: &[f64]) -> (f64, f64, f64) {
if prices.is_empty() {
panic!("Prices cannot be empty");
};
if prices.len() != 20 {
panic!(
"Prices must be 20 periods long not {} periods",
prices.len()
)
};
moving_constant_bands(
prices,
ConstantModelType::SimpleMovingAverage,
DeviationModel::StandardDeviation,
2.0,
)
}
#[inline]
pub fn macd(prices: &[f64]) -> (f64, f64, f64) {
if prices.len() != 34 {
panic!(
"Prices must be 34 periods long, not {} periods",
prices.len()
)
};
let mut macds = Vec::with_capacity(9);
let model = crate::ConstantModelType::ExponentialMovingAverage;
for i in 0..9 {
macds.push(macd_line(&prices[i..i + 26], 12_usize, model, model));
}
let signal = signal_line(&macds, model);
(macds[8], signal, macds[8] - signal)
}
#[inline]
pub fn rsi(prices: &[f64]) -> f64 {
if prices.len() != 14 {
panic!("RSI must have a period of 14 not {}", prices.len())
};
relative_strength_index(prices, ConstantModelType::SmoothedMovingAverage)
}
}
pub mod bulk {
use crate::standard_indicators::single;
#[inline]
pub fn simple_moving_average(prices: &[f64], period: usize) -> Vec<f64> {
let length = prices.len();
if period > length {
panic!(
"Period ({}) cannot be greater than length of prices ({})",
period, length
)
};
let mut mas = Vec::with_capacity(length - period + 1);
for window in prices.windows(period) {
mas.push(single::simple_moving_average(window));
}
mas
}
#[inline]
pub fn smoothed_moving_average(prices: &[f64], period: usize) -> Vec<f64> {
let length = prices.len();
if period > length {
panic!(
"Period ({}) cannot be greater than length of prices ({})",
period, length
)
};
let mut mas = Vec::with_capacity(length - period + 1);
for window in prices.windows(period) {
mas.push(single::smoothed_moving_average(window));
}
mas
}
#[inline]
pub fn exponential_moving_average(prices: &[f64], period: usize) -> Vec<f64> {
let length = prices.len();
if period > length {
panic!(
"Period ({}) cannot be greater than length of prices ({})",
period, length
)
};
let mut mas = Vec::with_capacity(length - period + 1);
for window in prices.windows(period) {
mas.push(single::exponential_moving_average(window));
}
mas
}
#[inline]
pub fn bollinger_bands(prices: &[f64]) -> Vec<(f64, f64, f64)> {
let length = prices.len();
if length < 20 {
panic!(
"Prices must be at least 20 periods long not {} periods",
length
)
};
let mut bbands = Vec::with_capacity(length - 19);
for window in prices.windows(20) {
bbands.push(single::bollinger_bands(window));
}
bbands
}
#[inline]
pub fn macd(prices: &[f64]) -> Vec<(f64, f64, f64)> {
let length = prices.len();
if length < 34 {
panic!(
"Prices must be at least 35 periods long, not {} periods",
length
)
};
let mut macds = Vec::with_capacity(length - 33);
for window in prices.windows(34) {
macds.push(single::macd(window));
}
macds
}
pub fn rsi(prices: &[f64]) -> Vec<f64> {
let length = prices.len();
if length < 14 {
panic!("RSI must have a period of at least 14 not {}", length)
};
let mut rsis = Vec::with_capacity(length - 13);
for window in prices.windows(14) {
rsis.push(single::rsi(window));
}
rsis
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single_simple_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
assert_eq!(100.352, single::simple_moving_average(&prices));
}
#[test]
#[should_panic]
fn single_simple_moving_average_panic() {
let prices = Vec::new();
single::simple_moving_average(&prices);
}
#[test]
fn bulk_simple_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 4;
assert_eq!(
vec![100.3925, 100.39],
bulk::simple_moving_average(&prices, period)
);
}
#[test]
#[should_panic]
fn bulk_simple_moving_average_panic() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 40;
bulk::simple_moving_average(&prices, period);
}
#[test]
fn single_smoothed_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
assert_eq!(100.34228938600666, single::smoothed_moving_average(&prices));
}
#[test]
#[should_panic]
fn single_smoothed_moving_average_panic() {
let prices = Vec::new();
single::smoothed_moving_average(&prices);
}
#[test]
fn bulk_smoothed_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 4;
assert_eq!(
vec![100.40982857142858, 100.35371428571428],
bulk::smoothed_moving_average(&prices, period)
);
}
#[test]
#[should_panic]
fn bulk_smoothed_moving_average_panic() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 40;
bulk::smoothed_moving_average(&prices, period);
}
#[test]
fn single_exponential_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
assert_eq!(
100.32810426540287,
single::exponential_moving_average(&prices)
);
}
#[test]
#[should_panic]
fn single_exponential_moving_average_panic() {
let prices = Vec::new();
single::exponential_moving_average(&prices);
}
#[test]
fn bulk_exponential_moving_average() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 4;
assert_eq!(
vec![100.41672794117645, 100.32544117647058],
bulk::exponential_moving_average(&prices, period)
);
}
#[test]
#[should_panic]
fn bulk_exponential_moving_average_panic() {
let prices = vec![100.2, 100.46, 100.53, 100.38, 100.19];
let period: usize = 40;
bulk::exponential_moving_average(&prices, period);
}
#[test]
fn single_bollinger_bands() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63,
];
assert_eq!(
(97.73388801467088, 99.25200000000002, 100.77011198532917),
single::bollinger_bands(&prices)
);
}
#[test]
#[should_panic]
fn single_bollinger_band_panic_empty_prices() {
let prices = Vec::new();
single::bollinger_bands(&prices);
}
#[test]
#[should_panic]
fn single_bollinger_band_panic_wrong_period() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31,
];
single::bollinger_bands(&prices);
}
#[test]
fn bulk_bollinger_bands() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63, 99.75, 99.55, 98.8,
];
assert_eq!(
vec![
(97.73388801467088, 99.25200000000002, 100.77011198532917),
(97.7373030306026, 99.27000000000001, 100.80269696939742),
(97.73687492346315, 99.268, 100.79912507653685),
(97.69218538980725, 99.224, 100.75581461019276)
],
bulk::bollinger_bands(&prices)
);
}
#[test]
#[should_panic]
fn bulk_bollinger_band_panic_wrong_period() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31,
];
bulk::bollinger_bands(&prices);
}
#[test]
fn single_macd() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63, 99.75, 99.55, 98.8, 98.97,
98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5, 97.22, 98.03, 98.21,
];
assert_eq!(
(
-0.6285719796983358,
-0.6158898367280627,
-0.012682142970273036
),
single::macd(&prices)
);
}
#[test]
#[should_panic]
fn single_macd_panic() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63, 99.75, 99.55, 98.8,
];
single::macd(&prices);
}
#[test]
fn bulk_macd() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63, 99.75, 99.55, 98.8, 98.97,
98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5, 97.22, 98.03, 98.21, 98.05, 98.24,
];
assert_eq!(
vec![
(
-0.6285719796983358,
-0.6158898367280627,
-0.012682142970273036
),
(-0.54985540794776, -0.61936157195289, 0.06950616400512999),
(
-0.4749341506892648,
-0.6001186622390476,
0.12518451154978283
)
],
bulk::macd(&prices)
);
}
#[test]
#[should_panic]
fn bulk_macd_panic() {
let prices = vec![
99.39, 99.59, 99.68, 99.98, 99.06, 98.39, 99.23, 98.66, 98.88, 98.31, 98.16, 97.87,
98.74, 99.47, 98.86, 99.73, 100.06, 100.66, 99.69, 100.63, 99.75, 99.55, 98.8,
];
bulk::macd(&prices);
}
#[test]
fn single_rsi() {
let prices = vec![
99.75, 99.55, 98.8, 98.97, 98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5, 97.22,
98.03, 98.21,
];
assert_eq!(49.49693728728258, single::rsi(&prices));
}
#[test]
#[should_panic]
fn single_rsi_panic() {
let prices = vec![
99.75, 99.55, 98.8, 98.97, 98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5,
];
single::rsi(&prices);
}
#[test]
fn bulk_rsi() {
let prices = vec![
99.75, 99.55, 98.8, 98.97, 98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5, 97.22,
98.03, 98.21, 98.05, 98.24,
];
assert_eq!(
vec![49.49693728728258, 51.7387808206744, 49.93948387240627],
bulk::rsi(&prices)
);
}
#[test]
#[should_panic]
fn bulk_rsi_panic() {
let prices = vec![
99.75, 99.55, 98.8, 98.97, 98.83, 98.15, 97.42, 96.94, 96.51, 96.71, 96.5,
];
bulk::rsi(&prices);
}
}