quantwave_plugins/
custom_3.rs1use polars::prelude::*;
2use pyo3_polars::derive::polars_expr;
3use serde::Deserialize;
4use quantwave_core::*;
5use quantwave_core::traits::Next;
6
7#[derive(Deserialize)]
8struct HmaKwargs {
9 period: usize,
10}
11
12pub fn hma_output(_: &[Field]) -> PolarsResult<Field> {
13 Ok(Field::new("hma".into(), DataType::Float64))
14}
15
16#[polars_expr(output_type_func=hma_output)]
17fn hma(inputs: &[Series], kwargs: HmaKwargs) -> PolarsResult<Series> {
18 let s = inputs[0].f64()?;
19 let mut hma = HMA::new(kwargs.period);
20 let mut values = Vec::with_capacity(s.len());
21
22 for i in 0..s.len() {
23 let val = s.get(i).unwrap_or(0.0);
24 values.push(hma.next(val));
25 }
26
27 Ok(Series::new("hma".into(), values))
28}
29
30#[derive(Deserialize)]
31struct ObvmKwargs {
32 obvm_period: usize,
33 signal_period: usize,
34}
35
36pub fn obvm_output(_: &[Field]) -> PolarsResult<Field> {
37 Ok(Field::new(
38 "obvm_data".into(),
39 DataType::Struct(vec![
40 Field::new("obvm".into(), DataType::Float64),
41 Field::new("signal".into(), DataType::Float64),
42 ]),
43 ))
44}
45
46#[polars_expr(output_type_func=obvm_output)]
47fn obvm(inputs: &[Series], kwargs: ObvmKwargs) -> PolarsResult<Series> {
48 let high = inputs[0].f64()?;
49 let low = inputs[1].f64()?;
50 let close = inputs[2].f64()?;
51 let volume = inputs[3].f64()?;
52
53 let mut indicator = Obvm::new(kwargs.obvm_period, kwargs.signal_period);
54 let mut obvm_vals = Vec::with_capacity(high.len());
55 let mut signal_vals = Vec::with_capacity(high.len());
56
57 for i in 0..high.len() {
58 let h = high.get(i).unwrap_or(f64::NAN);
59 let l = low.get(i).unwrap_or(f64::NAN);
60 let c = close.get(i).unwrap_or(f64::NAN);
61 let v = volume.get(i).unwrap_or(f64::NAN);
62 let (o, sig) = indicator.next((h, l, c, v));
63 obvm_vals.push(o);
64 signal_vals.push(sig);
65 }
66
67 let s_obvm = Series::new("obvm".into(), obvm_vals);
68 let s_signal = Series::new("signal".into(), signal_vals);
69 let out = StructChunked::from_series(
70 "obvm_data".into(),
71 high.len(),
72 [s_obvm, s_signal].iter(),
73 )?;
74 Ok(out.into_series())
75}
76
77pub fn fractals_output(_: &[Field]) -> PolarsResult<Field> {
78 Ok(Field::new(
79 "fractals_data".into(),
80 DataType::Struct(vec![
81 Field::new("bearish".into(), DataType::Boolean),
82 Field::new("bullish".into(), DataType::Boolean),
83 ]),
84 ))
85}
86
87#[polars_expr(output_type_func=fractals_output)]
88fn bill_williams_fractals(inputs: &[Series]) -> PolarsResult<Series> {
89 let high = inputs[0].f64()?;
90 let low = inputs[1].f64()?;
91
92 let mut fractals = BillWilliamsFractals::new();
93 let mut bearish_vals = Vec::with_capacity(high.len());
94 let mut bullish_vals = Vec::with_capacity(high.len());
95
96 for i in 0..high.len() {
97 let h = high.get(i).unwrap_or(0.0);
98 let l = low.get(i).unwrap_or(0.0);
99 let (bear, bull) = fractals.next((h, l));
100 bearish_vals.push(bear);
101 bullish_vals.push(bull);
102 }
103
104 let bearish_series = Series::new("bearish".into(), bearish_vals);
105 let bullish_series = Series::new("bullish".into(), bullish_vals);
106
107 let out = StructChunked::from_series(
108 "fractals_data".into(),
109 high.len(),
110 [bearish_series, bullish_series].iter(),
111 )?;
112 Ok(out.into_series())
113}
114
115#[derive(Deserialize)]
116struct PeriodKwargs {
117 period: usize,
118}
119
120pub fn donchian_output(_: &[Field]) -> PolarsResult<Field> {
121 Ok(Field::new(
122 "donchian_data".into(),
123 DataType::Struct(vec![
124 Field::new("upper".into(), DataType::Float64),
125 Field::new("middle".into(), DataType::Float64),
126 Field::new("lower".into(), DataType::Float64),
127 ]),
128 ))
129}
130
131#[polars_expr(output_type_func=donchian_output)]
132fn donchian_channels(inputs: &[Series], kwargs: PeriodKwargs) -> PolarsResult<Series> {
133 let high = inputs[0].f64()?;
134 let low = inputs[1].f64()?;
135
136 let mut dc = DonchianChannels::new(kwargs.period);
137 let mut uppers = Vec::with_capacity(high.len());
138 let mut middles = Vec::with_capacity(high.len());
139 let mut lowers = Vec::with_capacity(high.len());
140
141 for i in 0..high.len() {
142 let h = high.get(i).unwrap_or(0.0);
143 let l = low.get(i).unwrap_or(0.0);
144 let (upper, middle, lower) = dc.next((h, l));
145 uppers.push(upper);
146 middles.push(middle);
147 lowers.push(lower);
148 }
149
150 let upper_series = Series::new("upper".into(), uppers);
151 let middle_series = Series::new("middle".into(), middles);
152 let lower_series = Series::new("lower".into(), lowers);
153
154 let out = StructChunked::from_series(
155 "donchian_data".into(),
156 high.len(),
157 [upper_series, middle_series, lower_series].iter(),
158 )?;
159 Ok(out.into_series())
160}
161
162#[derive(Deserialize)]
163struct GmmKwargs {
164 k: usize,
165}
166
167pub fn gmm_output(_: &[Field]) -> PolarsResult<Field> {
168 Ok(Field::new("gmm_regime".into(), DataType::UInt32))
169}
170
171#[polars_expr(output_type_func=gmm_output)]
172fn gmm(inputs: &[Series], kwargs: GmmKwargs) -> PolarsResult<Series> {
173 let n_rows = inputs[0].len();
174
175 let mut values = Vec::with_capacity(n_rows);
176 for _ in 0..n_rows {
177 values.push(0u32);
178 }
179
180 Ok(Series::new("gmm_regime".into(), values))
181}