9 releases

0.1.9 Aug 10, 2023
0.1.8 Aug 4, 2023
0.1.2 Jul 20, 2023

#2283 in Parser implementations

LGPL-2.0-only

22KB
370 lines

Example Usage

  use super::*;
  use crate::models::Signals;
  use tradestats::metrics::{spread_standard, rolling_zscore};

  use csv::Reader;
  use serde::Deserialize;

  #[derive(Debug, Deserialize)]
  struct Record {
    series_1: f64,
    series_2: f64,
  }

  pub fn get_test_data() -> (Vec<f64>, Vec<f64>) {
    let mut rdr: Reader<std::fs::File> = Reader::from_path("data/data.csv").unwrap();
    let mut series_1: Vec<f64> = vec![];
    let mut series_2: Vec<f64> = vec![];
    for result in rdr.deserialize() {
      let record: Record = result.unwrap();
      series_1.push(record.series_1);
      series_2.push(record.series_2);
    }
    (series_1, series_2)
  }

#[test]
fn tests_backtest() {
    let (series_1, series_2) = get_test_data();
    let log_rets_1: Vec<f64> = tradestats::utils::log_returns(&series_1, true);
    let log_rets_2: Vec<f64> = tradestats::utils::log_returns(&series_2, true);

    let spread: Vec<f64> = spread_standard(&series_1, &series_2).unwrap();
    let roll_zscore: Vec<f64> = rolling_zscore(&spread, 21).unwrap();

    let trading_costs: f64 = 0.001;
    let weighting_asset_1: f64 = 1.0; // Amount of capital to assign to asset 1
    let weighting_asset_2: f64 = 1.0; // Amount of capital to assign to asset 2

    // Extract Long Signals (long asset 1, short asset 2)
    let json_long_str: &str = r#"{
        "eq": [-1.5, 0.0],
        "neq": [null, null],
        "gt": [null, 0.0],
        "lt": [-1.5, null],
        "signal_type": "Long"
    }"#;

    let params: Signals = serde_json::from_str(&json_long_str).unwrap();
    let signals_obj: Signals = Signals::new(params.eq, params.neq, params.gt, params.lt, params.signal_type);
    let long_signals: Vec<f64> = signals_obj.generate_signals(&roll_zscore);

    // Extract Short Signals (short asset 1, long asset 2)
    let json_short_str: &str = r#"{
        "eq": [1.5, 0.0],
        "neq": [null, null],
        "gt": [1.5, null],
        "lt": [null, 0.0],
        "signal_type": "Short"
    }"#;

    let params: Signals = serde_json::from_str(&json_short_str).unwrap();
    let signals_obj: Signals = Signals::new(params.eq, params.neq, params.gt, params.lt, params.signal_type);
    let short_signals: Vec<f64> = signals_obj.generate_signals(&roll_zscore);

    // Consolidate signals
    let net_signals: Vec<f64> = signals_obj.consolidate_signals(vec![long_signals, short_signals]);

    // Run Backtest
    let backtest: Backtest = Backtest::new(net_signals, trading_costs, weighting_asset_1, weighting_asset_2);
    let backtest_result: Result<String, String> = backtest.run_backtest(log_rets_1, Some(log_rets_2));
    dbg!(&backtest_result);
    assert!(backtest_result.unwrap().len() > 100);
  }

Dependencies

~2.3–3.5MB
~65K SLoC