Skip to content

Commit

Permalink
ci
Browse files Browse the repository at this point in the history
  • Loading branch information
m5l14i11 committed Jun 22, 2023
1 parent c31efd5 commit ff70169
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 1 deletion.
20 changes: 20 additions & 0 deletions .github/workflows/quant.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: QUANT CI

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Set up Rust
uses: actions/setup-rust@v1

- name: Check out code
uses: actions/checkout@v2

- name: Test ta_lib
run: cargo test --manifest-path=ta_lib/Cargo.toml
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
__pycache__
.ipynb_checkpoints
.DS_Store
.csv
.csv
target
14 changes: 14 additions & 0 deletions ta_lib/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions ta_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[workspace]
members = [
"overlap",
"momentum"
]
9 changes: 9 additions & 0 deletions ta_lib/momentum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "momentum"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
overlap = { path = "../overlap"}
1 change: 1 addition & 0 deletions ta_lib/momentum/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod rsi;
90 changes: 90 additions & 0 deletions ta_lib/momentum/src/rsi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use overlap::smma::smma;

pub fn rsi(data: &[f64], period: usize) -> Vec<Option<f64>> {
if data.len() < period {
return vec![None; data.len()];
}

let mut gains = vec![0.0; data.len()];
let mut losses = vec![0.0; data.len()];

for i in 1..data.len() {
let change = data[i] - data[i - 1];

gains[i] = change.max(0.0);
losses[i] = (-change).max(0.0);
}

let avg_gain = smma(&gains, period);
let avg_loss = smma(&losses, period);

let rsi = avg_gain
.iter()
.zip(avg_loss.iter())
.map(|(&gain, &loss)| match (gain, loss) {
(Some(gain), Some(loss)) if gain + loss > 0.0 => {
let rs = gain / (loss + std::f64::EPSILON);
Some(100.0 - (100.0 / (1.0 + rs)))
}
_ => None,
})
.collect();

rsi
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_rsi_len() {
let data = vec![5.0];
let result = rsi(&data, 1);
assert_eq!(data.len(), result.len());
}

#[test]
fn test_rsi_empty() {
let data = vec![];
let result = rsi(&data, 14);
assert_eq!(result, vec![]);
}

#[test]
fn test_rsi_single_value() {
let data = [10.0];
let rsi_values = rsi(&data, 14);
assert_eq!(rsi_values, vec![None]);
}

#[test]
fn test_rsi_with_valid_data() {
let data = vec![
44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84,
];
let result = rsi(&data, 6);
let epsilon = 0.001;
let expected = vec![
None,
None,
None,
None,
None,
Some(69.602669),
Some(74.642227),
Some(79.480508),
Some(84.221979),
];

for i in 0..result.len() {
match (result[i], expected[i]) {
(Some(a), Some(b)) => {
assert!((a - b).abs() < epsilon, "at position {}: {} != {}", i, a, b)
}
(None, None) => {}
_ => panic!("at position {}: {:?} != {:?}", i, result[i], expected[i]),
}
}
}
}
8 changes: 8 additions & 0 deletions ta_lib/overlap/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "overlap"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
49 changes: 49 additions & 0 deletions ta_lib/overlap/src/ema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pub fn ema(data: &[f64], period: usize) -> Vec<Option<f64>> {
if data.len() < period {
return vec![None; data.len()];
}

let alpha = 2.0 / (period as f64 + 1.0);

let mut ema = vec![None; data.len()];

let mut ema_current = data[0];

for i in 1..data.len() {
ema_current = (data[i] - ema_current) * alpha + ema_current;
if i >= period - 1 {
ema[i] = Some(ema_current);
}
}

ema
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_ema_len() {
let data = vec![1.0, 2.0];
let result = ema(&data, 3);
assert_eq!(data.len(), result.len());
}

#[test]
fn test_ema_edge_case() {
let data = vec![1.0, 2.0];
let result = ema(&data, 3);
assert_eq!(result, vec![None, None]);
}

#[test]
fn test_ema() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = ema(&data, 3);
assert_eq!(
result,
vec![None, None, Some(2.25), Some(3.125), Some(4.0625)]
);
}
}
3 changes: 3 additions & 0 deletions ta_lib/overlap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod ema;
pub mod sma;
pub mod smma;
43 changes: 43 additions & 0 deletions ta_lib/overlap/src/sma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pub fn sma(data: &[f64], period: usize) -> Vec<Option<f64>> {
let mut sma = vec![None; data.len()];
let mut sum = 0.0;

for i in 0..data.len() {
sum += data[i];

if i >= period {
sum -= data[i - period];
sma[i] = Some(sum / period as f64);
} else if i + 1 == period {
sma[i] = Some(sum / period as f64);
}
}

sma
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_sma_len() {
let data = vec![1.0, 2.0];
let result = sma(&data, 3);
assert_eq!(data.len(), result.len());
}

#[test]
fn test_sma_edge_case() {
let data = vec![1.0, 2.0];
let result = sma(&data, 3);
assert_eq!(result, vec![None, None]);
}

#[test]
fn test_sma() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = sma(&data, 3);
assert_eq!(result, vec![None, None, Some(2.0), Some(3.0), Some(4.0)]);
}
}
57 changes: 57 additions & 0 deletions ta_lib/overlap/src/smma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pub fn smma(data: &[f64], period: usize) -> Vec<Option<f64>> {
if data.len() < period {
return vec![None; data.len()];
}

let alpha = 1.0 / period as f64;

let mut smma = vec![None; data.len()];

let mut smma_current = data[0];

for i in 1..data.len() {
smma_current = (data[i] - smma_current) * alpha + smma_current;
if i >= period - 1 {
smma[i] = Some(smma_current);
}
}

smma
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_smma_len() {
let data = vec![1.0, 2.0];
let result = smma(&data, 3);
assert_eq!(data.len(), result.len());
}

#[test]
fn test_smmma_edge_case() {
let data = vec![1.0, 2.0];
let result = smma(&data, 3);
assert_eq!(result, vec![None, None]);
}

#[test]
fn test_smma() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = smma(&data, 3);
let expected = vec![None, None, Some(1.888), Some(2.592), Some(3.395)];
let epsilon = 0.001;

for i in 0..result.len() {
match (result[i], expected[i]) {
(Some(a), Some(b)) => {
assert!((a - b).abs() < epsilon, "at position {}: {} != {}", i, a, b)
}
(None, None) => {}
_ => panic!("at position {}: {:?} != {:?}", i, result[i], expected[i]),
}
}
}
}

0 comments on commit ff70169

Please sign in to comment.