use crate::interpreter::{Func, VarValue};
use std::sync::Arc;
pub fn sma() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 1 {
panic!("`sma` expects 1 argument: a numeric array (data window)");
}
let data_window: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`sma`: expected array as first argument, got {other:?}"),
};
let sma = quant_mathema::smoothing::sma(&data_window);
VarValue::Float(sma)
})))
}
pub fn sma_batch() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 2 {
panic!("`sma_batch` expects 2 arguments: a numeric array, and a window length");
}
let data: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`sma_batch`: expected array as first argument, got {other:?}"),
};
let window_len = match &args[1] {
VarValue::Int(n) => *n as usize,
other => panic!("`sma_batch`: expected int as second argument, got {other:?}"),
};
let series = quant_mathema::smoothing::sma_series(&data, window_len);
VarValue::Array(series.into_iter().map(VarValue::Float).collect())
})))
}
pub fn ema() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 1 {
panic!("`ema` expects 1 argument: a numeric array (data window)");
}
let data_window = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect::<Vec<f64>>(),
other => panic!("`ema`: expected array as first argument, got {other:?}"),
};
let ema = quant_mathema::smoothing::ema(&data_window);
VarValue::Float(ema)
})))
}
pub fn ema_batch() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 2 {
panic!("`ema_batch` expects 2 arguments: an array and a window length");
}
let series = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect::<Vec<f64>>(),
other => panic!("`ema_batch`: expected array as first argument, got {other:?}"),
};
let window_len = match &args[1] {
VarValue::Int(n) => *n as usize,
other => panic!("`ema_batch`: expected int as second argument, got {other:?}"),
};
let ema_series = quant_mathema::smoothing::ema_series(&series, window_len);
VarValue::Array(ema_series.into_iter().map(VarValue::Float).collect())
})))
}
pub fn vwma() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 3 {
panic!("`vwma` expects 2 arguments: price array, volume array");
}
let price_window: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`vwma`: expected array as first argument, got {other:?}"),
};
let volume_window: Vec<u32> = match &args[1] {
VarValue::Array(vals) => vals
.iter()
.map(|val| match val {
VarValue::Int(x) => *x as u32,
other => panic!(
"`vwma`: expected array of integers as second argument, got {other:?}",
),
})
.collect(),
other => panic!("`vwma`: expected array as second argument, got {other:?}"),
};
let vwma = quant_mathema::smoothing::vwma(&price_window, &volume_window);
VarValue::Float(vwma)
})))
}
pub fn vwma_batch() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 3 {
panic!("`vwma_batch` expects 3 arguments: prices array, volumes array, window length");
}
let prices: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`vwma_batch`: expected array as first argument, got {other:?}"),
};
let volumes: Vec<u32> = match &args[1] {
VarValue::Array(vals) => vals
.iter()
.map(|val| match val {
VarValue::Int(x) => *x as u32,
other => panic!(
"`vwma_batch`: expected array of integers as second argument, got {other:?}",
),
})
.collect(),
other => panic!("`vwma_batch`: expected array as second argument, got {other:?}"),
};
let window_len = match &args[2] {
VarValue::Int(n) => *n as usize,
other => panic!("`vwma_batch`: expected int as third argument, got {other:?}"),
};
let series = quant_mathema::smoothing::vwma_series(&prices, &volumes, window_len);
VarValue::Array(series.into_iter().map(VarValue::Float).collect())
})))
}
pub fn lsma() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 1 {
panic!("`lsma` expects 1 argument: a numeric array (data window)");
}
let data_window: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`lsma`: expected array as first argument, got {other:?}"),
};
if let Ok(lsma) = quant_mathema::smoothing::lsma(&data_window) {
VarValue::Float(lsma)
} else {
VarValue::Float(0.0)
}
})))
}
pub fn lsma_batch() -> Func {
Func::Builtin(Arc::new(Box::new(|args: Vec<VarValue>| {
if args.len() != 2 {
panic!("`lsma_batch` expects 2 arguments: a numeric array, and a window length");
}
let data: Vec<f64> = match &args[0] {
VarValue::Array(vals) => vals.iter().map(to_f64_or_panic).collect(),
other => panic!("`lsma_batch`: expected array as first argument, got {other:?}"),
};
let window_len = match &args[1] {
VarValue::Int(n) => *n as usize,
other => panic!("`lsma_batch`: expected int as second argument, got {other:?}"),
};
if let Ok(series) = quant_mathema::smoothing::lsma_series(&data, window_len) {
VarValue::Array(series.into_iter().map(VarValue::Float).collect())
} else {
VarValue::Array(Vec::new())
}
})))
}
fn to_f64_or_panic(v: &VarValue) -> f64 {
match v {
VarValue::Float(f) => *f,
VarValue::Int(i) => *i as f64,
other => panic!("expected numeric array element, got {other:?}"),
}
}