Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable ci #6

Merged
merged 1 commit into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: gate

on:
push:
branches:
- main
pull_request:

jobs:
check-style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: setup rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt
- name: check style
uses: actions-rust-lang/rustfmt@v1

analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: setup rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
- name: lint
run: cargo clippy

run-unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: setup rust
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: run unit tests
run: cargo test
54 changes: 20 additions & 34 deletions src/indicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use itertools::{izip, multiunzip};

use crate::smooth;

fn vforce(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f64> {
fn vforce(h: &[f64], l: &[f64], c: &[f64], v: &[f64]) -> Vec<f64> {
izip!(&h[1..], &l[1..], &c[1..], &v[1..])
.scan(
(h[0], l[0], c[0], 99, 0.0, h[0] - l[0]),
Expand Down Expand Up @@ -31,14 +31,7 @@ fn vforce(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f64> {

/// klinger oscillator
/// https://www.investopedia.com/terms/k/klingeroscillator.asp
pub fn klinger(
h: &Vec<f64>,
l: &Vec<f64>,
c: &Vec<f64>,
v: &Vec<f64>,
short: u8,
long: u8,
) -> Vec<f64> {
pub fn klinger(h: &[f64], l: &[f64], c: &[f64], v: &[f64], short: u8, long: u8) -> Vec<f64> {
let vf = vforce(h, l, c, v);
let short_ma = smooth::ewma(&vf, short);
let long_ma = smooth::ewma(&vf, long);
Expand All @@ -49,7 +42,7 @@ pub fn klinger(
.collect::<Vec<f64>>()
}

fn vforce_simple(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f64> {
fn vforce_simple(h: &[f64], l: &[f64], c: &[f64], v: &[f64]) -> Vec<f64> {
izip!(&h[1..], &l[1..], &c[1..], &v[1..])
.scan((h[0], l[0], c[0], 99), |state, (h, l, c, v)| {
let trend: i8 = {
Expand All @@ -67,14 +60,7 @@ fn vforce_simple(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<

/// klinger volume oscillator
/// designed to match yahoo
pub fn klinger_vol(
h: &Vec<f64>,
l: &Vec<f64>,
c: &Vec<f64>,
v: &Vec<f64>,
short: u8,
long: u8,
) -> Vec<f64> {
pub fn klinger_vol(h: &[f64], l: &[f64], c: &[f64], v: &[f64], short: u8, long: u8) -> Vec<f64> {
let vf = vforce_simple(h, l, c, v);
let short_ma = smooth::ewma(&vf, short);
let long_ma = smooth::ewma(&vf, long);
Expand All @@ -87,7 +73,7 @@ pub fn klinger_vol(

/// quick stick
/// https://www.investopedia.com/terms/q/qstick.asp
pub fn qstick(o: &Vec<f64>, c: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn qstick(o: &[f64], c: &[f64], window: u8) -> Vec<f64> {
let q = c
.iter()
.zip(o.iter())
Expand All @@ -99,7 +85,7 @@ pub fn qstick(o: &Vec<f64>, c: &Vec<f64>, window: u8) -> Vec<f64> {
/// twiggs money flow
/// https://www.marketvolume.com/technicalanalysis/twiggsmoneyflow.asp
/// https://www.incrediblecharts.com/indicators/twiggs_money_flow.php
pub fn twiggs(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn twiggs(h: &[f64], l: &[f64], c: &[f64], v: &[f64], window: u8) -> Vec<f64> {
let data = izip!(h, l, c, v);
let ma_range = smooth::wilder(
&data
Expand All @@ -124,7 +110,7 @@ pub fn twiggs(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>, window: u8

/// shinohara intensity ratio
/// https://www.sevendata.co.jp/shihyou/technical/shinohara.html
pub fn shinohara(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, period: u8) -> (Vec<f64>, Vec<f64>) {
pub fn shinohara(h: &[f64], l: &[f64], c: &[f64], period: u8) -> (Vec<f64>, Vec<f64>) {
// yahoo uses close rather than open for weak ratio described above
let high = h
.windows(period.into())
Expand All @@ -150,9 +136,9 @@ pub fn shinohara(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, period: u8) -> (Vec<f
/// average directional index
/// https://www.investopedia.com/terms/a/adx.asp
pub fn adx(
h: &Vec<f64>,
l: &Vec<f64>,
c: &Vec<f64>,
h: &[f64],
l: &[f64],
c: &[f64],
period: u8,
smoothing: u8,
) -> (Vec<f64>, Vec<f64>, Vec<f64>) {
Expand Down Expand Up @@ -194,7 +180,7 @@ pub fn adx(

/// relative strength index
/// https://www.investopedia.com/terms/r/rsi.asp
pub fn rsi(values: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn rsi(values: &[f64], window: u8) -> Vec<f64> {
let (gain, loss): (Vec<f64>, Vec<f64>) = values[1..]
.iter()
.zip(values[..values.len() - 1].iter())
Expand All @@ -209,7 +195,7 @@ pub fn rsi(values: &Vec<f64>, window: u8) -> Vec<f64> {

/// moving average convergence/divergence
/// https://www.investopedia.com/terms/m/macd.asp
pub fn macd(close: &Vec<f64>, fast: u8, slow: u8) -> Vec<f64> {
pub fn macd(close: &[f64], fast: u8, slow: u8) -> Vec<f64> {
let fast_ma = smooth::ewma(close, fast);
let slow_ma = smooth::ewma(close, slow);
fast_ma[fast_ma.len() - slow_ma.len()..]
Expand All @@ -221,7 +207,7 @@ pub fn macd(close: &Vec<f64>, fast: u8, slow: u8) -> Vec<f64> {

/// chande momentum oscillator
/// https://www.investopedia.com/terms/c/chandemomentumoscillator.asp
pub fn cmo(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn cmo(data: &[f64], window: u8) -> Vec<f64> {
smooth::_cmo(data, window)
.iter()
.map(|x| x * 100.0)
Expand All @@ -230,7 +216,7 @@ pub fn cmo(data: &Vec<f64>, window: u8) -> Vec<f64> {

/// centre of gravity
/// https://www.stockmaniacs.net/center-of-gravity-indicator/
pub fn cog(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn cog(data: &[f64], window: u8) -> Vec<f64> {
data.windows(window.into())
.map(|w| {
-w.iter()
Expand All @@ -245,7 +231,7 @@ pub fn cog(data: &Vec<f64>, window: u8) -> Vec<f64> {

/// accumulation/distribution
/// https://www.investopedia.com/terms/a/accumulationdistribution.asp
pub fn acc_dist(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f64> {
pub fn acc_dist(h: &[f64], l: &[f64], c: &[f64], v: &[f64]) -> Vec<f64> {
izip!(h, l, c, v)
.scan(0.0, |state, (high, low, close, vol)| {
let mfm = ((close - low) - (high - close)) / (high - low);
Expand All @@ -259,7 +245,7 @@ pub fn acc_dist(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f

/// accumulation/distribution
/// like yahoo
pub fn acc_dist_yahoo(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) -> Vec<f64> {
pub fn acc_dist_yahoo(h: &[f64], l: &[f64], c: &[f64], v: &[f64]) -> Vec<f64> {
izip!(&h[1..], &l[1..], &c[1..], &v[1..])
.scan((c[0], 0.0), |state, (high, low, close, vol)| {
let mfm = if *close > state.0 {
Expand All @@ -277,7 +263,7 @@ pub fn acc_dist_yahoo(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>) ->

/// elder ray
/// https://www.investopedia.com/articles/trading/03/022603.asp
pub fn elder_ray(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, window: u8) -> (Vec<f64>, Vec<f64>) {
pub fn elder_ray(h: &[f64], l: &[f64], c: &[f64], window: u8) -> (Vec<f64>, Vec<f64>) {
let close_ma = smooth::ewma(c, window);
izip!(
&h[h.len() - close_ma.len()..],
Expand All @@ -290,7 +276,7 @@ pub fn elder_ray(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, window: u8) -> (Vec<f

/// elder force index
/// https://www.investopedia.com/articles/trading/03/031203.asp
pub fn elder_force(c: &Vec<f64>, v: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn elder_force(c: &[f64], v: &[f64], window: u8) -> Vec<f64> {
smooth::ewma(
&izip!(&c[..c.len() - 1], &c[1..], &v[1..])
.map(|(prev, curr, vol)| (curr - prev) * vol)
Expand All @@ -301,11 +287,11 @@ pub fn elder_force(c: &Vec<f64>, v: &Vec<f64>, window: u8) -> Vec<f64> {

/// williams alligator
/// https://www.investopedia.com/articles/trading/072115/exploring-williams-alligator-indicator.asp
pub fn alligator(data: &Vec<f64>) {}
pub fn alligator(_data: &[f64]) {}

/// money flow index
/// https://www.investopedia.com/terms/m/mfi.asp
pub fn mfi(h: &Vec<f64>, l: &Vec<f64>, c: &Vec<f64>, v: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn mfi(h: &[f64], l: &[f64], c: &[f64], v: &[f64], window: u8) -> Vec<f64> {
let (pos_mf, neg_mf): (Vec<f64>, Vec<f64>) = izip!(&h[1..], &l[1..], &c[1..], &v[1..])
.scan(
(h[0] + l[0] + c[0]) / 3.0,
Expand Down
16 changes: 8 additions & 8 deletions src/smooth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn wma(data: &[f64], window: u8) -> Vec<f64> {
}

/// welles wilder's moving average
pub fn wilder(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn wilder(data: &[f64], window: u8) -> Vec<f64> {
data[window as usize..]
.iter()
.scan(
Expand All @@ -62,9 +62,9 @@ pub fn wilder(data: &Vec<f64>, window: u8) -> Vec<f64> {
}

/// hull's moving average
pub fn hull(data: &Vec<f64>, window: u8) -> Vec<f64> {
let ma = wma(&data, window);
let ma2 = wma(&data, u8::div_ceil(window, 2));
pub fn hull(data: &[f64], window: u8) -> Vec<f64> {
let ma = wma(data, window);
let ma2 = wma(data, u8::div_ceil(window, 2));
wma(
&ma2[(ma2.len() - ma.len())..]
.iter()
Expand All @@ -76,7 +76,7 @@ pub fn hull(data: &Vec<f64>, window: u8) -> Vec<f64> {
}

/// standard deviation
fn std_dev(data: &Vec<f64>, window: u8) -> Vec<f64> {
fn std_dev(data: &[f64], window: u8) -> Vec<f64> {
data.windows(window.into())
.map(|w| {
let mean = w.iter().sum::<f64>() / window as f64;
Expand All @@ -86,7 +86,7 @@ fn std_dev(data: &Vec<f64>, window: u8) -> Vec<f64> {
}

/// volatility index dynamic average (vidya)
pub fn vidya(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn vidya(data: &[f64], window: u8) -> Vec<f64> {
let alpha = 2.0 / (window + 1) as f64;
let std5 = std_dev(data, 5);
let std20 = sma(&std5, 20);
Expand All @@ -103,7 +103,7 @@ pub fn vidya(data: &Vec<f64>, window: u8) -> Vec<f64> {
}

/// chande momentum oscillator
pub(crate) fn _cmo(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub(crate) fn _cmo(data: &[f64], window: u8) -> Vec<f64> {
let (gain, loss): (Vec<f64>, Vec<f64>) = data[..data.len() - 1]
.iter()
.zip(data[1..].iter())
Expand All @@ -120,7 +120,7 @@ pub(crate) fn _cmo(data: &Vec<f64>, window: u8) -> Vec<f64> {
}

/// variable moving average (vma)
pub fn vma(data: &Vec<f64>, window: u8) -> Vec<f64> {
pub fn vma(data: &[f64], window: u8) -> Vec<f64> {
let alpha = 2.0 / (window + 1) as f64;
let vi = _cmo(data, 9); // maybe make this configurable?
izip!(&vi, &data[data.len() - vi.len()..])
Expand Down