pub use self::adf_test::{ADFType, ADFResult, adf};
pub use self::t_test::{TTestResult, TTestTwoSampleCase, t_test_two_sample, t_test_lr};
pub use self::f_test::{nested_f_statistic, FTestResult, f_test_anova};
pub use self::granger_causality::{
GrangerCausalityTestType, GrangerCausalityRejectReason, GrangerCausalityResult, GrangerCausalitySettings,
granger_causality_test, simple_granger_causality_test,
};
mod adf_test;
mod f_test;
mod t_test;
mod granger_causality;
use std::fmt::Display;
use ndarray::{Array1, Array2};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
use crate::error::{DigiFiError};
use crate::utilities::{LARGE_TEXT_BREAK, compare_len};
use crate::statistics::linear_regression;
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ConfidenceLevel {
Ten,
#[default]
Five,
TwoHalf,
One,
}
impl ConfidenceLevel {
pub fn get_p(&self) -> f64 {
match self {
Self::Ten => 0.1,
Self::Five => 0.05,
Self::TwoHalf => 0.25,
Self::One => 0.01,
}
}
}
impl Display for ConfidenceLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_p().to_string())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CointegrationResult {
pub cointegrated: bool,
pub adf_results: Option<Vec<ADFResult>>,
}
impl Display for CointegrationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let result: String = match &self.adf_results {
Some(tests) => {
tests.iter().map(|t| t.to_string() ).collect::<Vec<String>>().join("\n\n")
},
None => "".to_owned(),
} + "\n\n"
+ LARGE_TEXT_BREAK
+ "Cointegration Test Result\n"
+ LARGE_TEXT_BREAK
+ &format!("Cointegrated: {}\n", self.cointegrated)
+ LARGE_TEXT_BREAK;
write!(f, "{}", result)
}
}
pub fn cointegration(x: &Array1<f64>, y: &Array1<f64>, cl: Option<ConfidenceLevel>) -> Result<CointegrationResult, DigiFiError> {
compare_len(&x.iter(), &y.iter(), "x", "y")?;
let data_matrix: Array2<f64> = Array2::from_shape_vec((x.len(), 1), x.to_vec())?;
let params: Array1<f64> = linear_regression(&data_matrix, y)?;
let prediction: Array1<f64> = data_matrix.dot(¶ms);
let u_t: Array1<f64> = y - &prediction;
let adf_variations: Vec<ADFType> = vec![ADFType::Simple, ADFType::Constant, ADFType::ConstantAndTrend];
let mut cointegrated: bool = false;
let mut adf_results: Vec<ADFResult> = Vec::<ADFResult>::new();
for adf_type in &adf_variations {
let adf_result: ADFResult = adf(&u_t, None, adf_type, cl)?;
let stationary_u_t: bool = !adf_result.unit_root_exists;
adf_results.push(adf_result);
if stationary_u_t {
cointegrated = true;
break;
}
}
Ok(CointegrationResult { cointegrated, adf_results: Some(adf_results), })
}
#[cfg(test)]
mod tests {
#[cfg(all(test, feature = "sample_data"))]
#[test]
fn unit_test_cointegration() -> () {
use ndarray::Array1;
use crate::utilities::sample_data::SampleData;
use crate::statistics::stat_tests::{ConfidenceLevel, CointegrationResult, cointegration};
let sample: SampleData = SampleData::Portfolio;
let (_, mut sample_data) = sample.load_sample_data();
let jpm: Array1<f64> = sample_data.remove("JPM").unwrap();
let gs: Array1<f64> = sample_data.remove("GS").unwrap();
let cointegration_result: CointegrationResult = cointegration(&jpm, &gs, Some(ConfidenceLevel::One)).unwrap();
assert_eq!(cointegration_result.cointegrated, true);
}
}