1use crate::indicators::av;
8use crate::kernels;
9
10fn rolling_sum(x: &[f64], n: usize) -> Vec<f64> {
13 (kernels::sma(av(x), n) * n as f64).to_vec()
14}
15
16pub fn vortex(high: &[f64], low: &[f64], close: &[f64], n: usize, plus: bool) -> Vec<f64> {
20 let len = high.len();
21 let tr = super::tr(high, low, close); let vm: Vec<f64> = (0..len)
23 .map(|i| {
24 if i == 0 {
25 f64::NAN
26 } else if plus {
27 (high[i] - low[i - 1]).abs()
28 } else {
29 (low[i] - high[i - 1]).abs()
30 }
31 })
32 .collect();
33 let sum_vm = rolling_sum(&vm, n);
34 let sum_tr = rolling_sum(&tr, n);
35 (0..len).map(|i| sum_vm[i] / sum_tr[i]).collect()
36}
37
38pub fn brar_ar(open: &[f64], high: &[f64], low: &[f64], n: usize) -> Vec<f64> {
41 let len = high.len();
42 let ho: Vec<f64> = (0..len).map(|i| high[i] - open[i]).collect();
43 let ol: Vec<f64> = (0..len).map(|i| open[i] - low[i]).collect();
44 let (s_ho, s_ol) = (rolling_sum(&ho, n), rolling_sum(&ol, n));
45 (0..len).map(|i| s_ho[i] / s_ol[i] * 100.0).collect()
46}
47
48pub fn brar_br(high: &[f64], low: &[f64], close: &[f64], n: usize) -> Vec<f64> {
52 let len = high.len();
53 let up: Vec<f64> = (0..len)
54 .map(|i| if i == 0 { f64::NAN } else { (high[i] - close[i - 1]).max(0.0) })
55 .collect();
56 let dn: Vec<f64> = (0..len)
57 .map(|i| if i == 0 { f64::NAN } else { (close[i - 1] - low[i]).max(0.0) })
58 .collect();
59 let (s_up, s_dn) = (rolling_sum(&up, n), rolling_sum(&dn, n));
60 (0..len).map(|i| s_up[i] / s_dn[i] * 100.0).collect()
61}
62
63pub fn vr(close: &[f64], volume: &[f64], n: usize) -> Vec<f64> {
67 let len = close.len();
68 let (mut uv, mut dv, mut pv) = (vec![f64::NAN; len], vec![f64::NAN; len], vec![f64::NAN; len]);
69 for i in 1..len {
70 let (mut u, mut d, mut p) = (0.0, 0.0, 0.0);
71 if close[i] > close[i - 1] {
72 u = volume[i];
73 } else if close[i] < close[i - 1] {
74 d = volume[i];
75 } else {
76 p = volume[i];
77 }
78 uv[i] = u;
79 dv[i] = d;
80 pv[i] = p;
81 }
82 let (suv, sdv, spv) = (rolling_sum(&uv, n), rolling_sum(&dv, n), rolling_sum(&pv, n));
83 (0..len)
84 .map(|i| (suv[i] + 0.5 * spv[i]) / (sdv[i] + 0.5 * spv[i]) * 100.0)
85 .collect()
86}
87
88pub fn coppock(close: &[f64], w: usize, roc_long: usize, roc_short: usize) -> Vec<f64> {
91 let len = close.len();
92 let roc = |p: usize| -> Vec<f64> {
93 (0..len)
94 .map(|i| if i >= p { (close[i] / close[i - p] - 1.0) * 100.0 } else { f64::NAN })
95 .collect::<Vec<_>>()
96 };
97 let (rl, rs) = (roc(roc_long), roc(roc_short));
98 let sum: Vec<f64> = (0..len).map(|i| rl[i] + rs[i]).collect();
99 super::wma(&sum, w)
100}
101
102fn swma4(x: &[f64]) -> Vec<f64> {
105 (0..x.len())
106 .map(|i| {
107 if i >= 3 {
108 (x[i] + 2.0 * x[i - 1] + 2.0 * x[i - 2] + x[i - 3]) / 6.0
109 } else {
110 f64::NAN
111 }
112 })
113 .collect()
114}
115
116pub fn relative_vigor(open: &[f64], high: &[f64], low: &[f64], close: &[f64], n: usize) -> Vec<f64> {
119 let len = close.len();
120 let co: Vec<f64> = (0..len).map(|i| close[i] - open[i]).collect();
121 let hl: Vec<f64> = (0..len).map(|i| high[i] - low[i]).collect();
122 let num = kernels::sma(av(&swma4(&co)), n);
123 let den = kernels::sma(av(&swma4(&hl)), n);
124 (0..len).map(|i| num[i] / den[i]).collect()
125}
126
127pub fn relative_vigor_signal(
129 open: &[f64],
130 high: &[f64],
131 low: &[f64],
132 close: &[f64],
133 n: usize,
134) -> Vec<f64> {
135 swma4(&relative_vigor(open, high, low, close, n))
136}
137
138pub fn dkx(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> {
141 let mid: Vec<f64> = (0..close.len())
142 .map(|i| (3.0 * close[i] + low[i] + open[i] + high[i]) / 6.0)
143 .collect();
144 super::wma(&mid, 20)
145}
146
147pub fn dkx_ma(open: &[f64], high: &[f64], low: &[f64], close: &[f64], m: usize) -> Vec<f64> {
149 super::ma(&dkx(open, high, low, close), m)
150}
151
152pub fn wvad(
154 open: &[f64],
155 high: &[f64],
156 low: &[f64],
157 close: &[f64],
158 volume: &[f64],
159 n: usize,
160) -> Vec<f64> {
161 let w: Vec<f64> = (0..close.len())
162 .map(|i| (close[i] - open[i]) / (high[i] - low[i]) * volume[i])
163 .collect();
164 rolling_sum(&w, n)
165}
166
167#[derive(Clone, Copy)]
169pub enum CdpLine {
170 Cdp,
171 Ah,
172 Nh,
173 Nl,
174 Al,
175}
176
177pub fn cdp(high: &[f64], low: &[f64], close: &[f64], line: CdpLine) -> Vec<f64> {
181 (0..high.len())
182 .map(|i| {
183 if i == 0 {
184 return f64::NAN;
185 }
186 let (h, l, c) = (high[i - 1], low[i - 1], close[i - 1]);
187 let cdp = (h + l + 2.0 * c) / 4.0;
188 match line {
189 CdpLine::Cdp => cdp,
190 CdpLine::Ah => cdp + (h - l),
191 CdpLine::Nh => 2.0 * cdp - l,
192 CdpLine::Nl => 2.0 * cdp - h,
193 CdpLine::Al => cdp - (h - l),
194 }
195 })
196 .collect()
197}
198
199pub fn wad(high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> {
203 let mut out = vec![0.0; close.len()];
204 let mut acc = 0.0;
205 for i in 1..close.len() {
206 acc += wad_step(high[i], low[i], close[i], close[i - 1]);
207 out[i] = acc;
208 }
209 out
210}
211
212fn wad_step(h: f64, l: f64, c: f64, prev_c: f64) -> f64 {
214 if c > prev_c {
215 c - prev_c.min(l)
216 } else if c < prev_c {
217 c - prev_c.max(h)
218 } else {
219 0.0
220 }
221}
222
223pub fn wad_final_state(high: &[f64], low: &[f64], close: &[f64]) -> Option<Vec<f64>> {
225 let n = close.len();
226 if n == 0 {
227 return None;
228 }
229 let mut acc = 0.0;
230 for i in 1..n {
231 acc += wad_step(high[i], low[i], close[i], close[i - 1]);
232 }
233 Some(vec![acc, close[n - 1]])
234}
235
236pub fn wad_resume(
239 high: &[f64],
240 low: &[f64],
241 close: &[f64],
242 from: usize,
243 state: &[f64],
244) -> (Vec<f64>, Vec<f64>) {
245 let mut acc = state[0];
246 let mut prev = state[1];
247 let mut out = Vec::with_capacity(close.len().saturating_sub(from));
248 for i in from..close.len() {
249 acc += wad_step(high[i], low[i], close[i], prev);
250 out.push(acc);
251 prev = close[i];
252 }
253 (out, vec![acc, prev])
254}
255
256fn asi_si(o: f64, h: f64, l: f64, c: f64, op: f64, cp: f64, t: f64) -> f64 {
260 let n = (c - cp) + 0.5 * (c - o) + 0.25 * (cp - op);
261 let (tr1, tr2, tr3) = ((h - cp).abs(), (l - cp).abs(), (h - l).abs());
262 let move_term = 0.25 * (cp - op).abs();
263 let r = if tr1 >= tr2 && tr1 >= tr3 {
264 tr1 - 0.5 * tr2 + move_term
265 } else if tr2 >= tr1 && tr2 >= tr3 {
266 tr2 - 0.5 * tr1 + move_term
267 } else {
268 tr3 + move_term
269 };
270 let k = tr1.max(tr2);
271 50.0 * (n / r) * (k / t)
272}
273
274pub fn asi(open: &[f64], high: &[f64], low: &[f64], close: &[f64], t: f64) -> Vec<f64> {
278 let mut out = vec![0.0; close.len()];
279 let mut acc = 0.0;
280 for i in 1..close.len() {
281 acc += asi_si(open[i], high[i], low[i], close[i], open[i - 1], close[i - 1], t);
282 out[i] = acc;
283 }
284 out
285}
286
287pub fn asi_final_state(
289 open: &[f64],
290 high: &[f64],
291 low: &[f64],
292 close: &[f64],
293 t: f64,
294) -> Option<Vec<f64>> {
295 let n = close.len();
296 if n == 0 {
297 return None;
298 }
299 let mut acc = 0.0;
300 for i in 1..n {
301 acc += asi_si(open[i], high[i], low[i], close[i], open[i - 1], close[i - 1], t);
302 }
303 Some(vec![acc, close[n - 1], open[n - 1]])
304}
305
306pub fn asi_resume(
308 open: &[f64],
309 high: &[f64],
310 low: &[f64],
311 close: &[f64],
312 t: f64,
313 from: usize,
314 state: &[f64],
315) -> (Vec<f64>, Vec<f64>) {
316 let (mut acc, mut pc, mut po) = (state[0], state[1], state[2]);
317 let mut out = Vec::with_capacity(close.len().saturating_sub(from));
318 for i in from..close.len() {
319 acc += asi_si(open[i], high[i], low[i], close[i], po, pc, t);
320 out.push(acc);
321 pc = close[i];
322 po = open[i];
323 }
324 (out, vec![acc, pc, po])
325}
326
327#[derive(Clone, Copy)]
329pub enum PivotLine {
330 Pp,
331 R1,
332 S1,
333 R2,
334 S2,
335 R3,
336 S3,
337}
338
339pub fn pivot_points(high: &[f64], low: &[f64], close: &[f64], line: PivotLine) -> Vec<f64> {
343 (0..high.len())
344 .map(|i| {
345 if i == 0 {
346 return f64::NAN;
347 }
348 let (h, l, c) = (high[i - 1], low[i - 1], close[i - 1]);
349 let pp = (h + l + c) / 3.0;
350 match line {
351 PivotLine::Pp => pp,
352 PivotLine::R1 => 2.0 * pp - l,
353 PivotLine::S1 => 2.0 * pp - h,
354 PivotLine::R2 => pp + (h - l),
355 PivotLine::S2 => pp - (h - l),
356 PivotLine::R3 => h + 2.0 * (pp - l),
357 PivotLine::S3 => l - 2.0 * (h - pp),
358 }
359 })
360 .collect()
361}
362
363#[derive(Clone, Copy)]
365pub enum MikeLine {
366 WeakR,
367 MidR,
368 StrongR,
369 WeakS,
370 MidS,
371 StrongS,
372}
373
374pub fn mike(high: &[f64], low: &[f64], close: &[f64], n: usize, line: MikeLine) -> Vec<f64> {
378 let len = high.len();
379 let hh = super::hhv(high, n);
380 let ll = super::llv(low, n);
381 (0..len)
382 .map(|i| {
383 let typ = (high[i] + low[i] + close[i]) / 3.0;
384 let (hi, lo) = (hh[i], ll[i]);
385 match line {
386 MikeLine::WeakR => typ + (typ - lo),
387 MikeLine::MidR => typ + (hi - lo),
388 MikeLine::StrongR => 2.0 * hi - lo,
389 MikeLine::WeakS => typ - (hi - typ),
390 MikeLine::MidS => typ - (hi - lo),
391 MikeLine::StrongS => 2.0 * lo - hi,
392 }
393 })
394 .collect()
395}
396
397pub fn keltner_band(
401 close: &[f64],
402 high: &[f64],
403 low: &[f64],
404 ema_period: usize,
405 atr_period: usize,
406 mult: f64,
407 upper: bool,
408) -> Vec<f64> {
409 let ema = super::ema(close, ema_period);
410 let atr = super::atr(high, low, close, atr_period);
411 let sign = if upper { 1.0 } else { -1.0 };
412 (0..close.len()).map(|i| ema[i] + sign * mult * atr[i]).collect()
413}
414
415pub fn kcw(
422 close: &[f64],
423 high: &[f64],
424 low: &[f64],
425 ema_period: usize,
426 atr_period: usize,
427 mult: f64,
428) -> Vec<f64> {
429 let ema = super::ema(close, ema_period);
430 let atr = super::atr(high, low, close, atr_period);
431 (0..close.len())
432 .map(|i| {
433 if ema[i] != 0.0 {
434 2.0 * mult * atr[i] / ema[i]
435 } else {
436 f64::NAN
437 }
438 })
439 .collect()
440}
441
442pub fn keltner_band_final_state(
445 close: &[f64],
446 high: &[f64],
447 low: &[f64],
448 ema_period: usize,
449 atr_period: usize,
450) -> Option<Vec<f64>> {
451 let e = super::ema_final_state(close, ema_period)?;
452 let a = super::atr_final_state(high, low, close, atr_period)?;
453 Some(vec![e[0], a[0]])
454}
455
456#[allow(clippy::too_many_arguments)]
460pub fn keltner_band_resume(
461 close: &[f64],
462 high: &[f64],
463 low: &[f64],
464 ema_period: usize,
465 atr_period: usize,
466 mult: f64,
467 upper: bool,
468 from: usize,
469 state: &[f64],
470) -> Option<(Vec<f64>, Vec<f64>)> {
471 let (e_vals, e_state) = super::ema_resume(close, ema_period, from, &state[0..1]);
472 let (a_vals, a_state) = super::atr_resume(high, low, close, atr_period, from, &state[1..2])?;
473 let sign = if upper { 1.0 } else { -1.0 };
474 let vals: Vec<f64> = (0..e_vals.len()).map(|i| e_vals[i] + sign * mult * a_vals[i]).collect();
475 Some((vals, vec![e_state[0], a_state[0]]))
476}
477
478pub fn stoch_momentum(high: &[f64], low: &[f64], close: &[f64], k: usize, d: usize) -> Vec<f64> {
482 let len = high.len();
483 let hh = super::hhv(high, k);
484 let ll = super::llv(low, k);
485 let rdiff: Vec<f64> = (0..len).map(|i| close[i] - (hh[i] + ll[i]) / 2.0).collect();
486 let diff: Vec<f64> = (0..len).map(|i| hh[i] - ll[i]).collect();
487 let ds = super::ema(&super::ema(&rdiff, d), d);
488 let dhl = super::ema(&super::ema(&diff, d), d);
489 (0..len).map(|i| ds[i] / (dhl[i] * 0.5) * 100.0).collect()
490}
491
492pub fn stoch_momentum_signal(
494 high: &[f64],
495 low: &[f64],
496 close: &[f64],
497 k: usize,
498 d: usize,
499 signal: usize,
500) -> Vec<f64> {
501 super::ema(&stoch_momentum(high, low, close, k, d), signal)
502}
503
504fn shift_forward(x: &[f64], k: usize) -> Vec<f64> {
508 (0..x.len()).map(|i| if i >= k { x[i - k] } else { f64::NAN }).collect()
509}
510
511#[derive(Clone, Copy)]
513pub enum IchimokuLine {
514 Tenkan,
515 Kijun,
516 SenkouA,
517 SenkouB,
518 Chikou,
519}
520
521pub fn ichimoku(
527 high: &[f64],
528 low: &[f64],
529 close: &[f64],
530 tenkan: usize,
531 kijun: usize,
532 senkou_b: usize,
533 line: IchimokuLine,
534) -> Vec<f64> {
535 let midpoint = |period: usize| -> Vec<f64> {
536 let hh = super::hhv(high, period);
537 let ll = super::llv(low, period);
538 (0..high.len()).map(|i| (hh[i] + ll[i]) / 2.0).collect()
539 };
540 match line {
541 IchimokuLine::Tenkan => midpoint(tenkan),
542 IchimokuLine::Kijun => midpoint(kijun),
543 IchimokuLine::SenkouA => {
544 let (t, k) = (midpoint(tenkan), midpoint(kijun));
545 let raw: Vec<f64> = (0..high.len()).map(|i| (t[i] + k[i]) / 2.0).collect();
546 shift_forward(&raw, kijun)
547 }
548 IchimokuLine::SenkouB => shift_forward(&midpoint(senkou_b), kijun),
549 IchimokuLine::Chikou => close.to_vec(),
550 }
551}
552
553pub fn ttm_squeeze_momentum(high: &[f64], low: &[f64], close: &[f64], n: usize) -> Vec<f64> {
556 let len = high.len();
557 let hh = super::hhv(high, n);
558 let ll = super::llv(low, n);
559 let sma = super::ma(close, n);
560 let delta: Vec<f64> = (0..len)
561 .map(|i| close[i] - ((hh[i] + ll[i]) / 2.0 + sma[i]) / 2.0)
562 .collect();
563 let start = delta.iter().position(|x| !x.is_nan()).unwrap_or(len);
566 let mut out = vec![f64::NAN; len];
567 if start < len {
568 let sub = super::linearreg(&delta[start..], n);
569 out[start..].copy_from_slice(&sub);
570 }
571 out
572}
573
574pub fn ttm_squeeze_on(
578 high: &[f64],
579 low: &[f64],
580 close: &[f64],
581 n: usize,
582 bb_mult: f64,
583 kc_mult: f64,
584) -> Vec<f64> {
585 let len = high.len();
586 let sma = super::ma(close, n);
587 let sd = super::stddev(close, n, 1.0);
588 let tr = super::tr(high, low, close);
589 let atr = kernels::sma(av(&tr), n).to_vec(); (0..len)
591 .map(|i| {
592 let bb_u = sma[i] + bb_mult * sd[i];
593 let bb_l = sma[i] - bb_mult * sd[i];
594 let kc_u = sma[i] + kc_mult * atr[i];
595 let kc_l = sma[i] - kc_mult * atr[i];
596 if bb_u.is_nan() || kc_u.is_nan() {
597 f64::NAN
598 } else if bb_l > kc_l && bb_u < kc_u {
599 1.0
600 } else {
601 0.0
602 }
603 })
604 .collect()
605}
606
607#[allow(clippy::too_many_arguments)]
612fn supertrend_step(
613 hl2: f64,
614 atr: f64,
615 close: f64,
616 mult: f64,
617 prev_trend: f64,
618 prev_fu: f64,
619 prev_fl: f64,
620 prev_close: f64,
621) -> (f64, f64, f64) {
622 let (bu, bl) = (hl2 + mult * atr, hl2 - mult * atr);
623 let fu = if bu < prev_fu || prev_close > prev_fu { bu } else { prev_fu };
624 let fl = if bl > prev_fl || prev_close < prev_fl { bl } else { prev_fl };
625 let trend = if prev_trend < 0.0 {
626 if close > fu { 1.0 } else { -1.0 }
627 } else if close < fl {
628 -1.0
629 } else {
630 1.0
631 };
632 (trend, fu, fl)
633}
634
635fn supertrend_out(trend: f64, fu: f64, fl: f64, want_direction: bool) -> f64 {
638 if want_direction {
639 trend
640 } else if trend > 0.0 {
641 fl
642 } else {
643 fu
644 }
645}
646
647pub fn supertrend(
651 high: &[f64],
652 low: &[f64],
653 close: &[f64],
654 period: usize,
655 mult: f64,
656 want_direction: bool,
657) -> Vec<f64> {
658 let len = close.len();
659 let mut out = vec![f64::NAN; len];
660 let atr = super::atr(high, low, close, period);
661 if period >= len {
662 return out; }
664 let hl2 = |i: usize| (high[i] + low[i]) / 2.0;
665 let (mut trend, mut fu, mut fl, mut pc) = (
667 -1.0_f64,
668 hl2(period) + mult * atr[period],
669 hl2(period) - mult * atr[period],
670 close[period],
671 );
672 out[period] = supertrend_out(trend, fu, fl, want_direction);
673 for i in (period + 1)..len {
674 let step = supertrend_step(hl2(i), atr[i], close[i], mult, trend, fu, fl, pc);
675 (trend, fu, fl) = step;
676 out[i] = supertrend_out(trend, fu, fl, want_direction);
677 pc = close[i];
678 }
679 out
680}
681
682pub fn supertrend_final_state(
685 high: &[f64],
686 low: &[f64],
687 close: &[f64],
688 period: usize,
689 mult: f64,
690) -> Option<Vec<f64>> {
691 let len = close.len();
692 let atr_end = super::atr_final_state(high, low, close, period)?;
695 let atr = super::atr(high, low, close, period);
696 let hl2 = |i: usize| (high[i] + low[i]) / 2.0;
697 let (mut trend, mut fu, mut fl, mut pc) = (
698 -1.0_f64,
699 hl2(period) + mult * atr[period],
700 hl2(period) - mult * atr[period],
701 close[period],
702 );
703 for i in (period + 1)..len {
704 let step = supertrend_step(hl2(i), atr[i], close[i], mult, trend, fu, fl, pc);
705 (trend, fu, fl) = step;
706 pc = close[i];
707 }
708 Some(vec![trend, fu, fl, close[len - 1], atr_end[0]])
709}
710
711#[allow(clippy::too_many_arguments)]
715pub fn supertrend_resume(
716 high: &[f64],
717 low: &[f64],
718 close: &[f64],
719 period: usize,
720 mult: f64,
721 want_direction: bool,
722 from: usize,
723 state: &[f64],
724) -> Option<(Vec<f64>, Vec<f64>)> {
725 let (mut trend, mut fu, mut fl, mut pc) = (state[0], state[1], state[2], state[3]);
726 let (atr_tail, atr_new) = super::atr_resume(high, low, close, period, from, &state[4..5])?;
727 let hl2 = |i: usize| (high[i] + low[i]) / 2.0;
728 let mut out = Vec::with_capacity(close.len().saturating_sub(from));
729 for (j, i) in (from..close.len()).enumerate() {
730 let step = supertrend_step(hl2(i), atr_tail[j], close[i], mult, trend, fu, fl, pc);
731 (trend, fu, fl) = step;
732 out.push(supertrend_out(trend, fu, fl, want_direction));
733 pc = close[i];
734 }
735 Some((out, vec![trend, fu, fl, pc, atr_new[0]]))
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741 use crate::indicators::test_support::*;
742
743 #[test]
745 fn cumulative_final_state_declines_on_empty() {
746 assert!(wad_final_state(&[], &[], &[]).is_none());
747 assert!(asi_final_state(&[], &[], &[], &[], 3.0).is_none());
748 }
749
750 #[test]
753 fn cumulative_resume_is_bit_identical_to_full() {
754 let (high, low, close) = ohlc(160);
755 let open: Vec<f64> = close.iter().map(|c| c - 0.3).collect();
756 let wad_full = wad(&high, &low, &close);
757 let asi_full = asi(&open, &high, &low, &close, 3.0);
758 for &from in &[1usize, 2, 40, 80, 159] {
759 let st = wad_final_state(&high[..from], &low[..from], &close[..from]).unwrap();
760 assert_bits(&wad_resume(&high, &low, &close, from, &st).0, &wad_full[from..], "wad");
761
762 let st =
763 asi_final_state(&open[..from], &high[..from], &low[..from], &close[..from], 3.0)
764 .unwrap();
765 assert_bits(
766 &asi_resume(&open, &high, &low, &close, 3.0, from, &st).0,
767 &asi_full[from..],
768 "asi",
769 );
770 }
771 }
772
773 #[test]
776 fn supertrend_resume_and_guards() {
777 let (high, low, close) = ohlc(160);
778 assert!(supertrend(&high[..5], &low[..5], &close[..5], 10, 3.0, false)
780 .iter()
781 .all(|x| x.is_nan()));
782 assert!(supertrend_final_state(&high[..5], &low[..5], &close[..5], 10, 3.0).is_none());
783
784 let line_full = supertrend(&high, &low, &close, 10, 3.0, false);
785 let dir_full = supertrend(&high, &low, &close, 10, 3.0, true);
786 for &from in &[11usize, 20, 80, 159] {
787 let st = supertrend_final_state(&high[..from], &low[..from], &close[..from], 10, 3.0)
788 .unwrap();
789 let (line, _) =
790 supertrend_resume(&high, &low, &close, 10, 3.0, false, from, &st).unwrap();
791 assert_bits(&line, &line_full[from..], "supertrend");
792 let (dir, _) =
793 supertrend_resume(&high, &low, &close, 10, 3.0, true, from, &st).unwrap();
794 assert_bits(&dir, &dir_full[from..], "supertrend.direction");
795 }
796 }
797}