diff --git a/chan.py b/chan.py index 22cf0a0..7c9b3e6 100644 --- a/chan.py +++ b/chan.py @@ -2202,6 +2202,9 @@ class 缠论K线(object): return 序列[序列.index(始) : 序列.index(终) + 1] +分型模式 = True + + class 分型(object): """分型 — 由左中右三根缠论K线构成的顶/底分型结构。 @@ -2216,7 +2219,7 @@ class 分型(object): :ivar 与MACD柱子分型匹配: 是否与MACD柱子分型匹配 """ - __slots__ = ["左", "中", "右", "结构", "时间戳", "分型特征值"] + __slots__ = ["左", "中", "右", "_结构", "_时间戳", "_分型特征值"] def __init__(self, 左: Optional[缠论K线], 中: 缠论K线, 右: Optional[缠论K线]): """ @@ -2229,9 +2232,9 @@ class 分型(object): self.左: Optional[缠论K线] = 左 self.中: 缠论K线 = 中 self.右: Optional[缠论K线] = 右 - self.结构 = 中.分型 - self.时间戳 = 中.时间戳 - self.分型特征值 = 中.分型特征值 + self._结构 = 中.分型 + self._时间戳 = 中.时间戳 + self._分型特征值 = 中.分型特征值 def __str__(self): return f"{self.中.分型}<{self.时间戳}, {self.分型特征值:g}, None: {self.左 is None}, None: {self.右 is None}>" @@ -2239,6 +2242,24 @@ class 分型(object): def __repr__(self): return f"{self.中.分型}<{self.时间戳}, {self.分型特征值:g}, None: {self.左 is None}, None: {self.右 is None}>" + @property + def 时间戳(self): + if 分型模式: + return self._时间戳 + return self.中.时间戳 + + @property + def 分型特征值(self): + if 分型模式: + return self._分型特征值 + return self.中.分型特征值 + + @property + def 结构(self): + if 分型模式: + return self._结构 + return self.中.分型 + @property def 关系组(self) -> Optional[Tuple[相对方向, 相对方向, 相对方向]]: """左、中、右三对相对方向关系 diff --git a/chanlun-py/Cargo.toml b/chanlun-py/Cargo.toml index ed59c2f..e2e3488 100644 --- a/chanlun-py/Cargo.toml +++ b/chanlun-py/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chanlun-py" -version = "26.5.89" +version = "26.5.91" edition = "2021" description = "缠论技术分析库 — Rust 高性能 Python 绑定" authors = ["YuYuKunKun"] diff --git a/chanlun-py/pyproject.toml b/chanlun-py/pyproject.toml index d5d4846..181454e 100644 --- a/chanlun-py/pyproject.toml +++ b/chanlun-py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "chanlun" -version = "2605.89" +version = "2605.91" description = "缠论技术分析库 — Rust 高性能实现" readme = { file = "README.md", content-type = "text/markdown" } license = { file = "LICENSE", content-type = "text/plain" } diff --git a/chanlun-py/src/algorithm_py.rs b/chanlun-py/src/algorithm_py.rs index fc90757..dd1bb61 100644 --- a/chanlun-py/src/algorithm_py.rs +++ b/chanlun-py/src/algorithm_py.rs @@ -445,6 +445,7 @@ impl 笔Py { &mut bi_seq, &ck_list, &bar_list, + 递归层次, &config, )), None => Ok(递归层次), @@ -480,7 +481,7 @@ impl 笔Py { .map(|k| k.bind(py).borrow().inner.clone()) .collect(); let config = 配置.borrow().to_rust_config(py)?; - Ok(chanlun::algorithm::bi::笔::分析递归( + Ok(chanlun::algorithm::bi::笔::分析( Arc::clone(&当前分型.borrow().inner), &mut fr_seq, &mut bi_seq, diff --git a/chanlun-py/src/lib.rs b/chanlun-py/src/lib.rs index ea504ca..e050027 100644 --- a/chanlun-py/src/lib.rs +++ b/chanlun-py/src/lib.rs @@ -23,6 +23,7 @@ */ use pyo3::prelude::*; +use std::sync::atomic::Ordering; mod algorithm_py; mod business_py; @@ -32,10 +33,24 @@ mod kline_py; mod structure_py; mod types_py; +/// 分型模式 — True 时使用构造时缓存值,False 时从 中 缠K 实时读取 +#[pyfunction] +fn get_分型模式() -> bool { + chanlun::structure::fractal_obj::分型模式.load(Ordering::Relaxed) +} + +/// 设置 分型模式 +#[pyfunction] +fn set_分型模式(value: bool) { + chanlun::structure::fractal_obj::分型模式.store(value, Ordering::Relaxed); +} + /// 缠论技术分析库 — Rust 高性能实现 #[pymodule] /// 缠论技术分析库 — Rust 高性能实现 fn _chanlun(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(get_分型模式, m)?)?; + m.add_function(wrap_pyfunction!(set_分型模式, m)?)?; // 阶段 1: 枚举和基础类型 types_py::register(m)?; // 阶段 2: 配置 diff --git a/chanlun-py/src/structure_py.rs b/chanlun-py/src/structure_py.rs index 8d58614..e7895d7 100644 --- a/chanlun-py/src/structure_py.rs +++ b/chanlun-py/src/structure_py.rs @@ -185,19 +185,35 @@ impl 分型Py { #[getter] fn 结构(&self) -> 分型结构Py { - 分型结构Py { - inner: self.inner.结构, + if chanlun::structure::fractal_obj::分型模式.load(Ordering::Relaxed) { + 分型结构Py { + inner: self.inner.结构, + } + } else { + 分型结构Py { + inner: self + .inner + .中 + .分型 + .read() + .unwrap() + .unwrap_or(chanlun::types::分型结构::散), + } } } #[getter] fn 时间戳(&self) -> i64 { - self.inner.时间戳 + self.inner.时间戳() } #[getter] fn 分型特征值(&self) -> f64 { - self.inner.分型特征值 + if chanlun::structure::fractal_obj::分型模式.load(Ordering::Relaxed) { + self.inner.分型特征值 + } else { + self.inner.中.分型特征值.get() + } } fn __str__(&self) -> String { diff --git a/chanlun/src/algorithm/bi.rs b/chanlun/src/algorithm/bi.rs index e80aa29..749a77d 100644 --- a/chanlun/src/algorithm/bi.rs +++ b/chanlun/src/algorithm/bi.rs @@ -336,7 +336,7 @@ impl 笔 { /// 核心笔分析 — 使用显式栈模拟递归 /// /// 返回: 递归层次数 - pub fn 分析( + pub fn 分析_显式栈( 初始分型: Arc<分型>, 分型序列: &mut Vec>, 笔序列: &mut Vec>, @@ -415,7 +415,7 @@ impl 笔 { let 之前分型 = Arc::clone(分型序列.last().unwrap()); // Python line 2330-2335: 清理无效数据 - if 之前分型.时间戳 == 当前分型.时间戳 + if 之前分型.中.时间戳.load(Ordering::Relaxed) == 当前分型.中.时间戳.load(Ordering::Relaxed) || matches!(之前分型.结构, 分型结构::上 | 分型结构::下) { Self::弹出旧笔(分型序列, 笔序列); @@ -430,7 +430,7 @@ impl 笔 { let 之前分型 = Arc::clone(分型序列.last().unwrap()); // Python line 2338: 时序检查 — skip out-of-order fractals - if 之前分型.时间戳 > 当前分型.时间戳 + if 之前分型.中.时间戳.load(Ordering::Relaxed) > 当前分型.中.时间戳.load(Ordering::Relaxed) && 之前分型.中.序号.load(Ordering::Relaxed) - 当前分型.中.序号.load(Ordering::Relaxed) > 1 @@ -608,7 +608,7 @@ impl 笔 { /// 核心笔分析 — 递归实现,逐句对照 chan.py 笔.分析 / 笔递归分析 /// /// 返回: 递归层次数 - pub fn 分析递归( + pub fn 分析( 当前分型: Arc<分型>, 分型序列: &mut Vec>, 笔序列: &mut Vec>, @@ -637,7 +637,7 @@ impl 笔 { // Python line 2329-2335: 清理无效数据 let 之前分型 = Arc::clone(分型序列.last().unwrap()); - if 之前分型.时间戳 == 当前分型.时间戳 + if 之前分型.中.时间戳.load(Ordering::Relaxed) == 当前分型.中.时间戳.load(Ordering::Relaxed) || matches!(之前分型.结构, 分型结构::上 | 分型结构::下) { Self::弹出旧笔(分型序列, 笔序列); @@ -651,7 +651,7 @@ impl 笔 { // Python line 2337-2341: 时序检查 let 之前分型 = Arc::clone(分型序列.last().unwrap()); - if 之前分型.时间戳 > 当前分型.时间戳 + if 之前分型.中.时间戳.load(Ordering::Relaxed) > 当前分型.中.时间戳.load(Ordering::Relaxed) && 之前分型.中.序号.load(Ordering::Relaxed) - 当前分型.中.序号.load(Ordering::Relaxed) > 1 { @@ -674,7 +674,7 @@ impl 笔 { && 当前分型.结构 == 分型结构::顶); if 破位 { Self::弹出旧笔(分型序列, 笔序列); - return Self::分析递归( + return Self::分析( 当前分型, 分型序列, 笔序列, @@ -712,7 +712,7 @@ impl 笔 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 文官_k) { - let 递归层次 = Self::分析递归( + let 递归层次 = Self::分析( Arc::new(临时分型), 分型序列, 笔序列, @@ -721,7 +721,7 @@ impl 笔 { 递归层次 + 1, 配置, ); - return Self::分析递归( + return Self::分析( 当前分型, 分型序列, 笔序列, @@ -770,7 +770,7 @@ impl 笔 { if let Some(ref 右) = 当前分型.右 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 右) { - return Self::分析递归( + return Self::分析( Arc::new(临时分型), 分型序列, 笔序列, @@ -812,7 +812,7 @@ impl 笔 { let 临时分型_rc = Arc::new(临时分型); if !分型序列.is_empty() { - let mut 递归层次 = Self::分析递归( + let mut 递归层次 = Self::分析( Arc::clone(&临时分型_rc), 分型序列, 笔序列, @@ -841,7 +841,7 @@ impl 笔 { ) { let 错过分型_rc = Arc::new(错过分型); - 递归层次 = Self::分析递归( + 递归层次 = Self::分析( Arc::clone(&错过分型_rc), 分型序列, 笔序列, @@ -856,7 +856,7 @@ impl 笔 { } } - return Self::分析递归( + return Self::分析( 当前分型, 分型序列, 笔序列, @@ -873,7 +873,7 @@ impl 笔 { } else if 分型序列.is_empty() { 分型::向序列中添加(分型序列, 当前分型); } else { - return Self::分析递归( + return Self::分析( 当前分型, 分型序列, 笔序列, diff --git a/chanlun/src/algorithm/divergence.rs b/chanlun/src/algorithm/divergence.rs index 52cab8f..f61585c 100644 --- a/chanlun/src/algorithm/divergence.rs +++ b/chanlun/src/algorithm/divergence.rs @@ -69,14 +69,14 @@ impl 背驰分析 { /// 斜率背驰 — 价格斜率背驰 pub fn 斜率背驰(进入段: &虚线, 离开段: &虚线) -> bool { - let dx = (进入段.武.read().unwrap().时间戳 - 进入段.文.时间戳) as f64; + let dx = (进入段.武.read().unwrap().时间戳() - 进入段.文.时间戳()) as f64; if dx == 0.0 { return false; } let dy = 进入段.武.read().unwrap().分型特征值 - 进入段.文.分型特征值; let 进入斜率 = dy / dx; - let dx = (离开段.武.read().unwrap().时间戳 - 离开段.文.时间戳) as f64; + let dx = (离开段.武.read().unwrap().时间戳() - 离开段.文.时间戳()) as f64; if dx == 0.0 { return false; } @@ -92,11 +92,11 @@ impl 背驰分析 { /// 测度背驰 — 价格时间测度背驰 pub fn 测度背驰(进入段: &虚线, 离开段: &虚线) -> bool { - let dx = (进入段.武.read().unwrap().时间戳 - 进入段.文.时间戳) as f64; + let dx = (进入段.武.read().unwrap().时间戳() - 进入段.文.时间戳()) as f64; let dy = 进入段.武.read().unwrap().分型特征值 - 进入段.文.分型特征值; let 进入测度 = (dx * dx + dy * dy).sqrt(); - let dx = (离开段.武.read().unwrap().时间戳 - 离开段.文.时间戳) as f64; + let dx = (离开段.武.read().unwrap().时间戳() - 离开段.文.时间戳()) as f64; let dy = 离开段.武.read().unwrap().分型特征值 - 离开段.文.分型特征值; let 离开测度 = (dx * dx + dy * dy).sqrt(); diff --git a/chanlun/src/algorithm/hub.rs b/chanlun/src/algorithm/hub.rs index 70a7660..90c6c02 100644 --- a/chanlun/src/algorithm/hub.rs +++ b/chanlun/src/algorithm/hub.rs @@ -165,9 +165,9 @@ impl 中枢 { self.标识.read().unwrap(), self.序号.load(Ordering::Relaxed), self.级别.load(Ordering::Relaxed), - self.文().时间戳, + self.文().时间戳(), crate::utils::format_f64_g(self.文().分型特征值), - self.武().时间戳, + self.武().时间戳(), crate::utils::format_f64_g(self.武().分型特征值), 第三买卖线_str, 本级_第三买卖线_str, diff --git a/chanlun/src/algorithm/segment.rs b/chanlun/src/algorithm/segment.rs index 872420e..b4afe82 100644 --- a/chanlun/src/algorithm/segment.rs +++ b/chanlun/src/algorithm/segment.rs @@ -106,7 +106,7 @@ impl 线段 { return; } if 段.武.read().unwrap().分型特征值 == 武.分型特征值 - && 段.武.read().unwrap().时间戳 != 武.时间戳 + && 段.武.read().unwrap().时间戳() != 武.时间戳() { eprintln!( "线段.武斗[{}], 发现特征值相等但时间戳不同 {} {}", diff --git a/chanlun/src/business/observer.rs b/chanlun/src/business/observer.rs index b9f20ca..3a5b0f5 100644 --- a/chanlun/src/business/observer.rs +++ b/chanlun/src/business/observer.rs @@ -177,6 +177,7 @@ impl 观察者 { &mut self.笔序列, &self.缠论K线序列, &self.普通K线序列, + 0, &self.配置, ); } @@ -289,6 +290,7 @@ impl 观察者 { &mut self.笔序列, &self.缠论K线序列, &self.普通K线序列, + 0, &self.配置, ); } @@ -434,7 +436,7 @@ impl 观察者 { format!( "分型, {}, {}, {:?}, {}, {}, {}", i, - fx.时间戳, + fx.时间戳(), fx.结构, fx.分型特征值, fx.中.时间戳.load(Ordering::Relaxed), @@ -640,7 +642,7 @@ mod tests { let 文_ptr = Arc::as_ptr(&bi.文); let 文_found = obs_ref.分型序列.iter().any(|f| Arc::as_ptr(f) == 文_ptr); if !文_found { - println!("笔 {}: 文(时间戳={}) 不在分型序列中!", i, bi.文.时间戳); + println!("笔 {}: 文(时间戳={}) 不在分型序列中!", i, bi.文.时间戳()); } let 武_ptr = Arc::as_ptr(&*bi.武.read().unwrap()); @@ -649,7 +651,7 @@ mod tests { println!( "笔 {}: 武(时间戳={}) 不在分型序列中!", i, - bi.武.read().unwrap().时间戳 + bi.武.read().unwrap().时间戳() ); } } diff --git a/chanlun/src/structure/dash_line.rs b/chanlun/src/structure/dash_line.rs index 4134e3f..bd660db 100644 --- a/chanlun/src/structure/dash_line.rs +++ b/chanlun/src/structure/dash_line.rs @@ -239,9 +239,9 @@ impl 虚线 { self.标识.read().unwrap(), self.序号.load(Ordering::Relaxed), self.级别.load(Ordering::Relaxed), - self.文.时间戳, + self.文.时间戳(), format_f64_g(self.文.分型特征值), - self.武.read().unwrap().时间戳, + self.武.read().unwrap().时间戳(), format_f64_g(self.武.read().unwrap().分型特征值), if self.有效性.load(Ordering::Relaxed) { "True" @@ -330,9 +330,9 @@ impl 虚线 { self.标识.read().unwrap(), self.序号.load(Ordering::Relaxed), self.级别.load(Ordering::Relaxed), - self.文.时间戳, + self.文.时间戳(), format_f64_g(self.文.分型特征值), - self.武.read().unwrap().时间戳, + self.武.read().unwrap().时间戳(), format_f64_g(self.武.read().unwrap().分型特征值), if self.有效性.load(Ordering::Relaxed) { "True" } else { "False" }, self.基础序列.read().unwrap().len(), @@ -1232,7 +1232,7 @@ mod tests { assert_eq!(Arc::as_ptr(&笔.文), 文_ptr_before); // 但方向变了(因为武从底1变成底2) - let 新武耗时 = 笔.武.read().unwrap().时间戳; + let 新武耗时 = 笔.武.read().unwrap().时间戳(); assert_eq!(新武耗时, 300); } } diff --git a/chanlun/src/structure/fractal_obj.rs b/chanlun/src/structure/fractal_obj.rs index d8774a6..b5ecdd1 100644 --- a/chanlun/src/structure/fractal_obj.rs +++ b/chanlun/src/structure/fractal_obj.rs @@ -25,9 +25,13 @@ use crate::kline::chan_kline::缠论K线; use crate::types::分型结构; use crate::types::相对方向; +use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; +/// 分型模式 — True 时使用构造时缓存值(默认),False 时从 中 缠K 实时读取 +pub static 分型模式: AtomicBool = AtomicBool::new(true); + /// 分型 — 由三根缠K构成(可能缺左或右) #[derive(Debug, Clone)] pub struct 分型 { @@ -56,6 +60,15 @@ impl 分型 { } } + /// 时间戳 — 根据 分型模式 决定返回缓存值(True)或实时值(False) + pub fn 时间戳(&self) -> i64 { + if 分型模式.load(Ordering::Relaxed) { + self.时间戳 + } else { + self.中.时间戳.load(Ordering::Relaxed) + } + } + /// 左中右三组关系 pub fn 关系组(&self) -> Option<(相对方向, 相对方向, 相对方向)> { let 左 = self.左.as_ref()?; @@ -215,7 +228,7 @@ impl std::fmt::Display for 分型 { .read() .unwrap() .unwrap_or(crate::types::分型结构::散), - self.时间戳, + self.时间戳(), crate::utils::format_f64_g(self.分型特征值), if self.左.is_none() { "True" } else { "False" }, if self.右.is_none() { "True" } else { "False" }, diff --git a/chanlun/src/structure/segment_feat.rs b/chanlun/src/structure/segment_feat.rs index 2edcc9b..e1e4dee 100644 --- a/chanlun/src/structure/segment_feat.rs +++ b/chanlun/src/structure/segment_feat.rs @@ -63,7 +63,7 @@ impl 线段特征 { .分型特征值 .partial_cmp(&b.文.分型特征值) .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| a.文.时间戳.cmp(&b.文.时间戳)) + .then_with(|| a.文.时间戳().cmp(&b.文.时间戳())) }) .map(|x| Arc::clone(&x.文)) .unwrap_or_else(|| Arc::clone(&self.元素[0].文)) @@ -75,7 +75,7 @@ impl 线段特征 { .分型特征值 .partial_cmp(&b.文.分型特征值) .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| b.文.时间戳.cmp(&a.文.时间戳)) + .then_with(|| b.文.时间戳().cmp(&a.文.时间戳())) }) .map(|x| Arc::clone(&x.文)) .unwrap_or_else(|| Arc::clone(&self.元素[0].文)) @@ -99,8 +99,8 @@ impl 线段特征 { a.武 .read() .unwrap() - .时间戳 - .cmp(&b.武.read().unwrap().时间戳) + .时间戳() + .cmp(&b.武.read().unwrap().时间戳()) }) }) .map(|x| x.武.read().unwrap().clone()) @@ -119,8 +119,8 @@ impl 线段特征 { b.武 .read() .unwrap() - .时间戳 - .cmp(&a.武.read().unwrap().时间戳) + .时间戳() + .cmp(&a.武.read().unwrap().时间戳()) }) }) .map(|x| x.武.read().unwrap().clone()) @@ -527,7 +527,7 @@ mod tests { let 文 = feat.文(); // 向上取最大特征值:都是100 → tiebreaker取后时间戳 → 笔2.文(300) - assert_eq!(文.时间戳, 300); + assert_eq!(文.时间戳(), 300); } #[test] @@ -544,7 +544,7 @@ mod tests { let 武 = feat.武(); // 向上取最大特征值:都是80 → tiebreaker取后时间戳 → 笔2.武(400) - assert_eq!(武.时间戳, 400); + assert_eq!(武.时间戳(), 400); } // ============================================================