Skip to content

Commit

Permalink
add vhf and ultimate indicators (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
chungg authored May 13, 2024
1 parent 4dbac04 commit 275b592
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 16 deletions.
55 changes: 40 additions & 15 deletions benches/my_benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
//use criterion::{black_box, criterion_group, criterion_main, Criterion};
//
//use traquer::*;
//
//pub fn criterion_benchmark(c: &mut Criterion) {
// c.bench_function("fib 20", |b| b.iter(|| black_box(main())));
//}
//
//criterion_group!(benches, criterion_benchmark);
//criterion_main!(benches);
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use serde::{Deserialize, Serialize};
use std::fs;

use traquer::indicator;

#[divan::bench]
fn run() {
divan::black_box(traquer::main());
#[derive(Deserialize, Serialize, Debug)]
struct SecStats {
high: Vec<f64>,
low: Vec<f64>,
open: Vec<f64>,
close: Vec<f64>,
volume: Vec<f64>,
}

fn main() {
divan::main();
pub fn criterion_benchmark(c: &mut Criterion) {
let data = fs::read_to_string("./aapl.input").expect("Unable to read file");
let stats: SecStats = serde_json::from_str(&data).expect("JSON does not have correct format.");
c.bench_function("fib 20", |b| {
b.iter(|| {
black_box(indicator::ultimate(
&stats.high,
&stats.low,
&stats.close,
6,
12,
24,
))
})
});
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

//#[divan::bench]
//fn run() {
// divan::black_box(traquer::main());
//}
//
//fn main() {
// divan::main();
//}
52 changes: 52 additions & 0 deletions src/indicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,55 @@ pub fn po(data: &[f64], short: u8, long: u8) -> Vec<f64> {
.map(|(x, y)| 100.0 * (x / y - 1.0))
.collect::<Vec<f64>>()
}

/// vertical horizontal filter
/// https://www.upcomingtrader.com/blog/the-vertical-horizontal-filter-a-traders-guide-to-market-phases/
pub fn vhf(h: &[f64], l: &[f64], c: &[f64], window: u8) -> Vec<f64> {
let diffs = &c[1..]
.iter()
.zip(&c[..c.len() - 1])
.map(|(curr, prev)| (curr - prev).abs())
.collect::<Vec<f64>>();
izip!(
diffs.windows(window.into()),
h.windows(window.into()).skip(1),
l.windows(window.into()).skip(1)
)
.map(|(diff, highs, lows)| {
(highs.iter().fold(f64::NAN, |state, &x| state.max(x))
- lows.iter().fold(f64::NAN, |state, &x| state.min(x)))
/ diff.iter().sum::<f64>()
})
.collect::<Vec<f64>>()
}

/// ultimate oscillator
/// https://www.investopedia.com/terms/u/ultimateoscillator.asp
pub fn ultimate(h: &[f64], l: &[f64], c: &[f64], win1: u8, win2: u8, win3: u8) -> Vec<f64> {
let bp_tr_vals = izip!(&h[1..], &l[1..], &c[..c.len() - 1], &c[1..],)
.map(|(h, l, prevc, c)| {
(
c - f64::min(*l, *prevc),
f64::max(*h, *prevc) - f64::min(*l, *prevc),
)
})
.collect::<Vec<(f64, f64)>>();
bp_tr_vals
.windows(win3.into())
.map(|w| {
let (bp_sum1, tr_sum1) = w
.iter()
.skip((win3 - win1).into())
.fold((0.0, 0.0), |acc, (bp, tr)| (acc.0 + bp, acc.1 + tr));
let (bp_sum2, tr_sum2) = w
.iter()
.skip((win3 - win2).into())
.fold((0.0, 0.0), |acc, (bp, tr)| (acc.0 + bp, acc.1 + tr));
let (bp_sum3, tr_sum3) = w
.iter()
.fold((0.0, 0.0), |acc, (bp, tr)| (acc.0 + bp, acc.1 + tr));
100.0 * (bp_sum1 / tr_sum1 * 4.0 + bp_sum2 / tr_sum2 * 2.0 + bp_sum3 / tr_sum3)
/ (4 + 2 + 1) as f64
})
.collect::<Vec<f64>>()
}
9 changes: 8 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,12 @@ fn main() {
let data = fs::read_to_string("./tests/rddt.input").expect("Unable to read file");
let stats: SecStats = serde_json::from_str(&data).expect("JSON does not have correct format.");

dbg!(indicator::po(&stats.volume, 10, 16));
dbg!(indicator::ultimate(
&stats.high,
&stats.low,
&stats.close,
6,
12,
24
));
}
50 changes: 50 additions & 0 deletions tests/indicator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,3 +676,53 @@ fn test_po() {
result
);
}

#[test]
fn test_vhf() {
let stats = common::test_data();
let result = indicator::vhf(&stats.high, &stats.low, &stats.close, 16);
assert_eq!(
vec![
0.5669216159971233,
0.7107794587594408,
0.5482664867838217,
0.4309723520119755,
0.40721343838432617,
0.44011310017913846,
0.5021691775026703,
0.4751003004570894,
0.4435695260250405,
0.4595960007629394,
0.4405808834558327,
0.4357521288992697,
0.4843910183060343,
0.5122550500601386,
0.5359587346575249,
0.5841583342518132,
0.7716635213608084,
0.7671760704973449,
],
result
);
}

#[test]
fn test_ultimate() {
let stats = common::test_data();
let result = indicator::ultimate(&stats.high, &stats.low, &stats.close, 6, 12, 24);
assert_eq!(
vec![
52.64489292919164,
51.59059656807282,
46.03014177584667,
46.83402417416914,
47.63501864800235,
43.80674742529631,
38.16680505680669,
44.10353752395525,
44.154676988833835,
42.65072465563253,
],
result
);
}

0 comments on commit 275b592

Please sign in to comment.