use super::{bi::BI, direction::Direction};
#[cfg(feature = "python")]
use crate::utils::common::create_naive_pandas_timestamp;
use chrono::{DateTime, Utc};
use core::f64;
use derive_builder::Builder;
#[cfg(feature = "python")]
use parking_lot::RwLock;
#[cfg(feature = "python")]
use pyo3::types::{PyDict, PyDictMethods};
#[cfg(feature = "python")]
use pyo3::{Py, PyObject, PyResult, Python, pyclass, pymethods};
#[cfg(feature = "python")]
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
use std::sync::Arc;
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(module = "czsc._native"))]
#[derive(Debug, Clone, Builder)]
pub struct ZS {
pub bis: Vec<BI>,
pub sdt: DateTime<Utc>,
pub edt: DateTime<Utc>,
pub sdir: Direction,
pub edir: Direction,
pub zg: f64,
pub zd: f64,
pub zz: f64,
pub gg: f64,
pub dd: f64,
#[cfg(feature = "python")]
#[builder(default = "Arc::new(RwLock::new(None))")]
pub cache: Arc<RwLock<Option<Py<PyDict>>>>,
}
impl ZS {
pub fn new(bis: Vec<BI>) -> Self {
let sdt = bis.first().unwrap().start_dt();
let edt = bis.last().unwrap().end_dt();
let sdir = bis.first().unwrap().direction;
let edir = bis.last().unwrap().direction;
let zg = bis
.iter()
.take(3)
.map(|x| x.get_high())
.fold(f64::INFINITY, f64::min);
let zd = bis
.iter()
.take(3)
.map(|x| x.get_low())
.fold(f64::NEG_INFINITY, f64::max);
let gg = bis
.iter()
.map(|x| x.get_high())
.fold(f64::NEG_INFINITY, f64::max);
let dd = bis
.iter()
.map(|x| x.get_low())
.fold(f64::INFINITY, f64::min);
let zz = zd + (zg - zd) * 0.5;
ZS {
bis,
sdt,
edt,
sdir,
edir,
zg,
zd,
zz,
gg,
dd,
#[cfg(feature = "python")]
cache: Arc::new(RwLock::new(None)),
}
}
pub fn is_valid(&self) -> bool {
let zg = self.zg;
let zd = self.zd;
if zg < zd {
return false;
}
self.bis.iter().all(|bi| {
let high_in_range = (bi.get_high() <= zg) && (bi.get_high() >= zd);
let low_in_range = (bi.get_low() <= zg) && (bi.get_low() >= zd);
let contains_range = (bi.get_high() >= zg) && (bi.get_low() <= zd);
high_in_range || low_in_range || contains_range
})
}
}
#[cfg(feature = "python")]
#[cfg_attr(feature = "python", gen_stub_pymethods)]
#[cfg_attr(feature = "python", pymethods)]
impl ZS {
#[new]
fn new_py(bis: Vec<BI>) -> Self {
Self::new(bis)
}
#[getter]
fn bis(&self) -> Vec<BI> {
self.bis.clone()
}
#[getter]
fn sdt(&self, py: Python) -> PyResult<PyObject> {
create_naive_pandas_timestamp(py, self.sdt)
}
#[getter]
fn edt(&self, py: Python) -> PyResult<PyObject> {
create_naive_pandas_timestamp(py, self.edt)
}
#[getter]
fn sdir(&self) -> Direction {
self.sdir
}
#[getter]
fn edir(&self) -> Direction {
self.edir
}
#[getter]
fn zg(&self) -> f64 {
self.zg
}
#[getter]
fn zd(&self) -> f64 {
self.zd
}
#[getter]
fn zz(&self) -> f64 {
self.zz
}
#[getter]
fn gg(&self) -> f64 {
self.gg
}
#[getter]
fn dd(&self) -> f64 {
self.dd
}
#[pyo3(name = "is_valid")]
fn is_valid_py(&self) -> bool {
self.is_valid()
}
#[getter]
fn get_cache<'py>(&'py self, py: Python<'py>) -> Py<PyDict> {
{
let cache_read = self.cache.read();
if let Some(ref cached_dict) = *cache_read {
return cached_dict.clone_ref(py);
}
}
let mut cache_write = self.cache.write();
if cache_write.is_none() {
let dict = PyDict::new(py);
dict.set_item("sdt", create_naive_pandas_timestamp(py, self.sdt).unwrap())
.unwrap();
dict.set_item("edt", create_naive_pandas_timestamp(py, self.edt).unwrap())
.unwrap();
dict.set_item("sdir", self.sdir).unwrap();
dict.set_item("edir", self.edir).unwrap();
dict.set_item("zg", self.zg).unwrap();
dict.set_item("zd", self.zd).unwrap();
dict.set_item("zz", self.zz).unwrap();
dict.set_item("gg", self.gg).unwrap();
dict.set_item("dd", self.dd).unwrap();
dict.set_item("bis", py.None()).unwrap(); *cache_write = Some(dict.unbind());
}
cache_write.as_ref().unwrap().clone_ref(py)
}
#[setter]
#[gen_stub(skip)] fn set_cache(&self, dict: Py<PyDict>) {
let mut cache_write = self.cache.write();
*cache_write = Some(dict);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::objects::bi::tests::create_bi;
#[test]
fn test_new_zs() {
let bi1 = create_bi();
let zs1 = ZS::new(vec![bi1.clone(), bi1.clone(), bi1]);
println!("{:?}", zs1.sdt);
}
}