quantwave_plugins/
custom_0.rs1use polars::prelude::*;
2use pyo3_polars::derive::polars_expr;
3use serde::Deserialize;
4use quantwave_core::*;
5use quantwave_core::traits::Next;
6
7#[polars_expr(output_type=Float64)]
8fn anchored_vwap(inputs: &[Series]) -> PolarsResult<Series> {
9 let price_s = &inputs[0];
10 let volume_s = &inputs[1];
11 let anchor_s = &inputs[2];
12
13 let price = price_s.f64()?;
14 let volume = volume_s.f64()?;
15 let anchor = anchor_s.bool()?;
16
17 let mut avwap = quantwave_core::AnchoredVWAP::new();
18 let mut values = Vec::with_capacity(price_s.len());
19
20 for i in 0..price_s.len() {
21 let p = price.get(i).unwrap_or(0.0);
22 let v = volume.get(i).unwrap_or(0.0);
23 let a = anchor.get(i).unwrap_or(false);
24 values.push(avwap.next((p, v, a)));
25 }
26
27 Ok(Series::new("anchored_vwap".into(), values))
28}
29
30#[derive(Deserialize)]
31pub struct KinematicKalmanKwargs {
32 pub q_pos: f64,
33 pub q_vel: f64,
34 pub r: f64,
35}
36
37#[polars_expr(output_type=Float64)]
38fn kinematic_kalman(inputs: &[Series], kwargs: KinematicKalmanKwargs) -> PolarsResult<Series> {
39 let s = inputs[0].f64()?;
40 let mut indicator = quantwave_core::indicators::kinematic_kalman::KinematicKalmanFilter::new(
41 kwargs.q_pos, kwargs.q_vel, kwargs.r
42 );
43 let mut values = Vec::with_capacity(s.len());
44
45 for i in 0..s.len() {
46 let val = s.get(i).unwrap_or(f64::NAN);
47 values.push(indicator.next(val));
48 }
49
50 Ok(Series::new("kinematic_kalman".into(), values))
51}
52
53#[derive(Deserialize)]
54pub struct VortexKwargs {
55 pub period: usize,
56}
57
58pub fn vortex_output(_: &[Field]) -> PolarsResult<Field> {
59 Ok(Field::new(
60 "vortex".into(),
61 DataType::Struct(vec![
62 Field::new("vi_plus".into(), DataType::Float64),
63 Field::new("vi_minus".into(), DataType::Float64),
64 ]),
65 ))
66}
67
68#[polars_expr(output_type_func=vortex_output)]
69fn vortex_indicator(inputs: &[Series], kwargs: VortexKwargs) -> PolarsResult<Series> {
70 let high = inputs[0].f64()?;
71 let low = inputs[1].f64()?;
72 let close = inputs[2].f64()?;
73
74 let mut vi = quantwave_core::VortexIndicator::new(kwargs.period);
75 let mut plus_vals = Vec::with_capacity(high.len());
76 let mut minus_vals = Vec::with_capacity(high.len());
77
78 for i in 0..high.len() {
79 let h = high.get(i).unwrap_or(0.0);
80 let l = low.get(i).unwrap_or(0.0);
81 let c = close.get(i).unwrap_or(0.0);
82 let (plus, minus) = vi.next((h, l, c));
83 plus_vals.push(plus);
84 minus_vals.push(minus);
85 }
86
87 let plus_series = Series::new("vi_plus".into(), plus_vals);
88 let minus_series = Series::new("vi_minus".into(), minus_vals);
89
90 let out = StructChunked::from_series(
91 "vortex_output".into(),
92 high.len(),
93 [plus_series, minus_series].iter(),
94 )?;
95
96 Ok(out.into_series())
97}
98
99#[derive(Deserialize)]
100pub struct SveKwargs {
101 pub bands_period: usize,
102 pub bands_deviation: f64,
103 pub low_band_adjust: f64,
104 pub mid_line_length: usize,
105}
106
107pub fn sve_bands_output(_: &[Field]) -> PolarsResult<Field> {
108 Ok(Field::new(
109 "sve_bands".into(),
110 DataType::Struct(vec![
111 Field::new("upper".into(), DataType::Float64),
112 Field::new("middle".into(), DataType::Float64),
113 Field::new("lower".into(), DataType::Float64),
114 ]),
115 ))
116}
117
118#[polars_expr(output_type_func=sve_bands_output)]
119fn sve_volatility_bands(inputs: &[Series], kwargs: SveKwargs) -> PolarsResult<Series> {
120 let high = inputs[0].f64()?;
121 let low = inputs[1].f64()?;
122 let close = inputs[2].f64()?;
123
124 let mut indicator = quantwave_core::SVEVolatilityBands::new(
125 kwargs.bands_period,
126 kwargs.bands_deviation,
127 kwargs.low_band_adjust,
128 kwargs.mid_line_length,
129 );
130 let mut upper_vals = Vec::with_capacity(high.len());
131 let mut mid_vals = Vec::with_capacity(high.len());
132 let mut lower_vals = Vec::with_capacity(high.len());
133
134 for i in 0..high.len() {
135 let h = high.get(i).unwrap_or(f64::NAN);
136 let l = low.get(i).unwrap_or(f64::NAN);
137 let c = close.get(i).unwrap_or(f64::NAN);
138 let (upper, mid, lower) = indicator.next((h, l, c));
139 upper_vals.push(upper);
140 mid_vals.push(mid);
141 lower_vals.push(lower);
142 }
143
144 let s_upper = Series::new("upper".into(), upper_vals);
145 let s_mid = Series::new("middle".into(), mid_vals);
146 let s_lower = Series::new("lower".into(), lower_vals);
147
148 let out = StructChunked::from_series(
149 "sve_bands_data".into(),
150 high.len(),
151 [s_upper, s_mid, s_lower].iter(),
152 )?;
153
154 Ok(out.into_series())
155}
156
157#[derive(Deserialize)]
158pub struct TtmKwargs {
159 pub period: usize,
160 pub multiplier_bb: f64,
161 pub multiplier_kc: f64,
162}
163
164pub fn ttm_squeeze_output(_: &[Field]) -> PolarsResult<Field> {
165 Ok(Field::new(
166 "ttm_squeeze".into(),
167 DataType::Struct(vec![
168 Field::new("histogram".into(), DataType::Float64),
169 Field::new("is_squeezed".into(), DataType::Boolean),
170 ]),
171 ))
172}
173
174#[polars_expr(output_type_func=ttm_squeeze_output)]
175fn ttm_squeeze(inputs: &[Series], kwargs: TtmKwargs) -> PolarsResult<Series> {
176 let high = inputs[0].f64()?;
177 let low = inputs[1].f64()?;
178 let close = inputs[2].f64()?;
179
180 let mut ttm = quantwave_core::TTMSqueeze::new(kwargs.period, kwargs.multiplier_bb, kwargs.multiplier_kc);
181 let mut histograms = Vec::with_capacity(high.len());
182 let mut squeezed = Vec::with_capacity(high.len());
183
184 for i in 0..high.len() {
185 let h = high.get(i).unwrap_or(0.0);
186 let l = low.get(i).unwrap_or(0.0);
187 let c = close.get(i).unwrap_or(0.0);
188 let (hist, is_sq) = ttm.next((h, l, c));
189 histograms.push(hist);
190 squeezed.push(is_sq);
191 }
192
193 let hist_series = Series::new("histogram".into(), histograms);
194 let squeezed_series = Series::new("is_squeezed".into(), squeezed);
195
196 let out = StructChunked::from_series(
197 "ttm_squeeze_output".into(),
198 high.len(),
199 [hist_series, squeezed_series].iter(),
200 )?;
201
202 Ok(out.into_series())
203}