diff --git a/chanlun-py/Cargo.toml b/chanlun-py/Cargo.toml index 08abe10..4e5c45d 100644 --- a/chanlun-py/Cargo.toml +++ b/chanlun-py/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chanlun-py" -version = "26.5.67" +version = "26.5.86" edition = "2021" description = "缠论技术分析库 — Rust 高性能 Python 绑定" authors = ["YuYuKunKun"] @@ -12,7 +12,7 @@ crate-type = ["cdylib"] name = "chanlun" [dependencies] -chanlun = "26.5.2" # { path = "../chanlun" } +chanlun = "26.5.3" # { path = "../chanlun" } pyo3 = { version = "0.28", features = ["extension-module", "experimental-inspect"] } serde_json = "1" chrono = "0.4" diff --git a/chanlun-py/chanlun.pyi b/chanlun-py/chanlun.pyi index f686bcd..2ab0178 100644 --- a/chanlun-py/chanlun.pyi +++ b/chanlun-py/chanlun.pyi @@ -16,7 +16,6 @@ __all__ = [ "基础买卖点", "平滑异同移动平均线", "指标", - "测试_读取数据", "特征分型", "相对强弱指数", "相对方向", diff --git a/chanlun-py/chanlun/__init__.py b/chanlun-py/chanlun/__init__.py index 2387df7..6d17b33 100644 --- a/chanlun-py/chanlun/__init__.py +++ b/chanlun-py/chanlun/__init__.py @@ -11,7 +11,6 @@ __all__ = [ "基础买卖点", "平滑异同移动平均线", "指标", - "测试_读取数据", "特征分型", "相对强弱指数", "相对方向", diff --git a/chanlun-py/chanlun/__init__.pyi b/chanlun-py/chanlun/__init__.pyi index f686bcd..2ab0178 100644 --- a/chanlun-py/chanlun/__init__.pyi +++ b/chanlun-py/chanlun/__init__.pyi @@ -16,7 +16,6 @@ __all__ = [ "基础买卖点", "平滑异同移动平均线", "指标", - "测试_读取数据", "特征分型", "相对强弱指数", "相对方向", diff --git a/chanlun-py/pyproject.toml b/chanlun-py/pyproject.toml index b10a1de..aedcc33 100644 --- a/chanlun-py/pyproject.toml +++ b/chanlun-py/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "chanlun" -version = "2605.67" +version = "2605.86" 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 39fbf5d..fc90757 100644 --- a/chanlun-py/src/algorithm_py.rs +++ b/chanlun-py/src/algorithm_py.rs @@ -22,9 +22,37 @@ * SOFTWARE. */ +use crate::kline_py::chan_kline_to_py; +use crate::structure_py::{dashed_to_py, fractal_to_py}; use pyo3::prelude::*; use pyo3::types::{PyDict, PyType}; -use std::rc::Rc; +use std::collections::HashMap; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::sync::RwLock; + +thread_local! { + static HUB_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); +} + +pub(crate) fn hub_to_py( + py: Python<'_>, inner: Arc +) -> Py<中枢Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + HUB_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + HUB_IDENTITY.with(|c| { + c.write().unwrap().retain(|_, v| v.get_refcnt(py) > 1); + }); + let obj = Py::new(py, 中枢Py { inner }).unwrap(); + HUB_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} use crate::business_py::观察者Py; use crate::config_py::缠论配置Py; @@ -60,7 +88,7 @@ impl 背驰分析Py { 方式: &str, py: Python<'_>, ) -> bool { - let rc_list: Vec> = K线序列 + let rc_list: Vec> = K线序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -107,7 +135,7 @@ impl 背驰分析Py { 普K序列: Vec>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -127,7 +155,7 @@ impl 背驰分析Py { 普K序列: Vec>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -148,7 +176,7 @@ impl 背驰分析Py { 配置: &Bound<'_, 缠论配置Py>, py: Python<'_>, ) -> PyResult { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -170,7 +198,7 @@ impl 背驰分析Py { 普K序列: Vec>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -192,7 +220,7 @@ impl 背驰分析Py { 模式: &str, py: Python<'_>, ) -> PyResult { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -234,13 +262,13 @@ impl 笔Py { 配置: &Bound<'_, 缠论配置Py>, py: Python<'_>, ) -> PyResult { - let ck_list: Vec> = 缠K序列 + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); - let bi_list: Vec> = 笔序列 + let bi_list: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::bi::笔::获取缠K数量( @@ -255,13 +283,13 @@ impl 笔Py { 缠K序列: Vec>, 取舍: bool, py: Python<'_>, - ) -> Option { - let ck_list: Vec> = 缠K序列 + ) -> Option> { + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::次高(&ck_list, 取舍) - .map(|inner| crate::kline_py::缠论K线Py::from_rc(inner)) + .map(|inner| crate::kline_py::chan_kline_to_py(py, inner)) } #[classmethod] @@ -271,13 +299,13 @@ impl 笔Py { 缠K序列: Vec>, 取舍: bool, py: Python<'_>, - ) -> Option { - let ck_list: Vec> = 缠K序列 + ) -> Option> { + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::次低(&ck_list, 取舍) - .map(|inner| crate::kline_py::缠论K线Py::from_rc(inner)) + .map(|inner| crate::kline_py::chan_kline_to_py(py, inner)) } #[classmethod] @@ -287,13 +315,13 @@ impl 笔Py { 缠K序列: Vec>, 取舍: bool, py: Python<'_>, - ) -> Option { - let ck_list: Vec> = 缠K序列 + ) -> Option> { + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::实际高点(&ck_list, 取舍) - .map(|inner| crate::kline_py::缠论K线Py::from_rc(inner)) + .map(|inner| crate::kline_py::chan_kline_to_py(py, inner)) } #[classmethod] @@ -303,13 +331,13 @@ impl 笔Py { 缠K序列: Vec>, 取舍: bool, py: Python<'_>, - ) -> Option { - let ck_list: Vec> = 缠K序列 + ) -> Option> { + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::实际低点(&ck_list, 取舍) - .map(|inner| crate::kline_py::缠论K线Py::from_rc(inner)) + .map(|inner| crate::kline_py::chan_kline_to_py(py, inner)) } #[classmethod] @@ -335,9 +363,9 @@ impl 笔Py { 文: &Bound<'_, 分型Py>, py: Python<'_>, ) -> Option<虚线Py> { - let bi_list: Vec> = 笔序列 + let bi_list: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::以文会友(&bi_list, &文.borrow().inner) .map(|inner| 虚线Py { inner }) @@ -351,9 +379,9 @@ impl 笔Py { 武: &Bound<'_, 分型Py>, py: Python<'_>, ) -> Option<虚线Py> { - let bi_list: Vec> = 笔序列 + let bi_list: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::以武会友(&bi_list, &武.borrow().inner) .map(|inner| 虚线Py { inner }) @@ -369,9 +397,9 @@ impl 笔Py { 偏移: i64, py: Python<'_>, ) -> Option<虚线Py> { - let bi_list: Vec> = 笔序列 + let bi_list: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::bi::笔::根据缠K找笔(&bi_list, &缠K.borrow().inner, 偏移) .map(|inner| 虚线Py { inner }) @@ -392,20 +420,20 @@ impl 笔Py { py: Python<'_>, ) -> PyResult { let _ = 递归层次; // Python API 兼容参数,核心从0开始计数 - let 当前分型_rc = 当前分型.map(|f| Rc::clone(&f.borrow().inner)); - let mut fr_seq: Vec> = 分型序列 + let 当前分型_rc = 当前分型.map(|f| Arc::clone(&f.borrow().inner)); + let mut fr_seq: Vec> = 分型序列 .iter() - .map(|f| Rc::clone(&f.bind(py).borrow().inner)) + .map(|f| Arc::clone(&f.bind(py).borrow().inner)) .collect(); - let mut bi_seq: Vec> = 笔序列 + let mut bi_seq: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let ck_list: Vec> = 缠K序列 + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); - let bar_list: Vec> = 普K序列 + let bar_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -435,25 +463,25 @@ impl 笔Py { 配置: &Bound<'_, 缠论配置Py>, py: Python<'_>, ) -> PyResult { - let mut fr_seq: Vec> = 分型序列 + let mut fr_seq: Vec> = 分型序列 .iter() - .map(|f| Rc::clone(&f.bind(py).borrow().inner)) + .map(|f| Arc::clone(&f.bind(py).borrow().inner)) .collect(); - let mut bi_seq: Vec> = 笔序列 + let mut bi_seq: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let ck_list: Vec> = 缠K序列 + let ck_list: Vec> = 缠K序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); - let bar_list: Vec> = 普K序列 + let bar_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::bi::笔::分析递归( - Rc::clone(&当前分型.borrow().inner), + Arc::clone(&当前分型.borrow().inner), &mut fr_seq, &mut bi_seq, &ck_list, @@ -486,7 +514,7 @@ impl 笔Py { let obs_ref = obs.obs(); chanlun::algorithm::bi::笔::获取所有停顿位置(&筆.borrow().inner, &*obs_ref) .into_iter() - .map(|d| 虚线Py { inner: Rc::new(d) }) + .map(|d| 虚线Py { inner: Arc::new(d) }) .collect() } @@ -496,12 +524,13 @@ impl 笔Py { _cls: &Bound<'_, PyType>, 当前筆: &Bound<'_, 虚线Py>, 观察员: &Bound<'_, 观察者Py>, - ) -> Vec<缠论K线Py> { + py: Python<'_>, + ) -> Vec> { let obs = 观察员.borrow(); let obs_ref = obs.obs(); chanlun::algorithm::bi::笔::是否背驰过(&当前筆.borrow().inner, &*obs_ref) .into_iter() - .map(|ck| 缠论K线Py::from_rc(ck)) + .map(|ck| chan_kline_to_py(py, ck)) .collect() } } @@ -538,7 +567,7 @@ impl 线段Py { 段: &Bound<'_, 虚线Py>, 筆: &Bound<'_, 虚线Py>, ) -> PyResult<()> { - let bi_rc = Rc::clone(&筆.borrow().inner); + let bi_rc = Arc::clone(&筆.borrow().inner); let mut ref_mut = 段.borrow_mut(); chanlun::algorithm::segment::线段::添加虚线(&mut ref_mut.inner, bi_rc); Ok(()) @@ -555,7 +584,7 @@ impl 线段Py { let mut ref_mut = 段.borrow_mut(); chanlun::algorithm::segment::线段::武斗( &mut ref_mut.inner, - &Rc::clone(&武.borrow().inner), + &Arc::clone(&武.borrow().inner), 行号, ); Ok(()) @@ -578,9 +607,9 @@ impl 线段Py { py: Python<'_>, ) -> PyResult<()> { let mut ref_mut = 段.borrow_mut(); - let rc_list: Vec> = 序列 + let rc_list: Vec> = 序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::segment::线段::验证序列(&mut ref_mut.inner, &rc_list); Ok(()) @@ -595,9 +624,9 @@ impl 线段Py { py: Python<'_>, ) -> PyResult<()> { let mut ref_mut = 段.borrow_mut(); - let rc_list: Vec> = 序列 + let rc_list: Vec> = 序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::segment::线段::序列重置(&mut ref_mut.inner, &rc_list); Ok(()) @@ -659,7 +688,8 @@ impl 线段Py { 序列: &Bound<'_, PyAny>, 行号: u32, ) -> PyResult<()> { - let seq: Vec>> = if 序列.is_none() { + let seq: Vec>> = if 序列.is_none() + { vec![] } else if let Ok(list) = 序列.downcast::() { let mut result = Vec::with_capacity(list.len()); @@ -668,7 +698,7 @@ impl 线段Py { result.push(None); } else { let feat: PyRef<'_, 线段特征Py> = item.extract()?; - result.push(Some(Rc::clone(&feat.inner))); + result.push(Some(Arc::clone(&feat.inner))); } } result @@ -704,6 +734,7 @@ impl 线段Py { } #[classmethod] + #[pyo3(signature = (段, 所属中枢 = None))] /// 将线段基础序列分割为前/后/第三买卖/贯穿伤四部分 fn 分割序列( _cls: &Bound<'_, PyType>, @@ -719,7 +750,7 @@ impl 线段Py { let borrowed = 段.borrow(); let (a, b, c, d) = if let Some(hub_bound) = 所属中枢 { if let Ok(mut hub_ref) = hub_bound.extract::>() { - let inner_mut = Rc::make_mut(&mut hub_ref.inner); + let inner_mut = Arc::make_mut(&mut hub_ref.inner); chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, Some(inner_mut)) } else { chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, None) @@ -727,7 +758,7 @@ impl 线段Py { } else { chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, None) }; - let wrap = |v: Vec>| -> PyResult>> { + let wrap = |v: Vec>| -> PyResult>> { let mut result = Vec::new(); for x in v { result.push(Py::new(py, 虚线Py { inner: x })?); @@ -770,7 +801,7 @@ impl 线段Py { &mut ref_mut.inner, &config, ); - let pk_list = |v: Vec>| -> PyResult> { + let pk_list = |v: Vec>| -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in v { list.append(Py::new(py, 中枢Py { inner: h })?)?; @@ -791,10 +822,10 @@ impl 线段Py { py: Python<'_>, ) -> PyResult<()> { let config = 配置.borrow().to_rust_config(py)?; - let mut seg_seq: Vec> = vec![]; + let mut seg_seq: Vec> = vec![]; chanlun::algorithm::segment::线段::_添加线段( &mut seg_seq, - Rc::clone(&待添加线段.borrow().inner), + Arc::clone(&待添加线段.borrow().inner), &config, 行号, ); @@ -812,10 +843,10 @@ impl 线段Py { py: Python<'_>, ) -> PyResult> { let config = 配置.borrow().to_rust_config(py)?; - let mut seg_seq: Vec> = vec![]; + let mut seg_seq: Vec> = vec![]; let result = chanlun::algorithm::segment::线段::_弹出线段( &mut seg_seq, - &Rc::clone(&待弹出线段.borrow().inner), + &Arc::clone(&待弹出线段.borrow().inner), &config, 行号, ); @@ -831,9 +862,9 @@ impl 线段Py { 层级: i64, py: Python<'_>, ) -> PyResult { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::segment::线段::_缺口突破( @@ -852,9 +883,9 @@ impl 线段Py { 层级: i64, py: Python<'_>, ) -> PyResult { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::segment::线段::_非缺口下穿刺( @@ -873,9 +904,9 @@ impl 线段Py { 层级: i64, py: Python<'_>, ) -> PyResult { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::segment::线段::_缺口后紧急修正( @@ -894,9 +925,9 @@ impl 线段Py { 层级: i64, py: Python<'_>, ) -> PyResult { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; Ok(chanlun::algorithm::segment::线段::_修正( @@ -918,13 +949,13 @@ impl 线段Py { 关系序列: Option>, py: Python<'_>, ) -> PyResult<()> { - let bi_list: Vec> = 笔序列 + let bi_list: Vec> = 笔序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; let default_rel = vec![ @@ -953,13 +984,13 @@ impl 线段Py { 行号: u32, py: Python<'_>, ) -> PyResult<()> { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::segment::线段::_添加扩展线段( &mut seg_seq, - Rc::clone(&待添加线段.borrow().inner), + Arc::clone(&待添加线段.borrow().inner), 行号, ); Ok(()) @@ -974,13 +1005,13 @@ impl 线段Py { 行号: u32, py: Python<'_>, ) -> PyResult> { - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let result = chanlun::algorithm::segment::线段::_弹出扩展线段( &mut seg_seq, - &Rc::clone(&待弹出线段.borrow().inner), + &Arc::clone(&待弹出线段.borrow().inner), 行号, ); Ok(result.map(|inner| 虚线Py { inner })) @@ -995,13 +1026,13 @@ impl 线段Py { 配置: &Bound<'_, 缠论配置Py>, py: Python<'_>, ) -> PyResult<()> { - let dash_list: Vec> = 虚线序列 + let dash_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let mut seg_seq: Vec> = 线段序列 + let mut seg_seq: Vec> = 线段序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(py)?; chanlun::algorithm::segment::线段::扩展分析(&dash_list, &mut seg_seq, &config); @@ -1034,7 +1065,7 @@ impl 线段Py { let obs_ref = obs.obs(); chanlun::algorithm::segment::线段::获取所有停顿位置(&段.borrow().inner, &*obs_ref) .into_iter() - .map(|d| 虚线Py { inner: Rc::new(d) }) + .map(|d| 虚线Py { inner: Arc::new(d) }) .collect() } @@ -1044,12 +1075,13 @@ impl 线段Py { _cls: &Bound<'_, PyType>, 当前段: &Bound<'_, 虚线Py>, 观察员: &Bound<'_, 观察者Py>, - ) -> Vec<缠论K线Py> { + py: Python<'_>, + ) -> Vec> { let obs = 观察员.borrow(); let obs_ref = obs.obs(); chanlun::algorithm::segment::线段::是否背驰过(&当前段.borrow().inner, &*obs_ref) .into_iter() - .map(|ck| 缠论K线Py::from_rc(ck)) + .map(|ck| chan_kline_to_py(py, ck)) .collect() } } @@ -1093,10 +1125,10 @@ impl 线段Py { /// 向中枢序列尾部添加(中枢序列, 新中枢) — 维护中枢序列顺序 /// 从中枢序列尾部弹出(中枢序列, 配置) — 弹出最后一个中枢并更新相邻中枢 /// 分析(虚线序列, 中枢序列容器, 允许重叠?, 标识前缀?, ...) — 中枢分析主流程 -#[pyclass(name = "中枢", module = "chanlun._chanlun", unsendable, from_py_object)] +#[pyclass(name = "中枢", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 中枢Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -1105,12 +1137,12 @@ impl 中枢Py { fn new( 序号: i64, 标识: String, 级别: i64, 基础序列: Vec>, py: Python<'_> ) -> Self { - let rc_list: Vec> = 基础序列 + let rc_list: Vec> = 基础序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); Self { - inner: Rc::new(chanlun::algorithm::hub::中枢::new( + inner: Arc::new(chanlun::algorithm::hub::中枢::new( 序号, 标识, 级别, rc_list, )), } @@ -1118,48 +1150,51 @@ impl 中枢Py { #[getter] fn 序号(&self) -> i64 { - self.inner.序号 + self.inner.序号.load(Ordering::Relaxed) } #[getter] fn 标识(&self) -> String { - self.inner.标识.clone() + self.inner.标识.read().unwrap().clone() } #[getter] fn 级别(&self) -> i64 { - self.inner.级别 + self.inner.级别.load(Ordering::Relaxed) } #[getter] fn 基础序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for d in &self.inner.基础序列 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + for d in self.inner.基础序列.read().unwrap().iter() { + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } #[getter] - fn 第三买卖线(&self) -> Option<虚线Py> { - self.inner.第三买卖线.as_ref().map(|d| 虚线Py { - inner: Rc::clone(d), - }) + fn 第三买卖线(&self, py: Python<'_>) -> Option> { + self.inner + .第三买卖线 + .read() + .unwrap() + .as_ref() + .map(|d| dashed_to_py(py, Arc::clone(d))) } #[getter] - fn 本级_第三买卖线(&self) -> Option<虚线Py> { - self.inner.本级_第三买卖线.as_ref().map(|d| 虚线Py { - inner: Rc::clone(d), - }) + fn 本级_第三买卖线(&self, py: Python<'_>) -> Option> { + self.inner + .本级_第三买卖线 + .read() + .unwrap() + .as_ref() + .map(|d| dashed_to_py(py, Arc::clone(d))) } /// 向中枢添加新虚线(延伸),重置第三买卖线 - fn 添加虚线(&mut self, 实线: &Bound<'_, 虚线Py>) { - let inner = Rc::make_mut(&mut self.inner); - inner.添加虚线(Rc::clone(&实线.borrow().inner)); + fn 添加虚线(&self, 实线: &Bound<'_, 虚线Py>) { + self.inner.添加虚线(Arc::clone(&实线.borrow().inner)); } #[getter] @@ -1170,10 +1205,8 @@ impl 中枢Py { #[getter] /// :return: 最后一条虚线 - fn 离开段(&self) -> 虚线Py { - 虚线Py { - inner: self.inner.离开段(), - } + fn 离开段(&self, py: Python<'_>) -> Py<虚线Py> { + dashed_to_py(py, self.inner.离开段()) } #[getter] @@ -1210,24 +1243,20 @@ impl 中枢Py { #[getter] /// :return: 起点分型 - fn 文(&self) -> 分型Py { - 分型Py { - inner: self.inner.文(), - } + fn 文(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, self.inner.文()) } #[getter] /// :return: 终点分型 - fn 武(&self) -> 分型Py { - 分型Py { - inner: self.inner.武(), - } + fn 武(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, self.inner.武()) } /// 设置第三类买卖点关联虚线 fn 设置第三买卖线(&mut self, 线: &Bound<'_, 虚线Py>) { - let inner = Rc::make_mut(&mut self.inner); - inner.设置第三买卖线(Rc::clone(&线.borrow().inner)); + let inner = Arc::make_mut(&mut self.inner); + inner.设置第三买卖线(Arc::clone(&线.borrow().inner)); } /// 获取中枢的完整虚线序列(基础序列+第三买卖线) @@ -1253,11 +1282,11 @@ impl 中枢Py { py: Python<'_>, ) -> bool { let _ = 中枢序列; // Python 版声明了此参数但未使用 - let rc_list: Vec> = 序列 + let rc_list: Vec> = 序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let inner = Rc::make_mut(&mut self.inner); + let inner = Arc::make_mut(&mut self.inner); inner.校验合法性(&rc_list) } @@ -1274,9 +1303,9 @@ impl 中枢Py { 配置: &Bound<'_, crate::config_py::缠论配置Py>, py: Python<'_>, ) -> PyResult<()> { - let mut hub_seq: Vec> = 扩展中枢 + let mut hub_seq: Vec> = 扩展中枢 .iter() - .map(|h| Rc::clone(&h.bind(py).borrow().inner)) + .map(|h| Arc::clone(&h.bind(py).borrow().inner)) .collect(); let config = 配置.borrow().to_rust_config(配置.py())?; self.inner.获取扩展中枢(&mut hub_seq, &config); @@ -1315,13 +1344,13 @@ impl 中枢Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } // ---- classmethods ---- @@ -1353,10 +1382,10 @@ impl 中枢Py { 标识: &str, ) -> Self { Self { - inner: Rc::new(chanlun::algorithm::hub::中枢::创建( - Rc::clone(&左.borrow().inner), - Rc::clone(&中.borrow().inner), - Rc::clone(&右.borrow().inner), + inner: Arc::new(chanlun::algorithm::hub::中枢::创建( + Arc::clone(&左.borrow().inner), + Arc::clone(&中.borrow().inner), + Arc::clone(&右.borrow().inner), 级别, 标识, )), @@ -1372,9 +1401,9 @@ impl 中枢Py { 标识: &str, py: Python<'_>, ) -> Option { - let rc_list: Vec> = 虚线序列 + let rc_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::algorithm::hub::中枢::从序列中获取中枢( &rc_list, @@ -1391,7 +1420,7 @@ impl 中枢Py { 中枢序列: &Bound<'_, PyAny>, 待添加中枢: &Bound<'_, Self>, ) -> PyResult<()> { - let inner = Rc::clone(&待添加中枢.borrow().inner); + let inner = Arc::clone(&待添加中枢.borrow().inner); let wrapper = Py::new(中枢序列.py(), Self { inner })?; 中枢序列.call_method1("append", (wrapper,))?; Ok(()) @@ -1410,7 +1439,7 @@ impl 中枢Py { } let bound: Bound<'_, Self> = result.extract()?; Ok(Some(Self { - inner: Rc::clone(&bound.borrow().inner), + inner: Arc::clone(&bound.borrow().inner), })) } @@ -1426,13 +1455,13 @@ impl 中枢Py { 层级: i64, py: Python<'_>, ) -> PyResult<()> { - let rc_list: Vec> = 虚线序列 + let rc_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); - let mut hub_seq: Vec> = 中枢序列 + let mut hub_seq: Vec> = 中枢序列 .iter() - .map(|h| Rc::clone(&h.bind(py).borrow().inner)) + .map(|h| Arc::clone(&h.bind(py).borrow().inner)) .collect(); chanlun::algorithm::hub::中枢::分析(&rc_list, &mut hub_seq, 跳过首部, 标识, 层级); Ok(()) diff --git a/chanlun-py/src/business_py.rs b/chanlun-py/src/business_py.rs index ae8afa4..561a1b2 100644 --- a/chanlun-py/src/business_py.rs +++ b/chanlun-py/src/business_py.rs @@ -24,9 +24,13 @@ use pyo3::prelude::*; use pyo3::types::{PyDict, PyType}; -use std::cell::RefCell; +use std::sync::RwLock; + +use crate::algorithm_py::hub_to_py; +use crate::kline_py::bar_to_py; +use crate::structure_py::{dashed_to_py, fractal_to_py}; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; use crate::algorithm_py::中枢Py; use crate::config_py::缠论配置Py; @@ -44,12 +48,7 @@ use crate::types_py::买卖点类型Py; /// 有效性: bool — 买卖点是否仍有效 /// 与MACD柱子匹配: bool|None — 是否与MACD柱状图方向匹配 /// 与MACD柱子分型匹配: bool|None — 是否与MACD柱分型匹配 -#[pyclass( - name = "基础买卖点", - module = "chanlun._chanlun", - unsendable, - from_py_object -)] +#[pyclass(name = "基础买卖点", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 基础买卖点Py { pub(crate) inner: chanlun::business::bsp::基础买卖点, @@ -69,7 +68,7 @@ impl 基础买卖点Py { inner: chanlun::business::bsp::基础买卖点::new( 类型.borrow().inner, 当前K线.borrow().inner.clone(), - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 备注, 中枢破位值, ), @@ -97,35 +96,35 @@ impl 基础买卖点Py { #[getter] fn 买卖点分型(&self) -> 分型Py { 分型Py { - inner: Rc::clone(&self.inner.买卖点分型), + inner: Arc::clone(&self.inner.买卖点分型), } } #[getter] - fn 买卖点K线(&self) -> 缠论K线Py { - 缠论K线Py::from_rc(Rc::clone(&self.inner.买卖点K线)) + fn 买卖点K线(&self, py: Python<'_>) -> Py<缠论K线Py> { + crate::kline_py::chan_kline_to_py(py, Arc::clone(&self.inner.买卖点K线)) } #[getter] /// 当前K线 - fn 当前K线(&self) -> K线Py { - K线Py { - inner: self.inner.当前K线.clone(), - } + fn 当前K线(&self, py: Python<'_>) -> Py { + bar_to_py(py, self.inner.当前K线.clone()) } #[getter] - fn 失效K线(&self) -> Option { - self.inner.失效K线.as_ref().map(|k| K线Py { - inner: Rc::clone(k), - }) + fn 失效K线(&self, py: Python<'_>) -> Option> { + self.inner + .失效K线 + .as_ref() + .map(|k| bar_to_py(py, Arc::clone(k))) } #[getter] - fn 终结K线(&self) -> Option { - self.inner.终结K线.as_ref().map(|k| K线Py { - inner: Rc::clone(k), - }) + fn 终结K线(&self, py: Python<'_>) -> Option> { + self.inner + .终结K线 + .as_ref() + .map(|k| bar_to_py(py, Arc::clone(k))) } #[getter] @@ -223,7 +222,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::一卖点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -244,7 +243,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::一买点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -265,7 +264,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::二卖点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -286,7 +285,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::二买点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -307,7 +306,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::三卖点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -328,7 +327,7 @@ impl 买卖点Py { ) -> 基础买卖点Py { 基础买卖点Py { inner: chanlun::business::bsp::买卖点::三买点( - Rc::clone(&买卖点分型.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), 当前K线.borrow().inner.clone(), 标识, 备注, @@ -352,8 +351,8 @@ impl 买卖点Py { 特征, 序号, 级别, - Rc::clone(&买卖点分型.borrow().inner), - Rc::clone(&当前缠K.borrow().inner), + Arc::clone(&买卖点分型.borrow().inner), + Arc::clone(&当前缠K.borrow().inner), ), } } @@ -390,24 +389,30 @@ impl 买卖点Py { /// 调试方法: /// 测试_保存数据(root?) — 将各层级序列保存到文件,用于与Python版对比 /// 读取数据文件(文件路径, 配置) -> 观察者 (classmethod) — 从 .nb 文件加载数据 -#[pyclass(name = "观察者", module = "chanlun._chanlun", subclass, unsendable)] +#[pyclass(name = "观察者", module = "chanlun._chanlun", subclass)] pub struct 观察者Py { - pub(crate) inner: Option>>, + pub(crate) inner: Option>>, } impl 观察者Py { - pub(crate) fn obs(&self) -> std::cell::Ref<'_, chanlun::business::observer::观察者> { + pub(crate) fn obs( + &self, + ) -> std::sync::RwLockReadGuard<'_, chanlun::business::observer::观察者> { self.inner .as_ref() .expect("观察者 尚未初始化,请通过 __init__(符号, 周期, 配置) 构造") - .borrow() + .read() + .unwrap_or_else(|e| e.into_inner()) } - pub(crate) fn obs_mut(&self) -> std::cell::RefMut<'_, chanlun::business::observer::观察者> { + pub(crate) fn obs_mut( + &self, + ) -> std::sync::RwLockWriteGuard<'_, chanlun::business::observer::观察者> { self.inner .as_ref() .expect("观察者 尚未初始化,请通过 __init__(符号, 周期, 配置) 构造") - .borrow_mut() + .write() + .unwrap_or_else(|e| e.into_inner()) } } @@ -492,18 +497,16 @@ impl 观察者Py { #[getter] /// :return: 最后一根原始K线 - fn 当前K线(&self) -> Option { - self.obs().当前K线().map(|k| K线Py { - inner: Rc::clone(k), - }) + fn 当前K线(&self, py: Python<'_>) -> Option> { + self.obs().当前K线().map(|k| bar_to_py(py, Arc::clone(k))) } #[getter] /// :return: 最后一根缠论K线 - fn 当前缠K(&self) -> Option<缠论K线Py> { + fn 当前缠K(&self, py: Python<'_>) -> Option> { self.obs() .当前缠K() - .map(|k| 缠论K线Py::from_rc(Rc::clone(k))) + .map(|k| crate::kline_py::chan_kline_to_py(py, Arc::clone(k))) } #[getter] @@ -551,7 +554,7 @@ impl 观察者Py { let k线_py = Py::new( py, K线Py { - inner: Rc::new(k线), + inner: Arc::new(k线), }, )?; slf.call_method1("增加原始K线", (k线_py,))?; @@ -564,6 +567,7 @@ impl 观察者Py { self.obs_mut().静态重新分析(); } + #[pyo3(signature = (root = None))] /// 拆分各序列数据,单独存文件,文件名为对应变量名 fn 测试_保存数据(&self, root: Option<&str>) { self.obs().测试_保存数据(root); @@ -618,7 +622,7 @@ impl 观察者Py { let k线_py = Py::new( py, K线Py { - inner: Rc::new(k线), + inner: Arc::new(k线), }, )?; obj.call_method1("增加原始K线", (k线_py,))?; @@ -634,18 +638,38 @@ impl 观察者Py { fn 普通K线序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for k in &self.obs().普通K线序列 { - list.append(K线Py { - inner: Rc::clone(k), - })?; + list.append(bar_to_py(py, Arc::clone(k)))?; } Ok(list.into()) } + #[getter] + fn 基础缠K序列(&self, py: Python<'_>) -> PyResult> { + let list = pyo3::types::PyList::empty(py); + for k in &self.obs().基础缠K序列 { + list.append(crate::kline_py::chan_kline_to_py(py, Arc::clone(k)))?; + } + Ok(list.into()) + } + + #[setter] + #[pyo3(name = "基础缠K序列")] + fn 设置_基础缠K序列(&mut self, value: &Bound<'_, PyAny>) -> PyResult<()> { + let list: &Bound<'_, pyo3::types::PyList> = value.cast()?; + let mut vec = Vec::new(); + for item in list { + let 缠k: PyRef<'_, 缠论K线Py> = item.extract()?; + vec.push(Arc::clone(&缠k.inner)); + } + self.obs_mut().基础缠K序列 = vec; + Ok(()) + } + #[getter] fn 缠论K线序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for k in &self.obs().缠论K线序列 { - list.append(缠论K线Py::from_rc(Rc::clone(k)))?; + list.append(crate::kline_py::chan_kline_to_py(py, Arc::clone(k)))?; } Ok(list.into()) } @@ -654,9 +678,7 @@ impl 观察者Py { fn 分型序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for f in &self.obs().分型序列 { - list.append(分型Py { - inner: Rc::clone(f), - })?; + list.append(fractal_to_py(py, Arc::clone(f)))?; } Ok(list.into()) } @@ -665,9 +687,7 @@ impl 观察者Py { fn 笔序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().笔序列 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -676,9 +696,7 @@ impl 观察者Py { fn 笔_中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().笔_中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -687,9 +705,7 @@ impl 观察者Py { fn 线段序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().线段序列 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -698,9 +714,7 @@ impl 观察者Py { fn 中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -709,9 +723,7 @@ impl 观察者Py { fn 扩展线段序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().扩展线段序列 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -720,9 +732,7 @@ impl 观察者Py { fn 扩展中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().扩展中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -731,9 +741,7 @@ impl 观察者Py { fn 扩展线段序列_线段(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().扩展线段序列_线段 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -742,9 +750,7 @@ impl 观察者Py { fn 扩展中枢序列_线段(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().扩展中枢序列_线段 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -753,9 +759,7 @@ impl 观察者Py { fn 线段_线段序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().线段_线段序列 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -764,9 +768,7 @@ impl 观察者Py { fn 线段_中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().线段_中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -775,9 +777,7 @@ impl 观察者Py { fn 扩展线段序列_扩展线段(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.obs().扩展线段序列_扩展线段 { - list.append(虚线Py { - inner: Rc::clone(d), - })?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -786,9 +786,7 @@ impl 观察者Py { fn 扩展中枢序列_扩展线段(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for h in &self.obs().扩展中枢序列_扩展线段 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -806,7 +804,7 @@ impl 观察者Py { /// 投喂(时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量) -> list[(周期, K线)] /// — 快捷入口,免去构造K线对象 /// 获取当前K线(周期) -> K线|None — 获取指定周期的当前合成结果 -#[pyclass(name = "K线合成器", module = "chanlun._chanlun", unsendable)] +#[pyclass(name = "K线合成器", module = "chanlun._chanlun")] pub struct K线合成器Py { pub(crate) inner: chanlun::business::synthesizer::K线合成器, } @@ -829,7 +827,7 @@ impl K线合成器Py { let results = self.inner.投喂K线((*普K.borrow().inner).clone()); Ok(results .into_iter() - .map(|(周期, k)| (周期, K线Py { inner: Rc::new(k) })) + .map(|(周期, k)| (周期, K线Py { inner: Arc::new(k) })) .collect()) } @@ -858,14 +856,21 @@ impl K线合成器Py { let results = self.inner.投喂K线(k); results .into_iter() - .map(|(周期, k2)| (周期, K线Py { inner: Rc::new(k2) })) + .map(|(周期, k2)| { + ( + 周期, + K线Py { + inner: Arc::new(k2), + }, + ) + }) .collect() } /// 获取指定周期当前正在合成的K线 fn 获取当前K线(&self, 周期: i64) -> Option { self.inner.获取当前K线(周期).map(|k| K线Py { - inner: Rc::new(k.clone()), + inner: Arc::new(k.clone()), }) } @@ -893,7 +898,7 @@ impl K线合成器Py { /// 方法: /// 投喂K线(普K) — 喂入最小周期K线,自动合成大周期并分发给各周期观察者 /// 测试_保存数据(root?) — 保存各周期的分析数据到文件 -#[pyclass(name = "立体分析器", module = "chanlun._chanlun", unsendable)] +#[pyclass(name = "立体分析器", module = "chanlun._chanlun")] pub struct 立体分析器Py { pub(crate) inner: chanlun::business::multi_frame::立体分析器, } diff --git a/chanlun-py/src/config_py.rs b/chanlun-py/src/config_py.rs index 7cdc325..20f7d2b 100644 --- a/chanlun-py/src/config_py.rs +++ b/chanlun-py/src/config_py.rs @@ -183,20 +183,16 @@ impl 缠论配置Py { } /// 保存配置到 JSON 文件(默认路径 "缠论配置.json")。 - fn 保存配置(&self, py: Python<'_>, path: Option<&str>) -> PyResult<()> { - let path = path.unwrap_or("缠论配置.json"); + #[pyo3(signature = (path = "缠论配置.json"))] + fn 保存配置(&self, py: Python<'_>, path: &str) -> PyResult<()> { let json = self.to_json(py)?; std::fs::write(path, json).map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string())) } /// 从 JSON 文件加载配置(默认路径 "缠论配置.json")。 #[classmethod] - fn 加载配置( - _cls: &Bound<'_, PyType>, - py: Python<'_>, - path: Option<&str>, - ) -> PyResult { - let path = path.unwrap_or("缠论配置.json"); + #[pyo3(signature = (path = "缠论配置.json"))] + fn 加载配置(_cls: &Bound<'_, PyType>, py: Python<'_>, path: &str) -> PyResult { let json_str = std::fs::read_to_string(path) .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))?; Self::from_json_str(py, &json_str) @@ -336,11 +332,104 @@ fn dict_to_rust_config( let mut value: serde_json::Value = serde_json::from_str(&json_str) .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("配置转换失败: {e}")))?; coerce_strings_to_numbers(&mut value); - serde_json::from_value(value) + + // 获取默认配置的 JSON 表示作为 schema + let default_config = chanlun::config::缠论配置::default(); + let default_json = serde_json::to_value(&default_config) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("配置转换失败: {e}")))?; + + // 用默认值做基准,只合并类型匹配的字段 + let mut merged = default_json.clone(); + if let serde_json::Value::Object(ref input_map) = value { + if let serde_json::Value::Object(ref default_map) = default_json { + for (key, input_val) in input_map { + if let Some(default_val) = default_map.get(key) { + match validate_field(key, input_val, default_val) { + Ok(()) => { + merged[key] = input_val.clone(); + } + Err(msg) => { + eprintln!("\x1b[33m[配置警告]\x1b[m {key}: {msg},已使用默认值 {default_val}"); + } + } + } + } + } + } + + serde_json::from_value(merged) .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("配置转换失败: {e}"))) }) } +/// 字符串字段的有效值集合 +fn valid_string_values(field: &str) -> Option<&'static [&'static str]> { + match field { + "指标计算方式" => Some(&[ + "开", + "高", + "低", + "收", + "高低均值", + "高低收均值", + "开高低收均值", + ]), + "买卖点_指标模式" => Some(&["任意", "配置", "全量", "相对"]), + "线段内部背驰_模式" => Some(&["任意", "配置", "全量", "相对"]), + _ => None, + } +} + +/// 验证单个字段的值是否与默认值类型兼容 +fn validate_field( + key: &str, + input: &serde_json::Value, + default: &serde_json::Value, +) -> Result<(), String> { + use serde_json::Value; + + // 输入为 null → 跳过(保留默认) + if input.is_null() { + return Err("值为 null".into()); + } + + // 字符串字段:检查有效值白名单 + if default.is_string() && input.is_string() { + if let Some(valid) = valid_string_values(key) { + let s = input.as_str().unwrap(); + if !valid.contains(&s) { + return Err(format!("\"{s}\" 不在有效值 {valid:?} 内")); + } + } + return Ok(()); + } + + // 类型匹配:直接通过 + match (default, input) { + (Value::Bool(_), Value::Bool(_)) => return Ok(()), + (Value::Number(_), Value::Number(_)) => return Ok(()), + (Value::String(_), Value::String(_)) => return Ok(()), + _ => {} + } + + // 类型不匹配 + let type_name = match input { + Value::Bool(_) => "布尔", + Value::Number(_) => "数值", + Value::String(_) => "字符串", + Value::Array(_) => "数组", + Value::Object(_) => "字典", + Value::Null => "null", + }; + let expected = match default { + Value::Bool(_) => "布尔", + Value::Number(_) => "数值", + Value::String(_) => "字符串", + _ => "其他", + }; + Err(format!("类型不匹配(需要 {expected},收到 {type_name})")) +} + /// 递归遍历 JSON Value,将数字/布尔字符串转为对应类型。 fn coerce_strings_to_numbers(value: &mut serde_json::Value) { match value { diff --git a/chanlun-py/src/kline_py.rs b/chanlun-py/src/kline_py.rs index 32d96d7..752eab8 100644 --- a/chanlun-py/src/kline_py.rs +++ b/chanlun-py/src/kline_py.rs @@ -25,7 +25,9 @@ use pyo3::prelude::*; use pyo3::types::{PyBytes, PyDict, PyType}; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::sync::RwLock; use crate::config_py::缠论配置Py; use crate::indicators_py::{平滑异同移动平均线Py, 相对强弱指数Py, 随机指标Py}; @@ -52,9 +54,9 @@ use crate::types_py::相对方向Py; /// 获取MACD(K线序列, 计算方式, 快线周期?, 慢线周期?, 信号周期?) -> list[平滑异同移动平均线] /// — 对整个K线序列批量计算 MACD /// 截取(序列, 起点K线, 终点K线) -> list — 按时间戳截取K线区间 -#[pyclass(name = "K线", module = "chanlun._chanlun", unsendable)] +#[pyclass(name = "K线", module = "chanlun._chanlun")] pub struct K线Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -73,7 +75,7 @@ impl K线Py { 成交量: f64, ) -> Self { Self { - inner: Rc::new(chanlun::kline::bar::K线 { + inner: Arc::new(chanlun::kline::bar::K线 { 标识: 标识.to_string(), 序号, 周期, @@ -94,82 +96,46 @@ impl K线Py { fn 标识(&self) -> String { self.inner.标识.clone() } - #[setter] - fn set_标识(&mut self, v: String) { - Rc::make_mut(&mut self.inner).标识 = v; - } #[getter] fn 序号(&self) -> i64 { self.inner.序号 } - #[setter] - fn set_序号(&mut self, v: i64) { - Rc::make_mut(&mut self.inner).序号 = v; - } #[getter] fn 周期(&self) -> i64 { self.inner.周期 } - #[setter] - fn set_周期(&mut self, v: i64) { - Rc::make_mut(&mut self.inner).周期 = v; - } #[getter] fn 时间戳(&self) -> i64 { self.inner.时间戳 } - #[setter] - fn set_时间戳(&mut self, v: i64) { - Rc::make_mut(&mut self.inner).时间戳 = v; - } #[getter] fn 高(&self) -> f64 { self.inner.高 } - #[setter] - fn set_高(&mut self, v: f64) { - Rc::make_mut(&mut self.inner).高 = v; - } #[getter] fn 低(&self) -> f64 { self.inner.低 } - #[setter] - fn set_低(&mut self, v: f64) { - Rc::make_mut(&mut self.inner).低 = v; - } #[getter] fn 开盘价(&self) -> f64 { self.inner.开盘价 } - #[setter] - fn set_开盘价(&mut self, v: f64) { - Rc::make_mut(&mut self.inner).开盘价 = v; - } #[getter] fn 收盘价(&self) -> f64 { self.inner.收盘价 } - #[setter] - fn set_收盘价(&mut self, v: f64) { - Rc::make_mut(&mut self.inner).收盘价 = v; - } #[getter] fn 成交量(&self) -> f64 { self.inner.成交量 } - #[setter] - fn set_成交量(&mut self, v: f64) { - Rc::make_mut(&mut self.inner).成交量 = v; - } #[getter] /// :return: 相对方向.向上(开盘<收盘)或 相对方向.向下(开盘>收盘) @@ -243,13 +209,13 @@ impl K线Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } #[classmethod] @@ -268,7 +234,7 @@ impl K线Py { 周期: Option, ) -> Self { Self { - inner: Rc::new(chanlun::kline::bar::K线::创建普K( + inner: Arc::new(chanlun::kline::bar::K线::创建普K( 标识, 时间戳, 开盘价, @@ -306,7 +272,7 @@ impl K线Py { ) -> Option { chanlun::kline::bar::K线::读取大端字节数组(字节组.as_bytes(), 周期, 标识).map(|inner| { Self { - inner: Rc::new(inner), + inner: Arc::new(inner), } }) } @@ -333,21 +299,21 @@ impl K线Py { 终: &Bound<'_, Self>, py: Python<'_>, ) -> PyResult>> { - let start_ptr = Rc::as_ptr(&始.borrow().inner); - let end_ptr = Rc::as_ptr(&终.borrow().inner); + let start_ptr = Arc::as_ptr(&始.borrow().inner); + let end_ptr = Arc::as_ptr(&终.borrow().inner); let start_ts = 始.borrow().inner.时间戳; let end_ts = 终.borrow().inner.时间戳; let start_idx = 序列 .iter() .position(|k| { - Rc::as_ptr(&k.borrow(py).inner) == start_ptr + Arc::as_ptr(&k.borrow(py).inner) == start_ptr || k.borrow(py).inner.时间戳 == start_ts }) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("始 不在序列中"))?; let end_idx = 序列 .iter() .position(|k| { - Rc::as_ptr(&k.borrow(py).inner) == end_ptr || k.borrow(py).inner.时间戳 == end_ts + Arc::as_ptr(&k.borrow(py).inner) == end_ptr || k.borrow(py).inner.时间戳 == end_ts }) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("终 不在序列中"))?; if start_idx > end_idx { @@ -380,31 +346,71 @@ impl K线Py { /// 分析(缠K序列, 配置, 可以逆序包含?, 忽视顺序包含?, 可以逆序包含新?) -> (str, 分型|None) /// — 分析分型形成结果 /// 截取(序列, 起点分型, 终点分型) -> list — 截取分型间的缠K子序列 -#[pyclass( - name = "缠论K线", - module = "chanlun._chanlun", - unsendable, - from_py_object -)] +#[pyclass(name = "缠论K线", module = "chanlun._chanlun", from_py_object)] pub struct 缠论K线Py { - pub(crate) inner: std::rc::Rc, - bsp_set: std::cell::RefCell>>, + pub(crate) inner: std::sync::Arc, + bsp_set: std::sync::RwLock>>, } impl 缠论K线Py { - pub(crate) fn from_rc(inner: std::rc::Rc) -> Self { + pub(crate) fn from_rc(inner: std::sync::Arc) -> Self { Self { inner, - bsp_set: std::cell::RefCell::new(None), + bsp_set: std::sync::RwLock::new(None), } } } +thread_local! { + /// 对象标识缓存:Rc 地址 → 规范 Python 对象 + /// 确保同一底层 Rc 指针在 Python 侧始终映射到同一 PyObject + + static BAR_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); + + static KLINE_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); +} + +/// 将 Rc 转为 Py,确保同一 Rc 地址总是返回同一 Python 对象 +pub(crate) fn bar_to_py( + py: Python<'_>, + inner: std::sync::Arc, +) -> Py { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + BAR_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + let obj = Py::new(py, K线Py { inner }).unwrap(); + BAR_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} + +/// 将 Rc<缠论K线> 转为 Py<缠论K线Py>,确保同一 Rc 地址总是返回同一 Python 对象 +pub(crate) fn chan_kline_to_py( + py: Python<'_>, + inner: std::sync::Arc, +) -> Py<缠论K线Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + KLINE_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + let obj = Py::new(py, 缠论K线Py::from_rc(inner)).unwrap(); + KLINE_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} + impl Clone for 缠论K线Py { fn clone(&self) -> Self { Self { - inner: std::rc::Rc::clone(&self.inner), - bsp_set: std::cell::RefCell::new(None), + inner: std::sync::Arc::clone(&self.inner), + bsp_set: std::sync::RwLock::new(None), } } } @@ -418,28 +424,28 @@ impl 缠论K线Py { #[getter] fn 序号(&self) -> i64 { - self.inner.序号 + self.inner.序号.load(Ordering::Relaxed) } #[getter] fn 时间戳(&self) -> i64 { - self.inner.时间戳 + self.inner.时间戳.load(Ordering::Relaxed) } #[getter] fn 高(&self) -> f64 { - self.inner.高 + self.inner.高.get() } #[getter] fn 低(&self) -> f64 { - self.inner.低 + self.inner.低.get() } #[getter] fn 方向(&self) -> 相对方向Py { 相对方向Py { - inner: self.inner.方向, + inner: *self.inner.方向.read().unwrap(), } } @@ -447,6 +453,8 @@ impl 缠论K线Py { fn 分型(&self) -> Option { self.inner .分型 + .read() + .unwrap() .map(|f| crate::types_py::分型结构Py { inner: f }) } @@ -462,7 +470,7 @@ impl 缠论K线Py { #[getter] fn 分型特征值(&self) -> f64 { - self.inner.分型特征值 + self.inner.分型特征值.get() } #[getter] @@ -472,14 +480,12 @@ impl 缠论K线Py { #[getter] fn 原始结束序号(&self) -> i64 { - self.inner.原始结束序号 + self.inner.原始结束序号.load(Ordering::Relaxed) } #[getter] - fn 标的K线(&self) -> K线Py { - K线Py { - inner: self.inner.标的K线.clone(), - } + fn 标的K线(&self, py: Python<'_>) -> Py { + bar_to_py(py, self.inner.标的K线.read().unwrap().clone()) } /// pandas 兼容 — 返回所有字段构成的字典 @@ -516,28 +522,28 @@ impl 缠论K线Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } #[getter] /// 创建当前缠K的浅拷贝副本 fn 镜像(&self, py: Python<'_>) -> Self { let mut mirror = Self { - inner: std::rc::Rc::new(self.inner.镜像()), - bsp_set: std::cell::RefCell::new(None), + inner: std::sync::Arc::new(self.inner.镜像()), + bsp_set: std::sync::RwLock::new(None), }; - if let Some(ref src_set) = *self.bsp_set.borrow() { + if let Some(ref src_set) = *self.bsp_set.read().unwrap() { if let Ok(new_set) = pyo3::types::PySet::empty(py) { for item in src_set.bind(py).iter() { let _ = new_set.add(item); } - mirror.bsp_set = std::cell::RefCell::new(Some(new_set.into())); + mirror.bsp_set = std::sync::RwLock::new(Some(new_set.into())); } } mirror @@ -563,16 +569,17 @@ impl 缠论K线Py { #[getter] fn 买卖点信息(&self, py: Python<'_>) -> PyResult> { - if self.bsp_set.borrow().is_none() { + if self.bsp_set.read().unwrap().is_none() { let set = pyo3::types::PySet::empty(py)?; - for s in self.inner.买卖点信息.borrow().iter() { + for s in self.inner.买卖点信息.read().unwrap().iter() { set.add(s.clone())?; } - *self.bsp_set.borrow_mut() = Some(set.into()); + *self.bsp_set.write().unwrap() = Some(set.into()); } Ok(self .bsp_set - .borrow() + .read() + .unwrap() .as_ref() .unwrap() .clone_ref(py) @@ -589,12 +596,13 @@ impl 缠论K线Py { ) -> i64 { let rc_list: Vec<_> = 基线 .iter() - .map(|k| std::rc::Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| std::sync::Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::kline::chan_kline::缠论K线::时间戳对齐(&rc_list, &k线.borrow().inner) } #[classmethod] + #[pyo3(signature = (时间戳, 高, 低, 方向, 结构, 原始序号, 普k, 之前 = None))] /// 创建新的缠论K线 fn 创建缠K( _cls: &Bound<'_, PyType>, @@ -606,7 +614,8 @@ impl 缠论K线Py { 原始序号: i64, 普k: &Bound<'_, K线Py>, 之前: Option<&Bound<'_, Self>>, - ) -> Self { + py: Python<'_>, + ) -> Py { let prev_ref = 之前.map(|prev| prev.borrow()); let prev_inner = prev_ref.as_ref().map(|r| r.inner.as_ref()); let inner = chanlun::kline::chan_kline::缠论K线::创建缠K( @@ -619,7 +628,7 @@ impl 缠论K线Py { 普k.borrow().inner.clone(), prev_inner, ); - Self::from_rc(std::rc::Rc::new(inner)) + chan_kline_to_py(py, std::sync::Arc::new(inner)) } #[classmethod] @@ -631,7 +640,7 @@ impl 缠论K线Py { 当前普K: &Bound<'_, K线Py>, 配置: &Bound<'_, 缠论配置Py>, py: Python<'_>, - ) -> PyResult<(Option, Option)> { + ) -> PyResult<(Option>, Option)> { let mut ck_inner = (*当前缠K.borrow().inner).clone(); let config = 配置.borrow().to_rust_config(py)?; let prev_ref = 之前缠K.map(|prev| prev.borrow()); @@ -642,7 +651,7 @@ impl 缠论K线Py { &当前普K.borrow().inner, &config, ); - Ok((result.map(Self::from_rc), mode)) + Ok((result.map(|rc| chan_kline_to_py(py, rc)), mode)) } #[classmethod] @@ -660,7 +669,7 @@ impl 缠论K线Py { let mut ck_seq: Vec<_> = 缠K序列 .iter() - .map(|k| std::rc::Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| std::sync::Arc::clone(&k.bind(py).borrow().inner)) .collect(); let mut bar_seq: Vec<_> = 普K序列 .iter() @@ -685,21 +694,22 @@ impl 缠论K线Py { 终: &Bound<'_, Self>, py: Python<'_>, ) -> PyResult>> { - let start_ptr = Rc::as_ptr(&始.borrow().inner); - let end_ptr = Rc::as_ptr(&终.borrow().inner); - let start_ts = 始.borrow().inner.时间戳; - let end_ts = 终.borrow().inner.时间戳; + let start_ptr = Arc::as_ptr(&始.borrow().inner); + let end_ptr = Arc::as_ptr(&终.borrow().inner); + let start_ts = 始.borrow().inner.时间戳.load(Ordering::Relaxed); + let end_ts = 终.borrow().inner.时间戳.load(Ordering::Relaxed); let start_idx = 序列 .iter() .position(|k| { - Rc::as_ptr(&k.borrow(py).inner) == start_ptr - || k.borrow(py).inner.时间戳 == start_ts + Arc::as_ptr(&k.borrow(py).inner) == start_ptr + || k.borrow(py).inner.时间戳.load(Ordering::Relaxed) == start_ts }) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("始 不在序列中"))?; let end_idx = 序列 .iter() .position(|k| { - Rc::as_ptr(&k.borrow(py).inner) == end_ptr || k.borrow(py).inner.时间戳 == end_ts + Arc::as_ptr(&k.borrow(py).inner) == end_ptr + || k.borrow(py).inner.时间戳.load(Ordering::Relaxed) == end_ts }) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("终 不在序列中"))?; if start_idx > end_idx { diff --git a/chanlun-py/src/structure_py.rs b/chanlun-py/src/structure_py.rs index 45776fd..8d58614 100644 --- a/chanlun-py/src/structure_py.rs +++ b/chanlun-py/src/structure_py.rs @@ -25,11 +25,103 @@ use pyo3::prelude::*; use pyo3::types::{PyDict, PyType}; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::sync::RwLock; -use crate::algorithm_py::中枢Py; +use crate::algorithm_py::{hub_to_py, 中枢Py}; use crate::config_py::缠论配置Py; use crate::kline_py::{缠论K线Py, K线Py}; + +// ---- 身份缓存 (弱引用:通过 refcnt 检测存活,仅缓存持有则视为过期) ---- + +thread_local! { + static FRACTAL_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); + static DASHED_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); + static SEGFEAT_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); + static FEATFRAC_IDENTITY: RwLock>> = RwLock::new(HashMap::new()); +} + +pub(crate) fn fractal_to_py( + py: Python<'_>, + inner: Arc, +) -> Py<分型Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + FRACTAL_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + // 清理 refcnt==1 的过期条目(仅缓存持有,Python 侧已无引用) + FRACTAL_IDENTITY.with(|c| { + c.write().unwrap().retain(|_, v| v.get_refcnt(py) > 1); + }); + let obj = Py::new(py, 分型Py { inner }).unwrap(); + FRACTAL_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} + +pub(crate) fn dashed_to_py( + py: Python<'_>, + inner: Arc, +) -> Py<虚线Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + DASHED_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + DASHED_IDENTITY.with(|c| { + c.write().unwrap().retain(|_, v| v.get_refcnt(py) > 1); + }); + let obj = Py::new(py, 虚线Py { inner }).unwrap(); + DASHED_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} + +pub(crate) fn segfeat_to_py( + py: Python<'_>, + inner: Arc, +) -> Py<线段特征Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + SEGFEAT_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + SEGFEAT_IDENTITY.with(|c| { + c.write().unwrap().retain(|_, v| v.get_refcnt(py) > 1); + }); + let obj = Py::new(py, 线段特征Py { inner }).unwrap(); + SEGFEAT_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} + +pub(crate) fn featfrac_to_py( + py: Python<'_>, + inner: Arc, +) -> Py<特征分型Py> { + let key = Arc::as_ptr(&inner) as usize; + if let Some(cached) = + FEATFRAC_IDENTITY.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py))) + { + return cached; + } + FEATFRAC_IDENTITY.with(|c| { + c.write().unwrap().retain(|_, v| v.get_refcnt(py) > 1); + }); + let obj = Py::new(py, 特征分型Py { inner }).unwrap(); + FEATFRAC_IDENTITY.with(|c| { + c.write().unwrap().insert(key, obj.clone_ref(py)); + }); + obj +} use crate::types_py::{分型结构Py, 相对方向Py, 缺口Py}; // ========== 分型 ========== @@ -47,10 +139,10 @@ use crate::types_py::{分型结构Py, 相对方向Py, 缺口Py}; /// 判断分型(缠K序列, 索引, 配置) -> 分型|None — 在缠K序列中指定位置尝试创建分型 /// 从缠K序列中获取分型(缠K序列, 配置) -> list[分型] — 扫描全序列提取所有分型 /// 向序列中添加(分型序列, 新分型) — 维护分型序列的顺序一致性 -#[pyclass(name = "分型", module = "chanlun._chanlun", unsendable, from_py_object)] +#[pyclass(name = "分型", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 分型Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -62,33 +154,33 @@ impl 分型Py { 右: Option<&Bound<'_, 缠论K线Py>>, ) -> Self { Self { - inner: Rc::new(chanlun::structure::fractal_obj::分型::new( - 左.map(|k| Rc::clone(&k.borrow().inner)), - Rc::clone(&中.borrow().inner), - 右.map(|k| Rc::clone(&k.borrow().inner)), + inner: Arc::new(chanlun::structure::fractal_obj::分型::new( + 左.map(|k| Arc::clone(&k.borrow().inner)), + Arc::clone(&中.borrow().inner), + 右.map(|k| Arc::clone(&k.borrow().inner)), )), } } #[getter] - fn 左(&self) -> Option<缠论K线Py> { + fn 左(&self, py: Python<'_>) -> Option> { self.inner .左 .as_ref() - .map(|k| 缠论K线Py::from_rc(Rc::clone(k))) + .map(|k| crate::kline_py::chan_kline_to_py(py, Arc::clone(k))) } #[getter] - fn 中(&self) -> 缠论K线Py { - 缠论K线Py::from_rc(Rc::clone(&self.inner.中)) + fn 中(&self, py: Python<'_>) -> Py<缠论K线Py> { + crate::kline_py::chan_kline_to_py(py, Arc::clone(&self.inner.中)) } #[getter] - fn 右(&self) -> Option<缠论K线Py> { + fn 右(&self, py: Python<'_>) -> Option> { self.inner .右 .as_ref() - .map(|k| 缠论K线Py::from_rc(Rc::clone(k))) + .map(|k| crate::kline_py::chan_kline_to_py(py, Arc::clone(k))) } #[getter] @@ -118,13 +210,13 @@ impl 分型Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } #[getter] @@ -160,11 +252,11 @@ impl 分型Py { dict.set_item("分型特征值", self.分型特征值())?; dict.set_item("强度", self.强度())?; dict.set_item("与MACD柱子分型匹配", self.与MACD柱子分型匹配())?; - if let Some(v) = self.左() { + if let Some(v) = self.左(py) { dict.set_item("左", v)?; } - dict.set_item("中", self.中())?; - if let Some(v) = self.右() { + dict.set_item("中", self.中(py))?; + if let Some(v) = self.右(py) { dict.set_item("右", v)?; } if let Some(v) = self.关系组() { @@ -196,16 +288,16 @@ impl 分型Py { 中: &Bound<'_, 缠论K线Py>, py: Python<'_>, ) -> Option { - let ck_seq: Vec> = K线序列 + let ck_seq: Vec> = K线序列 .iter() - .map(|k| Rc::clone(&k.bind(py).borrow().inner)) + .map(|k| Arc::clone(&k.bind(py).borrow().inner)) .collect(); chanlun::structure::fractal_obj::分型::从缠K序列中获取分型( &ck_seq, &中.borrow().inner, ) .map(|inner| Self { - inner: Rc::new(inner), + inner: Arc::new(inner), }) } @@ -215,13 +307,7 @@ impl 分型Py { 分型序列: &Bound<'_, PyAny>, 当前分型: &Bound<'_, Self> ) -> PyResult<()> { let py = 分型序列.py(); - let inner = Rc::clone(&当前分型.borrow().inner); - let wrapper = Py::new( - py, - Self { - inner: Rc::clone(&inner), - }, - )?; + let wrapper = fractal_to_py(py, Arc::clone(&当前分型.borrow().inner)); 分型序列.call_method1("append", (wrapper,))?; Ok(()) } @@ -257,10 +343,10 @@ impl 分型Py { /// 计算MACD柱子均值 / 武之全量MACD均值 / 武之MACD均值 / 武之MACD极值 /// 计算K线序列MACD趋向背驰 / 买卖意义 / 计算MACD柱子分段 /// 密集区域按间隔 / 统计MACD行为 -#[pyclass(name = "虚线", module = "chanlun._chanlun", unsendable, from_py_object)] +#[pyclass(name = "虚线", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 虚线Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -276,11 +362,11 @@ impl 虚线Py { 有效性: bool, ) -> Self { Self { - inner: Rc::new(chanlun::structure::dash_line::虚线::new( + inner: Arc::new(chanlun::structure::dash_line::虚线::new( 序号, 标识, - Rc::clone(&文.borrow().inner), - Rc::clone(&武.borrow().inner), + Arc::clone(&文.borrow().inner), + Arc::clone(&武.borrow().inner), 级别, 有效性, )), @@ -291,59 +377,50 @@ impl 虚线Py { #[getter] fn 标识(&self) -> String { - self.inner.标识.clone() + self.inner.标识.read().unwrap().clone() } #[getter] fn 序号(&self) -> i64 { - self.inner.序号 + self.inner.序号.load(Ordering::Relaxed) } #[getter] fn 级别(&self) -> i64 { - self.inner.级别 + self.inner.级别.load(Ordering::Relaxed) } #[getter] - fn 文(&self) -> 分型Py { - 分型Py { - inner: Rc::clone(&self.inner.文), - } + fn 文(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, Arc::clone(&self.inner.文)) } #[getter] - fn 武(&self) -> 分型Py { - 分型Py { - inner: Rc::clone(&self.inner.武), - } + fn 武(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, Arc::clone(&*self.inner.武.read().unwrap())) } #[getter] fn 有效性(&self) -> bool { - self.inner.有效性 + self.inner.有效性.load(Ordering::Relaxed) } #[getter] fn 模式(&self) -> String { - self.inner.模式.clone() + self.inner.模式.read().unwrap().clone() } #[getter] fn _特征序列_显示(&self) -> bool { - self.inner._特征序列_显示 + self.inner._特征序列_显示.load(Ordering::Relaxed) } #[getter] fn 特征序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for item in &self.inner.特征序列 { + for item in self.inner.特征序列.read().unwrap().iter() { match item { - Some(feat) => list.append(Py::new( - py, - 线段特征Py { - inner: Rc::clone(feat), - }, - )?)?, + Some(feat) => list.append(segfeat_to_py(py, Arc::clone(feat)))?, None => { list.append(py.None())?; } @@ -354,27 +431,38 @@ impl 虚线Py { #[getter] fn 短路修正(&self) -> bool { - self.inner.短路修正 + self.inner.短路修正.load(Ordering::Relaxed) } #[getter] - fn 确认K线(&self) -> Option<缠论K线Py> { + fn 确认K线(&self, py: Python<'_>) -> Option> { self.inner .确认K线 + .read() + .unwrap() .as_ref() - .map(|k| 缠论K线Py::from_rc(Rc::clone(k))) + .map(|k| crate::kline_py::chan_kline_to_py(py, Arc::clone(k))) } #[getter] fn 前一缺口(&self) -> Option<缺口Py> { - self.inner.前一缺口.map(|q| 缺口Py { inner: q }) + self.inner + .前一缺口 + .read() + .unwrap() + .map(|q| 缺口Py { inner: q }) } #[getter] fn 前一结束位置(&self) -> Option { - self.inner.前一结束位置.as_ref().map(|d| Self { - inner: Rc::clone(d), - }) + self.inner + .前一结束位置 + .read() + .unwrap() + .as_ref() + .map(|d| Self { + inner: Arc::clone(d), + }) } // ---- 序列 getters ---- @@ -382,11 +470,11 @@ impl 虚线Py { #[getter] fn 基础序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for d in &self.inner.基础序列 { + for d in self.inner.基础序列.read().unwrap().iter() { list.append(Py::new( py, Self { - inner: Rc::clone(d), + inner: Arc::clone(d), }, )?)?; } @@ -396,10 +484,8 @@ impl 虚线Py { #[getter] fn 实_中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for h in &self.inner.实_中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + for h in self.inner.实_中枢序列.read().unwrap().iter() { + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -407,10 +493,8 @@ impl 虚线Py { #[getter] fn 虚_中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for h in &self.inner.虚_中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + for h in self.inner.虚_中枢序列.read().unwrap().iter() { + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -418,10 +502,8 @@ impl 虚线Py { #[getter] fn 合_中枢序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for h in &self.inner.合_中枢序列 { - list.append(中枢Py { - inner: Rc::clone(h), - })?; + for h in self.inner.合_中枢序列.read().unwrap().iter() { + list.append(hub_to_py(py, Arc::clone(h)))?; } Ok(list.into()) } @@ -432,11 +514,11 @@ impl 虚线Py { /// 笔序列 fn 笔序列(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); - for d in self.inner.笔序列() { + for d in self.inner.基础序列.read().unwrap().iter() { list.append(Py::new( py, Self { - inner: Rc::clone(d), + inner: Arc::clone(d), }, )?)?; } @@ -490,7 +572,7 @@ impl 虚线Py { let list = pyo3::types::PyList::empty(观察员.py()); for k in &result { list.append(K线Py { - inner: Rc::clone(k), + inner: Arc::clone(k), })?; } Ok(list.into()) @@ -502,21 +584,21 @@ impl 虚线Py { 观察员: &Bound<'_, crate::business_py::观察者Py>, ) -> PyResult> { let obs_ref = 观察员.borrow(); + let py = 观察员.py(); let observer_inner = obs_ref.obs(); let result = self.inner.获取缠K序列(&observer_inner.缠论K线序列); - let list = pyo3::types::PyList::empty(观察员.py()); + let list = pyo3::types::PyList::empty(py); for k in &result { - list.append(缠论K线Py::from_rc(Rc::clone(k)))?; + list.append(crate::kline_py::chan_kline_to_py(py, Arc::clone(k)))?; } Ok(list.into()) } #[classmethod] /// 递归获取虚线的终点分型(笔直接返回武,线段递归到底层笔的武) - fn 获取_武(_cls: &Bound<'_, PyType>, 实线: &Bound<'_, Self>) -> 分型Py { - 分型Py { - inner: 实线.borrow().inner.获取_武(), - } + fn 获取_武(_cls: &Bound<'_, PyType>, 实线: &Bound<'_, Self>) -> Py<分型Py> { + let py = _cls.py(); + fractal_to_py(py, 实线.borrow().inner.获取_武()) } /// 获取用于保存的数据文本 @@ -535,8 +617,8 @@ impl 虚线Py { dict.set_item("模式", self.模式())?; dict.set_item("短路修正", self.短路修正())?; dict.set_item("图表标题", self.图表标题())?; - dict.set_item("文_时间戳", self.文().时间戳())?; - dict.set_item("武_时间戳", self.武().时间戳())?; + dict.set_item("文_时间戳", self.文(py).bind(py).borrow().时间戳())?; + dict.set_item("武_时间戳", self.武(py).bind(py).borrow().时间戳())?; Ok(dict.into()) } @@ -550,18 +632,19 @@ impl 虚线Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } // ---- 静态工厂方法 ---- #[classmethod] + #[pyo3(signature = (文, 武, 有效性 = true))] /// :param 文: 起点分型 fn 创建笔( _cls: &Bound<'_, PyType>, @@ -570,9 +653,9 @@ impl 虚线Py { 有效性: bool, ) -> Self { Self { - inner: Rc::new(chanlun::structure::dash_line::虚线::创建笔( - Rc::clone(&文.borrow().inner), - Rc::clone(&武.borrow().inner), + inner: Arc::new(chanlun::structure::dash_line::虚线::创建笔( + Arc::clone(&文.borrow().inner), + Arc::clone(&武.borrow().inner), 有效性, )), } @@ -581,12 +664,12 @@ impl 虚线Py { #[classmethod] /// :param 虚线序列: 构成线段的虚线列表(笔) fn 创建线段(_cls: &Bound<'_, PyType>, 虚线序列: Vec>, py: Python<'_>) -> Self { - let rc_list: Vec> = 虚线序列 + let rc_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); Self { - inner: Rc::new(chanlun::structure::dash_line::虚线::创建线段( + inner: Arc::new(chanlun::structure::dash_line::虚线::创建线段( &rc_list, )), } @@ -654,7 +737,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> f64 { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -672,7 +755,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -690,7 +773,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -705,7 +788,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -720,7 +803,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> Option { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -738,7 +821,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> Option { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -756,7 +839,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -771,7 +854,7 @@ impl 虚线Py { 实线: &Bound<'_, Self>, py: Python<'_>, ) -> bool { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -786,7 +869,7 @@ impl 虚线Py { 方向: &Bound<'_, 相对方向Py>, py: Python<'_>, ) -> [bool; 3] { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -803,7 +886,7 @@ impl 虚线Py { k线序列: Vec>, py: Python<'_>, ) -> Vec> { - let rc_list: Vec> = k线序列 + let rc_list: Vec> = k线序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -811,6 +894,7 @@ impl 虚线Py { } #[classmethod] + #[pyo3(signature = (交叉标记, 最大间隔 = 5usize, 最少交叉数 = 3usize))] /// 交叉标记: 长度为len(macd_list)的列表,0=无交叉, 1=金叉, -1=死叉 fn 密集区域按间隔( _cls: &Bound<'_, PyType>, @@ -826,6 +910,7 @@ impl 虚线Py { } #[classmethod] + #[pyo3(signature = (普K序列, 最大间隔 = 8usize, 最少交叉数 = 3usize))] /// :param 普K序列: K线序列 fn 统计MACD行为( _cls: &Bound<'_, PyType>, @@ -834,7 +919,7 @@ impl 虚线Py { 最少交叉数: usize, py: Python<'_>, ) -> PyResult> { - let rc_list: Vec> = 普K序列 + let rc_list: Vec> = 普K序列 .iter() .map(|k| k.bind(py).borrow().inner.clone()) .collect(); @@ -898,15 +983,10 @@ impl 虚线Py { /// 新建(序号, 文, 武, 基础序列?) -> 线段特征 /// 静态分析(虚线序列, 配置) -> 线段特征|None /// 获取分型序列(虚线序列, 配置) -> list[线段特征] -#[pyclass( - name = "线段特征", - module = "chanlun._chanlun", - unsendable, - from_py_object -)] +#[pyclass(name = "线段特征", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 线段特征Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -918,12 +998,12 @@ impl 线段特征Py { 线段方向: &Bound<'_, 相对方向Py>, py: Python<'_>, ) -> Self { - let rc_list: Vec> = 基础序列 + let rc_list: Vec> = 基础序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); Self { - inner: Rc::new(chanlun::structure::segment_feat::线段特征::new( + inner: Arc::new(chanlun::structure::segment_feat::线段特征::new( 标识, rc_list, 线段方向.borrow().inner, @@ -954,12 +1034,7 @@ impl 线段特征Py { fn 元素(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.inner.元素 { - list.append(Py::new( - py, - 虚线Py { - inner: Rc::clone(d), - }, - )?)?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } Ok(list.into()) } @@ -985,38 +1060,27 @@ impl 线段特征Py { ))); } let dash = &self.inner.元素[idx as usize]; - let obj: Py = Py::new( - py, - 虚线Py { - inner: Rc::clone(dash), - }, - )? - .into(); + let obj: Py = dashed_to_py(py, Arc::clone(dash)).into(); Ok(obj) } fn __iter__(&self, py: Python<'_>) -> PyResult> { let list = pyo3::types::PyList::empty(py); for d in &self.inner.元素 { - list.append(Py::new( - py, - 虚线Py { - inner: Rc::clone(d), - }, - )?)?; + list.append(dashed_to_py(py, Arc::clone(d)))?; } list.call_method0("__iter__").map(|iter| iter.into()) } fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } /// pandas 兼容 — 返回关键标量字段构成的字典 @@ -1040,18 +1104,14 @@ impl 线段特征Py { #[getter] /// 起点分型(向上线段取高高中的最大者,向下线段取低低中的最小者) - fn 文(&self) -> 分型Py { - 分型Py { - inner: self.inner.文(), - } + fn 文(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, self.inner.文()) } #[getter] /// 终点分型(向上线段取高高中的最大者,向下线段取低低中的最小者) - fn 武(&self) -> 分型Py { - 分型Py { - inner: self.inner.武(), - } + fn 武(&self, py: Python<'_>) -> Py<分型Py> { + fractal_to_py(py, self.inner.武()) } #[getter] @@ -1076,17 +1136,17 @@ impl 线段特征Py { /// :param 待添加虚线: 待添加的虚线 fn 添加(&mut self, 待添加虚线: &Bound<'_, 虚线Py>) -> PyResult<()> { - let inner = Rc::make_mut(&mut self.inner); + let inner = Arc::make_mut(&mut self.inner); inner - .添加(Rc::clone(&待添加虚线.borrow().inner)) + .添加(Arc::clone(&待添加虚线.borrow().inner)) .map_err(|e| pyo3::exceptions::PyValueError::new_err(e)) } /// :param 待删除虚线: 待删除的虚线 fn 删除(&mut self, 待删除虚线: &Bound<'_, 虚线Py>) -> PyResult<()> { - let inner = Rc::make_mut(&mut self.inner); + let inner = Arc::make_mut(&mut self.inner); inner - .删除(&Rc::clone(&待删除虚线.borrow().inner)) + .删除(&Arc::clone(&待删除虚线.borrow().inner)) .map_err(|e| pyo3::exceptions::PyValueError::new_err(e)) } @@ -1100,12 +1160,12 @@ impl 线段特征Py { 线段方向: &Bound<'_, 相对方向Py>, py: Python<'_>, ) -> Self { - let rc_list: Vec> = 虚线序列 + let rc_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); Self { - inner: Rc::new(chanlun::structure::segment_feat::线段特征::新建( + inner: Arc::new(chanlun::structure::segment_feat::线段特征::新建( rc_list, 线段方向.borrow().inner, )), @@ -1113,6 +1173,7 @@ impl 线段特征Py { } #[classmethod] + #[pyo3(signature = (虚线序列, 线段方向, 四象, 是否忽视 = false))] /// 静态分析虚线序列,生成特征序列 fn 静态分析( _cls: &Bound<'_, PyType>, @@ -1122,9 +1183,9 @@ impl 线段特征Py { 是否忽视: bool, py: Python<'_>, ) -> Vec { - let rc_list: Vec> = 虚线序列 + let rc_list: Vec> = 虚线序列 .iter() - .map(|d| Rc::clone(&d.bind(py).borrow().inner)) + .map(|d| Arc::clone(&d.bind(py).borrow().inner)) .collect(); chanlun::structure::segment_feat::线段特征::静态分析( &rc_list, @@ -1143,16 +1204,14 @@ impl 线段特征Py { _cls: &Bound<'_, PyType>, 特征序列: Vec>, py: Python<'_>, - ) -> Vec<特征分型Py> { - let rc_list: Vec> = 特征序列 + ) -> Vec> { + let rc_list: Vec> = 特征序列 .iter() - .map(|s| Rc::clone(&s.bind(py).borrow().inner)) + .map(|s| Arc::clone(&s.bind(py).borrow().inner)) .collect(); chanlun::structure::segment_feat::线段特征::获取分型序列(&rc_list) .into_iter() - .map(|inner| 特征分型Py { - inner: Rc::new(inner), - }) + .map(|inner| featfrac_to_py(py, Arc::new(inner))) .collect() } } @@ -1164,15 +1223,10 @@ impl 线段特征Py { /// 属性 (只读): /// 左: 线段特征|None / 中: 线段特征 / 右: 线段特征|None /// 结构: 分型结构 — 顶/底分型判定结果 -#[pyclass( - name = "特征分型", - module = "chanlun._chanlun", - unsendable, - from_py_object -)] +#[pyclass(name = "特征分型", module = "chanlun._chanlun", from_py_object)] #[derive(Clone)] pub struct 特征分型Py { - pub(crate) inner: Rc, + pub(crate) inner: Arc, } #[pymethods] @@ -1185,34 +1239,28 @@ impl 特征分型Py { 结构: &Bound<'_, 分型结构Py>, ) -> Self { Self { - inner: Rc::new(chanlun::structure::feat_fractal::特征分型::new( - Rc::clone(&左.borrow().inner), - Rc::clone(&中.borrow().inner), - Rc::clone(&右.borrow().inner), + inner: Arc::new(chanlun::structure::feat_fractal::特征分型::new( + Arc::clone(&左.borrow().inner), + Arc::clone(&中.borrow().inner), + Arc::clone(&右.borrow().inner), 结构.borrow().inner, )), } } #[getter] - fn 左(&self) -> 线段特征Py { - 线段特征Py { - inner: Rc::clone(&self.inner.左), - } + fn 左(&self, py: Python<'_>) -> Py<线段特征Py> { + segfeat_to_py(py, Arc::clone(&self.inner.左)) } #[getter] - fn 中(&self) -> 线段特征Py { - 线段特征Py { - inner: Rc::clone(&self.inner.中), - } + fn 中(&self, py: Python<'_>) -> Py<线段特征Py> { + segfeat_to_py(py, Arc::clone(&self.inner.中)) } #[getter] - fn 右(&self) -> 线段特征Py { - 线段特征Py { - inner: Rc::clone(&self.inner.右), - } + fn 右(&self, py: Python<'_>) -> Py<线段特征Py> { + segfeat_to_py(py, Arc::clone(&self.inner.右)) } #[getter] @@ -1240,13 +1288,13 @@ impl 特征分型Py { fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { if let Ok(other) = other.extract::>() { - return Rc::as_ptr(&self.inner) == Rc::as_ptr(&other.inner); + return Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner); } false } fn __hash__(&self) -> u64 { - Rc::as_ptr(&self.inner) as u64 + Arc::as_ptr(&self.inner) as u64 } } diff --git a/chanlun-py/src/types_py.rs b/chanlun-py/src/types_py.rs index 4ba34fd..f802402 100644 --- a/chanlun-py/src/types_py.rs +++ b/chanlun-py/src/types_py.rs @@ -286,17 +286,15 @@ impl 分型结构Py { /// 返回: /// 分型结构 或 None — 无法判定时返回 None #[classmethod] + #[pyo3(signature = (左, 中, 右, 可以逆序包含 = false, 忽视顺序包含 = false))] fn 分析( _cls: &Bound<'_, PyType>, 左: &Bound<'_, PyAny>, 中: &Bound<'_, PyAny>, 右: &Bound<'_, PyAny>, - 可以逆序包含: Option, - 忽视顺序包含: Option, + 可以逆序包含: bool, + 忽视顺序包含: bool, ) -> PyResult> { - let 可以逆序包含 = 可以逆序包含.unwrap_or(false); - let 忽视顺序包含 = 忽视顺序包含.unwrap_or(false); - let get_hl = |obj: &Bound<'_, PyAny>| -> PyResult<(f64, f64)> { Ok(( obj.getattr("高")?.extract::()?, @@ -456,13 +454,13 @@ impl 缺口Py { /// 返回: /// 缺口 或 None — 起点==终点时返回 None #[classmethod] + #[pyo3(signature = (起点, 终点, 比例 = 0.15))] fn 居中截取区间( _cls: &Bound<'_, PyType>, 起点: f64, 终点: f64, - 比例: Option, + 比例: f64, ) -> Option { - let 比例 = 比例.unwrap_or(0.15); chanlun::types::缺口::居中截取区间(起点, 终点, 比例).map(|inner| Self { inner }) } } diff --git a/chanlun-py/tests/test_identity.py b/chanlun-py/tests/test_identity.py new file mode 100644 index 0000000..46c18e3 --- /dev/null +++ b/chanlun-py/tests/test_identity.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +""" +对象标识测试:验证同一 Rc 底层数据通过不同路径访问时, +Python 侧始终返回相同的 PyObject(`is` 比较为 True)。 + +涉及的 Rc 包装类型: + - K线 (Rc) — 原始OHLCV数据 + - 缠论K线 (Rc<缠论K线>) — 包含处理后的K线 + - 分型 (Rc<分型>) — 顶底分型 + - 虚线 (Rc<虚线>) — 笔/线段的通用抽象 + - 中枢 (Rc<中枢>) — 三段虚线重叠区间 + - 线段特征 (Rc<线段特征>) — 线段特征序列元素 + - 特征分型 (Rc<特征分型>) — 特征序列的分型 + +路径示例: + - 缠K序列[i] vs 分型序列[j].中 (同一根缠K) + - 分型序列[i] vs 笔序列[j].文 (同一个分型) + - 笔序列[i] vs 中枢[k].基础序列[m] (同一条虚线) +""" + +import chanlun +import math + + +def create_observer(symbol="btcusd", period=14400, n_bars=500): + """创建观察者并喂入模拟K线数据。""" + cfg = chanlun.缠论配置() + obs = chanlun.观察者(symbol, period, cfg) + + for i in range(n_bars): + trend = i * 3 + wave = math.sin(i * 0.05) * 2000 + mid = 68000.0 + trend + wave + high = mid + abs(math.cos(i * 0.3)) * 400 + 100 + low = mid - abs(math.sin(i * 0.5)) * 400 - 100 + k = chanlun.K线( + 标识=symbol, + 周期=period, + 时间戳=1771675200 + i * period, + 开盘价=mid - 50, + 高=high, + 低=low, + 收盘价=mid + 50, + 成交量=abs(math.sin(i)) * 1000, + ) + obs.增加原始K线(k) + + return obs + + +class Test缠K身份: + """缠论K线: 从序列、分型、笔端点、中枢等不同路径访问。""" + + def test_序列重复获取(self): + """同一序列获取两次,元素应相同。""" + obs = create_observer() + seq1 = obs.缠论K线序列 + seq2 = obs.缠论K线序列 + for i in range(min(len(seq1), 10)): + assert seq1[i] is seq2[i], f"缠K序列[{i}] 身份不一致" + + def test_分型中K(self): + """分型.中 与 缠K序列 对应元素应相同。""" + obs = create_observer() + seq = obs.缠论K线序列 + 分序 = obs.分型序列 + for fx in 分序[:10]: + 中 = fx.中 + for ck in seq: + if ck.时间戳 == 中.时间戳: + assert ck is 中, f"分型.中 (ts={中.时间戳}) 与序列中元素不匹配" + break + + def test_笔端点钟K(self): + """笔的端点分型的中间K线应与序列元素相同。""" + obs = create_observer() + seq = obs.缠论K线序列 + for bi in obs.笔序列: + for nm, getter in [("文", lambda b=bi: b.文), ("武", lambda b=bi: b.武)]: + ep = getter() + if ep is None: + continue + 中 = ep.中 + for ck in seq: + if ck.时间戳 == 中.时间戳: + assert ck is 中, f"笔.{nm}.中 (ts={中.时间戳}) 与序列中元素不匹配" + break + + def test_getter重复调用(self): + """同一getter调用两次返回同一对象。""" + obs = create_observer() + for fx in obs.分型序列[:5]: + 中1 = fx.中 + 中2 = fx.中 + assert 中1 is 中2, "分型.中 两次调用返回不同对象" + + +class Test分型身份: + """分型: 从分型序列、笔/线段端点、买卖点等不同路径访问。""" + + def test_序列重复获取(self): + """同一序列获取两次,元素应相同。""" + obs = create_observer() + seq1 = obs.分型序列 + seq2 = obs.分型序列 + for i in range(min(len(seq1), 9)): + assert seq1[i] is seq2[i], f"分型序列[{i}] 身份不一致" + + def test_笔端点与序列(self): + """笔.文 / 笔.武 应与分型序列中对应元素相同。""" + obs = create_observer() + 分序 = obs.分型序列 + for bi in obs.笔序列: + for nm in ["文", "武"]: + ep = getattr(bi, nm) + if ep is None: + continue + matched = False + for fx in 分序: + if fx.时间戳 == ep.时间戳 and fx.结构 == ep.结构: + assert fx is ep, f"笔.{nm} (ts={ep.时间戳}) 与分型序列中元素不匹配" + matched = True + break + assert matched, f"笔.{nm} (ts={ep.时间戳}) 在分型序列中未找到" + + def test_段端点与序列(self): + """段.文 / 段.武 应与分型序列中对应元素相同。""" + obs = create_observer() + 分序 = obs.分型序列 + for duan in obs.线段序列: + for nm in ["文", "武"]: + ep = getattr(duan, nm) + if ep is None: + continue + matched = False + for fx in 分序: + if fx.时间戳 == ep.时间戳 and fx.结构 == ep.结构: + assert fx is ep, f"段.{nm} (ts={ep.时间戳}) 与分型序列中元素不匹配" + matched = True + break + assert matched, f"段.{nm} (ts={ep.时间戳}) 在分型序列中未找到" + + def test_getter重复调用(self): + """同一getter调用两次返回同一对象。""" + obs = create_observer() + for bi in obs.笔序列: + 文1 = bi.文 + 文2 = bi.文 + assert 文1 is 文2, "笔.文 两次调用返回不同对象" + 武1 = bi.武 + 武2 = bi.武 + assert 武1 is 武2, "笔.武 两次调用返回不同对象" + break # 只测第一笔 + + +class Test虚线身份: + """虚线(笔/线段): 从笔序列、线段序列、中枢内部序列等不同路径访问。""" + + def test_笔序列重复获取(self): + obs = create_observer() + seq1 = obs.笔序列 + seq2 = obs.笔序列 + for i in range(min(len(seq1), 8)): + assert seq1[i] is seq2[i], f"笔序列[{i}] 身份不一致" + + def test_线段序列重复获取(self): + obs = create_observer() + seq1 = obs.线段序列 + seq2 = obs.线段序列 + for i in range(min(len(seq1), 5)): + assert seq1[i] is seq2[i], f"线段序列[{i}] 身份不一致" + + def test_多个扩展序列(self): + """扩展线段的不同序列获取同一虚线应相同。""" + obs = create_observer() + s1 = obs.扩展线段序列 + s2 = obs.扩展线段序列_线段 + s3 = obs.扩展线段序列_扩展线段 + # 这些序列可能包含不同的虚线,但如果同一个 Rc 出现在两个序列中应该相同 + for d1 in s1: + for d2 in s2: + if d1.序号 == d2.序号: + assert d1 is d2, f"扩展线段序列[{d1.序号}] 跨序列身份不一致" + break + + +class TestK线身份: + """原始K线: 从序列、买卖点、缠K标的等不同路径访问。""" + + def test_序列重复获取(self): + obs = create_observer() + seq1 = obs.普通K线序列 + seq2 = obs.普通K线序列 + for i in range(min(len(seq1), 10)): + assert seq1[i] is seq2[i], f"普K序列[{i}] 身份不一致" + + +class Test中枢身份: + """中枢: 从中枢序列、分型关联、笔中枢/线段中枢等不同路径访问。""" + + def test_序列重复获取(self): + obs = create_observer(period=3600, n_bars=800) + seq1 = obs.中枢序列 + seq2 = obs.中枢序列 + for i in range(min(len(seq1), 5)): + assert seq1[i] is seq2[i], f"中枢序列[{i}] 身份不一致" + + def test_笔中枢与线段中枢(self): + obs = create_observer(period=3600, n_bars=800) + 笔中 = obs.笔_中枢序列 + 段中 = obs.线段_中枢序列 + 扩展中 = obs.扩展中枢序列 + # 验证同一次获取内的身份 + for zs in 笔中: + 文1 = zs.文 + 文2 = zs.文 + assert 文1 is 文2, f"笔中枢.文 两次调用不同" + break + for zs in 段中: + 文1 = zs.文 + 文2 = zs.文 + assert 文1 is 文2, f"段中枢.文 两次调用不同" + break + + +class Test整体身份: + """跨类型综合身份测试。""" + + def test_买卖点分型(self): + """验证买卖点的关联分型身份。""" + obs = create_observer(period=3600, n_bars=800) + # 尝试访问可用的结构 + 分序 = obs.分型序列 + 笔序 = obs.笔序列 + assert len(分序) >= 0 and len(笔序) >= 0 # 至少不崩溃 + + def test_全链路一致性(self): + """缠K → 分型 → 笔 → 段 链路中所有对象身份一致。""" + obs = create_observer() + seq = obs.缠论K线序列 + + for bi in obs.笔序列: + # 笔的端点分型 + for nm, getter in [("文", lambda b=bi: b.文), ("武", lambda b=bi: b.武)]: + ep = getter() + if ep is None: + continue + # ep 中的 中 是一根缠K,应能在序列中找到相同对象 + 中 = ep.中 + for ck in seq: + if ck.时间戳 == 中.时间戳: + assert ck is 中 + break + # 左也应该是可访问的 + 左 = ep.左 + if 左 is not None: + for ck in seq: + if ck.时间戳 == 左.时间戳: + assert ck is 左 + break + # 右也应该是可访问的 + 右 = ep.右 + if 右 is not None: + for ck in seq: + if ck.时间戳 == 右.时间戳: + assert ck is 右 + break diff --git a/chanlun/Cargo.toml b/chanlun/Cargo.toml index 882bbbe..d32afcf 100644 --- a/chanlun/Cargo.toml +++ b/chanlun/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chanlun" -version = "26.5.2" +version = "26.5.3" edition = "2021" rust-version = "1.70" license = "MIT" diff --git a/chanlun/src/algorithm/bi.rs b/chanlun/src/algorithm/bi.rs index fc56b75..e80aa29 100644 --- a/chanlun/src/algorithm/bi.rs +++ b/chanlun/src/algorithm/bi.rs @@ -29,7 +29,8 @@ use crate::kline::chan_kline::缠论K线; use crate::structure::dash_line::虚线; use crate::structure::fractal_obj::分型; use crate::types::{分型结构, 相对方向}; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; /// 笔 — 从分型生成笔的算法集合(静态方法命名空间) pub struct 笔; @@ -37,8 +38,8 @@ pub struct 笔; impl 笔 { /// 获取可成笔的缠K数量(考虑弱化模式) pub fn 获取缠K数量( - 缠K序列: &[Rc<缠论K线>], - 笔序列: &[Rc<虚线>], + 缠K序列: &[Arc<缠论K线>], + 笔序列: &[Arc<虚线>], 配置: &缠论配置, ) -> usize { let 实际数量 = 缠K序列.len(); @@ -51,7 +52,9 @@ impl 笔 { let 实际低点 = Self::实际低点(缠K序列, 配置.笔内相同终点取舍); if let (Some(ref 高点), Some(ref 低点)) = (&实际高点, &实际低点) { - let 原始数量 = 1 + (低点.标的K线.序号 - 高点.标的K线.序号).unsigned_abs() as usize; + let 原始数量 = 1 + + (低点.标的K线.read().unwrap().序号 - 高点.标的K线.read().unwrap().序号) + .unsigned_abs() as usize; if 原始数量 >= 配置.笔内元素数量 as usize { return 配置.笔内元素数量 as usize; } @@ -70,16 +73,18 @@ impl 笔 { if let Some(ref 筆) = 筆 { if let (Some(ref 高_k), Some(ref 低_k)) = (&实际高点, &实际低点) { - let 原始数量 = - 1 + (低_k.标的K线.序号 - 高_k.标的K线.序号).unsigned_abs() as usize; + let 原始数量 = 1 + + (低_k.标的K线.read().unwrap().序号 + - 高_k.标的K线.read().unwrap().序号) + .unsigned_abs() as usize; // 向上笔 - if 筆.方向().是否向上() && 低_k.低 < 筆.低() { + if 筆.方向().是否向上() && 低_k.低.get() < 筆.低() { if 原始数量 >= 配置.笔弱化_原始数量 as usize { return 配置.笔内元素数量 as usize; } } // 向下笔 - if 筆.方向().是否向下() && 低_k.低 > 筆.高() { + if 筆.方向().是否向下() && 低_k.低.get() > 筆.高() { if 原始数量 >= 配置.笔弱化_原始数量 as usize { return 配置.笔内元素数量 as usize; } @@ -92,147 +97,182 @@ impl 笔 { } /// 次高 — 排除最高值后的次高点 - pub fn 次高(缠K序列: &[Rc<缠论K线>], 取舍: bool) -> Option> { + pub fn 次高(缠K序列: &[Arc<缠论K线>], 取舍: bool) -> Option> { if 缠K序列.len() < 2 { return 缠K序列.first().cloned(); } let max_高 = 缠K序列 .iter() - .map(|k| k.高) + .map(|k| k.高.get()) .fold(f64::NEG_INFINITY, f64::max); // 排除最高值 - let filtered: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.高 != max_高).collect(); + let filtered: Vec<&Arc<缠论K线>> = + 缠K序列.iter().filter(|k| k.高.get() != max_高).collect(); if filtered.is_empty() { return 缠K序列.first().cloned(); } // 筛选次高值 let second_高 = filtered .iter() - .map(|k| k.高) + .map(|k| k.高.get()) .fold(f64::NEG_INFINITY, f64::max); - let mut candidates: Vec<&Rc<缠论K线>> = filtered + let mut candidates: Vec<&Arc<缠论K线>> = filtered .iter() - .filter(|k| k.高 == second_高) + .filter(|k| k.高.get() == second_高) .copied() .collect(); // 按时间戳排序 - candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳)); + candidates.sort_by(|a, b| { + a.时间戳 + .load(Ordering::Relaxed) + .cmp(&b.时间戳.load(Ordering::Relaxed)) + }); if 取舍 { - Some(Rc::clone(candidates[candidates.len() - 1])) + Some(Arc::clone(candidates[candidates.len() - 1])) } else { - Some(Rc::clone(candidates[0])) + Some(Arc::clone(candidates[0])) } } /// 次低 — 排除最低值后的次低点 - pub fn 次低(缠K序列: &[Rc<缠论K线>], 取舍: bool) -> Option> { + pub fn 次低(缠K序列: &[Arc<缠论K线>], 取舍: bool) -> Option> { if 缠K序列.len() < 2 { return 缠K序列.first().cloned(); } - let min_低 = 缠K序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min); + let min_低 = 缠K序列 + .iter() + .map(|k| k.低.get()) + .fold(f64::INFINITY, f64::min); // 排除最低值 - let filtered: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.低 != min_低).collect(); + let filtered: Vec<&Arc<缠论K线>> = + 缠K序列.iter().filter(|k| k.低.get() != min_低).collect(); if filtered.is_empty() { return 缠K序列.first().cloned(); } // 筛选次低值 - let second_低 = filtered.iter().map(|k| k.低).fold(f64::INFINITY, f64::min); - let mut candidates: Vec<&Rc<缠论K线>> = filtered + let second_低 = filtered .iter() - .filter(|k| k.低 == second_低) + .map(|k| k.低.get()) + .fold(f64::INFINITY, f64::min); + let mut candidates: Vec<&Arc<缠论K线>> = filtered + .iter() + .filter(|k| k.低.get() == second_低) .copied() .collect(); // 按时间戳排序 - candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳)); + candidates.sort_by(|a, b| { + a.时间戳 + .load(Ordering::Relaxed) + .cmp(&b.时间戳.load(Ordering::Relaxed)) + }); if 取舍 { - Some(Rc::clone(candidates[candidates.len() - 1])) + Some(Arc::clone(candidates[candidates.len() - 1])) } else { - Some(Rc::clone(candidates[0])) + Some(Arc::clone(candidates[0])) } } /// 实际高点 - pub fn 实际高点(缠K序列: &[Rc<缠论K线>], 取舍: bool) -> Option> { + pub fn 实际高点(缠K序列: &[Arc<缠论K线>], 取舍: bool) -> Option> { if 缠K序列.is_empty() { return None; } let max_高 = 缠K序列 .iter() - .map(|k| k.高) + .map(|k| k.高.get()) .fold(f64::NEG_INFINITY, f64::max); - let mut candidates: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.高 == max_高).collect(); + let mut candidates: Vec<&Arc<缠论K线>> = + 缠K序列.iter().filter(|k| k.高.get() == max_高).collect(); if candidates.is_empty() { - return Some(Rc::clone(&缠K序列[0])); + return Some(Arc::clone(&缠K序列[0])); } // 按时间戳排序 - candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳)); + candidates.sort_by(|a, b| { + a.时间戳 + .load(Ordering::Relaxed) + .cmp(&b.时间戳.load(Ordering::Relaxed)) + }); if 取舍 { - Some(Rc::clone(candidates[candidates.len() - 1])) + Some(Arc::clone(candidates[candidates.len() - 1])) } else { - Some(Rc::clone(candidates[0])) + Some(Arc::clone(candidates[0])) } } /// 实际低点 - pub fn 实际低点(缠K序列: &[Rc<缠论K线>], 取舍: bool) -> Option> { + pub fn 实际低点(缠K序列: &[Arc<缠论K线>], 取舍: bool) -> Option> { if 缠K序列.is_empty() { return None; } - let min_低 = 缠K序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min); - let mut candidates: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.低 == min_低).collect(); + let min_低 = 缠K序列 + .iter() + .map(|k| k.低.get()) + .fold(f64::INFINITY, f64::min); + let mut candidates: Vec<&Arc<缠论K线>> = + 缠K序列.iter().filter(|k| k.低.get() == min_低).collect(); if candidates.is_empty() { - return Some(Rc::clone(&缠K序列[0])); + return Some(Arc::clone(&缠K序列[0])); } // 按时间戳排序 - candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳)); + candidates.sort_by(|a, b| { + a.时间戳 + .load(Ordering::Relaxed) + .cmp(&b.时间戳.load(Ordering::Relaxed)) + }); if 取舍 { - Some(Rc::clone(candidates[candidates.len() - 1])) + Some(Arc::clone(candidates[candidates.len() - 1])) } else { - Some(Rc::clone(candidates[0])) + Some(Arc::clone(candidates[0])) } } /// 判断笔的相对关系是否合理 pub fn 相对关系(筆: &虚线, 配置: &缠论配置) -> bool { let 文分型 = &筆.文; - let 武分型 = &筆.武; + let 武分型 = 筆.武.read().unwrap(); let 相对关系 = if 配置.笔内起始分型包含整笔 { - let 文中_rc = Rc::clone(&文分型.中); - let 武中_rc = Rc::clone(&武分型.中); - let 文_元素: [Option<&Rc<缠论K线>>; 3] = + let 文中_rc = Arc::clone(&文分型.中); + let 武中_rc = Arc::clone(&武分型.中); + let 文_元素: [Option<&Arc<缠论K线>>; 3] = [文分型.左.as_ref(), Some(&文中_rc), 文分型.右.as_ref()]; - let 有效序列: Vec<&Rc<缠论K线>> = 文_元素.iter().filter_map(|x| *x).collect(); + let 有效序列: Vec<&Arc<缠论K线>> = 文_元素.iter().filter_map(|x| *x).collect(); let 文高 = 有效序列 .iter() - .map(|k| k.高) + .map(|k| k.高.get()) .fold(f64::NEG_INFINITY, f64::max); - let 文低 = 有效序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min); + let 文低 = 有效序列 + .iter() + .map(|k| k.低.get()) + .fold(f64::INFINITY, f64::min); - let 武_右: Option<&Rc<缠论K线>> = if 配置.笔内起始分型包含整笔_包括右 { + let 武_右: Option<&Arc<缠论K线>> = if 配置.笔内起始分型包含整笔_包括右 { 武分型.右.as_ref() } else { None }; - let 武_元素: [Option<&Rc<缠论K线>>; 3] = [武分型.左.as_ref(), Some(&武中_rc), 武_右]; - let 有效序列: Vec<&Rc<缠论K线>> = 武_元素.iter().filter_map(|x| *x).collect(); + let 武_元素: [Option<&Arc<缠论K线>>; 3] = [武分型.左.as_ref(), Some(&武中_rc), 武_右]; + let 有效序列: Vec<&Arc<缠论K线>> = 武_元素.iter().filter_map(|x| *x).collect(); let 武高 = 有效序列 .iter() - .map(|k| k.高) + .map(|k| k.高.get()) .fold(f64::NEG_INFINITY, f64::max); - let 武低 = 有效序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min); + let 武低 = 有效序列 + .iter() + .map(|k| k.低.get()) + .fold(f64::INFINITY, f64::min); crate::types::相对方向::分析(文高, 文低, 武高, 武低) } else { let 相对关系 = crate::types::相对方向::分析( - 文分型.中.高, - 文分型.中.低, - 武分型.中.高, - 武分型.中.低, + 文分型.中.高.get(), + 文分型.中.低.get(), + 武分型.中.高.get(), + 武分型.中.低.get(), ); if 配置.笔内原始K线包含整笔 { - let 文标的 = &文分型.中.标的K线; - let 武标的 = &武分型.中.标的K线; + let 文标的 = 文分型.中.标的K线.read().unwrap(); + let 武标的 = 武分型.中.标的K线.read().unwrap(); if crate::types::相对方向::分析(文标的.高, 文标的.低, 武标的.高, 武标的.低) .是否包含() { @@ -249,43 +289,46 @@ impl 笔 { } /// 以文会友 — 根据起点分型找笔 - pub fn 以文会友(笔序列: &[Rc<虚线>], 文: &Rc<分型>) -> Option> { + pub fn 以文会友(笔序列: &[Arc<虚线>], 文: &Arc<分型>) -> Option> { 笔序列 .iter() - .find(|b| Rc::as_ptr(&b.文) == Rc::as_ptr(文)) + .find(|b| Arc::as_ptr(&b.文) == Arc::as_ptr(文)) .cloned() } /// 以武会友 — 根据终点分型找笔 - pub fn 以武会友(笔序列: &[Rc<虚线>], 武: &Rc<分型>) -> Option> { + pub fn 以武会友(笔序列: &[Arc<虚线>], 武: &Arc<分型>) -> Option> { 笔序列 .iter() .rev() - .find(|b| Rc::as_ptr(&b.武) == Rc::as_ptr(武)) + .find(|b| Arc::as_ptr(&*b.武.read().unwrap()) == Arc::as_ptr(武)) .cloned() } /// 根据缠K找对应的笔 pub fn 根据缠K找笔( - 笔序列: &[Rc<虚线>], - 缠K: &Rc<缠论K线>, + 笔序列: &[Arc<虚线>], + 缠K: &Arc<缠论K线>, 偏移: i64, - ) -> Option> { + ) -> Option> { // Python iterates in reverse: for 筆 in 笔序列[::-1] for b in 笔序列.iter().rev() { - // Python: 筆.文.中.序号 - 偏移 <= 缠K.序号 <= 筆.武.中.序号 - if b.文.中.序号 - 偏移 <= 缠K.序号 && 缠K.序号 <= b.武.中.序号 { - return Some(Rc::clone(b)); + // Python: 筆.文.中.序号 - 偏移 <= 缠K.序号.load(Ordering::Relaxed) <= 筆.武.read().unwrap().中.序号 + if b.文.中.序号.load(Ordering::Relaxed) - 偏移 <= 缠K.序号.load(Ordering::Relaxed) + && 缠K.序号.load(Ordering::Relaxed) + <= b.武.read().unwrap().中.序号.load(Ordering::Relaxed) + { + return Some(Arc::clone(b)); } } None } /// 从分型序列中弹出最后一个分型和对应的笔 - fn 弹出旧笔(分型序列: &mut Vec>, 笔序列: &mut Vec>) { + fn 弹出旧笔(分型序列: &mut Vec>, 笔序列: &mut Vec>) { 分型序列.pop(); if !笔序列.is_empty() { - // Python sets旧笔.有效性 = False; with Rc we just drop the笔 + // Python sets旧笔.有效性.store(False, Ordering::Relaxed); with Rc we just drop the笔 笔序列.pop(); } } @@ -294,19 +337,19 @@ impl 笔 { /// /// 返回: 递归层次数 pub fn 分析( - 初始分型: Rc<分型>, - 分型序列: &mut Vec>, - 笔序列: &mut Vec>, - 缠K序列: &[Rc<缠论K线>], - _普K序列: &[Rc], + 初始分型: Arc<分型>, + 分型序列: &mut Vec>, + 笔序列: &mut Vec>, + 缠K序列: &[Arc<缠论K线>], + _普K序列: &[Arc], 配置: &缠论配置, ) -> i64 { enum 栈项 { - 分型(Rc<分型>, i64), + 分型(Arc<分型>, i64), /// 修复错过笔哨兵: 若临时分型被接受为最后一个元素,则扫描武将之后的所有分型 修复错过笔 { - 临时分型: Rc<分型>, - 武将缠K: Rc<缠论K线>, + 临时分型: Arc<分型>, + 武将缠K: Arc<缠论K线>, 层次: i64, }, } @@ -325,20 +368,20 @@ impl 笔 { // Python line 2406: only scan if临时分型 was accepted as last element if !分型序列.is_empty() { if let Some(last_fx) = 分型序列.last() { - if Rc::as_ptr(last_fx) == Rc::as_ptr(&临时分型) { + if Arc::as_ptr(last_fx) == Arc::as_ptr(&临时分型) { if let Some(武_idx) = 缠K序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(&武将缠K)) + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(&武将缠K)) { - let mut 错过: Vec> = Vec::new(); + let mut 错过: Vec> = Vec::new(); for ck in &缠K序列[武_idx..] { - if ck.分型 == Some(分型结构::底) - || ck.分型 == Some(分型结构::顶) + if *ck.分型.read().unwrap() == Some(分型结构::底) + || *ck.分型.read().unwrap() == Some(分型结构::顶) { if let Some(fx) = 分型::从缠K序列中获取分型(缠K序列, ck) { - 错过.push(Rc::new(fx)); + 错过.push(Arc::new(fx)); } } } @@ -369,7 +412,7 @@ impl 笔 { continue; } - let 之前分型 = Rc::clone(分型序列.last().unwrap()); + let 之前分型 = Arc::clone(分型序列.last().unwrap()); // Python line 2330-2335: 清理无效数据 if 之前分型.时间戳 == 当前分型.时间戳 @@ -384,10 +427,13 @@ impl 笔 { } } - let 之前分型 = Rc::clone(分型序列.last().unwrap()); + let 之前分型 = Arc::clone(分型序列.last().unwrap()); // Python line 2338: 时序检查 — skip out-of-order fractals - if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1 + if 之前分型.时间戳 > 当前分型.时间戳 + && 之前分型.中.序号.load(Ordering::Relaxed) + - 当前分型.中.序号.load(Ordering::Relaxed) + > 1 { continue; } @@ -395,7 +441,9 @@ impl 笔 { // Python line 2343-2348: 笔弱化模式 if 配置.笔弱化 && !笔序列.is_empty() { let 前一笔 = 笔序列.last().unwrap(); - let 前一笔缠K数 = 前一笔.武.中.序号 - 前一笔.文.中.序号 + 1; + let 前一笔缠K数 = 前一笔.武.read().unwrap().中.序号.load(Ordering::Relaxed) + - 前一笔.文.中.序号.load(Ordering::Relaxed) + + 1; if 前一笔缠K数 == 3 { let 破位 = (前一笔.方向().是否向上() && 前一笔.低() > 当前分型.分型特征值 @@ -412,16 +460,16 @@ impl 笔 { } // Re-read之前分型 again after笔弱化 pop - let 之前分型 = Rc::clone(分型序列.last().unwrap()); + let 之前分型 = Arc::clone(分型序列.last().unwrap()); // Python line 2350: 分型结构相反 → 可能成笔 if 之前分型.结构 != 当前分型.结构 { let 文_idx = 缠K序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(&之前分型.中)); + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(&之前分型.中)); let 武_idx = 缠K序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(&当前分型.中)); + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(&当前分型.中)); if let (Some(文_idx), Some(武_idx)) = (文_idx, 武_idx) { let 基础序列 = &缠K序列[文_idx..=武_idx]; @@ -436,12 +484,12 @@ impl 笔 { // Python line 2359-2367: 文官 != 之前分型.中 → adjust if let Some(ref 文官_k) = 文官 { - if Rc::as_ptr(文官_k) != Rc::as_ptr(&之前分型.中) { + if Arc::as_ptr(文官_k) != Arc::as_ptr(&之前分型.中) { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 文官_k) { 栈.push(栈项::分型(当前分型, 递归层次)); - 栈.push(栈项::分型(Rc::new(临时分型), 递归层次 + 1)); + 栈.push(栈项::分型(Arc::new(临时分型), 递归层次 + 1)); continue; } } @@ -455,16 +503,16 @@ impl 笔 { _ => Self::实际高点(基础序列, 配置.笔内相同终点取舍), }; - let 新笔 = Rc::new(虚线::创建笔( - Rc::clone(&之前分型), - Rc::clone(&当前分型), + let 新笔 = Arc::new(虚线::创建笔( + Arc::clone(&之前分型), + Arc::clone(&当前分型), true, )); // Python line 2374-2376: 相对关系 and武将 matches if Self::相对关系(&新笔, 配置) { if let Some(ref 武将_k) = 武将 { - if Rc::as_ptr(武将_k) == Rc::as_ptr(&当前分型.中) { + if Arc::as_ptr(武将_k) == Arc::as_ptr(&当前分型.中) { Self::_添加新笔递归(分型序列, 笔序列, 当前分型, 新笔); continue; } @@ -478,7 +526,7 @@ impl 笔 { _ => Self::次高(基础序列, 配置.笔内相同终点取舍), }; if let Some(ref 武将_k) = 武将 { - if Rc::as_ptr(武将_k) == Rc::as_ptr(&当前分型.中) + if Arc::as_ptr(武将_k) == Arc::as_ptr(&当前分型.中) && Self::相对关系(&新笔, 配置) { Self::_添加新笔递归(分型序列, 笔序列, 当前分型, 新笔); @@ -492,7 +540,7 @@ impl 笔 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 右) { - 栈.push(栈项::分型(Rc::new(临时分型), 递归层次 + 1)); + 栈.push(栈项::分型(Arc::new(临时分型), 递归层次 + 1)); continue; } } @@ -509,7 +557,7 @@ impl 笔 { }; if 更强 { - let 被替换分型 = Rc::clone(&之前分型); + let 被替换分型 = Arc::clone(&之前分型); Self::弹出旧笔(分型序列, 笔序列); if let Some(k线序列) = 缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中) @@ -525,14 +573,14 @@ impl 笔 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 武将_k) { - let 临时分型_rc = Rc::new(临时分型); + let 临时分型_rc = Arc::new(临时分型); if !分型序列.is_empty() { // Push in reverse processing order (LIFO): - 栈.push(栈项::分型(Rc::clone(&当前分型), 递归层次 + 2)); + 栈.push(栈项::分型(Arc::clone(&当前分型), 递归层次 + 2)); 栈.push(栈项::修复错过笔 { - 临时分型: Rc::clone(&临时分型_rc), - 武将缠K: Rc::clone(武将_k), + 临时分型: Arc::clone(&临时分型_rc), + 武将缠K: Arc::clone(武将_k), 层次: 递归层次 + 1, }); 栈.push(栈项::分型(临时分型_rc, 递归层次 + 1)); @@ -561,11 +609,11 @@ impl 笔 { /// /// 返回: 递归层次数 pub fn 分析递归( - 当前分型: Rc<分型>, - 分型序列: &mut Vec>, - 笔序列: &mut Vec>, - 缠K序列: &[Rc<缠论K线>], - _普K序列: &[Rc], + 当前分型: Arc<分型>, + 分型序列: &mut Vec>, + 笔序列: &mut Vec>, + 缠K序列: &[Arc<缠论K线>], + _普K序列: &[Arc], 递归层次: i64, 配置: &缠论配置, ) -> i64 { @@ -588,7 +636,7 @@ impl 笔 { } // Python line 2329-2335: 清理无效数据 - let 之前分型 = Rc::clone(分型序列.last().unwrap()); + let 之前分型 = Arc::clone(分型序列.last().unwrap()); if 之前分型.时间戳 == 当前分型.时间戳 || matches!(之前分型.结构, 分型结构::上 | 分型结构::下) { @@ -602,8 +650,10 @@ impl 笔 { } // Python line 2337-2341: 时序检查 - let 之前分型 = Rc::clone(分型序列.last().unwrap()); - if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1 + let 之前分型 = Arc::clone(分型序列.last().unwrap()); + if 之前分型.时间戳 > 当前分型.时间戳 + && 之前分型.中.序号.load(Ordering::Relaxed) - 当前分型.中.序号.load(Ordering::Relaxed) + > 1 { println!("时序错误-{}, {}, {}", 递归层次, 之前分型, 当前分型); return 递归层次; @@ -612,7 +662,9 @@ impl 笔 { // Python line 2343-2348: 笔弱化模式 if 配置.笔弱化 && !笔序列.is_empty() { let 前一笔 = 笔序列.last().unwrap(); - let 前一笔缠K数 = 前一笔.武.中.序号 - 前一笔.文.中.序号 + 1; + let 前一笔缠K数 = 前一笔.武.read().unwrap().中.序号.load(Ordering::Relaxed) + - 前一笔.文.中.序号.load(Ordering::Relaxed) + + 1; if 前一笔缠K数 == 3 { let 破位 = (前一笔.方向().是否向上() && 前一笔.低() > 当前分型.分型特征值 @@ -636,13 +688,13 @@ impl 笔 { } // Python line 2350: 分型结构相反 → 可能成笔 - let 之前分型 = Rc::clone(分型序列.last().unwrap()); + let 之前分型 = Arc::clone(分型序列.last().unwrap()); if 之前分型.结构 != 当前分型.结构 { if let Some(基础序列) = 缠论K线::截取(缠K序列, &之前分型.中, &当前分型.中) { - let 当前笔 = Rc::new(虚线::创建笔( - Rc::clone(&之前分型), - Rc::clone(&当前分型), + let 当前笔 = Arc::new(虚线::创建笔( + Arc::clone(&之前分型), + Arc::clone(&当前分型), true, )); @@ -656,12 +708,12 @@ impl 笔 { // Python line 2359-2367: 文官调整 if let Some(ref 文官_k) = 文官 { - if Rc::as_ptr(文官_k) != Rc::as_ptr(&之前分型.中) { + if Arc::as_ptr(文官_k) != Arc::as_ptr(&之前分型.中) { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 文官_k) { let 递归层次 = Self::分析递归( - Rc::new(临时分型), + Arc::new(临时分型), 分型序列, 笔序列, 缠K序列, @@ -690,7 +742,7 @@ impl 笔 { if Self::相对关系(&当前笔, 配置) { if let Some(ref 武将_k) = 武将 { - if Rc::as_ptr(武将_k) == Rc::as_ptr(&当前分型.中) { + if Arc::as_ptr(武将_k) == Arc::as_ptr(&当前分型.中) { // 直接添加(对照 Python _添加新笔:直接 append) Self::_添加新笔递归(分型序列, 笔序列, 当前分型, 当前笔); return 递归层次; @@ -705,7 +757,7 @@ impl 笔 { _ => Self::次高(&基础序列, 配置.笔内相同终点取舍), }; if let Some(ref 武将_k) = 武将 { - if Rc::as_ptr(武将_k) == Rc::as_ptr(&当前分型.中) + if Arc::as_ptr(武将_k) == Arc::as_ptr(&当前分型.中) && Self::相对关系(&当前笔, 配置) { Self::_添加新笔递归(分型序列, 笔序列, 当前分型, 当前笔); @@ -719,7 +771,7 @@ impl 笔 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 右) { return Self::分析递归( - Rc::new(临时分型), + Arc::new(临时分型), 分型序列, 笔序列, 缠K序列, @@ -743,7 +795,7 @@ impl 笔 { if 更强 { // 保存被弹出的之前分型(用于修复错过笔的范围计算) - let 被替换分型 = Rc::clone(&之前分型); + let 被替换分型 = Arc::clone(&之前分型); Self::弹出旧笔(分型序列, 笔序列); if let Some(k线序列) = 缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中) @@ -757,11 +809,11 @@ impl 笔 { if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 武将_k) { - let 临时分型_rc = Rc::new(临时分型); + let 临时分型_rc = Arc::new(临时分型); if !分型序列.is_empty() { let mut 递归层次 = Self::分析递归( - Rc::clone(&临时分型_rc), + Arc::clone(&临时分型_rc), 分型序列, 笔序列, 缠K序列, @@ -772,25 +824,25 @@ impl 笔 { // 修复错过的笔: 扫描武将之后的所有分型 if !分型序列.is_empty() - && Rc::as_ptr(分型序列.last().unwrap()) - == Rc::as_ptr(&临时分型_rc) + && Arc::as_ptr(分型序列.last().unwrap()) + == Arc::as_ptr(&临时分型_rc) { if let Some(武_idx) = 缠K序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(武将_k)) + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(武将_k)) { for ck in &缠K序列[武_idx..] { - if ck.分型 == Some(分型结构::底) - || ck.分型 == Some(分型结构::顶) + if *ck.分型.read().unwrap() == Some(分型结构::底) + || *ck.分型.read().unwrap() == Some(分型结构::顶) { if let Some(错过分型) = 分型::从缠K序列中获取分型( 缠K序列, ck, ) { - let 错过分型_rc = Rc::new(错过分型); + let 错过分型_rc = Arc::new(错过分型); 递归层次 = Self::分析递归( - Rc::clone(&错过分型_rc), + Arc::clone(&错过分型_rc), 分型序列, 笔序列, 缠K序列, @@ -839,17 +891,20 @@ impl 笔 { /// 添加新笔到序列(递归版本 — 直接追加,对应 Python _添加新笔) fn _添加新笔递归( - 分型序列: &mut Vec>, - 笔序列: &mut Vec>, - 新分型: Rc<分型>, - mut 新笔: Rc<虚线>, + 分型序列: &mut Vec>, + 笔序列: &mut Vec>, + 新分型: Arc<分型>, + mut 新笔: Arc<虚线>, ) { 分型序列.push(新分型); if !笔序列.is_empty() { - let seg = Rc::make_mut(&mut 新笔); - seg.序号 = 笔序列.last().unwrap().序号 + 1; - if seg.武.左.is_none() && seg.武.右.is_none() { - seg.有效性 = false; + let seg = Arc::make_mut(&mut 新笔); + seg.序号.store( + 笔序列.last().unwrap().序号.load(Ordering::Relaxed) + 1, + Ordering::Relaxed, + ); + if seg.武.read().unwrap().左.is_none() && seg.武.read().unwrap().右.is_none() { + seg.有效性.store(false, Ordering::Relaxed); } } 笔序列.push(新笔); @@ -867,7 +922,8 @@ impl 笔 { Self::实际高点(&基础序列, false), Self::实际低点(&基础序列, 配置.笔内相同终点取舍), ) { - if Rc::ptr_eq(&筆.文.中, &实际高) && Rc::ptr_eq(&筆.武.中, &实际低) + if Arc::ptr_eq(&筆.文.中, &实际高) + && Arc::ptr_eq(&筆.武.read().unwrap().中, &实际低) { return true; } @@ -878,7 +934,8 @@ impl 笔 { Self::实际低点(&基础序列, false), Self::实际高点(&基础序列, 配置.笔内相同终点取舍), ) { - if Rc::ptr_eq(&筆.文.中, &实际低) && Rc::ptr_eq(&筆.武.中, &实际高) + if Arc::ptr_eq(&筆.文.中, &实际低) + && Arc::ptr_eq(&筆.武.read().unwrap().中, &实际高) { return true; } @@ -891,7 +948,7 @@ impl 笔 { /// 获取所有停顿位置 — 在笔范围内找出所有能成笔的分型组合 pub fn 获取所有停顿位置(筆: &虚线, 观察员: &观察者) -> Vec<虚线> { let mut 笔序列 = Vec::new(); - let 文 = Rc::clone(&筆.文); + let 文 = Arc::clone(&筆.文); let 基础序列 = 筆.获取缠K序列(&观察员.缠论K线序列); if 基础序列.len() < 5 { @@ -901,23 +958,30 @@ impl 笔 { for i in 3..基础序列.len() - 1 { let k = &基础序列[i]; - if k.分型 == Some(分型结构::顶) && 筆.方向() == 相对方向::向上 { - let 左 = Rc::clone(&基础序列[i - 1]); - let 中 = Rc::clone(k); - let 右 = Rc::clone(&基础序列[i + 1]); + if *k.分型.read().unwrap() == Some(分型结构::顶) && 筆.方向() == 相对方向::向上 + { + let 左 = Arc::clone(&基础序列[i - 1]); + let 中 = Arc::clone(k); + let 右 = Arc::clone(&基础序列[i + 1]); let 武 = 分型::new(Some(左), 中, Some(右)); - let mut 当前笔 = 虚线::创建笔(Rc::clone(&文), Rc::new(武), true); - 当前笔.序号 = 筆.序号; + let 当前笔 = 虚线::创建笔(Arc::clone(&文), Arc::new(武), true); + 当前笔 + .序号 + .store(筆.序号.load(Ordering::Relaxed), Ordering::Relaxed); if Self::自检(&当前笔, 观察员) { 笔序列.push(当前笔); } - } else if k.分型 == Some(分型结构::底) && 筆.方向() == 相对方向::向下 { - let 左 = Rc::clone(&基础序列[i - 1]); - let 中 = Rc::clone(k); - let 右 = Rc::clone(&基础序列[i + 1]); + } else if *k.分型.read().unwrap() == Some(分型结构::底) + && 筆.方向() == 相对方向::向下 + { + let 左 = Arc::clone(&基础序列[i - 1]); + let 中 = Arc::clone(k); + let 右 = Arc::clone(&基础序列[i + 1]); let 武 = 分型::new(Some(左), 中, Some(右)); - let mut 当前笔 = 虚线::创建笔(Rc::clone(&文), Rc::new(武), true); - 当前笔.序号 = 筆.序号; + let 当前笔 = 虚线::创建笔(Arc::clone(&文), Arc::new(武), true); + 当前笔 + .序号 + .store(筆.序号.load(Ordering::Relaxed), Ordering::Relaxed); if Self::自检(&当前笔, 观察员) { 笔序列.push(当前笔); } @@ -928,19 +992,19 @@ impl 笔 { } /// 是否背驰过 — 判断笔是否在停顿位置出现过MACD趋向背驰 - pub fn 是否背驰过(当前筆: &虚线, 观察员: &观察者) -> Vec> { + pub fn 是否背驰过(当前筆: &虚线, 观察员: &观察者) -> Vec> { let 停顿位置 = Self::获取所有停顿位置(当前筆, 观察员); let mut 结果 = Vec::new(); for 筆 in &停顿位置 { let k线范围 = K线::截取rc( &观察员.普通K线序列, - &当前筆.文.中.标的K线, - &当前筆.武.中.标的K线, + &当前筆.文.中.标的K线.read().unwrap().clone(), + &当前筆.武.read().unwrap().中.标的K线.read().unwrap().clone(), ); let 背驰信号 = 虚线::计算K线序列MACD趋向背驰(&k线范围, 筆.方向()); if 背驰信号.iter().all(|&x| x) { - 结果.push(Rc::clone(&筆.武.中)); + 结果.push(Arc::clone(&筆.武.read().unwrap().中)); } } diff --git a/chanlun/src/algorithm/divergence.rs b/chanlun/src/algorithm/divergence.rs index 078308c..52cab8f 100644 --- a/chanlun/src/algorithm/divergence.rs +++ b/chanlun/src/algorithm/divergence.rs @@ -26,7 +26,7 @@ use crate::config::缠论配置; use crate::kline::bar::K线; use crate::structure::dash_line::虚线; use crate::types::相对方向; -use std::rc::Rc; +use std::sync::Arc; /// 背驰分析 — 判断进入段和离开段之间是否存在背驰 pub struct 背驰分析; @@ -35,12 +35,18 @@ impl 背驰分析 { /// MACD背驰 — MACD柱状线面积背驰 /// 方式: "总"=阳+|阴|总面积, 其他=按进入段方向选阳或阴 pub fn MACD背驰( - 进入段: &虚线, 离开段: &虚线, K线序列: &[Rc], 方式: &str + 进入段: &虚线, 离开段: &虚线, K线序列: &[Arc], 方式: &str ) -> bool { - let 进入MACD = - Self::_获取MACD面积(K线序列, &进入段.文.中.标的K线, &进入段.武.中.标的K线); - let 离开MACD = - Self::_获取MACD面积(K线序列, &离开段.文.中.标的K线, &离开段.武.中.标的K线); + let 进入MACD = Self::_获取MACD面积( + K线序列, + &*进入段.文.中.标的K线.read().unwrap(), + &*进入段.武.read().unwrap().中.标的K线.read().unwrap(), + ); + let 离开MACD = Self::_获取MACD面积( + K线序列, + &*离开段.文.中.标的K线.read().unwrap(), + &*离开段.武.read().unwrap().中.标的K线.read().unwrap(), + ); // 计算面积(绝对值求和) let 进入面积 = if 方式 == "总" { @@ -63,18 +69,18 @@ impl 背驰分析 { /// 斜率背驰 — 价格斜率背驰 pub fn 斜率背驰(进入段: &虚线, 离开段: &虚线) -> bool { - let dx = (进入段.武.时间戳 - 进入段.文.时间戳) as f64; + let dx = (进入段.武.read().unwrap().时间戳 - 进入段.文.时间戳) as f64; if dx == 0.0 { return false; } - let dy = 进入段.武.分型特征值 - 进入段.文.分型特征值; + let dy = 进入段.武.read().unwrap().分型特征值 - 进入段.文.分型特征值; let 进入斜率 = dy / dx; - let dx = (离开段.武.时间戳 - 离开段.文.时间戳) as f64; + let dx = (离开段.武.read().unwrap().时间戳 - 离开段.文.时间戳) as f64; if dx == 0.0 { return false; } - let dy = 离开段.武.分型特征值 - 离开段.文.分型特征值; + let dy = 离开段.武.read().unwrap().分型特征值 - 离开段.文.分型特征值; let 离开斜率 = dy / dx; if 进入段.方向() == 相对方向::向上 { @@ -86,12 +92,12 @@ impl 背驰分析 { /// 测度背驰 — 价格时间测度背驰 pub fn 测度背驰(进入段: &虚线, 离开段: &虚线) -> bool { - let dx = (进入段.武.时间戳 - 进入段.文.时间戳) as f64; - let dy = 进入段.武.分型特征值 - 进入段.文.分型特征值; + let dx = (进入段.武.read().unwrap().时间戳 - 进入段.文.时间戳) as f64; + let dy = 进入段.武.read().unwrap().分型特征值 - 进入段.文.分型特征值; let 进入测度 = (dx * dx + dy * dy).sqrt(); - let dx = (离开段.武.时间戳 - 离开段.文.时间戳) as f64; - let dy = 离开段.武.分型特征值 - 离开段.文.分型特征值; + let dx = (离开段.武.read().unwrap().时间戳 - 离开段.文.时间戳) as f64; + let dy = 离开段.武.read().unwrap().分型特征值 - 离开段.文.分型特征值; let 离开测度 = (dx * dx + dy * dy).sqrt(); if 进入段.方向() == 相对方向::向上 { @@ -102,14 +108,14 @@ impl 背驰分析 { } /// 全量背驰 — MACD + 斜率 + 测度 三者全满足 - pub fn 全量背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc]) -> bool { + pub fn 全量背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Arc]) -> bool { Self::MACD背驰(进入段, 离开段, 普K序列, "总") && Self::测度背驰(进入段, 离开段) && Self::斜率背驰(进入段, 离开段) } /// 任意背驰 — 任一条件满足即可 - pub fn 任意背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc]) -> bool { + pub fn 任意背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Arc]) -> bool { Self::MACD背驰(进入段, 离开段, 普K序列, "总") || Self::测度背驰(进入段, 离开段) || Self::斜率背驰(进入段, 离开段) @@ -119,7 +125,7 @@ impl 背驰分析 { pub fn 配置背驰( 进入段: &虚线, 离开段: &虚线, - 普K序列: &[Rc], + 普K序列: &[Arc], 配置: &缠论配置, ) -> bool { match ( @@ -152,7 +158,7 @@ impl 背驰分析 { } /// 任选背驰 — 至少两个条件满足(多数投票) - pub fn 任选背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc]) -> bool { + pub fn 任选背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Arc]) -> bool { let 混沌槽 = [ Self::MACD背驰(进入段, 离开段, 普K序列, "总"), Self::测度背驰(进入段, 离开段), @@ -165,7 +171,7 @@ impl 背驰分析 { pub fn 背驰模式( 进入段: &虚线, 离开段: &虚线, - 普K序列: &[Rc], + 普K序列: &[Arc], 配置: &缠论配置, 模式: &str, ) -> bool { @@ -180,9 +186,13 @@ impl 背驰分析 { // ---- 内部辅助 ---- - fn _获取MACD面积(K线序列: &[Rc], 始: &Rc, 终: &Rc) -> MACD面积 { - let 始_idx = K线序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(始)); - let 终_idx = K线序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(终)); + fn _获取MACD面积(K线序列: &[Arc], 始: &Arc, 终: &Arc) -> MACD面积 { + let 始_idx = K线序列 + .iter() + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(始)); + let 终_idx = K线序列 + .iter() + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(终)); let mut 阳 = 0.0f64; let mut 阴 = 0.0f64; diff --git a/chanlun/src/algorithm/hub.rs b/chanlun/src/algorithm/hub.rs index 72d078e..70a7660 100644 --- a/chanlun/src/algorithm/hub.rs +++ b/chanlun/src/algorithm/hub.rs @@ -25,35 +25,50 @@ use crate::structure::dash_line::虚线; use crate::structure::fractal_obj::分型; use crate::types::相对方向; -use std::rc::Rc; +use std::sync::atomic::{AtomicI64, Ordering}; +use std::sync::{Arc, RwLock}; /// 中枢 — 三段虚线重叠区间构成的价格中枢 -#[derive(Debug, Clone)] +/// 可变字段使用 Cell/RefCell 实现内部可变性,确保 Rc 指针身份一致 +#[derive(Debug)] pub struct 中枢 { - pub 序号: i64, - pub 标识: String, - pub 级别: i64, - pub 基础序列: Vec>, - pub 第三买卖线: Option>, - pub 本级_第三买卖线: Option>, + pub 序号: AtomicI64, + pub 标识: RwLock, + pub 级别: AtomicI64, + pub 基础序列: RwLock>>, + pub 第三买卖线: RwLock>>, + pub 本级_第三买卖线: RwLock>>, +} + +impl Clone for 中枢 { + fn clone(&self) -> Self { + Self { + 序号: AtomicI64::new(self.序号.load(Ordering::Relaxed)), + 标识: RwLock::new(self.标识.read().unwrap().clone()), + 级别: AtomicI64::new(self.级别.load(Ordering::Relaxed)), + 基础序列: RwLock::new(self.基础序列.read().unwrap().clone()), + 第三买卖线: RwLock::new(self.第三买卖线.read().unwrap().clone()), + 本级_第三买卖线: RwLock::new(self.本级_第三买卖线.read().unwrap().clone()), + } + } } impl 中枢 { - pub fn new(序号: i64, 标识: String, 级别: i64, 基础序列: Vec>) -> Self { + pub fn new(序号: i64, 标识: String, 级别: i64, 基础序列: Vec>) -> Self { Self { - 序号, - 标识, - 级别, - 基础序列: 基础序列.into_iter().take(3).collect(), - 第三买卖线: None, - 本级_第三买卖线: None, + 序号: AtomicI64::new(序号), + 标识: RwLock::new(标识), + 级别: AtomicI64::new(级别), + 基础序列: RwLock::new(基础序列.into_iter().take(3).collect()), + 第三买卖线: RwLock::new(None), + 本级_第三买卖线: RwLock::new(None), } } - pub fn 添加虚线(&mut self, 实线: Rc<虚线>) { - self.基础序列.push(实线); - self.本级_第三买卖线 = None; - self.第三买卖线 = None; + pub fn 添加虚线(&self, 实线: Arc<虚线>) { + self.基础序列.write().unwrap().push(实线); + *self.本级_第三买卖线.write().unwrap() = None; + *self.第三买卖线.write().unwrap() = None; } pub fn 图表标题(&self) -> String { @@ -61,21 +76,21 @@ impl 中枢 { "{}:{}:{}:{}", self.文().中.标识, self.文().中.周期, - self.标识, - self.序号 + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed) ) } - pub fn 离开段(&self) -> Rc<虚线> { - Rc::clone(&self.基础序列[self.基础序列.len() - 1]) + pub fn 离开段(&self) -> Arc<虚线> { + Arc::clone(&self.基础序列.read().unwrap()[self.基础序列.read().unwrap().len() - 1]) } pub fn 方向(&self) -> 相对方向 { - self.基础序列[0].方向().翻转() + self.基础序列.read().unwrap()[0].方向().翻转() } pub fn 高(&self) -> f64 { - self.基础序列[..3] + self.基础序列.read().unwrap()[..3] .iter() .map(|x| x.高()) .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) @@ -83,7 +98,7 @@ impl 中枢 { } pub fn 低(&self) -> f64 { - self.基础序列[..3] + self.基础序列.read().unwrap()[..3] .iter() .map(|x| x.低()) .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) @@ -92,6 +107,8 @@ impl 中枢 { pub fn 高高(&self) -> f64 { self.基础序列 + .read() + .unwrap() .iter() .map(|x| x.高()) .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) @@ -100,47 +117,54 @@ impl 中枢 { pub fn 低低(&self) -> f64 { self.基础序列 + .read() + .unwrap() .iter() .map(|x| x.低()) .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) .unwrap_or(0.0) } - pub fn 文(&self) -> Rc<分型> { - Rc::clone(&self.基础序列[0].文) + pub fn 文(&self) -> Arc<分型> { + Arc::clone(&self.基础序列.read().unwrap()[0].文) } - pub fn 武(&self) -> Rc<分型> { - Rc::clone(&self.基础序列[self.基础序列.len() - 1].武) + pub fn 武(&self) -> Arc<分型> { + Arc::clone( + &*self.基础序列.read().unwrap()[self.基础序列.read().unwrap().len() - 1] + .武 + .read() + .unwrap(), + ) } - pub fn 设置第三买卖线(&mut self, 线: Rc<虚线>) { - self.第三买卖线 = Some(线); + pub fn 设置第三买卖线(&self, 线: Arc<虚线>) { + *self.第三买卖线.write().unwrap() = Some(线); } /// 获取序列 — 基础序列 + 第三买卖线(若有) - pub fn 获取序列(&self) -> Vec> { - let mut 序列: Vec> = self.基础序列.clone(); - if let Some(ref 三买) = self.第三买卖线 { - 序列.push(Rc::clone(三买)); + pub fn 获取序列(&self) -> Vec> { + let mut 序列: Vec> = self.基础序列.read().unwrap().clone(); + if let Some(ref 三买) = *self.第三买卖线.read().unwrap() { + 序列.push(Arc::clone(三买)); } 序列 } pub fn 获取数据文本(&self) -> String { - let 第三买卖线_str = match &self.第三买卖线 { + let 第三买卖线_str = match &*self.第三买卖线.read().unwrap() { Some(x) => format!("{}", x), None => "None".to_string(), }; - let 本级_第三买卖线_str = match &self.本级_第三买卖线 { + let 本级_第三买卖线_str = match &*self.本级_第三买卖线.read().unwrap() { Some(x) => format!("{}", x), None => "None".to_string(), }; format!( "{}, {}, {}, 文:({},{}), 武:({},{}), {}, {}", - self.标识, - self.序号, - self.级别, + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed), + self.级别.load(Ordering::Relaxed), self.文().时间戳, crate::utils::format_f64_g(self.文().分型特征值), self.武().时间戳, @@ -151,12 +175,12 @@ impl 中枢 { } /// 校验中枢合法性 - pub fn 校验合法性(&mut self, 序列: &[Rc<虚线>]) -> bool { - let mut 有效序列 = self.基础序列.clone(); - let mut 无效序列: Vec> = Vec::new(); - for 元素 in &self.基础序列 { - if !序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(元素)) { - 无效序列.push(Rc::clone(元素)); + pub fn 校验合法性(&self, 序列: &[Arc<虚线>]) -> bool { + let mut 有效序列 = self.基础序列.read().unwrap().clone(); + let mut 无效序列: Vec> = Vec::new(); + for 元素 in self.基础序列.read().unwrap().iter() { + if !序列.iter().any(|x| Arc::as_ptr(x) == Arc::as_ptr(元素)) { + 无效序列.push(Arc::clone(元素)); } } @@ -164,50 +188,52 @@ impl 中枢 { let 无效 = &无效序列[0]; if let Some(pos) = self .基础序列 + .read() + .unwrap() .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(无效)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(无效)) { - 有效序列 = self.基础序列[..pos].to_vec(); + 有效序列 = self.基础序列.read().unwrap()[..pos].to_vec(); } } if 有效序列.len() < 3 { - self.第三买卖线 = None; - self.本级_第三买卖线 = None; + *self.第三买卖线.write().unwrap() = None; + *self.本级_第三买卖线.write().unwrap() = None; return false; } - self.基础序列 = 有效序列; + *self.基础序列.write().unwrap() = 有效序列; let 中枢高 = self.高(); let 中枢低 = self.低(); 有效序列 = Vec::new(); - for 元素 in &self.基础序列 { + for 元素 in self.基础序列.read().unwrap().iter() { if crate::types::相对方向::分析(中枢高, 中枢低, 元素.高(), 元素.低()).是否缺口() { break; } - 有效序列.push(Rc::clone(元素)); + 有效序列.push(Arc::clone(元素)); } - self.基础序列 = 有效序列; + *self.基础序列.write().unwrap() = 有效序列; - if self.基础序列.len() < 3 { + if self.基础序列.read().unwrap().len() < 3 { return false; } - for i in 1..self.基础序列.len() { - let 前 = &self.基础序列[i - 1]; - let 后 = &self.基础序列[i]; + for i in 1..self.基础序列.read().unwrap().len() { + let 前 = &self.基础序列.read().unwrap()[i - 1]; + let 后 = &self.基础序列.read().unwrap()[i]; if !前.之后是(后) { return false; } } if !crate::types::相对方向::分析( - self.基础序列[0].高(), - self.基础序列[0].低(), - self.基础序列[2].高(), - self.基础序列[2].低(), + self.基础序列.read().unwrap()[0].高(), + self.基础序列.read().unwrap()[0].低(), + self.基础序列.read().unwrap()[2].高(), + self.基础序列.read().unwrap()[2].低(), ) .是否缺口() { @@ -218,10 +244,11 @@ impl 中枢 { } } - if let Some(ref 三买线) = self.第三买卖线.clone() { - if 序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(三买线)) { - if !self.基础序列.last().unwrap().之后是(三买线) { - self.第三买卖线 = None; + let 三买线_opt = self.第三买卖线.read().unwrap().clone(); + if let Some(ref 三买线) = 三买线_opt { + if 序列.iter().any(|x| Arc::as_ptr(x) == Arc::as_ptr(三买线)) { + if !self.基础序列.read().unwrap().last().unwrap().之后是(三买线) { + *self.第三买卖线.write().unwrap() = None; } else if !crate::types::相对方向::分析( self.高(), self.低(), @@ -230,11 +257,11 @@ impl 中枢 { ) .是否缺口() { - self.添加虚线(Rc::clone(三买线)); - self.第三买卖线 = None; + self.添加虚线(Arc::clone(三买线)); + *self.第三买卖线.write().unwrap() = None; } } else { - self.第三买卖线 = None; + *self.第三买卖线.write().unwrap() = None; } } true @@ -243,16 +270,18 @@ impl 中枢 { /// 完整性 — 详见教你炒股票43:有关背驰的补习课 /// 不完整时下一个中枢大概率会与当前中枢发生扩展 pub fn 完整性(&self, 虚实: &str) -> bool { - if self.基础序列[0].标识 == "笔" { - return self.第三买卖线.is_some(); + if *self.基础序列.read().unwrap()[0].标识.read().unwrap() == "笔" { + return self.第三买卖线.read().unwrap().is_some(); } - let 线段内部中枢 = if 虚实 == "合" { - &self.基础序列.last().unwrap().合_中枢序列 + let 基础序列_ref = self.基础序列.read().unwrap(); + let 最后段 = 基础序列_ref.last().unwrap(); + let 内部中枢_vec = if 虚实 == "合" { + 最后段.合_中枢序列.read().unwrap() } else { - &self.基础序列.last().unwrap().实_中枢序列 + 最后段.实_中枢序列.read().unwrap() }; - for 内部中枢 in 线段内部中枢 { + for 内部中枢 in 内部中枢_vec.iter() { if crate::types::相对方向::分析( self.高(), self.低(), @@ -269,16 +298,19 @@ impl 中枢 { /// 获取扩展中枢 — 当基础序列 >= 9 时生成扩展中枢 pub fn 获取扩展中枢( - &self, 扩展中枢: &mut Vec>, 配置: &crate::config::缠论配置 + &self, + 扩展中枢: &mut Vec>, + 配置: &crate::config::缠论配置, ) { - if self.基础序列.len() >= 9 { - let mut 扩展线段: Vec> = Vec::new(); - crate::algorithm::segment::线段::扩展分析(&self.基础序列, &mut 扩展线段, 配置); + if self.基础序列.read().unwrap().len() >= 9 { + let mut 扩展线段: Vec> = Vec::new(); + let 基础序列_ref = self.基础序列.read().unwrap(); + crate::algorithm::segment::线段::扩展分析(&基础序列_ref, &mut 扩展线段, 配置); 中枢::分析( &扩展线段, 扩展中枢, false, - &format!("{}_扩展中枢_", self.标识), + &format!("{}_扩展中枢_", self.标识.read().unwrap()), 0, ); } @@ -287,9 +319,15 @@ impl 中枢 { /// 当前状态 — 详见教你炒股票49:利润率最大的操作模式 /// 返回当前中枢最后一段所处的位置关系:中枢之中/中枢之上/中枢之下 pub fn 当前状态(&self) -> &str { - let 最后 = self.基础序列.last().unwrap(); + let 基础序列_ref = self.基础序列.read().unwrap(); + let 最后 = Arc::clone(基础序列_ref.last().unwrap()); let 尾部 = 最后.获取_武(); - let 关系 = crate::types::相对方向::分析(self.高(), self.低(), 尾部.中.高, 尾部.中.低); + let 关系 = crate::types::相对方向::分析( + self.高(), + self.低(), + 尾部.中.高.get(), + 尾部.中.低.get(), + ); if 关系 == crate::types::相对方向::向上缺口 { "中枢之上" } else if 关系 == crate::types::相对方向::向下缺口 { @@ -319,11 +357,11 @@ impl 中枢 { /// 创建中枢 pub fn 创建( - 左: Rc<虚线>, 中: Rc<虚线>, 右: Rc<虚线>, 级别: i64, 标识: &str + 左: Arc<虚线>, 中: Arc<虚线>, 右: Arc<虚线>, 级别: i64, 标识: &str ) -> Self { Self::new( 0, - format!("{}中枢<{}>", 标识, 中.标识), + format!("{}中枢<{}>", 标识, 中.标识.read().unwrap()), 级别, vec![左, 中, 右], ) @@ -331,17 +369,17 @@ impl 中枢 { /// 从序列中获取中枢 pub fn 从序列中获取中枢( - 虚线序列: &[Rc<虚线>], + 虚线序列: &[Arc<虚线>], 起始方向: 相对方向, 标识: &str, - ) -> Option> { + ) -> Option> { for i in 2..虚线序列.len() { let 左 = &虚线序列[i - 2]; let 中 = &虚线序列[i - 1]; let 右 = &虚线序列[i]; if Self::基础检查(左, 中, 右) && 左.方向() == 起始方向 { - let 中枢 = Self::创建(Rc::clone(左), Rc::clone(中), Rc::clone(右), 0, 标识); - return Some(Rc::new(中枢)); + let 中枢 = Self::创建(Arc::clone(左), Arc::clone(中), Arc::clone(右), 0, 标识); + return Some(Arc::new(中枢)); } } None @@ -349,19 +387,22 @@ impl 中枢 { /// 向中枢序列尾部添加 pub fn 向中枢序列尾部添加( - 中枢序列: &mut Vec>, mut 待添加中枢: Rc<中枢> + 中枢序列: &mut Vec>, mut 待添加中枢: Arc<中枢> ) { if let Some(前一个) = 中枢序列.last() { - let 新 = Rc::make_mut(&mut 待添加中枢); - 新.序号 = 前一个.序号 + 1; + 待添加中枢 + .序号 + .store(前一个.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); // Python: assert seq[-1].获取序列()[-1].序号 <= new.获取序列()[-1].序号 let 前_seq = 前一个.获取序列(); - let new_seq = 新.获取序列(); + let new_seq = 待添加中枢.获取序列(); if let (Some(前_last), Some(new_last)) = (前_seq.last(), new_seq.last()) { - if 前_last.序号 > new_last.序号 { + if 前_last.序号.load(Ordering::Relaxed) > new_last.序号.load(Ordering::Relaxed) + { panic!( "向中枢序列尾部添加 序号错误 前last={} > new_last={}", - 前_last.序号, new_last.序号 + 前_last.序号.load(Ordering::Relaxed), + new_last.序号.load(Ordering::Relaxed) ); } } @@ -371,10 +412,10 @@ impl 中枢 { /// 从中枢序列尾部弹出 pub fn 从中枢序列尾部弹出( - 中枢序列: &mut Vec>, - 待弹出: &Rc<中枢>, - ) -> Option> { - if 中枢序列.last().map(|x| Rc::as_ptr(x)) == Some(Rc::as_ptr(待弹出)) { + 中枢序列: &mut Vec>, + 待弹出: &Arc<中枢>, + ) -> Option> { + if 中枢序列.last().map(|x| Arc::as_ptr(x)) == Some(Arc::as_ptr(待弹出)) { 中枢序列.pop() } else { None @@ -385,8 +426,8 @@ impl 中枢 { /// /// 每收到新的虚线序列数据后调用,更新中枢序列 pub fn 分析( - 虚线序列: &[Rc<虚线>], - 中枢序列: &mut Vec>, + 虚线序列: &[Arc<虚线>], + 中枢序列: &mut Vec>, 跳过首部: bool, 标识: &str, 层级: i64, @@ -406,9 +447,9 @@ impl 中枢 { // Python: 序号 = 虚线序列.index(左) let 序号 = 虚线序列 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(左)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(左)) .unwrap_or(i - 1); - if 跳过首部 && (左.序号 == 0 || 序号 == 0) { + if 跳过首部 && (左.序号.load(Ordering::Relaxed) == 0 || 序号 == 0) { continue; } if 序号 >= 2 { @@ -422,11 +463,11 @@ impl 中枢 { continue; } } - let 新中枢 = Rc::new(Self::创建( - Rc::clone(左), - Rc::clone(中), - Rc::clone(右), - 中.级别, + let 新中枢 = Arc::new(Self::创建( + Arc::clone(左), + Arc::clone(中), + Arc::clone(右), + 中.级别.load(Ordering::Relaxed), 标识, )); Self::向中枢序列尾部添加(中枢序列, 新中枢); @@ -441,13 +482,10 @@ impl 中枢 { // 增量更新 let mut 当前中枢_idx = 中枢序列.len() - 1; - // Validate in-place via Rc::make_mut — avoids full中枢 struct clone - let needs_pop = { - let cur = Rc::make_mut(&mut 中枢序列[当前中枢_idx]); - !cur.校验合法性(虚线序列) - }; + // Validate via shared reference (中枢 uses RwLock internally) + let needs_pop = !中枢序列[当前中枢_idx].校验合法性(虚线序列); if needs_pop { - let 当前中枢 = Rc::clone(&中枢序列[当前中枢_idx]); + let 当前中枢 = Arc::clone(&中枢序列[当前中枢_idx]); Self::从中枢序列尾部弹出(中枢序列, &当前中枢); Self::分析(虚线序列, 中枢序列, 跳过首部, 标识, 层级); return; @@ -456,10 +494,10 @@ impl 中枢 { // 找到当前中枢最后一个元素在虚线序列中的位置 let 起始索引 = { let cur = &中枢序列[当前中枢_idx]; - let 最后元素 = &cur.基础序列[cur.基础序列.len() - 1]; + let 最后元素 = &cur.基础序列.read().unwrap()[cur.基础序列.read().unwrap().len() - 1]; match 虚线序列 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(最后元素)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(最后元素)) { Some(idx) => idx + 1, None => return, @@ -468,10 +506,10 @@ impl 中枢 { let mut 中枢高 = 中枢序列[当前中枢_idx].高(); let mut 中枢低 = 中枢序列[当前中枢_idx].低(); - let mut 候选序列: Vec> = Vec::new(); + let mut 候选序列: Vec> = Vec::new(); for i in 起始索引..虚线序列.len() { - let 当前虚线 = Rc::clone(&虚线序列[i]); + let 当前虚线 = Arc::clone(&虚线序列[i]); // 检查是否超出中枢范围(缺口) if crate::types::相对方向::分析(中枢高, 中枢低, 当前虚线.高(), 当前虚线.低()).是否缺口() @@ -481,16 +519,20 @@ impl 中枢 { // Python: if 当前中枢.基础序列[-1].之后是(当前虚线): let needs_三买 = { let cur = &中枢序列[当前中枢_idx]; - cur.基础序列.last().unwrap().之后是(&当前虚线) + cur.基础序列 + .read() + .unwrap() + .last() + .unwrap() + .之后是(&当前虚线) }; if needs_三买 { - Rc::make_mut(&mut 中枢序列[当前中枢_idx]) - .设置第三买卖线(当前虚线.clone()); + 中枢序列[当前中枢_idx].设置第三买卖线(当前虚线.clone()); } } else { if 候选序列.is_empty() { // 仍在范围内:延伸中枢 - Rc::make_mut(&mut 中枢序列[当前中枢_idx]).添加虚线(当前虚线); + 中枢序列[当前中枢_idx].添加虚线(当前虚线); } else { 候选序列.push(当前虚线); } @@ -500,6 +542,8 @@ impl 中枢 { while 候选序列.len() >= 3 { let 起始方向 = 中枢序列[当前中枢_idx] .基础序列 + .read() + .unwrap() .last() .unwrap() .方向() @@ -522,10 +566,317 @@ impl 中枢 { } } +#[cfg(test)] +mod tests { + use super::*; + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + use crate::structure::fractal_obj::分型; + use crate::types::分型结构; + + fn 辅助_创建K线(时间戳: i64, 高: f64, 低: f64, 开: f64, 收: f64) -> K线 { + let mut k = K线::default(); + k.时间戳 = 时间戳; + k.高 = 高; + k.低 = 低; + k.开盘价 = 开; + k.收盘价 = 收; + k + } + + fn 辅助_创建缠K( + 时间戳: i64, + 高: f64, + 低: f64, + 方向: 相对方向, + 结构: Option<分型结构>, + 序号: i64, + ) -> Arc<缠论K线> { + let 普K = Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)); + Arc::new(缠论K线::创建缠K( + 时间戳, 高, 低, 方向, 结构, 序号, 普K, None, + )) + } + + fn 辅助_创建顶分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 - 2.0, + 低 - 2.0, + 相对方向::向上, + Some(分型结构::上), + 序号 - 2, + ); + let 中 = 辅助_创建缠K(时间戳, 高, 低, 相对方向::向上, Some(分型结构::顶), 序号); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 - 1.0, + 低 - 1.0, + 相对方向::向下, + Some(分型结构::下), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + fn 辅助_创建底分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 + 2.0, + 低 + 2.0, + 相对方向::向下, + Some(分型结构::下), + 序号 - 2, + ); + let 中 = 缠论K线::创建缠K( + 时间戳, + 高, + 低, + 相对方向::向下, + Some(分型结构::底), + 序号, + Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)), + None, + ); + 中.分型特征值.set(低); + let 中 = Arc::new(中); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 + 1.0, + 低 + 1.0, + 相对方向::向上, + Some(分型结构::上), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + fn 辅助_创建笔( + 文时间戳: i64, + 文高: f64, + 文低: f64, + 武时间戳: i64, + 武高: f64, + 武低: f64, + ) -> Arc<虚线> { + let 顶 = 辅助_创建顶分型(文时间戳, 文高, 文低, 1); + let 底 = 辅助_创建底分型(武时间戳, 武高, 武低, 2); + Arc::new(虚线::创建笔(顶, 底, true)) + } + + // ============================================================ + // 中枢 Cell/RefCell 字段读写 + // ============================================================ + + #[test] + fn test_中枢创建后字段初始值正确() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + + let 中枢 = 中枢::new( + 1, + "测试中枢".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + + assert_eq!(中枢.序号.load(Ordering::Relaxed), 1); + assert_eq!(*中枢.标识.read().unwrap(), "测试中枢"); + assert_eq!(中枢.级别.load(Ordering::Relaxed), 1); + assert_eq!(中枢.基础序列.read().unwrap().len(), 3); + assert!(中枢.第三买卖线.read().unwrap().is_none()); + assert!(中枢.本级_第三买卖线.read().unwrap().is_none()); + } + + #[test] + fn test_中枢CellRefCell字段读写() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + + let 中枢 = 中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + + // Cell 序号读写 + 中枢.序号.store(99, Ordering::Relaxed); + assert_eq!(中枢.序号.load(Ordering::Relaxed), 99); + + // RefCell 第三买卖线读写 + 中枢.设置第三买卖线(Arc::clone(&笔1)); + assert!(中枢.第三买卖线.read().unwrap().is_some()); + assert_eq!( + Arc::as_ptr(&*中枢.第三买卖线.read().unwrap().as_ref().unwrap()), + Arc::as_ptr(&笔1) + ); + + // 本级_第三买卖线 + assert!(中枢.本级_第三买卖线.read().unwrap().is_none()); + *中枢.本级_第三买卖线.write().unwrap() = Some(Arc::clone(&笔3)); + assert!(中枢.本级_第三买卖线.read().unwrap().is_some()); + } + + // ============================================================ + // 中枢 添加虚线 + // ============================================================ + + #[test] + fn test_中枢添加虚线后基础序列扩展() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + let 笔4 = 辅助_创建笔(400, 25.0, 15.0, 500, 60.0, 50.0); + + let 中枢 = 中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + assert_eq!(中枢.基础序列.read().unwrap().len(), 3); + + 中枢.添加虚线(Arc::clone(&笔4)); + assert_eq!(中枢.基础序列.read().unwrap().len(), 4); + assert_eq!( + Arc::as_ptr(&中枢.基础序列.read().unwrap()[3]), + Arc::as_ptr(&笔4) + ); + } + + #[test] + fn test_中枢添加虚线后清除第三买卖线() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + let 笔4 = 辅助_创建笔(400, 25.0, 15.0, 500, 60.0, 50.0); + + let 中枢 = 中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + 中枢.设置第三买卖线(Arc::clone(&笔1)); + *中枢.本级_第三买卖线.write().unwrap() = Some(Arc::clone(&笔2)); + assert!(中枢.第三买卖线.read().unwrap().is_some()); + assert!(中枢.本级_第三买卖线.read().unwrap().is_some()); + + 中枢.添加虚线(Arc::clone(&笔4)); + // 添加虚线后第三买卖线被清除 + assert!(中枢.第三买卖线.read().unwrap().is_none()); + assert!(中枢.本级_第三买卖线.read().unwrap().is_none()); + } + + // ============================================================ + // Clone 后 Rc 指针身份一致 + // ============================================================ + + #[test] + fn test_中枢Clone后基础序列Rc指针一致() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + + let 中枢 = 中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + 中枢.设置第三买卖线(Arc::clone(&笔1)); + + let 克隆 = 中枢.clone(); + + // 基础序列中的 Rc 指针应一致 + for i in 0..3 { + assert_eq!( + Arc::as_ptr(&中枢.基础序列.read().unwrap()[i]), + Arc::as_ptr(&克隆.基础序列.read().unwrap()[i]) + ); + } + + // 第三买卖线 Rc 指针应一致 + assert_eq!( + Arc::as_ptr(中枢.第三买卖线.read().unwrap().as_ref().unwrap()), + Arc::as_ptr(克隆.第三买卖线.read().unwrap().as_ref().unwrap()) + ); + } + + // ============================================================ + // 中枢 高/低/高高/低低计算 + // ============================================================ + + #[test] + fn test_中枢高低计算正确() { + // 笔1: 顶(高=50,低=45) →底(高=40,低=30) = 向下笔, 高=50, 低=30 + let 笔1 = 辅助_创建笔(100, 50.0, 45.0, 200, 40.0, 30.0); + + // 笔2: 底(高=40,低=30) →顶(高=55,低=50) = 向上笔, 高=55, 低=30 + let 底2 = 辅助_创建底分型(200, 40.0, 30.0, 10); + let 顶2 = 辅助_创建顶分型(300, 55.0, 50.0, 15); + let 笔2 = Arc::new(虚线::创建笔(底2, 顶2, true)); + + // 笔3: 顶(高=55,低=50) →底(高=35,低=25) = 向下笔, 高=55, 低=25 + let 笔3 = 辅助_创建笔(300, 55.0, 50.0, 400, 35.0, 25.0); + + let 中枢 = 中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + ); + + // 高 = min(笔1高, 笔2高, 笔3高) = min(50, 55, 55) = 50 + assert!((中枢.高() - 50.0).abs() < 0.01, "中枢高={}", 中枢.高()); + // 低 = max(笔1低, 笔2低, 笔3低) = max(30, 30, 25) = 30 + assert!((中枢.低() - 30.0).abs() < 0.01, "中枢低={}", 中枢.低()); + } + + // ============================================================ + // 多 Rc 共享下修改可见性 + // ============================================================ + + #[test] + fn test_多Rc共享中枢修改对所有引用可见() { + let 笔1 = 辅助_创建笔(100, 50.0, 40.0, 200, 30.0, 20.0); + let 笔2 = 辅助_创建笔(200, 30.0, 20.0, 300, 55.0, 45.0); + let 笔3 = 辅助_创建笔(300, 55.0, 45.0, 400, 25.0, 15.0); + let 笔4 = 辅助_创建笔(400, 25.0, 15.0, 500, 60.0, 50.0); + + let 中枢1 = Arc::new(中枢::new( + 0, + "测试".into(), + 1, + vec![Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)], + )); + let 中枢2 = Arc::clone(&中枢1); + + // 通过 rc1 修改序号 + 中枢1.序号.store(88, Ordering::Relaxed); + assert_eq!(中枢2.序号.load(Ordering::Relaxed), 88); + + // 通过 rc1 添加虚线 + 中枢1.添加虚线(Arc::clone(&笔4)); + assert_eq!(中枢2.基础序列.read().unwrap().len(), 4); + + // 验证共享的 Arc<虚线> 指针一致 + assert_eq!( + Arc::as_ptr(&中枢1.基础序列.read().unwrap()[3]), + Arc::as_ptr(&中枢2.基础序列.read().unwrap()[3]) + ); + } +} + impl std::fmt::Display for 中枢 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let 序列_str = self .基础序列 + .read() + .unwrap() .iter() .map(|d| format!("{}", d)) .collect::>() @@ -533,10 +884,10 @@ impl std::fmt::Display for 中枢 { write!( f, "{}({}, {}, 元素数量: {}, [{}], {} ===>>> {})", - self.标识, + self.标识.read().unwrap(), crate::utils::format_f64_g(self.高()), crate::utils::format_f64_g(self.低()), - self.基础序列.len(), + self.基础序列.read().unwrap().len(), 序列_str, self.文(), self.武(), diff --git a/chanlun/src/algorithm/segment.rs b/chanlun/src/algorithm/segment.rs index 3fe145c..872420e 100644 --- a/chanlun/src/algorithm/segment.rs +++ b/chanlun/src/algorithm/segment.rs @@ -32,7 +32,8 @@ use crate::structure::dash_line::虚线; use crate::structure::fractal_obj::分型; use crate::structure::segment_feat::线段特征; use crate::types::{分型结构, 相对方向, 缺口}; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; /// 线段 — 从笔生成线段的算法集合(静态方法命名空间) pub struct 线段; @@ -42,47 +43,76 @@ impl 线段 { // 基础操作 // ================================================================ - /// 获取Rc<虚线>的可变引用(clone-on-write) - fn 取段可变(段_rc: &mut Rc<虚线>) -> &mut 虚线 { - if Rc::strong_count(段_rc) > 1 { - let 克隆 = (**段_rc).clone(); - *段_rc = Rc::new(克隆); - } - Rc::get_mut(段_rc).unwrap() + /// 解引用 Arc<虚线> → &虚线。内部 RwLock/Atomic 字段支持通过不可变引用修改。 + fn 取段(段_rc: &Arc<虚线>) -> &虚线 { + 段_rc } /// 向线段的基础序列中添加一笔 - pub fn 添加虚线(段_rc: &mut Rc<虚线>, 筆: Rc<虚线>) { - let 段 = Self::取段可变(段_rc); - if !段.基础序列.is_empty() { - if !分型::判断分型(&段.基础序列.last().unwrap().武, &筆.文, "中") { + pub fn 添加虚线(段_rc: &Arc<虚线>, 筆: Arc<虚线>) { + let 段 = Self::取段(段_rc); + if !段.基础序列.read().unwrap().is_empty() { + if !分型::判断分型( + &*段 + .基础序列 + .read() + .unwrap() + .last() + .unwrap() + .武 + .read() + .unwrap(), + &筆.文, + "中", + ) { panic!( "线段.添加虚线 不连续 {} {}", - 段.基础序列.last().unwrap(), + 段.基础序列.read().unwrap().last().unwrap(), 筆 ); } - if 段.基础序列.last().unwrap().标识 != 筆.标识 { + if *段 + .基础序列 + .read() + .unwrap() + .last() + .unwrap() + .标识 + .read() + .unwrap() + != *筆.标识.read().unwrap() + { panic!( "线段.添加虚线 标识不符 {} {}", - 段.基础序列.last().unwrap().标识, - 筆.标识 + *段.基础序列 + .read() + .unwrap() + .last() + .unwrap() + .标识 + .read() + .unwrap(), + 筆.标识.read().unwrap() ); } } - 段.基础序列.push(筆); + 段.基础序列.write().unwrap().push(筆); } /// 更新线段的终点分型 - pub fn 武斗(段_rc: &mut Rc<虚线>, 武: &Rc<分型>, 行号: u32) { - let 段 = Self::取段可变(段_rc); - if Rc::as_ptr(&段.武) == Rc::as_ptr(武) { + pub fn 武斗(段_rc: &Arc<虚线>, 武: &Arc<分型>, 行号: u32) { + let 段 = Self::取段(段_rc); + if Arc::as_ptr(&*段.武.read().unwrap()) == Arc::as_ptr(武) { return; } - if 段.武.分型特征值 == 武.分型特征值 && 段.武.时间戳 != 武.时间戳 { + if 段.武.read().unwrap().分型特征值 == 武.分型特征值 + && 段.武.read().unwrap().时间戳 != 武.时间戳 + { eprintln!( "线段.武斗[{}], 发现特征值相等但时间戳不同 {} {}", - 行号, 段.武, 武 + 行号, + 段.武.read().unwrap(), + 武 ); } if 段.文.结构 == 武.结构 { @@ -99,22 +129,42 @@ impl 线段 { } if 段.方向() == 相对方向::向上 { if 武.分型特征值 < 段.文.分型特征值 { - panic!("向上线段, 结束点小于起点 {} {} {}", 段.标识, 段.文, 武); + panic!( + "向上线段, 结束点小于起点 {} {} {}", + 段.标识.read().unwrap(), + 段.文, + 武 + ); } } else { if 武.分型特征值 > 段.文.分型特征值 { - panic!("向下线段, 结束点大于起点 {} {} {}", 段.标识, 段.文, 武); + panic!( + "向下线段, 结束点大于起点 {} {} {}", + 段.标识.read().unwrap(), + 段.文, + 武 + ); } } - 段.武 = Rc::clone(武); + *段.武.write().unwrap() = Arc::clone(武); } /// 武终 — 线段终结时设置终点 - pub fn 武终(段_rc: &mut Rc<虚线>, 行号: u32) { + pub fn 武终(段_rc: &Arc<虚线>, 行号: u32) { let 武 = { - let 段 = Self::取段可变(段_rc); - if 段.模式 != "文武" { - Some(Rc::clone(&段.基础序列.last().unwrap().武)) + let 段 = Self::取段(段_rc); + if 段.模式.read().unwrap().as_str() != "文武" { + Some(Arc::clone( + &*段 + .基础序列 + .read() + .unwrap() + .last() + .unwrap() + .武 + .read() + .unwrap(), + )) } else { None } @@ -125,11 +175,11 @@ impl 线段 { } /// 验证序列 — 截断无效尾部 - pub fn 验证序列(段_rc: &mut Rc<虚线>, 序列: &[Rc<虚线>]) { - let 段 = Self::取段可变(段_rc); - let mut 基础序列: Vec> = Vec::new(); - for 元素 in &段.基础序列 { - if !序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(元素)) { + pub fn 验证序列(段_rc: &Arc<虚线>, 序列: &[Arc<虚线>]) { + let 段 = Self::取段(段_rc); + let mut 基础序列: Vec> = Vec::new(); + for 元素 in 段.基础序列.read().unwrap().iter() { + if !序列.iter().any(|x| Arc::as_ptr(x) == Arc::as_ptr(元素)) { break; } if !基础序列.is_empty() { @@ -138,20 +188,20 @@ impl 线段 { break; } } - 基础序列.push(Rc::clone(元素)); + 基础序列.push(Arc::clone(元素)); } if 基础序列.len() % 2 == 0 { 基础序列.pop(); } - 段.基础序列 = 基础序列; + *段.基础序列.write().unwrap() = 基础序列; } /// 序列重置 — 截取到序列中的有效部分 - pub fn 序列重置(段_rc: &mut Rc<虚线>, 序列: &[Rc<虚线>]) { - let 段 = Self::取段可变(段_rc); - let mut 基础序列: Vec> = Vec::new(); - for 元素 in &段.基础序列 { - if !序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(元素)) { + pub fn 序列重置(段_rc: &Arc<虚线>, 序列: &[Arc<虚线>]) { + let 段 = Self::取段(段_rc); + let mut 基础序列: Vec> = Vec::new(); + for 元素 in 段.基础序列.read().unwrap().iter() { + if !序列.iter().any(|x| Arc::as_ptr(x) == Arc::as_ptr(元素)) { break; } if !基础序列.is_empty() { @@ -159,11 +209,11 @@ impl 线段 { break; } } - 基础序列.push(Rc::clone(元素)); + 基础序列.push(Arc::clone(元素)); } - 段.基础序列 = 基础序列; - if 段.特征序列.len() > 2 { - 段.特征序列[2] = None; + *段.基础序列.write().unwrap() = 基础序列; + if 段.特征序列.read().unwrap().len() > 2 { + 段.特征序列.write().unwrap()[2] = None; } } @@ -214,7 +264,7 @@ impl 线段 { /// 小阳: 向上线段 /// 少阴: 向下线段 pub fn 四象(段: &虚线) -> String { - if 段.前一缺口.is_some() { + if 段.前一缺口.read().unwrap().is_some() { if 段.方向() == 相对方向::向上 { "老阳".into() } else { @@ -229,14 +279,15 @@ impl 线段 { /// 获取缺口 — 从特征序列第一二元素之间检测缺口 pub fn 获取缺口(段: &虚线) -> Option<缺口> { - if 段.模式 != "文武" { + if 段.模式.read().unwrap().as_str() != "文武" { return None; } - if 段.特征序列.len() < 2 { + if 段.特征序列.read().unwrap().len() < 2 { return None; } - let 左 = 段.特征序列[0].as_ref()?; - let 中 = 段.特征序列[1].as_ref()?; + let 特序 = 段.特征序列.read().unwrap(); + let 左 = 特序[0].as_ref()?; + let 中 = 特序[1].as_ref()?; let 相对关系 = 相对方向::分析(左.高(), 左.低(), 中.高(), 中.低()); if 相对关系.是否缺口() { let 高 = 左.文().分型特征值.max(中.文().分型特征值); @@ -249,7 +300,12 @@ impl 线段 { /// 特征分型终结 — 检查特征序列是否形成正常分型终结 pub fn 特征分型终结(段: &虚线) -> bool { - let 特征序列 = 线段特征::静态分析(&段.基础序列, 段.方向(), &Self::四象(段), false); + let 特征序列 = 线段特征::静态分析( + &*段.基础序列.read().unwrap(), + 段.方向(), + &Self::四象(段), + false, + ); if 特征序列.len() >= 3 { let idx = 特征序列.len(); if let Some(结构) = 分型结构::分析( @@ -271,16 +327,23 @@ impl 线段 { /// 特征序列状态 — 返回三个特征序列元素是否为 Some pub fn 特征序列状态(段: &虚线) -> (bool, bool, bool) { - let get = |i: usize| 段.特征序列.get(i).map(|x| x.is_some()).unwrap_or(false); + let get = |i: usize| { + 段.特征序列 + .read() + .unwrap() + .get(i) + .map(|x| x.is_some()) + .unwrap_or(false) + }; (get(0), get(1), get(2)) } /// 设置特征序列 pub fn 设置特征序列( - 段_rc: &mut Rc<虚线>, 序列: Vec>>, 行号: u32 + 段_rc: &Arc<虚线>, 序列: Vec>>, 行号: u32 ) { - let 段 = Self::取段可变(段_rc); - if 段.模式 != "文武" { + let 段 = Self::取段(段_rc); + if 段.模式.read().unwrap().as_str() != "文武" { return; } @@ -295,27 +358,29 @@ impl 线段 { let 左 = 序列[0].clone(); let 中 = 序列[1].clone(); let 右 = 序列[2].clone(); - 段.特征序列 = vec![左, 中, 右]; + *段.特征序列.write().unwrap() = vec![左, 中, 右]; - if let Some(ref 右特征) = 段.特征序列[2] { - let mut 基础序列: Vec> = Vec::new(); + if let Some(ref 右特征) = 段.特征序列.read().unwrap()[2] { + let mut 基础序列: Vec> = Vec::new(); let 右尾 = 右特征.元素.last().expect("特征序列元素不应为空"); if !段 .基础序列 + .read() + .unwrap() .iter() - .any(|x| Rc::as_ptr(x) == Rc::as_ptr(右尾)) + .any(|x| Arc::as_ptr(x) == Arc::as_ptr(右尾)) { panic!("右特征最后一个元素不在基础序列中"); } - for 元素 in &段.基础序列 { - 基础序列.push(Rc::clone(元素)); - if Rc::as_ptr(元素) == Rc::as_ptr(右尾) { + for 元素 in 段.基础序列.read().unwrap().iter() { + 基础序列.push(Arc::clone(元素)); + if Arc::as_ptr(元素) == Arc::as_ptr(右尾) { break; } } if 基础序列.len() >= 6 && 基础序列.len() % 2 == 0 { - 段.基础序列 = 基础序列; + *段.基础序列.write().unwrap() = 基础序列; } else { panic!("设置特征序列: 基础序列长度不足或非偶数"); } @@ -323,70 +388,79 @@ impl 线段 { } /// 刷新特征序列 - pub fn 刷新特征序列(段_rc: &mut Rc<虚线>, 配置: &缠论配置) { - let 段 = Rc::make_mut(段_rc); - if 段.模式 != "文武" { - return; - } - let mut 基础序列 = 段.基础序列.clone(); - if let Some(ref 前结束) = 段.前一结束位置 { - if let Some(idx) = 基础序列 - .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(前结束)) - { - if idx > 0 { - 基础序列 = 基础序列[idx - 1..].to_vec(); + pub fn 刷新特征序列(段_rc: &Arc<虚线>, 配置: &缠论配置) { + // Compute new feature sequence, then delegate to 设置特征序列 for truncation + let 序列: Vec>> = { + let 段 = &**段_rc; + if 段.模式.read().unwrap().as_str() != "文武" { + return; + } + let mut 基础序列 = 段.基础序列.read().unwrap().clone(); + if let Some(ref 前结束) = *段.前一结束位置.read().unwrap() { + if let Some(idx) = 基础序列 + .iter() + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(前结束)) + { + if idx > 0 { + 基础序列 = 基础序列[idx - 1..].to_vec(); + } } } - } - let 四象 = Self::四象(段); - let 特征序列 = - 线段特征::静态分析(&基础序列, 段.方向(), &四象, 配置.线段_特征序列忽视老阴老阳); + let 四象 = Self::四象(段); + let 特征序列 = 线段特征::静态分析( + &基础序列, + 段.方向(), + &四象, + 配置.线段_特征序列忽视老阴老阳, + ); - if 特征序列.len() >= 3 { - let 分型序列 = 线段特征::获取分型序列(&特征序列); - if !分型序列.is_empty() { - let 最后分型 = &分型序列[分型序列.len() - 1]; - if (段.方向() == 相对方向::向上 && 最后分型.结构 == 分型结构::顶) - || (段.方向() == 相对方向::向下 && 最后分型.结构 == 分型结构::底) - { - 段.特征序列 = vec![ - Some(Rc::clone(&最后分型.左)), - Some(Rc::clone(&最后分型.中)), - Some(Rc::clone(&最后分型.右)), - ]; + if 特征序列.len() >= 3 { + let 分型序列 = 线段特征::获取分型序列(&特征序列); + if !分型序列.is_empty() { + let 最后分型 = &分型序列[分型序列.len() - 1]; + if (段.方向() == 相对方向::向上 && 最后分型.结构 == 分型结构::顶) + || (段.方向() == 相对方向::向下 && 最后分型.结构 == 分型结构::底) + { + vec![ + Some(Arc::clone(&最后分型.左)), + Some(Arc::clone(&最后分型.中)), + Some(Arc::clone(&最后分型.右)), + ] + } else { + vec![ + Some(Arc::clone(&特征序列[特征序列.len() - 2])), + Some(Arc::clone(&特征序列[特征序列.len() - 1])), + None, + ] + } } else { - 段.特征序列 = vec![ - Some(Rc::clone(&特征序列[特征序列.len() - 2])), - Some(Rc::clone(&特征序列[特征序列.len() - 1])), + vec![ + Some(Arc::clone(&特征序列[特征序列.len() - 2])), + Some(Arc::clone(&特征序列[特征序列.len() - 1])), None, - ]; + ] } } else { - 段.特征序列 = vec![ - Some(Rc::clone(&特征序列[特征序列.len() - 2])), - Some(Rc::clone(&特征序列[特征序列.len() - 1])), - None, - ]; + let mut 填充: Vec>> = 特征序列.into_iter().map(Some).collect(); + 填充.resize(3, None); + 填充 } - } else { - let mut 填充: Vec>> = 特征序列.into_iter().map(Some).collect(); - 填充.resize(3, None); - 段.特征序列 = 填充; - } + }; // 段 borrow ends here + + Self::设置特征序列(段_rc, 序列, 0); } /// 查找贯穿伤 — 基础序列中穿透文分型特征值的笔 - pub fn 查找贯穿伤(段: &虚线) -> Option> { - for 贯穿伤 in 段.基础序列.iter().skip(3) { + pub fn 查找贯穿伤(段: &虚线) -> Option> { + for 贯穿伤 in 段.基础序列.read().unwrap().iter().skip(3) { if 段.方向().是否向上() { - if 贯穿伤.武.分型特征值 < 段.文.分型特征值 { - return Some(Rc::clone(贯穿伤)); + if 贯穿伤.武.read().unwrap().分型特征值 < 段.文.分型特征值 { + return Some(Arc::clone(贯穿伤)); } } else { - if 贯穿伤.武.分型特征值 > 段.文.分型特征值 { - return Some(Rc::clone(贯穿伤)); + if 贯穿伤.武.read().unwrap().分型特征值 > 段.文.分型特征值 { + return Some(Arc::clone(贯穿伤)); } } } @@ -402,45 +476,53 @@ impl 线段 { 段: &虚线, mut 所属中枢: Option<&mut 中枢>, ) -> ( - Vec>, - Vec>, - Vec>, - Option>, + Vec>, + Vec>, + Vec>, + Option>, ) { - if 段.模式 != "文武" { - return (段.基础序列.clone(), Vec::new(), Vec::new(), None); + if 段.模式.read().unwrap().as_str() != "文武" { + return ( + 段.基础序列.read().unwrap().clone(), + Vec::new(), + Vec::new(), + None, + ); } - let mut 前: Vec> = Vec::new(); - let mut 后: Vec> = Vec::new(); - let mut 第三买卖线: Vec> = Vec::new(); - let mut 贯穿伤: Option> = None; + let mut 前: Vec> = Vec::new(); + let mut 后: Vec> = Vec::new(); + let mut 第三买卖线: Vec> = Vec::new(); + let mut 贯穿伤: Option> = None; - for 筆 in &段.基础序列 { + for 筆 in 段.基础序列.read().unwrap().iter() { if 前.is_empty() { - 前.push(Rc::clone(筆)); + 前.push(Arc::clone(筆)); continue; } - if Rc::as_ptr(&前.last().unwrap().武) != Rc::as_ptr(&段.武) && 后.is_empty() { - 前.push(Rc::clone(筆)); + if Arc::as_ptr(&*前.last().unwrap().武.read().unwrap()) + != Arc::as_ptr(&*段.武.read().unwrap()) + && 后.is_empty() + { + 前.push(Arc::clone(筆)); } if !后.is_empty() { - 后.push(Rc::clone(筆)); + 后.push(Arc::clone(筆)); } - if Rc::as_ptr(&筆.文) == Rc::as_ptr(&段.武) { - 后.push(Rc::clone(筆)); + if Arc::as_ptr(&筆.文) == Arc::as_ptr(&*段.武.read().unwrap()) { + 后.push(Arc::clone(筆)); } } let mut 状态 = None; if let Some(ref mut 中枢) = 所属中枢 { - 中枢.本级_第三买卖线 = None; + *中枢.本级_第三买卖线.write().unwrap() = None; let 尾部 = if let Some(ref 后笔) = 后.last() { - Rc::clone(&后笔.武) + 后笔.武.read().unwrap().clone() } else { - Rc::clone(&段.武) + 段.武.read().unwrap().clone() }; if 中枢.高() >= 尾部.分型特征值 && 尾部.分型特征值 >= 中枢.低() { @@ -453,7 +535,7 @@ impl 线段 { } if 状态 == Some("中枢之上") { - for 筆 in 段.基础序列.iter().rev() { + for 筆 in 段.基础序列.read().unwrap().iter().rev() { if 筆.方向() == 相对方向::向下 { let 关系 = 相对方向::分析( 所属中枢.as_ref().unwrap().高(), @@ -462,7 +544,7 @@ impl 线段 { 筆.低(), ); if 关系 == 相对方向::向上缺口 { - 第三买卖线.push(Rc::clone(筆)); + 第三买卖线.push(Arc::clone(筆)); } else { break; } @@ -473,7 +555,7 @@ impl 线段 { } if 状态 == Some("中枢之下") { - for 筆 in 段.基础序列.iter().rev() { + for 筆 in 段.基础序列.read().unwrap().iter().rev() { if 筆.方向() == 相对方向::向上 { let 关系 = 相对方向::分析( 所属中枢.as_ref().unwrap().高(), @@ -482,7 +564,7 @@ impl 线段 { 筆.低(), ); if 关系 == 相对方向::向下缺口 { - 第三买卖线.push(Rc::clone(筆)); + 第三买卖线.push(Arc::clone(筆)); } else { break; } @@ -495,18 +577,18 @@ impl 线段 { if !第三买卖线.is_empty() { 第三买卖线.reverse(); if let Some(ref mut 中枢) = 所属中枢 { - 中枢.本级_第三买卖线 = Some(Rc::clone(&第三买卖线[0])); + *中枢.本级_第三买卖线.write().unwrap() = Some(Arc::clone(&第三买卖线[0])); } } if !后.is_empty() { if 段.方向().是否向上() { - if 后[0].武.分型特征值 < 段.文.分型特征值 { - 贯穿伤 = Some(Rc::clone(&后[0])); + if 后[0].武.read().unwrap().分型特征值 < 段.文.分型特征值 { + 贯穿伤 = Some(Arc::clone(&后[0])); } } else { - if 后[0].武.分型特征值 > 段.文.分型特征值 { - 贯穿伤 = Some(Rc::clone(&后[0])); + if 后[0].武.read().unwrap().分型特征值 > 段.文.分型特征值 { + 贯穿伤 = Some(Arc::clone(&后[0])); } } } @@ -515,12 +597,12 @@ impl 线段 { } /// 刷新 — 完整刷新线段的特征序列和内部中枢 - pub fn 刷新(段_rc: &mut Rc<虚线>, 配置: &缠论配置) { - let 段 = Self::取段可变(段_rc); - if 段.模式 != "文武" { + pub fn 刷新(段_rc: &Arc<虚线>, 配置: &缠论配置) { + let 段 = Self::取段(段_rc); + if 段.模式.read().unwrap().as_str() != "文武" { return; } - if 段.基础序列.is_empty() { + if 段.基础序列.read().unwrap().is_empty() { eprintln!(" 线段.刷新 基础序列为空"); return; } @@ -529,25 +611,29 @@ impl 线段 { // After 刷新特征序列, work with the updated segment let (武斗_武文, 特征后一笔_opt) = { - let 段2 = Self::取段可变(段_rc); - let 有效特征序列: Vec<&Rc<线段特征>> = - 段2.特征序列.iter().filter_map(|x| x.as_ref()).collect(); + let 段2 = Self::取段(段_rc); + let 特序_ref = 段2.特征序列.read().unwrap(); + let 有效特征序列: Vec<&Arc<线段特征>> = + 特序_ref.iter().filter_map(|x| x.as_ref()).collect(); if 有效特征序列.len() == 3 { - (Some(Rc::clone(&有效特征序列[1].文())), None) + (Some(Arc::clone(&有效特征序列[1].文())), None) } else if !有效特征序列.is_empty() { let 最近特征 = 有效特征序列[有效特征序列.len() - 1]; - let 特征后一笔 = if 最近特征 - .元素 - .last() - .map(|x| 段2.基础序列.iter().any(|b| Rc::as_ptr(b) == Rc::as_ptr(x))) - == Some(true) - { - Some(Rc::clone(最近特征.元素.last().unwrap())) - } else if let Some(b) = - 笔::以武会友(&段2.基础序列, &最近特征.元素.last().unwrap().武) + let 特征后一笔 = if 最近特征.元素.last().map(|x| { + 段2.基础序列 + .read() + .unwrap() + .iter() + .any(|b| Arc::as_ptr(b) == Arc::as_ptr(x)) + }) == Some(true) { + Some(Arc::clone(最近特征.元素.last().unwrap())) + } else if let Some(b) = 笔::以武会友( + &*段2.基础序列.read().unwrap(), + &*最近特征.元素.last().unwrap().武.read().unwrap(), + ) { Some(b) } else { None @@ -570,18 +656,20 @@ impl 线段 { Self::武斗(段_rc, &武文, 0); } else if let Some(特征后一笔) = 特征后一笔_opt { let 武斗候选 = { - let 段2 = Self::取段可变(段_rc); + let 段2 = Self::取段(段_rc); if let Some(序号) = 段2 .基础序列 + .read() + .unwrap() .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(&特征后一笔)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(&特征后一笔)) { - if 序号 < 段2.基础序列.len() - 1 { - let 下一笔 = Rc::clone(&段2.基础序列[序号 + 1]); + if 序号 < 段2.基础序列.read().unwrap().len() - 1 { + let 下一笔 = Arc::clone(&段2.基础序列.read().unwrap()[序号 + 1]); if (段2.方向() == 相对方向::向上 && 段2.高() <= 下一笔.高()) || (段2.方向() == 相对方向::向下 && 段2.低() >= 下一笔.低()) { - Some(Rc::clone(&下一笔.武)) + Some(下一笔.武.read().unwrap().clone()) } else { None } @@ -597,24 +685,32 @@ impl 线段 { } } - let 段3 = Self::取段可变(段_rc); + let 段3 = Self::取段(段_rc); let _ = Self::获取内部中枢序列_内部(段3, 配置); } /// 获取内部中枢序列 — 内部实现 fn 获取内部中枢序列_内部( - 段: &mut 虚线, + 段: &虚线, _配置: &缠论配置, - ) -> (Vec>, Vec>, Vec>) { - if 段.模式 != "文武" { + ) -> (Vec>, Vec>, Vec>) { + if 段.模式.read().unwrap().as_str() != "文武" { 中枢::分析( - &段.基础序列, - &mut 段.合_中枢序列, + &*段.基础序列.read().unwrap(), + &mut *段.合_中枢序列.write().unwrap(), true, - &format!("{}_{}_合_", 段.标识, 段.序号), + &format!( + "{}_{}_合_", + 段.标识.read().unwrap(), + 段.序号.load(Ordering::Relaxed) + ), 0, ); - return (Vec::new(), Vec::new(), 段.合_中枢序列.clone()); + return ( + Vec::new(), + Vec::new(), + 段.合_中枢序列.read().unwrap().clone(), + ); } // Use 分割序列 to get前/后 @@ -622,39 +718,51 @@ impl 线段 { 中枢::分析( &前, - &mut 段.实_中枢序列, + &mut *段.实_中枢序列.write().unwrap(), true, - &format!("{}_{}_实_", 段.标识, 段.序号), + &format!( + "{}_{}_实_", + 段.标识.read().unwrap(), + 段.序号.load(Ordering::Relaxed) + ), 0, ); 中枢::分析( &后, - &mut 段.虚_中枢序列, + &mut *段.虚_中枢序列.write().unwrap(), true, - &format!("{}_{}_虚_", 段.标识, 段.序号), + &format!( + "{}_{}_虚_", + 段.标识.read().unwrap(), + 段.序号.load(Ordering::Relaxed) + ), 0, ); 中枢::分析( - &段.基础序列, - &mut 段.合_中枢序列, + &*段.基础序列.read().unwrap(), + &mut *段.合_中枢序列.write().unwrap(), true, - &format!("{}_{}_合_", 段.标识, 段.序号), + &format!( + "{}_{}_合_", + 段.标识.read().unwrap(), + 段.序号.load(Ordering::Relaxed) + ), 0, ); ( - 段.虚_中枢序列.clone(), - 段.实_中枢序列.clone(), - 段.合_中枢序列.clone(), + 段.虚_中枢序列.read().unwrap().clone(), + 段.实_中枢序列.read().unwrap().clone(), + 段.合_中枢序列.read().unwrap().clone(), ) } /// 获取内部中枢序列 pub fn 获取内部中枢序列( - 段_rc: &mut Rc<虚线>, + 段_rc: &Arc<虚线>, 配置: &缠论配置, - ) -> (Vec>, Vec>, Vec>) { - let 段 = Self::取段可变(段_rc); + ) -> (Vec>, Vec>, Vec>) { + let 段 = Self::取段(段_rc); Self::获取内部中枢序列_内部(段, 配置) } @@ -664,31 +772,33 @@ impl 线段 { /// _添加线段 — 向线段序列尾部添加线段(内部方法) pub fn _添加线段( - 线段序列: &mut Vec>, - mut 待添加线段: Rc<虚线>, + 线段序列: &mut Vec>, + mut 待添加线段: Arc<虚线>, _配置: &缠论配置, 行号: String, ) { { - let seg = Rc::make_mut(&mut 待添加线段); - seg.模式 = "文武".into(); + let seg = Arc::make_mut(&mut 待添加线段); + *seg.模式.write().unwrap() = "文武".into(); if !线段序列.is_empty() { if let Some(前一个) = 线段序列.last() { if !前一个.之后是(seg) { panic!( "线段.向序列中添加 不连续[{}] {} {}", - 行号, 前一个.武, seg.文 + 行号, + 前一个.武.read().unwrap(), + seg.文 ); } } let 之前线段 = 线段序列.last().unwrap(); - // Check 之前线段.特征序列[2] is valid - if 之前线段.特征序列.len() >= 3 - && 之前线段.特征序列[2].is_none() - && !之前线段.短路修正 + // Check 之前线段.特征序列.read().unwrap()[2] is valid + if 之前线段.特征序列.read().unwrap().len() >= 3 + && 之前线段.特征序列.read().unwrap()[2].is_none() + && !之前线段.短路修正.load(Ordering::Relaxed) { // The Python code asserts here; we warn eprintln!( @@ -697,11 +807,9 @@ impl 线段 { ); } - if !seg - .基础序列 - .iter() - .any(|x| Rc::as_ptr(x) == Rc::as_ptr(之前线段.基础序列.last().unwrap())) - && !之前线段.短路修正 + if !seg.基础序列.read().unwrap().iter().any(|x| { + Arc::as_ptr(x) == Arc::as_ptr(之前线段.基础序列.read().unwrap().last().unwrap()) + }) && !之前线段.短路修正.load(Ordering::Relaxed) { panic!( "线段._向序列中添加[{}], 之前线段[-1] not in 待添加虚线! {}", @@ -709,12 +817,15 @@ impl 线段 { ); } - seg.序号 = 之前线段.序号 + 1; - seg.前一缺口 = Self::获取缺口(之前线段); - seg.前一结束位置 = Some(Rc::clone(之前线段.基础序列.last().unwrap())); + seg.序号 + .store(之前线段.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + *seg.前一缺口.write().unwrap() = Self::获取缺口(之前线段); + *seg.前一结束位置.write().unwrap() = Some(Arc::clone( + 之前线段.基础序列.read().unwrap().last().unwrap(), + )); if ["老阴", "老阳"].contains(&Self::四象(之前线段).as_str()) { - seg.前一缺口 = None; + *seg.前一缺口.write().unwrap() = None; } } } @@ -723,23 +834,23 @@ impl 线段 { /// _弹出线段 — 从线段序列尾部弹出线段(内部方法) pub fn _弹出线段( - 线段序列: &mut Vec>, - 待弹出线段: &Rc<虚线>, + 线段序列: &mut Vec>, + 待弹出线段: &Arc<虚线>, _配置: &缠论配置, 行号: String, - ) -> Option> { + ) -> Option> { if 线段序列.is_empty() { return None; } - if Rc::as_ptr(线段序列.last().unwrap()) != Rc::as_ptr(待弹出线段) { + if Arc::as_ptr(线段序列.last().unwrap()) != Arc::as_ptr(待弹出线段) { panic!("线段._从序列中删除 弹出数据不在列表中 {}", 待弹出线段); } - if 待弹出线段.特征序列.len() >= 3 { - let 左 = &待弹出线段.特征序列[0]; - let 中 = &待弹出线段.特征序列[1]; - let 右 = &待弹出线段.特征序列[2]; + if 待弹出线段.特征序列.read().unwrap().len() >= 3 { + let 左 = &待弹出线段.特征序列.read().unwrap()[0]; + let 中 = &待弹出线段.特征序列.read().unwrap()[1]; + let 右 = &待弹出线段.特征序列.read().unwrap()[2]; if let (Some(l), Some(m), Some(r)) = (左, 中, 右) { if let Some(结构) = 分型结构::分析(&**l, &**m, &**r, true, true) { if matches!(结构, 分型结构::顶 | 分型结构::底) @@ -755,9 +866,9 @@ impl 线段 { } let mut 弹出 = 线段序列.pop().unwrap(); - let seg = Rc::make_mut(&mut 弹出); - seg.前一结束位置 = None; - seg.有效性 = false; + let seg = Arc::make_mut(&mut 弹出); + *seg.前一结束位置.write().unwrap() = None; + seg.有效性.store(false, Ordering::Relaxed); Some(弹出) } @@ -768,17 +879,19 @@ impl 线段 { /// _缺口突破 — 老阳/老阴缺口突破修正 pub fn _缺口突破( - 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64 + 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64 ) -> bool { if 线段序列.is_empty() { return false; } - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - if 当前线段.基础序列.is_empty() { + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + if 当前线段.基础序列.read().unwrap().is_empty() { return false; } - let 当前虚线 = Rc::clone(&当前线段.基础序列[当前线段.基础序列.len() - 1]); + let 当前虚线 = Arc::clone( + &当前线段.基础序列.read().unwrap()[当前线段.基础序列.read().unwrap().len() - 1], + ); let 四象 = Self::四象(&当前线段); let 同向 = 当前虚线.方向() == 当前线段.方向(); @@ -793,7 +906,9 @@ impl 线段 { } // 条件3:当前线段特征序列[2]必须为None - if 当前线段.特征序列.len() >= 3 && 当前线段.特征序列[2].is_some() { + if 当前线段.特征序列.read().unwrap().len() >= 3 + && 当前线段.特征序列.read().unwrap()[2].is_some() + { return false; } @@ -805,10 +920,10 @@ impl 线段 { } // 执行修正 - let 序列 = 当前线段.基础序列.clone(); + let 序列 = 当前线段.基础序列.read().unwrap().clone(); Self::_弹出线段( 线段序列, - &Rc::clone(线段序列.last().unwrap()), + &Arc::clone(线段序列.last().unwrap()), 配置, format!("{}, {}", line!(), 层级), ); @@ -819,15 +934,16 @@ impl 线段 { { let idx = 线段序列.len() - 1; - let cur = Rc::make_mut(&mut 线段序列[idx]); - if cur.特征序列.len() < 3 || cur.特征序列[2].is_none() { - // Shouldn't happen after correction - return true; - } + let cur = Arc::make_mut(&mut 线段序列[idx]); + assert!( + cur.特征序列.read().unwrap().len() >= 3 + && cur.特征序列.read().unwrap()[2].is_some(), + "_缺口突破: 特征序列[2] 不可为 None" + ); let (前, _, _, _) = Self::分割序列(cur, None); let mut 当前线段基础序列 = 前; 当前线段基础序列.extend(序列); - cur.基础序列 = 当前线段基础序列; + *cur.基础序列.write().unwrap() = 当前线段基础序列; } let idx = 线段序列.len() - 1; Self::刷新(&mut 线段序列[idx], 配置); @@ -836,20 +952,20 @@ impl 线段 { /// _非缺口下穿刺 — 贯穿伤修复 pub fn _非缺口下穿刺( - 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64 + 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64 ) -> bool { if 线段序列.is_empty() { return false; } - let 当前线段 = Rc::clone(线段序列.last().unwrap()); + let 当前线段 = Arc::clone(线段序列.last().unwrap()); let 四象 = Self::四象(&当前线段); // 外层条件 if !(配置.线段_非缺口下穿刺 && (四象 == "小阳" || 四象 == "少阴") - && 当前线段.特征序列.len() >= 3 - && 当前线段.特征序列[2].is_none()) + && 当前线段.特征序列.read().unwrap().len() >= 3 + && 当前线段.特征序列.read().unwrap()[2].is_none()) { return false; } @@ -864,21 +980,24 @@ impl 线段 { // 切割基础序列 let 贯穿伤_idx = 当前线段 .基础序列 + .read() + .unwrap() .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(&贯穿伤)); + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(&贯穿伤)); if 贯穿伤_idx.is_none() { return false; } - let 基础序列: Vec> = 当前线段.基础序列[贯穿伤_idx.unwrap()..].to_vec(); + let 基础序列: Vec> = + 当前线段.基础序列.read().unwrap()[贯穿伤_idx.unwrap()..].to_vec(); // 长度条件 if !(基础序列.len() == 4 && 线段序列.len() >= 2) { return false; } - let 左 = Rc::clone(&基础序列[基础序列.len() - 3]); - let 右 = Rc::clone(&基础序列[基础序列.len() - 1]); + let 左 = Arc::clone(&基础序列[基础序列.len() - 3]); + let 右 = Arc::clone(&基础序列[基础序列.len() - 1]); // 方向条件 if 相对方向::分析(左.高(), 左.低(), 右.高(), 右.低()) != 当前线段.方向() @@ -889,10 +1008,10 @@ impl 线段 { // 执行修正 eprintln!("[警告<{}, {}>]: 线段.修复贯穿伤 {}", line!(), 层级, 贯穿伤); - let 原始基础序列 = 当前线段.基础序列.clone(); + let 原始基础序列 = 当前线段.基础序列.read().unwrap().clone(); Self::_弹出线段( 线段序列, - &Rc::clone(线段序列.last().unwrap()), + &Arc::clone(线段序列.last().unwrap()), 配置, format!("{}, {}", line!(), 层级), ); @@ -901,44 +1020,59 @@ impl 线段 { return true; } + let 开始序号_opt; + let 待添加元素: Vec>; { let idx = 线段序列.len() - 1; - let cur = Rc::make_mut(&mut 线段序列[idx]); - if cur.特征序列.len() >= 3 { - cur.特征序列[2] = None; + let cur = Arc::make_mut(&mut 线段序列[idx]); + if cur.特征序列.read().unwrap().len() >= 3 { + cur.特征序列.write().unwrap()[2] = None; } - let 开始笔 = Rc::clone(cur.基础序列.last().unwrap()); + let 开始笔 = Arc::clone(cur.基础序列.read().unwrap().last().unwrap()); let 开始序号 = 原始基础序列 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(&开始笔)); + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(&开始笔)); - if let Some(开始序号) = 开始序号 { - for 临时虚线 in &原始基础序列[开始序号 + 1..] { - cur.基础序列.push(Rc::clone(临时虚线)); - } + 开始序号_opt = 开始序号; + if let Some(序号) = 开始序号 { + 待添加元素 = 原始基础序列[序号 + 1..].to_vec(); + } else { + 待添加元素 = Vec::new(); } } + + if let Some(_) = 开始序号_opt { + let idx = 线段序列.len() - 1; + let seg_rc = Arc::clone(&线段序列[idx]); + for 临时虚线 in &待添加元素 { + Self::添加虚线(&seg_rc, Arc::clone(临时虚线)); + } + 线段序列[idx] = seg_rc; + } let idx = 线段序列.len() - 1; Self::刷新(&mut 线段序列[idx], 配置); - let 当前线段 = Rc::clone(&线段序列[idx]); - if 当前线段.特征序列.len() >= 3 && 当前线段.特征序列[2].is_some() { + let 当前线段 = Arc::clone(&线段序列[idx]); + if 当前线段.特征序列.read().unwrap().len() >= 3 + && 当前线段.特征序列.read().unwrap()[2].is_some() + { let 段 = 虚线::创建线段(&[ - Rc::clone(&基础序列[基础序列.len() - 3]), - Rc::clone(&基础序列[基础序列.len() - 2]), - Rc::clone(&基础序列[基础序列.len() - 1]), + Arc::clone(&基础序列[基础序列.len() - 3]), + Arc::clone(&基础序列[基础序列.len() - 2]), + Arc::clone(&基础序列[基础序列.len() - 1]), ]); - let 段_rc = Rc::new(段); + let 段_rc = Arc::new(段); Self::_添加线段(线段序列, 段_rc, 配置, format!("{}, {}", line!(), 层级)); // Set feature sequence [0] - let 新段 = Self::取段可变(线段序列.last_mut().unwrap()); - if 新段.特征序列.is_empty() { - 新段.特征序列.push(None); + let 新段 = Self::取段(线段序列.last_mut().unwrap()); + if 新段.特征序列.read().unwrap().is_empty() { + 新段.特征序列.write().unwrap().push(None); } - let 中笔 = Rc::clone(&基础序列[基础序列.len() - 2]); - 新段.特征序列[0] = Some(Rc::new(线段特征::新建(vec![中笔], 新段.方向()))); + let 中笔 = Arc::clone(&基础序列[基础序列.len() - 2]); + 新段.特征序列.write().unwrap()[0] = + Some(Arc::new(线段特征::新建(vec![中笔], 新段.方向()))); } true @@ -946,7 +1080,7 @@ impl 线段 { /// _缺口后紧急修正 — 老阴/老阳后的紧急修正 pub fn _缺口后紧急修正( - 线段序列: &mut Vec>, + 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64, ) -> bool { @@ -954,15 +1088,15 @@ impl 线段 { return false; } - let 当前线段 = Rc::clone(线段序列.last().unwrap()); + let 当前线段 = Arc::clone(线段序列.last().unwrap()); let 四象 = Self::四象(&当前线段); // 外层条件 if !(配置.线段_缺口后紧急修正 && !配置.线段_特征序列忽视老阴老阳 && (四象 == "小阳" || 四象 == "少阴") - && 当前线段.特征序列.len() >= 3 - && 当前线段.特征序列[2].is_none()) + && 当前线段.特征序列.read().unwrap().len() >= 3 + && 当前线段.特征序列.read().unwrap()[2].is_none()) { return false; } @@ -1010,24 +1144,26 @@ impl 线段 { // 执行修正 — set 短路修正 and create new segment let idx = 线段序列.len() - 1; - Rc::make_mut(&mut 线段序列[idx]).短路修正 = true; + 线段序列[idx].短路修正.store(true, Ordering::Relaxed); let 新段 = 虚线::创建线段(&基础序列); - let 新段_rc = Rc::new(新段); + let 新段_rc = Arc::new(新段); Self::_添加线段(线段序列, 新段_rc, 配置, format!("{}, {}", line!(), 层级)); true } /// _修正 — 通用线段修正(后段足够长时拆分) - pub fn _修正(线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64) -> bool { + pub fn _修正( + 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64 + ) -> bool { if 线段序列.is_empty() { return false; } - let 当前线段 = Rc::clone(线段序列.last().unwrap()); + let 当前线段 = Arc::clone(线段序列.last().unwrap()); // 条件1 - if !(配置.线段_修正 && 当前线段.基础序列.len() >= 9) { + if !(配置.线段_修正 && 当前线段.基础序列.read().unwrap().len() >= 9) { return false; } @@ -1038,8 +1174,8 @@ impl 线段 { return false; } - let 前 = Rc::clone(&之后基础序列[之后基础序列.len() - 3]); - let 后 = Rc::clone(&之后基础序列[之后基础序列.len() - 1]); + let 前 = Arc::clone(&之后基础序列[之后基础序列.len() - 3]); + let 后 = Arc::clone(&之后基础序列[之后基础序列.len() - 1]); // 条件3 if 当前线段.方向() != 相对方向::分析(前.高(), 前.低(), 后.高(), 后.低()) @@ -1049,23 +1185,26 @@ impl 线段 { // 执行修正 let idx = 线段序列.len() - 1; - Rc::make_mut(&mut 线段序列[idx]).短路修正 = true; + 线段序列[idx].短路修正.store(true, Ordering::Relaxed); // 第一个新段 let 新段1 = 虚线::创建线段(&之后基础序列[..之后基础序列.len() - 3]); - let mut 新段1_rc = Rc::new(新段1); + let 新段1_rc = Arc::new(新段1); // Set 短路修正 - Rc::make_mut(&mut 新段1_rc).短路修正 = true; + 新段1_rc.短路修正.store(true, Ordering::Relaxed); Self::_添加线段(线段序列, 新段1_rc, 配置, format!("{}, {}", line!(), 层级)); if ["老阴", "老阳"].contains(&Self::四象(&当前线段).as_str()) { - Self::取段可变(线段序列.last_mut().unwrap()).前一缺口 = None; + *Self::取段(线段序列.last_mut().unwrap()) + .前一缺口 + .write() + .unwrap() = None; } // 第二个新段 let start = 之后基础序列.len() - 3; let 新段2 = 虚线::创建线段(&之后基础序列[start..]); - let 新段2_rc = Rc::new(新段2); + let 新段2_rc = Arc::new(新段2); Self::_添加线段(线段序列, 新段2_rc, 配置, format!("{}, {}", line!(), 层级)); true @@ -1079,8 +1218,8 @@ impl 线段 { /// /// 使用显式栈(loop + continue)模拟 Python 的递归调用,避免栈溢出。 pub fn 分析( - 笔序列: &[Rc<虚线>], - 线段序列: &mut Vec>, + 笔序列: &[Arc<虚线>], + 线段序列: &mut Vec>, 配置: &缠论配置, 层级: i64, 关系序列: &[相对方向], @@ -1107,8 +1246,9 @@ impl 线段 { if !Self::基础判断(左, 中, 右, 关系序列) { continue; } - let 段 = 虚线::创建线段(&[Rc::clone(左), Rc::clone(中), Rc::clone(右)]); - let 段_rc = Rc::new(段); + let 段 = + 虚线::创建线段(&[Arc::clone(左), Arc::clone(中), Arc::clone(右)]); + let 段_rc = Arc::new(段); Self::_添加线段( 线段序列, 段_rc, @@ -1116,13 +1256,13 @@ impl 线段 { format!("{}, {}", line!(), 当前层级), ); - // 段.特征序列[0] = 线段特征.新建([中], 段.方向) - let 段 = Self::取段可变(线段序列.last_mut().unwrap()); - if 段.特征序列.is_empty() { - 段.特征序列.push(None); + // 段.特征序列.read().unwrap()[0] = 线段特征.新建([中], 段.方向) + let 段 = Self::取段(线段序列.last_mut().unwrap()); + if 段.特征序列.read().unwrap().is_empty() { + 段.特征序列.write().unwrap().push(None); } - 段.特征序列[0] = Some(Rc::new(线段特征::新建( - vec![Rc::clone(中)], + 段.特征序列.write().unwrap()[0] = Some(Arc::new(线段特征::新建( + vec![Arc::clone(中)], 段.方向(), ))); break; @@ -1133,14 +1273,30 @@ impl 线段 { } // ---- 2. 清理无效的尾部引用 ---- - while !线段序列.is_empty() && 线段序列.last().unwrap().前一结束位置.is_some() + while !线段序列.is_empty() + && 线段序列 + .last() + .unwrap() + .前一结束位置 + .read() + .unwrap() + .is_some() { - let 前一结束 = Rc::clone(线段序列.last().unwrap().前一结束位置.as_ref().unwrap()); + let 前一结束 = Arc::clone( + 线段序列 + .last() + .unwrap() + .前一结束位置 + .read() + .unwrap() + .as_ref() + .unwrap(), + ); if !笔序列 .iter() - .any(|x| Rc::as_ptr(x) == Rc::as_ptr(&前一结束)) + .any(|x| Arc::as_ptr(x) == Arc::as_ptr(&前一结束)) { - let 当前 = Rc::clone(线段序列.last().unwrap()); + let 当前 = Arc::clone(线段序列.last().unwrap()); Self::_弹出线段( 线段序列, &当前, @@ -1158,13 +1314,13 @@ impl 线段 { } // ---- 3. 确保当前线段有效 ---- - let mut 当前线段_rc = Rc::clone(线段序列.last().unwrap()); + let mut 当前线段_rc = Arc::clone(线段序列.last().unwrap()); Self::序列重置(&mut 当前线段_rc, 笔序列); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 当前线段_rc; - if 线段序列.last().unwrap().基础序列.len() < 3 { - let 当前 = Rc::clone(线段序列.last().unwrap()); + if 线段序列.last().unwrap().基础序列.read().unwrap().len() < 3 { + let 当前 = Arc::clone(线段序列.last().unwrap()); Self::_弹出线段(线段序列, &当前, 配置, format!("{}, {}", line!(), 当前层级)); if 线段序列.is_empty() { 当前层级 += 1; @@ -1174,11 +1330,13 @@ impl 线段 { // ---- 4. 特征序列已完整时的处理 ---- { - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - if 当前线段.特征序列.len() >= 3 && 当前线段.特征序列[2].is_some() { + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + if 当前线段.特征序列.read().unwrap().len() >= 3 + && 当前线段.特征序列.read().unwrap()[2].is_some() + { let (_, 基础序列, _, _) = Self::分割序列(&当前线段, None); let 新段 = 虚线::创建线段(&基础序列); - let 新段_rc = Rc::new(新段); + let 新段_rc = Arc::new(新段); Self::_添加线段( 线段序列, 新段_rc, @@ -1186,7 +1344,7 @@ impl 线段 { format!("{}, {}", line!(), 当前层级), ); if ["老阴", "老阳"].contains(&Self::四象(&当前线段).as_str()) { - Rc::make_mut(线段序列.last_mut().unwrap()).前一缺口 = None; + *线段序列.last().unwrap().前一缺口.write().unwrap() = None; } } } @@ -1202,14 +1360,14 @@ impl 线段 { Self::_修正(线段序列, 配置, 当前层级); // ---- 6. 循环处理后续的笔 ---- - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - if 当前线段.基础序列.is_empty() { + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + if 当前线段.基础序列.read().unwrap().is_empty() { panic!("线段.分析: 基础序列为空"); } - let 最后笔 = Rc::clone(当前线段.基础序列.last().unwrap()); + let 最后笔 = Arc::clone(当前线段.基础序列.read().unwrap().last().unwrap()); let 起始索引 = match 笔序列 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(&最后笔)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(&最后笔)) { Some(idx) => idx + 1, None => { @@ -1222,13 +1380,13 @@ impl 线段 { let mut 需要递归 = false; for i in 起始索引..笔序列.len() { - let 当前虚线 = Rc::clone(&笔序列[i]); - let 当前线段 = Rc::clone(线段序列.last().unwrap()); + let 当前虚线 = Arc::clone(&笔序列[i]); + let 当前线段 = Arc::clone(线段序列.last().unwrap()); let 四象 = Self::四象(&当前线段); // 向当前线段添加笔 - let mut 线段_rc = Rc::clone(线段序列.last().unwrap()); - Self::添加虚线(&mut 线段_rc, Rc::clone(&当前虚线)); + let mut 线段_rc = Arc::clone(线段序列.last().unwrap()); + Self::添加虚线(&mut 线段_rc, Arc::clone(&当前虚线)); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 线段_rc; @@ -1251,15 +1409,17 @@ impl 线段 { } // 无修正触发,检查特征序列 - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - if 当前线段.特征序列.len() < 3 || 当前线段.特征序列[2].is_none() { + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + if 当前线段.特征序列.read().unwrap().len() < 3 + || 当前线段.特征序列.read().unwrap()[2].is_none() + { continue; } // 特征序列[2]存在 → 创建新段 let (_, 基础序列, _, _) = Self::分割序列(&当前线段, None); let 新段 = 虚线::创建线段(&基础序列); - let 新段_rc = Rc::new(新段); + let 新段_rc = Arc::new(新段); Self::_添加线段( 线段序列, 新段_rc, @@ -1268,19 +1428,28 @@ impl 线段 { ); if ["老阴", "老阳"].contains(&四象.as_str()) { - Rc::make_mut(线段序列.last_mut().unwrap()).前一缺口 = None; + *线段序列.last().unwrap().前一缺口.write().unwrap() = None; } // 检查新段与当前虚线的连续性 - let 新段 = Rc::clone(线段序列.last().unwrap()); - if Rc::as_ptr(新段.基础序列.last().unwrap()) != Rc::as_ptr(&当前虚线) { - if !新段.基础序列.last().unwrap().之后是(&当前虚线) { + let 新段 = Arc::clone(线段序列.last().unwrap()); + if Arc::as_ptr(新段.基础序列.read().unwrap().last().unwrap()) + != Arc::as_ptr(&当前虚线) + { + if !新段 + .基础序列 + .read() + .unwrap() + .last() + .unwrap() + .之后是(&当前虚线) + { 需要递归 = true; break; } // 向新段添加当前虚线 - let mut 新段_rc = Rc::clone(线段序列.last().unwrap()); - Self::添加虚线(&mut 新段_rc, Rc::clone(&当前虚线)); + let mut 新段_rc = Arc::clone(线段序列.last().unwrap()); + Self::添加虚线(&mut 新段_rc, Arc::clone(&当前虚线)); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 新段_rc; } @@ -1304,13 +1473,21 @@ impl 线段 { /// _添加扩展线段 pub fn _添加扩展线段( - 线段序列: &mut Vec>, mut 待添加线段: Rc<虚线>, 行号: u32 + 线段序列: &mut Vec>, + mut 待添加线段: Arc<虚线>, + 行号: u32, ) { { - let seg = Rc::make_mut(&mut 待添加线段); - seg.模式 = "高低".into(); - seg.标识 = if seg.基础序列[0].标识 != "笔" { - format!("扩展{}", seg.标识) + let seg = Arc::make_mut(&mut 待添加线段); + *seg.模式.write().unwrap() = "高低".into(); + *seg.标识.write().unwrap() = if seg.基础序列.read().unwrap()[0] + .标识 + .read() + .unwrap() + .as_str() + != "笔" + { + format!("扩展{}", seg.标识.read().unwrap()) } else { "扩展线段".into() }; @@ -1319,11 +1496,14 @@ impl 线段 { if !前一个.之后是(seg) { panic!( "线段.向序列中添加 不连续[{}] {} {}", - 行号, 前一个.武, seg.文 + 行号, + 前一个.武.read().unwrap(), + seg.文 ); } let 之前线段 = 线段序列.last().unwrap(); - seg.序号 = 之前线段.序号 + 1; + seg.序号 + .store(之前线段.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); } } 线段序列.push(待添加线段); @@ -1331,18 +1511,18 @@ impl 线段 { /// _弹出扩展线段 pub fn _弹出扩展线段( - 线段序列: &mut Vec>, - 待弹出线段: &Rc<虚线>, + 线段序列: &mut Vec>, + 待弹出线段: &Arc<虚线>, _行号: u32, - ) -> Option> { + ) -> Option> { if 线段序列.is_empty() { return None; } - if Rc::as_ptr(线段序列.last().unwrap()) == Rc::as_ptr(待弹出线段) { + if Arc::as_ptr(线段序列.last().unwrap()) == Arc::as_ptr(待弹出线段) { let mut drop = 线段序列.pop().unwrap(); - let seg = Rc::make_mut(&mut drop); - seg.有效性 = false; + let seg = Arc::make_mut(&mut drop); + seg.有效性.store(false, Ordering::Relaxed); Some(drop) } else { panic!("线段._从序列中删除 弹出数据不在列表中 {}", 待弹出线段); @@ -1351,7 +1531,7 @@ impl 线段 { /// 扩展分析 — 将笔视为线段进行同级别分析 pub fn 扩展分析( - 虚线序列: &[Rc<虚线>], 线段序列: &mut Vec>, 配置: &缠论配置 + 虚线序列: &[Arc<虚线>], 线段序列: &mut Vec>, 配置: &缠论配置 ) { if 虚线序列.len() < 3 { return; @@ -1383,8 +1563,9 @@ impl 线段 { continue; } - let 段 = 虚线::创建线段(&[Rc::clone(左), Rc::clone(中), Rc::clone(右)]); - let 段_rc = Rc::new(段); + let 段 = + 虚线::创建线段(&[Arc::clone(左), Arc::clone(中), Arc::clone(右)]); + let 段_rc = Arc::new(段); Self::_添加扩展线段(线段序列, 段_rc, line!()); break; } @@ -1395,33 +1576,34 @@ impl 线段 { } // 验证当前线段 - let mut 当前线段_rc = Rc::clone(线段序列.last().unwrap()); + let mut 当前线段_rc = Arc::clone(线段序列.last().unwrap()); Self::验证序列(&mut 当前线段_rc, 虚线序列); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 当前线段_rc; - if 线段序列.last().unwrap().基础序列.len() < 3 { - let 当前 = Rc::clone(线段序列.last().unwrap()); + if 线段序列.last().unwrap().基础序列.read().unwrap().len() < 3 { + let 当前 = Arc::clone(线段序列.last().unwrap()); Self::_弹出扩展线段(线段序列, &当前, line!()); 当前层级 += 1; continue; } if !配置.扩展线段_当下分析 { - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - let 左 = Rc::clone(&当前线段.基础序列[0]); - let 右 = Rc::clone(&当前线段.基础序列[2]); + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + let 左 = Arc::clone(&当前线段.基础序列.read().unwrap()[0]); + let 右 = Arc::clone(&当前线段.基础序列.read().unwrap()[2]); if !相对方向::分析(左.高(), 左.低(), 右.高(), 右.低()).是否缺口() { { - let cur = Rc::make_mut(线段序列.last_mut().unwrap()); - cur.基础序列 = cur.基础序列[..3].to_vec(); + let cur = Arc::make_mut(线段序列.last_mut().unwrap()); + let 前三个 = cur.基础序列.read().unwrap()[..3].to_vec(); + *cur.基础序列.write().unwrap() = 前三个; } let seg_idx = 线段序列.len() - 1; Self::武终(&mut 线段序列[seg_idx], 0); } else { - let 当前 = Rc::clone(线段序列.last().unwrap()); + let 当前 = Arc::clone(线段序列.last().unwrap()); Self::_弹出扩展线段(线段序列, &当前, line!()); 当前层级 += 1; continue; @@ -1432,16 +1614,25 @@ impl 线段 { let idx = 线段序列.len() - 1; Self::武终(&mut 线段序列[idx], 0); - let 当前线段 = Rc::clone(线段序列.last().unwrap()); - if 当前线段.基础序列.last().unwrap().序号 + 3 > 虚线序列.last().unwrap().序号 + let 当前线段 = Arc::clone(线段序列.last().unwrap()); + if 当前线段 + .基础序列 + .read() + .unwrap() + .last() + .unwrap() + .序号 + .load(Ordering::Relaxed) + + 3 + > 虚线序列.last().unwrap().序号.load(Ordering::Relaxed) { return; } - let 最后笔 = Rc::clone(当前线段.基础序列.last().unwrap()); + let 最后笔 = Arc::clone(当前线段.基础序列.read().unwrap().last().unwrap()); let 序号 = match 虚线序列 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(&最后笔)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(&最后笔)) { Some(idx) => idx + 1, None => return, @@ -1460,13 +1651,13 @@ impl 线段 { let 相对关系 = 相对方向::分析(左.高(), 左.低(), 右.高(), 右.低()); if 相对关系.是否缺口() { - let mut 段_rc = Rc::clone(线段序列.last().unwrap()); - Self::添加虚线(&mut 段_rc, Rc::clone(左)); + let mut 段_rc = Arc::clone(线段序列.last().unwrap()); + Self::添加虚线(&mut 段_rc, Arc::clone(左)); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 段_rc; - let mut 段_rc = Rc::clone(线段序列.last().unwrap()); - Self::添加虚线(&mut 段_rc, Rc::clone(中)); + let mut 段_rc = Arc::clone(线段序列.last().unwrap()); + Self::添加虚线(&mut 段_rc, Arc::clone(中)); let seg_idx = 线段序列.len() - 1; 线段序列[seg_idx] = 段_rc; @@ -1479,14 +1670,16 @@ impl 线段 { .last() .unwrap() .基础序列 + .read() + .unwrap() .iter() - .any(|x| Rc::as_ptr(x) == Rc::as_ptr(左)) + .any(|x| Arc::as_ptr(x) == Arc::as_ptr(左)) { continue; } - let 段 = 虚线::创建线段(&[Rc::clone(左), Rc::clone(中), Rc::clone(右)]); - let 段_rc = Rc::new(段); + let 段 = 虚线::创建线段(&[Arc::clone(左), Arc::clone(中), Arc::clone(右)]); + let 段_rc = Arc::new(段); Self::_添加扩展线段(线段序列, 段_rc, line!()); 需要递归 = true; break; @@ -1522,7 +1715,7 @@ impl 线段 { let 进入段 = &阳[阳.len() - 3]; let 离开段 = &阳[阳.len() - 1]; - if 进入段.序号 >= 离开段.序号 { + if 进入段.序号.load(Ordering::Relaxed) >= 离开段.序号.load(Ordering::Relaxed) { return false; } let 关系 = 相对方向::分析(进入段.高(), 进入段.低(), 离开段.高(), 离开段.低()); @@ -1541,31 +1734,44 @@ impl 线段 { { let k线序列 = K线::截取rc( &观察员.普通K线序列, - &阳[阳.len() - 3].文.中.标的K线, - &阳[阳.len() - 1].武.中.标的K线, + &*阳[阳.len() - 3].文.中.标的K线.read().unwrap(), + &*阳[阳.len() - 1] + .武 + .read() + .unwrap() + .中 + .标的K线 + .read() + .unwrap(), ); if 虚线::计算MACD柱子分段(&k线序列).len() >= 3 { 盘整背驰 = true; } } - if !实.is_empty() { - let 最后中枢 = &实[实.len() - 1]; + let 实_ref = 实.read().unwrap(); + if !实_ref.is_empty() { + let 最后中枢 = &实_ref[实_ref.len() - 1]; if 最后中枢 .基础序列 + .read() + .unwrap() .iter() - .any(|b| Rc::ptr_eq(b, &阳[阳.len() - 1])) + .any(|b| Arc::ptr_eq(b, &阳[阳.len() - 1])) { // 最后一笔在最后一个中枢内 if let Some(序号) = 当前段 .基础序列 + .read() + .unwrap() .iter() - .position(|b| Rc::ptr_eq(b, &最后中枢.基础序列[0])) + .position(|b| Arc::ptr_eq(b, &最后中枢.基础序列.read().unwrap()[0])) { if 序号 > 0 { - let 进入段 = &当前段.基础序列[序号 - 1]; + let 进入段 = &当前段.基础序列.read().unwrap()[序号 - 1]; let 离开段 = &阳[阳.len() - 1]; - if 进入段.序号 < 离开段.序号 { + if 进入段.序号.load(Ordering::Relaxed) < 离开段.序号.load(Ordering::Relaxed) + { if 进入段.方向() != 离开段.方向() { return crate::algorithm::divergence::背驰分析::测度背驰( 进入段, 离开段, @@ -1592,11 +1798,12 @@ impl 线段 { } } } - } else if 最后中枢.第三买卖线.is_some() { + } else if 最后中枢.第三买卖线.read().unwrap().is_some() { // 第三买卖点后盘整背驰 let 进入段 = &阳[阳.len() - 3]; let 离开段 = &阳[阳.len() - 1]; - if 进入段.序号 < 离开段.序号 { + if 进入段.序号.load(Ordering::Relaxed) < 离开段.序号.load(Ordering::Relaxed) + { if 进入段.方向() != 离开段.方向() { return crate::algorithm::divergence::背驰分析::测度背驰( 进入段, 离开段, @@ -1631,7 +1838,8 @@ impl 线段 { /// 获取所有停顿位置 — 在线段范围内找出所有停顿位置 pub fn 获取所有停顿位置(段: &虚线, 观察员: &观察者) -> Vec<虚线> { let mut 结果 = Vec::new(); - if 段.模式 != "文武" || 段.标识 != "线段" { + if 段.模式.read().unwrap().as_str() != "文武" || 段.标识.read().unwrap().as_str() != "线段" + { return 结果; } @@ -1640,20 +1848,22 @@ impl 线段 { return 结果; } - let mut 线段序列: Vec> = Vec::new(); - let mut 笔序列: Vec> = Vec::new(); - let mut 当前停顿: Option> = None; + let mut 线段序列: Vec> = Vec::new(); + let mut 笔序列: Vec> = Vec::new(); + let mut 当前停顿: Option> = None; for 筆 in &阳 { if 笔序列.len() >= 3 { let 筆停顿 = 笔::获取所有停顿位置(筆, 观察员); - let mut 停顿列表: Vec> = 筆停顿.into_iter().map(|b| Rc::new(b)).collect(); - 停顿列表.push(Rc::clone(筆)); + let mut 停顿列表: Vec> = + 筆停顿.into_iter().map(|b| Arc::new(b)).collect(); + 停顿列表.push(Arc::clone(筆)); for 停顿 in &停顿列表 { - 笔序列.push(Rc::clone(停顿)); + 笔序列.push(Arc::clone(停顿)); 线段序列.clear(); - let 笔序列_slice: Vec> = 笔序列.iter().map(|b| Rc::clone(b)).collect(); + let 笔序列_slice: Vec> = + 笔序列.iter().map(|b| Arc::clone(b)).collect(); Self::分析( &笔序列_slice, &mut 线段序列, @@ -1669,49 +1879,54 @@ impl 线段 { ); let 重复 = match (&线段序列.last(), &当前停顿) { - (Some(a), Some(ref b)) => Rc::ptr_eq(&a.武, b), + (Some(a), Some(ref b)) => Arc::ptr_eq(&*a.武.read().unwrap(), b), _ => false, }; if !重复 { if let Some(最后线段) = 线段序列.last() { - if 最后线段.基础序列.len() % 2 == 1 { - let mut 新段 = 虚线::创建线段(&最后线段.基础序列); - 新段.序号 = 段.序号; - let mut 新段_rc = Rc::new(新段); + if 最后线段.基础序列.read().unwrap().len() % 2 == 1 { + let 新段 = + 虚线::创建线段(&*最后线段.基础序列.read().unwrap()); + 新段 + .序号 + .store(段.序号.load(Ordering::Relaxed), Ordering::Relaxed); + let mut 新段_rc = Arc::new(新段); Self::刷新(&mut 新段_rc, &观察员.配置); let 新段_inner = - Rc::try_unwrap(新段_rc).unwrap_or_else(|rc| (*rc).clone()); + Arc::try_unwrap(新段_rc).unwrap_or_else(|rc| (*rc).clone()); if 新段_inner.方向() == 段.方向() { - 当前停顿 = Some(Rc::clone(&线段序列.last().unwrap().武)); + 当前停顿 = Some(Arc::clone( + &*线段序列.last().unwrap().武.read().unwrap(), + )); 结果.push(新段_inner); } } } } - if Rc::as_ptr(停顿) != Rc::as_ptr(筆) { - if let Some(mut popped) = 笔序列.pop() { - Rc::make_mut(&mut popped).有效性 = false; + if Arc::as_ptr(停顿) != Arc::as_ptr(筆) { + if let Some(popped) = 笔序列.pop() { + popped.有效性.store(false, Ordering::Relaxed); } } } } else { - 笔序列.push(Rc::clone(筆)); + 笔序列.push(Arc::clone(筆)); } } 结果 } /// 是否背驰过 — 判断线段是否在停顿位置出现过背驰 - pub fn 是否背驰过(当前段: &虚线, 观察员: &观察者) -> Vec> { + pub fn 是否背驰过(当前段: &虚线, 观察员: &观察者) -> Vec> { let 停顿位置 = Self::获取所有停顿位置(当前段, 观察员); let mut 结果 = Vec::new(); for 段 in 停顿位置 { - let mut 段_rc = Rc::new(段); + let mut 段_rc = Arc::new(段); Self::获取内部中枢序列(&mut 段_rc, &观察员.配置); if Self::判断线段内部是否背驰(&段_rc, 观察员) { - 结果.push(Rc::clone(&段_rc.武.中)); + 结果.push(Arc::clone(&段_rc.武.read().unwrap().中)); } } diff --git a/chanlun/src/business/bsp.rs b/chanlun/src/business/bsp.rs index 929947f..991179c 100644 --- a/chanlun/src/business/bsp.rs +++ b/chanlun/src/business/bsp.rs @@ -27,18 +27,19 @@ use crate::kline::chan_kline::缠论K线; use crate::structure::fractal_obj::分型; use crate::types::bsp_type::买卖点类型; use crate::types::分型结构; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; /// 基础买卖点 — 买卖点的基础数据结构 #[derive(Debug, Clone)] pub struct 基础买卖点 { pub 备注: String, pub 类型: 买卖点类型, - pub 买卖点分型: Rc<分型>, - pub 买卖点K线: Rc<缠论K线>, - pub 当前K线: Rc, - pub 失效K线: Option>, - pub 终结K线: Option>, + pub 买卖点分型: Arc<分型>, + pub 买卖点K线: Arc<缠论K线>, + pub 当前K线: Arc, + pub 失效K线: Option>, + pub 终结K线: Option>, pub 破位值: f64, pub 结构: Option<分型结构>, } @@ -46,12 +47,12 @@ pub struct 基础买卖点 { impl 基础买卖点 { pub fn new( 类型: 买卖点类型, - 当前K线: Rc, - 买卖点分型: Rc<分型>, + 当前K线: Arc, + 买卖点分型: Arc<分型>, 备注: String, 中枢破位值: f64, ) -> Self { - let 买卖点K线 = Rc::clone(&买卖点分型.中); + let 买卖点K线 = Arc::clone(&买卖点分型.中); Self { 备注, 类型, @@ -67,13 +68,13 @@ impl 基础买卖点 { /// 偏移 — 当前K线与买卖点K线的序号差 pub fn 偏移(&self) -> i64 { - self.当前K线.序号 - self.买卖点K线.序号 + self.当前K线.序号 - self.买卖点K线.序号.load(Ordering::Relaxed) } /// 失效偏移 pub fn 失效偏移(&self) -> i64 { match &self.失效K线 { - Some(k) => k.序号 - self.买卖点K线.序号, + Some(k) => k.序号 - self.买卖点K线.序号.load(Ordering::Relaxed), None => -1, } } @@ -112,8 +113,8 @@ pub struct 买卖点; impl 买卖点 { pub fn 一卖点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -122,8 +123,8 @@ impl 买卖点 { } pub fn 一买点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -132,8 +133,8 @@ impl 买卖点 { } pub fn 二卖点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -142,8 +143,8 @@ impl 买卖点 { } pub fn 二买点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -152,8 +153,8 @@ impl 买卖点 { } pub fn 三卖点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -162,8 +163,8 @@ impl 买卖点 { } pub fn 三买点( - 买卖点分型: Rc<分型>, - 当前K线: Rc, + 买卖点分型: Arc<分型>, + 当前K线: Arc, _标识: &str, 备注: String, 中枢破位值: f64, @@ -176,8 +177,8 @@ impl 买卖点 { 特征: &str, 序号: &str, 级别: &str, - 买卖点分型: Rc<分型>, - 当前缠K: Rc<缠论K线>, + 买卖点分型: Arc<分型>, + 当前缠K: Arc<缠论K线>, ) -> 基础买卖点 { let 买卖 = if matches!(买卖点分型.结构, 分型结构::底 | 分型结构::下) { "买" @@ -188,7 +189,7 @@ impl 买卖点 { let 破位值 = 买卖点分型.分型特征值; // 当前K线 — 从缠K获取其标的K线 - let 当前K线 = Rc::clone(&当前缠K.标的K线); + let 当前K线 = Arc::clone(&*当前缠K.标的K线.read().unwrap()); let 类型 = match (序号, 买卖) { ("一", "买") => 买卖点类型::一买, diff --git a/chanlun/src/business/multi_frame.rs b/chanlun/src/business/multi_frame.rs index ccc31ec..c7b5ead 100644 --- a/chanlun/src/business/multi_frame.rs +++ b/chanlun/src/business/multi_frame.rs @@ -26,9 +26,9 @@ use crate::business::observer::观察者; use crate::business::synthesizer::K线合成器; use crate::config::缠论配置; use crate::kline::bar::K线; -use std::cell::RefCell; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; +use std::sync::RwLock; /// 立体分析器 — 多周期协调器 /// @@ -38,7 +38,7 @@ pub struct 立体分析器 { pub 周期组: Vec, 输入周期: i64, K线合成器: K线合成器, - 单体分析器: HashMap>>, + 单体分析器: HashMap>>, } impl 立体分析器 { @@ -96,13 +96,13 @@ impl 立体分析器 { // Dispatch on completion events (matching Python's __K线回调) for (周期, 完成K线) in 完成事件 { if let Some(观察员) = self.单体分析器.get(&周期) { - 观察员.borrow_mut().增加原始K线(完成K线); + 观察员.write().unwrap().增加原始K线(完成K线); } } } /// 获取指定周期的观察者 - pub fn 获取观察者(&self, 周期: i64) -> Option>> { + pub fn 获取观察者(&self, 周期: i64) -> Option>> { self.单体分析器.get(&周期).cloned() } @@ -116,23 +116,23 @@ impl 立体分析器 { let 起始时间 = self .单体分析器 .get(&self.输入周期) - .and_then(|o| o.borrow().普通K线序列.first().map(|k| k.时间戳)) + .and_then(|o| o.read().unwrap().普通K线序列.first().map(|k| k.时间戳)) .unwrap_or(0); let 结束时间 = self .单体分析器 .get(&self.输入周期) - .and_then(|o| o.borrow().普通K线序列.last().map(|k| k.时间戳)) + .and_then(|o| o.read().unwrap().普通K线序列.last().map(|k| k.时间戳)) .unwrap_or(0); let 标识 = self .单体分析器 .get(&self.输入周期) - .map(|o| o.borrow().符号.clone()) + .map(|o| o.read().unwrap().符号.clone()) .unwrap_or_default(); let 周期 = self .单体分析器 .get(&self.输入周期) - .map(|o| o.borrow().周期) + .map(|o| o.read().unwrap().周期) .unwrap_or_default(); let 目录标识 = format!("RustM_{}:{}_{}_{}", 标识, 周期, 起始时间, 结束时间); @@ -146,7 +146,8 @@ impl 立体分析器 { for 周期 in &self.周期组 { if let Some(观察员) = self.单体分析器.get(周期) { 观察员 - .borrow() + .read() + .unwrap() .测试_保存数据(Some(&保存路径.to_string_lossy())); } } diff --git a/chanlun/src/business/observer.rs b/chanlun/src/business/observer.rs index 498b140..b9f20ca 100644 --- a/chanlun/src/business/observer.rs +++ b/chanlun/src/business/observer.rs @@ -32,8 +32,8 @@ use crate::structure::dash_line::虚线; use crate::structure::fractal_obj::分型; use crate::types::相对方向; use crate::utils::datetime; -use std::cell::RefCell; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::{Arc, RwLock}; /// 观察者 — 单周期分析器,持有所有层级序列,接收K线流式输入后逐层计算 pub struct 观察者 { @@ -42,40 +42,41 @@ pub struct 观察者 { pub 配置: 缠论配置, // K线序列 - pub 普通K线序列: Vec>, - pub 缠论K线序列: Vec>, + pub 普通K线序列: Vec>, + pub 基础缠K序列: Vec>, + pub 缠论K线序列: Vec>, // 分型与笔 - pub 分型序列: Vec>, - pub 笔序列: Vec>, - pub 笔_中枢序列: Vec>, + pub 分型序列: Vec>, + pub 笔序列: Vec>, + pub 笔_中枢序列: Vec>, // 线段 - pub 线段序列: Vec>, - pub 中枢序列: Vec>, + pub 线段序列: Vec>, + pub 中枢序列: Vec>, // 扩展线段(笔级) - pub 扩展线段序列: Vec>, - pub 扩展中枢序列: Vec>, + pub 扩展线段序列: Vec>, + pub 扩展中枢序列: Vec>, // 扩展线段(线段级) - pub 扩展线段序列_线段: Vec>, - pub 扩展中枢序列_线段: Vec>, + pub 扩展线段序列_线段: Vec>, + pub 扩展中枢序列_线段: Vec>, // 线段之线段 - pub 线段_线段序列: Vec>, - pub 线段_中枢序列: Vec>, + pub 线段_线段序列: Vec>, + pub 线段_中枢序列: Vec>, // 扩展线段之扩展线段 - pub 扩展线段序列_扩展线段: Vec>, - pub 扩展中枢序列_扩展线段: Vec>, + pub 扩展线段序列_扩展线段: Vec>, + pub 扩展中枢序列_扩展线段: Vec>, // 终止时间戳 终止时间戳: Option, } impl 观察者 { - pub fn new(符号: String, 周期: i64, 配置: 缠论配置) -> Rc> { + pub fn new(符号: String, 周期: i64, 配置: 缠论配置) -> Arc> { let 终止时间戳 = if 配置.手动终止 != "1970-01-01 00:00:00" && !配置.手动终止.is_empty() { datetime::转化为时间戳(&配置.手动终止) @@ -88,6 +89,7 @@ impl 观察者 { 周期, 配置, 普通K线序列: Vec::new(), + 基础缠K序列: Vec::new(), 缠论K线序列: Vec::new(), 分型序列: Vec::new(), 笔序列: Vec::new(), @@ -105,7 +107,7 @@ impl 观察者 { 终止时间戳, }; instance.配置.标识 = 符号; - Rc::new(RefCell::new(instance)) + Arc::new(RwLock::new(instance)) } /// 标识 @@ -114,18 +116,19 @@ impl 观察者 { } /// 当前K线 - pub fn 当前K线(&self) -> Option<&Rc> { + pub fn 当前K线(&self) -> Option<&Arc> { self.普通K线序列.last() } /// 当前缠K - pub fn 当前缠K(&self) -> Option<&Rc<缠论K线>> { + pub fn 当前缠K(&self) -> Option<&Arc<缠论K线>> { self.缠论K线序列.last() } /// 重置基础序列 pub fn 重置基础序列(&mut self) { self.普通K线序列.clear(); + self.基础缠K序列.clear(); self.缠论K线序列.clear(); self.分型序列.clear(); self.笔序列.clear(); @@ -232,13 +235,7 @@ impl 观察者 { &mut self.线段_线段序列, &self.配置, 0, - &[ - 相对方向::向下, - 相对方向::向上, - 相对方向::顺, - 相对方向::逆, - 相对方向::同, - ], + &[相对方向::向上, 相对方向::向下], ); } if self.配置.分析线段中枢 { @@ -282,12 +279,12 @@ impl 观察者 { for i in 1..self.缠论K线序列.len() - 1 { let 当前分型 = 分型::new( - Some(Rc::clone(&self.缠论K线序列[i - 1])), - Rc::clone(&self.缠论K线序列[i]), - Some(Rc::clone(&self.缠论K线序列[i + 1])), + Some(Arc::clone(&self.缠论K线序列[i - 1])), + Arc::clone(&self.缠论K线序列[i]), + Some(Arc::clone(&self.缠论K线序列[i + 1])), ); 笔::分析( - Rc::new(当前分型), + Arc::new(当前分型), &mut self.分型序列, &mut self.笔序列, &self.缠论K线序列, @@ -339,13 +336,7 @@ impl 观察者 { &mut self.线段_线段序列, &self.配置, 0, - &[ - 相对方向::向下, - 相对方向::向上, - 相对方向::顺, - 相对方向::逆, - 相对方向::同, - ], + &[相对方向::向上, 相对方向::向下], ); } if self.配置.分析线段中枢 { @@ -424,14 +415,14 @@ impl 观察者 { .map(|ck| { format!( "缠K, {}, {}, {:?}, {}, {}, {}, {}, {}", - ck.序号, - ck.时间戳, + ck.序号.load(Ordering::Relaxed), + ck.时间戳.load(Ordering::Relaxed), ck.分型, - ck.方向, - ck.高, - ck.低, + *ck.方向.read().unwrap(), + ck.高.get(), + ck.低.get(), ck.原始起始序号, - ck.原始结束序号 + ck.原始结束序号.load(Ordering::Relaxed) ) }) .collect(); @@ -442,7 +433,12 @@ impl 观察者 { .map(|(i, fx)| { format!( "分型, {}, {}, {:?}, {}, {}, {}", - i, fx.时间戳, fx.结构, fx.分型特征值, fx.中.时间戳, fx.中.低, + i, + fx.时间戳, + fx.结构, + fx.分型特征值, + fx.中.时间戳.load(Ordering::Relaxed), + fx.中.低.get(), ) }) .collect(); @@ -510,7 +506,7 @@ impl 观察者 { pub fn 读取数据文件( 文件路径: &str, 配置: Option<缠论配置>, - ) -> Result>, String> { + ) -> Result>, String> { let 配置 = 配置.unwrap_or_default(); // Parse filename: btcusd-300-1631772074-1632222374.nb @@ -535,7 +531,7 @@ impl 观察者 { for i in 0..data.len() / size { let offset = i * size; if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 周期, "nb") { - 实例.borrow_mut().增加原始K线(k线); + 实例.write().unwrap().增加原始K线(k线); } } @@ -548,37 +544,42 @@ mod tests { use super::*; use crate::config::缠论配置; + const TEST_DATA_PATH: &str = "/home/moscow/chanlun.rs/btcusd-300-1777649100-1778398800.nb"; + #[test] fn test_普k序列指针一致性() { let config = 缠论配置::default(); - let obs = 观察者::读取数据文件( - "/home/moscow/chanlun.rs/btcusd-300-1777649100-1778398800.nb", - Some(config), - ) - .unwrap(); - let obs_ref = obs.borrow(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); - // 1. Check that each 笔's 获取普K序列 returns K lines whose Rc pointers - // match entries in 普通K线序列 for (i, bi) in obs_ref.笔序列.iter().enumerate() { let pu_seq = bi.获取普K序列(&obs_ref.普通K线序列); if pu_seq.is_empty() { println!("笔 {}: 获取普K序列 返回空 (fallback failed)", i); println!(" 文.中.标的K线 原始起始序号: {}", bi.文.中.原始起始序号); - println!(" 武.中.标的K线 原始结束序号: {}", bi.武.中.原始结束序号); + println!( + " 武.中.标的K线 原始结束序号: {}", + bi.武 + .read() + .unwrap() + .中 + .原始结束序号 + .load(Ordering::Relaxed) + ); println!(" 普通K线序列.len: {}", obs_ref.普通K线序列.len()); } else { - // Check first element's pointer - let first_ptr = Rc::as_ptr(&pu_seq[0]); + let first_ptr = Arc::as_ptr(&pu_seq[0]); let found = obs_ref .普通K线序列 .iter() - .any(|k| Rc::as_ptr(k) == first_ptr); + .any(|k| Arc::as_ptr(k) == first_ptr); if !found { println!("笔 {}: 获取普K序列[0] 的 Rc 指针不在 普通K线序列 中!", i); - // Check if 文.中.标的K线 pointer is in 普通K线序列 - let wen_ptr = Rc::as_ptr(&bi.文.中.标的K线); - let wen_found = obs_ref.普通K线序列.iter().any(|k| Rc::as_ptr(k) == wen_ptr); + let wen_ptr = Arc::as_ptr(&*bi.文.中.标的K线.read().unwrap()); + let wen_found = obs_ref + .普通K线序列 + .iter() + .any(|k| Arc::as_ptr(k) == wen_ptr); println!(" 文.中.标的K线 在序列中: {}", wen_found); } else { println!("笔 {}: OK, 获取普K序列[0] 在序列中找到", i); @@ -589,49 +590,476 @@ mod tests { #[test] fn test_pyo3_flow_pointer_consistency() { - // Simulate what the PyO3 读取数据文件 classmethod does: - // 1. Parse K lines from file - // 2. Create "K线Py { inner: Rc::new(k线) }" for each - // 3. Call observer.增加原始K线(k线_value) - let config = 缠论配置::default(); let obs_ref = 观察者::new("btcusd".into(), 300, config); - let file_path = "/home/moscow/chanlun.rs/btcusd-300-1777649100-1778398800.nb"; - let data = std::fs::read(file_path).unwrap(); + let data = std::fs::read(TEST_DATA_PATH).unwrap(); let size = 48; for i in 0..data.len() / size { let offset = i * size; if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") { - // Simulate: K线Py { inner: Rc::new(k线) } - let _k线_py_inner = Rc::new(k线.clone()); - // In the actual PyO3 path, (*普K.borrow().inner).clone() extracts K线 value - // which then gets Rc::wrapped inside the observer - obs_ref.borrow_mut().增加原始K线(k线); + let _k线_py_inner = Arc::new(k线.clone()); + obs_ref.write().unwrap().增加原始K线(k线); } } - let obs = obs_ref.borrow(); + let obs = obs_ref.read().unwrap(); println!("普通K线序列.len: {}", obs.普通K线序列.len()); println!("笔序列.len: {}", obs.笔序列.len()); - // Now check: does 获取普K序列 return K lines whose pointers match 普通K线序列? for (i, bi) in obs.笔序列.iter().enumerate() { let pu_seq = bi.获取普K序列(&obs.普通K线序列); if pu_seq.is_empty() { println!("笔 {}: 获取普K序列 返回空!", i); } else { - let first_ptr = Rc::as_ptr(&pu_seq[0]); - let found = obs.普通K线序列.iter().any(|k| Rc::as_ptr(k) == first_ptr); + let first_ptr = Arc::as_ptr(&pu_seq[0]); + let found = obs.普通K线序列.iter().any(|k| Arc::as_ptr(k) == first_ptr); if !found { println!("笔 {}: 获取普K序列[0] 指针不在序列中!", i); } - // Only print first few if i < 5 { println!("笔 {}: OK, len={}", i, pu_seq.len()); } } } } + + // ============================================================ + // 分型到笔的 Rc 指针一致性 + // ============================================================ + + #[test] + fn test_分型到笔的文武Rc指针一致性() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + // 每个笔的文/武 分型 Rc 指针必须在 分型序列 中 + for (i, bi) in obs_ref.笔序列.iter().enumerate() { + let 文_ptr = Arc::as_ptr(&bi.文); + let 文_found = obs_ref.分型序列.iter().any(|f| Arc::as_ptr(f) == 文_ptr); + if !文_found { + println!("笔 {}: 文(时间戳={}) 不在分型序列中!", i, bi.文.时间戳); + } + + let 武_ptr = Arc::as_ptr(&*bi.武.read().unwrap()); + let 武_found = obs_ref.分型序列.iter().any(|f| Arc::as_ptr(f) == 武_ptr); + if !武_found { + println!( + "笔 {}: 武(时间戳={}) 不在分型序列中!", + i, + bi.武.read().unwrap().时间戳 + ); + } + } + } + + // ============================================================ + // 笔到线段的 Rc 指针一致性 + // ============================================================ + + #[test] + fn test_笔到线段的基础序列Rc指针一致性() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + // 每个线段的基础序列中的笔 Rc 指针必须在 笔序列 中 + for (i, seg) in obs_ref.线段序列.iter().enumerate() { + for (j, bi_in_seg) in seg.基础序列.read().unwrap().iter().enumerate() { + let bi_ptr = Arc::as_ptr(bi_in_seg); + let found = obs_ref.笔序列.iter().any(|b| Arc::as_ptr(b) == bi_ptr); + if !found { + println!("线段 {} 的基础序列[{}] 不在笔序列中!", i, j); + } + } + } + } + + // ============================================================ + // 中枢基础序列与源的 Rc 指针一致性 + // ============================================================ + + #[test] + fn test_中枢基础序列与笔序列Rc指针一致() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + for (i, hub) in obs_ref.笔_中枢序列.iter().enumerate() { + for (j, bi_in_hub) in hub.基础序列.read().unwrap().iter().enumerate() { + let bi_ptr = Arc::as_ptr(bi_in_hub); + let found = obs_ref.笔序列.iter().any(|b| Arc::as_ptr(b) == bi_ptr); + if !found { + println!("笔中枢 {} 的基础序列[{}] 不在笔序列中!", i, j); + } + } + } + + for (i, hub) in obs_ref.中枢序列.iter().enumerate() { + for (j, seg_in_hub) in hub.基础序列.read().unwrap().iter().enumerate() { + let seg_ptr = Arc::as_ptr(seg_in_hub); + let found = obs_ref.线段序列.iter().any(|s| Arc::as_ptr(s) == seg_ptr); + if !found { + println!("线段中枢 {} 的基础序列[{}] 不在线段序列中!", i, j); + } + } + } + } + + // ============================================================ + // 重复计算一致性 + // ============================================================ + + #[test] + fn test_重复计算后结果一致() { + let data = std::fs::read(TEST_DATA_PATH).unwrap(); + let size = 48; + + let 计算 = || { + let config = 缠论配置::default(); + let obs_ref = 观察者::new("btcusd".into(), 300, config); + for i in 0..data.len() / size { + let offset = i * size; + if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") { + obs_ref.write().unwrap().增加原始K线(k线); + } + } + let obs = obs_ref.read().unwrap(); + ( + obs.笔序列.len(), + obs.线段序列.len(), + obs.中枢序列.len(), + obs.笔_中枢序列.len(), + ) + }; + + let (笔数1, 段数1, 中枢1, 笔中枢1) = 计算(); + let (笔数2, 段数2, 中枢2, 笔中枢2) = 计算(); + + assert_eq!(笔数1, 笔数2, "重复计算笔数不一致"); + assert_eq!(段数1, 段数2, "重复计算线段数不一致"); + assert_eq!(中枢1, 中枢2, "重复计算中枢数不一致"); + assert_eq!(笔中枢1, 笔中枢2, "重复计算笔中枢数不一致"); + + println!( + "两次计算结果一致: 笔={}, 线段={}, 中枢={}, 笔中枢={}", + 笔数1, 段数1, 中枢1, 笔中枢1 + ); + } + + // ============================================================ + // 重置后重新投喂数据一致性 + // ============================================================ + + #[test] + fn test_重置后重新投喂数据一致() { + let config = 缠论配置::default(); + let obs_ref = 观察者::new("btcusd".into(), 300, config); + + let data = std::fs::read(TEST_DATA_PATH).unwrap(); + let size = 48; + + for i in 0..data.len() / size { + let offset = i * size; + if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") { + obs_ref.write().unwrap().增加原始K线(k线); + } + } + + let 第一次笔数 = obs_ref.read().unwrap().笔序列.len(); + let 第一次段数 = obs_ref.read().unwrap().线段序列.len(); + + // 重置 + obs_ref.write().unwrap().重置基础序列(); + assert_eq!(obs_ref.read().unwrap().笔序列.len(), 0); + assert_eq!(obs_ref.read().unwrap().线段序列.len(), 0); + + // 重新投喂 + for i in 0..data.len() / size { + let offset = i * size; + if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") { + obs_ref.write().unwrap().增加原始K线(k线); + } + } + + let 第二次笔数 = obs_ref.read().unwrap().笔序列.len(); + let 第二次段数 = obs_ref.read().unwrap().线段序列.len(); + + assert_eq!(第一次笔数, 第二次笔数, "重置后重新投喂笔数不一致"); + assert_eq!(第一次段数, 第二次段数, "重置后重新投喂线段数不一致"); + println!("重置后重投一致: 笔={}, 线段={}", 第一次笔数, 第一次段数); + } + + // ============================================================ + // RefCell 借用安全性 — 连续大量操作不应 panic + // ============================================================ + + #[test] + fn test_RefCell借用安全性_连续读取不panic() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + // 连续大量读取所有 RefCell 字段,不应 panic + for _ in 0..100 { + for bi in &obs_ref.笔序列 { + let _标识 = bi.标识.read().unwrap().clone(); + let _wu = bi.武.read().unwrap().clone(); + let _基础序列 = bi.基础序列.read().unwrap().len(); + let _特征序列 = bi.特征序列.read().unwrap().len(); + let _模式 = bi.模式.read().unwrap().clone(); + let _实中枢 = bi.实_中枢序列.read().unwrap().len(); + let _虚中枢 = bi.虚_中枢序列.read().unwrap().len(); + let _合中枢 = bi.合_中枢序列.read().unwrap().len(); + let _确认K = bi.确认K线.read().unwrap().is_some(); + let _序号 = bi.序号.load(Ordering::Relaxed); + let _有效性 = bi.有效性.load(Ordering::Relaxed); + let _短路 = bi.短路修正.load(Ordering::Relaxed); + let _前一缺口 = *bi.前一缺口.read().unwrap(); + } + for seg in &obs_ref.线段序列 { + let _ = seg.标识.read().unwrap().clone(); + let _ = seg.基础序列.read().unwrap().len(); + } + } + // 到达这里 = 无 panic + } + + #[test] + fn test_RefCell借用安全性_交替读写不panic() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + // 交替读写 RefCell 字段 — 先读再写同字段,分离 borrow 作用域 + if !obs_ref.笔序列.is_empty() { + let bi = &obs_ref.笔序列[0]; + // 读 + let old_mode = bi.模式.read().unwrap().clone(); + // Ref 已释放,可以写 + *bi.模式.write().unwrap() = "测试模式".into(); + let new_mode = bi.模式.read().unwrap().clone(); + assert_eq!(new_mode, "测试模式"); + // 恢复 + *bi.模式.write().unwrap() = old_mode; + + // 读武 + let old_wu = bi.武.read().unwrap().clone(); + // Ref 已释放,可以检查 + assert!(Arc::as_ptr(&old_wu) == Arc::as_ptr(&old_wu)); + } + } + + // ============================================================ + // 缠K 到 分型 的 Rc 指针一致性 + // ============================================================ + + #[test] + fn test_缠K到分型的Rc指针一致性() { + let config = 缠论配置::default(); + let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap(); + let obs_ref = obs.read().unwrap(); + + // 每个分型的左/中/右 缠K 指针必须在 缠论K线序列 中 + for (i, f) in obs_ref.分型序列.iter().enumerate() { + let 中_ptr = Arc::as_ptr(&f.中); + let 中_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 中_ptr); + if !中_found { + println!("分型 {} 的 中(时间戳={}) 不在缠论K线序列中!", i, f.时间戳); + } + + if let Some(ref 左) = f.左 { + let 左_ptr = Arc::as_ptr(左); + let 左_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 左_ptr); + if !左_found { + println!("分型 {} 的 左 不在缠论K线序列中!", i); + } + } + + if let Some(ref 右) = f.右 { + let 右_ptr = Arc::as_ptr(右); + let 右_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 右_ptr); + if !右_found { + println!("分型 {} 的 右 不在缠论K线序列中!", i); + } + } + } + } + + // ========== 跨线程安全测试 ========== + + // 编译期断言:核心类型必须实现 Send + Sync + #[allow(dead_code)] + fn 断言_Send_Sync_编译期检查() { + fn _需要_Send() {} + fn _需要_Sync() {} + fn _需要_Send_Sync() {} + + // 核心数据结构 + _需要_Send::(); + _需要_Send::(); + _需要_Send::(); + _需要_Send_Sync::(); + _需要_Send_Sync::(); + _需要_Send_Sync::(); + + // Arc 包装后的 Send 检查 + _需要_Send::>(); + _需要_Send::>(); + _需要_Send::>(); + + // 观察者 + _需要_Send::(); + } + + /// 测试:Arc<缠论K线> 可跨线程传递 + #[test] + fn test_跨线程_缠论K线_Send() { + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + + let 普k = Arc::new(K线::创建普K( + "test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300, + )); + let ck = 缠论K线::创建缠K( + 1000, + 110.0, + 90.0, + crate::types::相对方向::向上, + None, + 1, + 普k, + None, + ); + let arc_ck = Arc::new(ck); + let arc_ck2 = Arc::clone(&arc_ck); + + let handle = std::thread::spawn(move || { + let _ = arc_ck2; + 42 + }); + assert_eq!(handle.join().unwrap(), 42); + assert!((arc_ck.高.get() - 110.0).abs() < 0.01); + } + + /// 测试:Arc<虚线> 可跨线程传递 + #[test] + fn test_跨线程_虚线_Send() { + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + use crate::structure::dash_line::虚线; + use crate::structure::fractal_obj::分型; + + let 普k = Arc::new(K线::创建普K( + "test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300, + )); + let ck = Arc::new(缠论K线::创建缠K( + 1000, + 110.0, + 90.0, + crate::types::相对方向::向上, + None, + 1, + 普k, + None, + )); + let frac = Arc::new(分型::new(None, Arc::clone(&ck), None)); + let frac2 = Arc::new(分型::new(None, ck, None)); + + let dash = Arc::new(虚线::创建笔(frac, frac2, true)); + let dash2 = Arc::clone(&dash); + + let handle = std::thread::spawn(move || { + let _ = Arc::as_ptr(&dash2.文); + 99 + }); + assert_eq!(handle.join().unwrap(), 99); + assert_eq!(dash.标识.read().unwrap().as_str(), "笔"); + } + + /// 测试:Arc<中枢> 可跨线程传递 + #[test] + fn test_跨线程_中枢_Send() { + let hub = crate::algorithm::hub::中枢::new(1, "test".into(), 1, vec![]); + let arc_hub = Arc::new(hub); + let arc_hub2 = Arc::clone(&arc_hub); + + let handle = std::thread::spawn(move || { + let _ = arc_hub2.序号.load(Ordering::Relaxed); + 77 + }); + assert_eq!(handle.join().unwrap(), 77); + assert_eq!(arc_hub.序号.load(Ordering::Relaxed), 1); + } + + /// 测试:多线程并发读取 观察者 + #[test] + fn test_跨线程_观察者_多线程读取() { + let obs = 观察者::new("btcusd".into(), 86400, Default::default()); + let obs2 = Arc::clone(&obs); + let obs3 = Arc::clone(&obs); + + let h1 = std::thread::spawn(move || { + let guard = obs2.read().unwrap(); + guard.符号.clone() + }); + let h2 = std::thread::spawn(move || { + let guard = obs3.read().unwrap(); + guard.周期 + }); + + assert_eq!(h1.join().unwrap(), "btcusd"); + assert_eq!(h2.join().unwrap(), 86400); + } + + /// 测试:Cell 字段跨线程读写不 panic + #[test] + fn test_跨线程_Cell字段_并发读写() { + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + + let 普k = Arc::new(K线::创建普K( + "test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300, + )); + let ck = Arc::new(缠论K线::创建缠K( + 1000, + 110.0, + 90.0, + crate::types::相对方向::向上, + None, + 1, + 普k, + None, + )); + let ck2 = Arc::clone(&ck); + + let handle = std::thread::spawn(move || { + let 序号 = ck2.序号.load(Ordering::Relaxed); + let 高 = ck2.高.get(); + (序号, 高) + }); + + let (序号, 高) = handle.join().unwrap(); + assert_eq!(序号, 0); // 序号 初始值为 0 + assert!((高 - 110.0).abs() < 0.01); + ck.序号.store(2, Ordering::Relaxed); + assert_eq!(ck.序号.load(Ordering::Relaxed), 2); + } + + /// 测试:Arc<观察者> 直接跨线程传递 + #[test] + fn test_跨线程_观察者_所有权转移() { + let obs = 观察者::new("ethusd".into(), 7200, Default::default()); + + let handle = std::thread::spawn(move || { + let guard = obs.read().unwrap(); + (guard.符号.clone(), guard.周期) + }); + + let (符号, 周期) = handle.join().unwrap(); + assert_eq!(符号, "ethusd"); + assert_eq!(周期, 7200); + } } diff --git a/chanlun/src/config.rs b/chanlun/src/config.rs index 6551c40..2cad0e0 100644 --- a/chanlun/src/config.rs +++ b/chanlun/src/config.rs @@ -22,7 +22,7 @@ * SOFTWARE. */ -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; fn is_infinite_f64(v: &f64) -> bool { v.is_infinite() @@ -70,6 +70,7 @@ pub struct 缠论配置 { // ---- 指标 ---- pub 计算指标: bool, + #[serde(deserialize_with = "deserialize_指标计算方式")] pub 指标计算方式: String, // ---- MACD ---- @@ -115,6 +116,7 @@ pub struct 缠论配置 { pub 买卖点激进识别: bool, pub 买卖点与MACD柱强相关: bool, pub 买卖点错过误差值: f64, + #[serde(deserialize_with = "deserialize_买卖点_指标模式")] pub 买卖点_指标模式: String, pub 买卖点_指标匹配_MACD: bool, pub 买卖点_指标匹配_KDJ: bool, @@ -136,12 +138,66 @@ pub struct 缠论配置 { pub 线段内部背驰_MACD: bool, pub 线段内部背驰_斜率: bool, pub 线段内部背驰_测度: bool, + #[serde(deserialize_with = "deserialize_线段内部背驰_模式")] pub 线段内部背驰_模式: String, // ---- 文件 ---- pub 加载文件路径: String, } +fn deserialize_指标计算方式<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + const VALID: &[&str] = &[ + "开", + "高", + "低", + "收", + "高低均值", + "高低收均值", + "开高低收均值", + ]; + const DEFAULT: &str = "收"; + if VALID.contains(&s.as_str()) { + Ok(s) + } else { + eprintln!("\x1b[33m[配置警告]\x1b[m 指标计算方式: \"{s}\" 不在有效值 {VALID:?} 内,已使用默认值 \"{DEFAULT}\""); + Ok(DEFAULT.to_string()) + } +} + +fn deserialize_买卖点_指标模式<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + const VALID: &[&str] = &["任意", "配置", "全量", "相对"]; + const DEFAULT: &str = "配置"; + if VALID.contains(&s.as_str()) { + Ok(s) + } else { + eprintln!("\x1b[33m[配置警告]\x1b[m 买卖点_指标模式: \"{s}\" 不在有效值 {VALID:?} 内,已使用默认值 \"{DEFAULT}\""); + Ok(DEFAULT.to_string()) + } +} + +fn deserialize_线段内部背驰_模式<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + const VALID: &[&str] = &["任意", "配置", "全量", "相对"]; + const DEFAULT: &str = "相对"; + if VALID.contains(&s.as_str()) { + Ok(s) + } else { + eprintln!("\x1b[33m[配置警告]\x1b[m 线段内部背驰_模式: \"{s}\" 不在有效值 {VALID:?} 内,已使用默认值 \"{DEFAULT}\""); + Ok(DEFAULT.to_string()) + } +} + impl Default for 缠论配置 { fn default() -> Self { Self { @@ -353,6 +409,39 @@ mod tests { assert_eq!(config.买卖点偏移, 1); } + #[test] + fn test_invalid_enum_field_fallback() { + // 无效的 指标计算方式 → 回退默认值 "收" + let json = r#"{"指标计算方式": "胡写"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.指标计算方式, "收"); + + // 有效的 指标计算方式 → 正常通过 + let json = r#"{"指标计算方式": "开"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.指标计算方式, "开"); + + // 无效的 买卖点_指标模式 → 回退默认值 "配置" + let json = r#"{"买卖点_指标模式": "瞎搞"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.买卖点_指标模式, "配置"); + + // 有效的 买卖点_指标模式 → 正常通过 + let json = r#"{"买卖点_指标模式": "任意"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.买卖点_指标模式, "任意"); + + // 无效的 线段内部背驰_模式 → 回退默认值 "相对" + let json = r#"{"线段内部背驰_模式": "乱来"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.线段内部背驰_模式, "相对"); + + // 有效的 线段内部背驰_模式 → 正常通过 + let json = r#"{"线段内部背驰_模式": "全量"}"#; + let config: 缠论配置 = serde_json::from_str(json).unwrap(); + assert_eq!(config.线段内部背驰_模式, "全量"); + } + #[test] fn test_不推送() { let config = 缠论配置::default(); diff --git a/chanlun/src/kline/bar.rs b/chanlun/src/kline/bar.rs index c55fa2d..851ffe4 100644 --- a/chanlun/src/kline/bar.rs +++ b/chanlun/src/kline/bar.rs @@ -28,7 +28,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::io::Write; -use std::rc::Rc; +use std::sync::Arc; /// 原始K线 (OHLCV + 指标) #[derive(Debug, Clone, Serialize, Deserialize)] @@ -202,12 +202,12 @@ impl K线 { Some(&序列[始_idx..=终_idx]) } - /// 截取Rc序列中从始到终的片段 - pub fn 截取rc(序列: &[Rc], 始: &Rc, 终: &Rc) -> Vec> { - let 始_ptr = Rc::as_ptr(始); - let 终_ptr = Rc::as_ptr(终); - let 始_idx = 序列.iter().position(|k| Rc::as_ptr(k) == 始_ptr); - let 终_idx = 序列.iter().position(|k| Rc::as_ptr(k) == 终_ptr); + /// 截取Arc序列中从始到终的片段 + pub fn 截取rc(序列: &[Arc], 始: &Arc, 终: &Arc) -> Vec> { + let 始_ptr = Arc::as_ptr(始); + let 终_ptr = Arc::as_ptr(终); + let 始_idx = 序列.iter().position(|k| Arc::as_ptr(k) == 始_ptr); + let 终_idx = 序列.iter().position(|k| Arc::as_ptr(k) == 终_ptr); match (始_idx, 终_idx) { (Some(s), Some(e)) => 序列[s..=e].to_vec(), _ => Vec::new(), diff --git a/chanlun/src/kline/chan_kline.rs b/chanlun/src/kline/chan_kline.rs index 1e55d85..337e59f 100644 --- a/chanlun/src/kline/chan_kline.rs +++ b/chanlun/src/kline/chan_kline.rs @@ -30,24 +30,49 @@ use crate::kline::bar::K线; use crate::structure::fractal_obj::分型; use crate::types::分型结构; use crate::types::相对方向; -use std::rc::Rc; +use crate::types::SyncF64; +use std::sync::atomic::{AtomicI64, Ordering}; +use std::sync::{Arc, RwLock}; /// 缠论K线 — 经包含处理过后的K线 -#[derive(Debug, Clone)] +/// +/// 部分字段使用 Cell/RefCell 实现内部可变性,确保包含处理原地修改时 +/// Rc 指针不变,所有持有该 Rc 的引用(如分型.右)能看到最新数据。 +#[derive(Debug)] pub struct 缠论K线 { - pub 序号: i64, - pub 时间戳: i64, - pub 高: f64, - pub 低: f64, - pub 方向: 相对方向, - pub 分型: Option<分型结构>, + pub 序号: AtomicI64, + pub 时间戳: AtomicI64, + pub 高: SyncF64, + pub 低: SyncF64, + pub 方向: RwLock<相对方向>, + pub 分型: RwLock>, pub 周期: i64, pub 标识: String, - pub 分型特征值: f64, + pub 分型特征值: SyncF64, pub 原始起始序号: i64, - pub 原始结束序号: i64, - pub 标的K线: Rc, - pub 买卖点信息: std::cell::RefCell>, + pub 原始结束序号: AtomicI64, + pub 标的K线: RwLock>, + pub 买卖点信息: RwLock>, +} + +impl Clone for 缠论K线 { + fn clone(&self) -> Self { + Self { + 序号: AtomicI64::new(self.序号.load(Ordering::Relaxed)), + 时间戳: AtomicI64::new(self.时间戳.load(Ordering::Relaxed)), + 高: SyncF64::new(self.高.get()), + 低: SyncF64::new(self.低.get()), + 方向: RwLock::new(*self.方向.read().unwrap()), + 分型: RwLock::new(*self.分型.read().unwrap()), + 周期: self.周期, + 标识: self.标识.clone(), + 分型特征值: SyncF64::new(self.分型特征值.get()), + 原始起始序号: self.原始起始序号, + 原始结束序号: AtomicI64::new(self.原始结束序号.load(Ordering::Relaxed)), + 标的K线: RwLock::new(Arc::clone(&self.标的K线.read().unwrap())), + 买卖点信息: RwLock::new(self.买卖点信息.read().unwrap().clone()), + } + } } impl std::fmt::Display for 缠论K线 { @@ -57,13 +82,16 @@ impl std::fmt::Display for 缠论K线 { f, "{}<{}, {}, {}, {}, {}, {}, {}>", self.标识, - self.序号, - self.分型.map_or("None".to_string(), |fx| fx.to_string()), + self.序号.load(Ordering::Relaxed), + self.分型 + .read() + .unwrap() + .map_or("None".to_string(), |fx| fx.to_string()), self.周期, - self.方向, - self.时间戳, - format_f64_g(self.高), - format_f64_g(self.低) + *self.方向.read().unwrap(), + self.时间戳.load(Ordering::Relaxed), + format_f64_g(self.高.get()), + format_f64_g(self.低.get()) ) } } @@ -72,34 +100,34 @@ impl 缠论K线 { /// 创建镜像(浅拷贝 Rc 引用) pub fn 镜像(&self) -> Self { Self { - 序号: self.序号, - 时间戳: self.时间戳, - 高: self.高, - 低: self.低, - 方向: self.方向, - 分型: self.分型, + 序号: AtomicI64::new(self.序号.load(Ordering::Relaxed)), + 时间戳: AtomicI64::new(self.时间戳.load(Ordering::Relaxed)), + 高: SyncF64::new(self.高.get()), + 低: SyncF64::new(self.低.get()), + 方向: RwLock::new(*self.方向.read().unwrap()), + 分型: RwLock::new(*self.分型.read().unwrap()), 周期: self.周期, 标识: self.标识.clone(), - 分型特征值: self.分型特征值, + 分型特征值: SyncF64::new(self.分型特征值.get()), 原始起始序号: self.原始起始序号, - 原始结束序号: self.原始结束序号, - 标的K线: Rc::clone(&self.标的K线), - 买卖点信息: std::cell::RefCell::new(self.买卖点信息.borrow().clone()), + 原始结束序号: AtomicI64::new(self.原始结束序号.load(Ordering::Relaxed)), + 标的K线: RwLock::new(Arc::clone(&self.标的K线.read().unwrap())), + 买卖点信息: RwLock::new(self.买卖点信息.read().unwrap().clone()), } } /// 与MACD柱子匹配 — 底分型时MACD柱应<0, 顶分型时>0 pub fn 与MACD柱子匹配(&self) -> bool { - match self.分型 { + match *self.分型.read().unwrap() { Some(分型结构::底) | Some(分型结构::下) => { - if let Some(ref macd) = self.标的K线.macd { + if let Some(ref macd) = self.标的K线.read().unwrap().macd { macd.MACD柱 < 0.0 } else { false } } Some(分型结构::顶) | Some(分型结构::上) => { - if let Some(ref macd) = self.标的K线.macd { + if let Some(ref macd) = self.标的K线.read().unwrap().macd { macd.MACD柱 > 0.0 } else { false @@ -111,9 +139,9 @@ impl 缠论K线 { /// 与RSI匹配 — 底分型时RSI应低于SMA, 顶分型时高于SMA pub fn 与RSI匹配(&self) -> bool { - match self.分型 { + match *self.分型.read().unwrap() { Some(分型结构::底) | Some(分型结构::下) => { - if let Some(ref rsi) = self.标的K线.rsi { + if let Some(ref rsi) = self.标的K线.read().unwrap().rsi { match (rsi.RSI, rsi.RSI_SMA) { (Some(r), Some(sma)) => r < sma, _ => false, @@ -123,7 +151,7 @@ impl 缠论K线 { } } Some(分型结构::顶) | Some(分型结构::上) => { - if let Some(ref rsi) = self.标的K线.rsi { + if let Some(ref rsi) = self.标的K线.read().unwrap().rsi { match (rsi.RSI, rsi.RSI_SMA) { (Some(r), Some(sma)) => r > sma, _ => false, @@ -138,9 +166,9 @@ impl 缠论K线 { /// 与KDJ匹配 — 底分型时K应低于D(死叉后), 顶分型时K应高于D(金叉后) pub fn 与KDJ匹配(&self) -> bool { - match self.分型 { + match *self.分型.read().unwrap() { Some(分型结构::底) | Some(分型结构::下) => { - if let Some(ref kdj) = self.标的K线.kdj { + if let Some(ref kdj) = self.标的K线.read().unwrap().kdj { match (kdj.K, kdj.D) { (Some(k), Some(d)) => k < d, _ => false, @@ -150,7 +178,7 @@ impl 缠论K线 { } } Some(分型结构::顶) | Some(分型结构::上) => { - if let Some(ref kdj) = self.标的K线.kdj { + if let Some(ref kdj) = self.标的K线.read().unwrap().kdj { match (kdj.K, kdj.D) { (Some(k), Some(d)) => k > d, _ => false, @@ -164,25 +192,30 @@ impl 缠论K线 { } /// 时间戳对齐 — 从基线序列中找匹配的时间戳 - pub fn 时间戳对齐(基线: &[Rc<缠论K线>], k线: &缠论K线) -> i64 { + pub fn 时间戳对齐(基线: &[Arc<缠论K线>], k线: &缠论K线) -> i64 { if let Some(基) = 基线.first() { for k in 基线.iter().rev() { if 基.周期 < k线.周期 { - if k线.时间戳 <= k.时间戳 && k.时间戳 <= k线.时间戳 + k线.周期 + if k线.时间戳.load(Ordering::Relaxed) <= k.时间戳.load(Ordering::Relaxed) + && k.时间戳.load(Ordering::Relaxed) + <= k线.时间戳.load(Ordering::Relaxed) + k线.周期 { - if (k线.分型特征值 - k.分型特征值).abs() < f64::EPSILON { - return k.时间戳; + if (k线.分型特征值.get() - k.分型特征值.get()).abs() < f64::EPSILON + { + return k.时间戳.load(Ordering::Relaxed); } } - } else if k.时间戳 <= k线.时间戳 && k线.时间戳 <= k.时间戳 + k.周期 + } else if k.时间戳.load(Ordering::Relaxed) <= k线.时间戳.load(Ordering::Relaxed) + && k线.时间戳.load(Ordering::Relaxed) + <= k.时间戳.load(Ordering::Relaxed) + k.周期 { - if (k线.分型特征值 - k.分型特征值).abs() < f64::EPSILON { - return k.时间戳; + if (k线.分型特征值.get() - k.分型特征值.get()).abs() < f64::EPSILON { + return k.时间戳.load(Ordering::Relaxed); } } } } - k线.时间戳 + k线.时间戳.load(Ordering::Relaxed) } /// 创建缠K @@ -193,7 +226,7 @@ impl 缠论K线 { 方向: 相对方向, 结构: Option<分型结构>, 原始序号: i64, - 普k: Rc, + 普k: Arc, 之前: Option<&缠论K线>, ) -> Self { if 高.is_nan() || 低.is_nan() { @@ -204,25 +237,28 @@ impl 缠论K线 { let 周期 = 普k.周期; let 标识 = 普k.标识.clone(); - let mut 当前 = Self { - 序号: 0, - 时间戳, - 高, - 低, - 方向, - 分型: 结构, + let 当前 = Self { + 序号: AtomicI64::new(0), + 时间戳: AtomicI64::new(时间戳), + 高: SyncF64::new(高), + 低: SyncF64::new(低), + 方向: RwLock::new(方向), + 分型: RwLock::new(结构), 周期, 标识, - 分型特征值: 高, + 分型特征值: SyncF64::new(高), 原始起始序号: 原始序号, - 原始结束序号: 原始序号, - 标的K线: 普k, - 买卖点信息: std::cell::RefCell::new(Vec::new()), + 原始结束序号: AtomicI64::new(原始序号), + 标的K线: RwLock::new(普k), + 买卖点信息: RwLock::new(Vec::new()), }; if let Some(之前) = 之前 { - 当前.序号 = 之前.序号 + 1; - let 关系 = 相对方向::分析(之前.高, 之前.低, 当前.高, 当前.低); + 当前 + .序号 + .store(之前.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + let 关系 = + 相对方向::分析(之前.高.get(), 之前.低.get(), 当前.高.get(), 当前.低.get()); if 关系.是否包含() { panic!( "创建缠K 包含关系: {:?}\n 之前: {}\n 当前: {}", @@ -238,11 +274,11 @@ impl 缠论K线 { /// 返回 (新缠K, 模式) — 模式: "添加"/"替换"/None pub fn 兼并( 之前缠K: Option<&缠论K线>, - 当前缠K: &mut 缠论K线, - 当前普K: &Rc, + 当前缠K: &缠论K线, + 当前普K: &Arc, 配置: &缠论配置, - ) -> (Option>, Option) { - let 关系 = 相对方向::分析(当前缠K.高, 当前缠K.低, 当前普K.高, 当前普K.低); + ) -> (Option>, Option) { + let 关系 = 相对方向::分析(当前缠K.高.get(), 当前缠K.低.get(), 当前普K.高, 当前普K.低); // 无包含关系 — 创建新元素追加 if !关系.是否包含() { @@ -251,37 +287,47 @@ impl 缠论K线 { } else { Some(分型结构::上) }; - let mut 新缠K = Self::创建缠K( + let 新缠K = Self::创建缠K( 当前普K.时间戳, 当前普K.高, 当前普K.低, 当前普K.方向(), 结构, 当前普K.序号, - Rc::clone(当前普K), + Arc::clone(当前普K), Some(当前缠K), ); - 新缠K.序号 = 当前缠K.序号 + 1; - return (Some(Rc::new(新缠K)), Some("添加".into())); + 新缠K + .序号 + .store(当前缠K.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + return (Some(Arc::new(新缠K)), Some("添加".into())); } // 重复提交检测 — 当序号相同时认为是重复提交K线 - if 当前普K.序号 == 当前缠K.原始结束序号 { + if 当前普K.序号 == 当前缠K.原始结束序号.load(Ordering::Relaxed) { return (None, None); } // 序号连续性检查 - if 当前普K.序号 - 1 != 当前缠K.原始结束序号 && 当前普K.序号 != 当前缠K.原始结束序号 + if 当前普K.序号 - 1 != 当前缠K.原始结束序号.load(Ordering::Relaxed) + && 当前普K.序号 != 当前缠K.原始结束序号.load(Ordering::Relaxed) { panic!( "兼并: 不可追加不连续元素 缠K.原始结束序号: {}, 当前普K.序号: {}", - 当前缠K.原始结束序号, 当前普K.序号 + 当前缠K.原始结束序号.load(Ordering::Relaxed), + 当前普K.序号 ); } // 包含关系 — 原地合并到当前缠K let 取值函数: fn(f64, f64) -> f64 = if let Some(之前) = 之前缠K { - if 相对方向::分析(之前.高, 之前.低, 当前缠K.高, 当前缠K.低).是否向下() + if 相对方向::分析( + 之前.高.get(), + 之前.低.get(), + 当前缠K.高.get(), + 当前缠K.低.get(), + ) + .是否向下() { f64::min } else { @@ -293,20 +339,22 @@ impl 缠论K线 { // 逆序包含时更新时间和标的K线 if 关系 != 相对方向::顺 { - 当前缠K.时间戳 = 当前普K.时间戳; - 当前缠K.标的K线 = Rc::clone(当前普K); + 当前缠K.时间戳.store(当前普K.时间戳, Ordering::Relaxed); + *当前缠K.标的K线.write().unwrap() = Arc::clone(当前普K); } - 当前缠K.高 = 取值函数(当前缠K.高, 当前普K.高); - 当前缠K.低 = 取值函数(当前缠K.低, 当前普K.低); - 当前缠K.原始结束序号 = 当前普K.序号; - 当前缠K.方向 = 当前普K.方向(); + 当前缠K.高.set(取值函数(当前缠K.高.get(), 当前普K.高)); + 当前缠K.低.set(取值函数(当前缠K.低.get(), 当前普K.低)); + 当前缠K.原始结束序号.store(当前普K.序号, Ordering::Relaxed); + *当前缠K.方向.write().unwrap() = 当前普K.方向(); if let Some(之前) = 之前缠K { - 当前缠K.序号 = 之前.序号 + 1; + 当前缠K + .序号 + .store(之前.序号.load(Ordering::Relaxed) + 1, Ordering::Relaxed); } if 配置.缠K合并替换 { - (Some(Rc::new(当前缠K.镜像())), Some("替换".into())) + (Some(Arc::new(当前缠K.镜像())), Some("替换".into())) } else { (None, None) } @@ -317,10 +365,10 @@ impl 缠论K线 { /// 返回 (状态, 形态) pub fn 分析( mut 当前K线: K线, - 缠K序列: &mut Vec>, - 普K序列: &mut Vec>, + 缠K序列: &mut Vec>, + 普K序列: &mut Vec>, 配置: &缠论配置, - ) -> (String, Option>) { + ) -> (String, Option>) { 当前K线.标识 = 配置.标识.clone(); // ---- 阶段1: 普K序列管理 + 指标增量计算 ---- @@ -365,7 +413,7 @@ impl 缠论K线 { 配置.随机指标_超卖阈值, )); } - let 当前K线_rc = Rc::new(当前K线); + let 当前K线_rc = Arc::new(当前K线); 普K序列.push(当前K线_rc); } else { let 之前普K = 普K序列.last().unwrap(); @@ -412,7 +460,7 @@ impl 缠论K线 { } } 普K序列.pop(); - 普K序列.push(Rc::new(当前K线)); + 普K序列.push(Arc::new(当前K线)); } else { if 之前普K.时间戳 > 当前K线.时间戳 { panic!("时序错误: 之前={}, 当前={}", 之前普K.时间戳, 当前K线.时间戳); @@ -455,20 +503,20 @@ impl 缠论K线 { )); } } - 普K序列.push(Rc::new(当前K线)); + 普K序列.push(Arc::new(当前K线)); } } // ---- 阶段2: 缠K合并 ---- let 状态: String; - let 当前K线_ref: &Rc = 普K序列.last().unwrap(); + let 当前K线_ref: &Arc = 普K序列.last().unwrap(); if !缠K序列.is_empty() { let len = 缠K序列.len(); let (左边, 右边) = 缠K序列.split_at_mut(len - 1); - let 之前缠K: Option<&缠论K线> = 左边.last().map(|rc| Rc::as_ref(rc)); - let 最后一个缠K_mut = Rc::make_mut(&mut 右边[0]); - let (新缠K, 模式) = Self::兼并(之前缠K, 最后一个缠K_mut, 当前K线_ref, 配置); + let 之前缠K: Option<&缠论K线> = 左边.last().map(|rc| Arc::as_ref(rc)); + let 最后一个缠K = &*右边[0]; + let (新缠K, 模式) = Self::兼并(之前缠K, 最后一个缠K, 当前K线_ref, 配置); if let Some(k) = 新缠K { match 模式.as_deref() { @@ -477,9 +525,8 @@ impl 缠论K线 { 状态 = "创建".into(); } Some("替换") => { - 缠K序列.pop(); - 缠K序列.push(k); - 状态 = "替换".into(); + // Cell::set 已原地更新数据,无需 pop+push 打破 Rc 身份 + 状态 = "兼并".into(); } _ => { 状态 = "兼并".into(); @@ -496,10 +543,10 @@ impl 缠论K线 { 当前K线_ref.方向(), None, 当前K线_ref.序号, - Rc::clone(普K序列.last().unwrap()), + Arc::clone(普K序列.last().unwrap()), None, ); - 缠K序列.push(Rc::new(新缠K)); + 缠K序列.push(Arc::new(新缠K)); 状态 = "新建".into(); } @@ -509,106 +556,89 @@ impl 缠论K线 { } let idx = 缠K序列.len(); - let 左 = Rc::clone(&缠K序列[idx - 3]); - let 中 = Rc::clone(&缠K序列[idx - 2]); - let 右 = Rc::clone(&缠K序列[idx - 1]); + let 左 = Arc::clone(&缠K序列[idx - 3]); + let 中 = Arc::clone(&缠K序列[idx - 2]); + let 右 = Arc::clone(&缠K序列[idx - 1]); let 结构 = 分型结构::分析(&*左, &*中, &*右, false, false); - // 需要通过 Rc::get_mut 或 RefCell 修改 中.分型 - // 由于使用 Rc,中是不可变的。这里采用创建新 Rc 替换的方式。 - // 但这是在 Vec 内部修改,需要使用 Rc::make_mut 或重新构建 + // 对齐 Python:无条件设置 中.分型、中.分型特征值、右.分型特征值、右.分型 + *缠K序列[idx - 2].分型.write().unwrap() = 结构; + if let Some(结构) = 结构 { - // 只在分型未设置或需要更新时才修改缠K,以保持 Rc 指针不变 - let 当前分型标记 = 缠K序列[idx - 2].分型; - let 中需要更新 = 当前分型标记.is_none() || 当前分型标记 != Some(结构); - - if 中需要更新 { - let 中_mut = Rc::make_mut(&mut 缠K序列[idx - 2]); - 中_mut.分型 = Some(结构); - - match 结构 { - 分型结构::底 => { - 中_mut.分型特征值 = 中_mut.低; - let 右标记 = 缠K序列[idx - 1].分型; - if 右标记.is_none() { - let 右_mut = Rc::make_mut(&mut 缠K序列[idx - 1]); - 右_mut.分型特征值 = 右_mut.高; - 右_mut.分型 = Some(分型结构::顶); - } - } - 分型结构::顶 => { - 中_mut.分型特征值 = 中_mut.高; - let 右标记 = 缠K序列[idx - 1].分型; - if 右标记.is_none() { - let 右_mut = Rc::make_mut(&mut 缠K序列[idx - 1]); - 右_mut.分型特征值 = 右_mut.低; - 右_mut.分型 = Some(分型结构::底); - } - } - 分型结构::上 => { - 中_mut.分型特征值 = 中_mut.高; - let 右标记 = 缠K序列[idx - 1].分型; - if 右标记.is_none() { - let 右_mut = Rc::make_mut(&mut 缠K序列[idx - 1]); - 右_mut.分型特征值 = 右_mut.高; - 右_mut.分型 = Some(分型结构::顶); - } - } - 分型结构::下 => { - 中_mut.分型特征值 = 中_mut.低; - let 右标记 = 缠K序列[idx - 1].分型; - if 右标记.is_none() { - let 右_mut = Rc::make_mut(&mut 缠K序列[idx - 1]); - 右_mut.分型特征值 = 右_mut.低; - 右_mut.分型 = Some(分型结构::底); - } - } - 分型结构::散 => {} + match 结构 { + 分型结构::底 => { + 缠K序列[idx - 2].分型特征值.set(缠K序列[idx - 2].低.get()); + 缠K序列[idx - 1].分型特征值.set(缠K序列[idx - 1].高.get()); + *缠K序列[idx - 1].分型.write().unwrap() = Some(分型结构::顶); } + 分型结构::顶 => { + 缠K序列[idx - 2].分型特征值.set(缠K序列[idx - 2].高.get()); + 缠K序列[idx - 1].分型特征值.set(缠K序列[idx - 1].低.get()); + *缠K序列[idx - 1].分型.write().unwrap() = Some(分型结构::底); + } + 分型结构::上 => { + 缠K序列[idx - 2].分型特征值.set(缠K序列[idx - 2].高.get()); + 缠K序列[idx - 1].分型特征值.set(缠K序列[idx - 1].高.get()); + *缠K序列[idx - 1].分型.write().unwrap() = Some(分型结构::顶); + } + 分型结构::下 => { + 缠K序列[idx - 2].分型特征值.set(缠K序列[idx - 2].低.get()); + 缠K序列[idx - 1].分型特征值.set(缠K序列[idx - 1].低.get()); + *缠K序列[idx - 1].分型.write().unwrap() = Some(分型结构::底); + } + 分型结构::散 => {} } let 形态 = if matches!(结构, 分型结构::上 | 分型结构::下) { // Python: 形态 = 分型(中, 右, None) — 左=中K线, 中=右K线, 右=None - Rc::new(分型::new( - Some(Rc::clone(&缠K序列[idx - 2])), - Rc::clone(&缠K序列[idx - 1]), + Arc::new(分型::new( + Some(Arc::clone(&缠K序列[idx - 2])), + Arc::clone(&缠K序列[idx - 1]), None, )) } else { - Rc::new(分型::new( - Some(Rc::clone(&缠K序列[idx - 3])), - Rc::clone(&缠K序列[idx - 2]), - Some(Rc::clone(&缠K序列[idx - 1])), + Arc::new(分型::new( + Some(Arc::clone(&缠K序列[idx - 3])), + Arc::clone(&缠K序列[idx - 2]), + Some(Arc::clone(&缠K序列[idx - 1])), )) }; return (状态, Some(形态)); } - (状态, None) + // 对齐 Python:结构为 None 时仍创建并返回分型 + let 形态 = Arc::new(分型::new( + Some(Arc::clone(&缠K序列[idx - 3])), + Arc::clone(&缠K序列[idx - 2]), + Some(Arc::clone(&缠K序列[idx - 1])), + )); + return (状态, Some(形态)); } /// 截取缠K序列从始到终 pub fn 截取( - 序列: &[Rc<缠论K线>], 始: &缠论K线, 终: &缠论K线 - ) -> Option>> { + 序列: &[Arc<缠论K线>], + 始: &缠论K线, + 终: &缠论K线, + ) -> Option>> { let 始_idx = 序列 .iter() - .position(|k| Rc::as_ptr(k) == (始 as *const _))?; + .position(|k| Arc::as_ptr(k) == (始 as *const _))?; let 终_idx = 序列 .iter() - .position(|k| Rc::as_ptr(k) == (终 as *const _))?; + .position(|k| Arc::as_ptr(k) == (终 as *const _))?; Some(序列[始_idx..=终_idx].to_vec()) } } impl crate::types::fractal::有高低 for 缠论K线 { fn 高(&self) -> f64 { - self.高 + self.高.get() } fn 低(&self) -> f64 { - self.低 + self.低.get() } } @@ -623,11 +653,11 @@ mod tests { #[test] fn test_创建缠K_basic() { - let pk = Rc::new(make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0)); + let pk = Arc::new(make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0)); let ck = 缠论K线::创建缠K(1000, 110.0, 95.0, 相对方向::向上, None, 0, pk, None); - assert_eq!(ck.高, 110.0); - assert_eq!(ck.低, 95.0); - assert_eq!(ck.序号, 0); + assert_eq!(ck.高.get(), 110.0); + assert_eq!(ck.低.get(), 95.0); + assert_eq!(ck.序号.load(Ordering::Relaxed), 0); } #[test] diff --git a/chanlun/src/main.rs b/chanlun/src/main.rs index 90f7d2d..b38af6b 100644 --- a/chanlun/src/main.rs +++ b/chanlun/src/main.rs @@ -79,7 +79,7 @@ fn 测试_读取数据(文件路径: &str) { let 配置 = 缠论配置::default().不推送(); match 观察者::读取数据文件(文件路径, Some(配置)) { Ok(观察员) => { - let 观察员 = 观察员.borrow(); + let 观察员 = 观察员.read().unwrap(); let 消耗用时 = 启动时间.elapsed(); println!( "测试_读取数据 耗时 {:.2?} 普K数量 {}", @@ -162,7 +162,7 @@ fn 测试_周期合成(文件路径: &str) { // Display stats per period for &p in &[周期, 周期 * 5, 周期 * 5 * 6] { if let Some(观察员) = 多级别分析.获取观察者(p) { - let 观察员 = 观察员.borrow(); + let 观察员 = 观察员.read().unwrap(); println!( "周期<{}>: 缠K={}, 分型={}, 笔={}, 线段={}, 中枢={}", p, diff --git a/chanlun/src/structure/dash_line.rs b/chanlun/src/structure/dash_line.rs index 00a0417..4134e3f 100644 --- a/chanlun/src/structure/dash_line.rs +++ b/chanlun/src/structure/dash_line.rs @@ -29,30 +29,32 @@ use crate::kline::chan_kline::缠论K线; use crate::structure::fractal_obj::分型; use crate::structure::segment_feat::线段特征; use crate::types::{分型结构, 相对方向, 缺口}; -use std::rc::Rc; +use std::sync::atomic::{AtomicBool, AtomicI64, Ordering}; +use std::sync::{Arc, RwLock}; /// 虚线 — 笔和线段的通用数据结构 /// /// 笔和线段共享此 struct,通过 `标识` 字段区分 ("笔"/"线段"/"扩展线段"等) -#[derive(Debug, Clone)] +/// 可变字段使用 Cell/RefCell 实现内部可变性,确保 Rc 指针身份一致 +#[derive(Debug)] pub struct 虚线 { - pub 标识: String, - pub 序号: i64, - pub 级别: i64, - pub 文: Rc<分型>, - pub 武: Rc<分型>, - pub 有效性: bool, - pub 基础序列: Vec>, - pub 特征序列: Vec>>, - pub 实_中枢序列: Vec>, - pub 虚_中枢序列: Vec>, - pub 合_中枢序列: Vec>, - pub 确认K线: Option>, - pub 模式: String, - pub _特征序列_显示: bool, - pub 前一缺口: Option<缺口>, - pub 前一结束位置: Option>, - pub 短路修正: bool, + pub 标识: RwLock, + pub 序号: AtomicI64, + pub 级别: AtomicI64, + pub 文: Arc<分型>, + pub 武: RwLock>, + pub 有效性: AtomicBool, + pub 基础序列: RwLock>>, + pub 特征序列: RwLock>>>, + pub 实_中枢序列: RwLock>>, + pub 虚_中枢序列: RwLock>>, + pub 合_中枢序列: RwLock>>, + pub 确认K线: RwLock>>, + pub 模式: RwLock, + pub _特征序列_显示: AtomicBool, + pub 前一缺口: RwLock>, + pub 前一结束位置: RwLock>>, + pub 短路修正: AtomicBool, } /// MACD行为统计 — 统计MACD行为 方法的返回类型 @@ -67,51 +69,73 @@ pub struct MACD行为统计 { pub 密集交叉区域: Vec<(usize, usize, usize)>, } +impl Clone for 虚线 { + fn clone(&self) -> Self { + Self { + 标识: RwLock::new(self.标识.read().unwrap().clone()), + 序号: AtomicI64::new(self.序号.load(Ordering::Relaxed)), + 级别: AtomicI64::new(self.级别.load(Ordering::Relaxed)), + 文: Arc::clone(&self.文), + 武: RwLock::new(Arc::clone(&self.武.read().unwrap())), + 有效性: AtomicBool::new(self.有效性.load(Ordering::Relaxed)), + 基础序列: RwLock::new(self.基础序列.read().unwrap().clone()), + 特征序列: RwLock::new(self.特征序列.read().unwrap().clone()), + 实_中枢序列: RwLock::new(self.实_中枢序列.read().unwrap().clone()), + 虚_中枢序列: RwLock::new(self.虚_中枢序列.read().unwrap().clone()), + 合_中枢序列: RwLock::new(self.合_中枢序列.read().unwrap().clone()), + 确认K线: RwLock::new(self.确认K线.read().unwrap().clone()), + 模式: RwLock::new(self.模式.read().unwrap().clone()), + _特征序列_显示: AtomicBool::new(self._特征序列_显示.load(Ordering::Relaxed)), + 前一缺口: RwLock::new(*self.前一缺口.read().unwrap()), + 前一结束位置: RwLock::new(self.前一结束位置.read().unwrap().clone()), + 短路修正: AtomicBool::new(self.短路修正.load(Ordering::Relaxed)), + } + } +} + impl 虚线 { pub fn new( 序号: i64, 标识: String, - 文: Rc<分型>, - 武: Rc<分型>, + 文: Arc<分型>, + 武: Arc<分型>, 级别: i64, 有效性: bool, ) -> Self { Self { - 序号, - 标识, - 级别, + 序号: AtomicI64::new(序号), + 标识: RwLock::new(标识), + 级别: AtomicI64::new(级别), 文, - 武, - 有效性, - 基础序列: Vec::new(), - 特征序列: Vec::new(), - 实_中枢序列: Vec::new(), - 虚_中枢序列: Vec::new(), - 合_中枢序列: Vec::new(), - 确认K线: None, - 模式: "文武".into(), - _特征序列_显示: false, - 前一缺口: None, - 前一结束位置: None, - 短路修正: false, + 武: RwLock::new(武), + 有效性: AtomicBool::new(有效性), + 基础序列: RwLock::new(Vec::new()), + 特征序列: RwLock::new(Vec::new()), + 实_中枢序列: RwLock::new(Vec::new()), + 虚_中枢序列: RwLock::new(Vec::new()), + 合_中枢序列: RwLock::new(Vec::new()), + 确认K线: RwLock::new(None), + 模式: RwLock::new("文武".into()), + _特征序列_显示: AtomicBool::new(false), + 前一缺口: RwLock::new(None), + 前一结束位置: RwLock::new(None), + 短路修正: AtomicBool::new(false), } } - /// 笔序列(基础序列的别名) - pub fn 笔序列(&self) -> &Vec> { - &self.基础序列 - } - pub fn 图表标题(&self) -> String { format!( "{}:{}:{}:{}", - self.文.中.标识, self.文.中.周期, self.标识, self.序号 + self.文.中.标识, + self.文.中.周期, + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed) ) } /// 方向 — 文到武的方向 pub fn 方向(&self) -> 相对方向 { - match (self.文.结构, self.武.结构) { + match (self.文.结构, self.武.read().unwrap().结构) { (分型结构::顶, 分型结构::底) => 相对方向::向下, (分型结构::顶, 分型结构::下) => 相对方向::向下, (分型结构::上, 分型结构::底) => 相对方向::向下, @@ -123,54 +147,60 @@ impl 虚线 { /// 虚线高 pub fn 高(&self) -> f64 { if self.方向() == 相对方向::向下 { - self.文.中.高 + self.文.中.高.get() } else { - self.武.中.高 + self.武.read().unwrap().中.高.get() } } /// 虚线低 pub fn 低(&self) -> f64 { if self.方向() == 相对方向::向下 { - self.武.中.低 + self.武.read().unwrap().中.低.get() } else { - self.文.中.低 + self.文.中.低.get() } } /// 判断两个虚线是否首尾相连 pub fn 之前是(&self, 之前: &虚线) -> bool { - if self.标识 != 之前.标识 { + if *self.标识.read().unwrap() != *之前.标识.read().unwrap() { return false; } - Rc::as_ptr(&之前.武) == Rc::as_ptr(&self.文) + Arc::as_ptr(&*之前.武.read().unwrap()) == Arc::as_ptr(&self.文) } /// 判断两个虚线是否首尾相连 pub fn 之后是(&self, 之后: &虚线) -> bool { - if self.标识 != 之后.标识 { + if *self.标识.read().unwrap() != *之后.标识.read().unwrap() { return false; } - Rc::as_ptr(&self.武) == Rc::as_ptr(&之后.文) + Arc::as_ptr(&*self.武.read().unwrap()) == Arc::as_ptr(&之后.文) } /// 获取该虚线范围内的普K序列 - pub fn 获取普K序列(&self, 普K序列: &[Rc]) -> Vec> { + pub fn 获取普K序列(&self, 普K序列: &[Arc]) -> Vec> { // 使用指针查找(与 Python list.index 身份匹配行为一致), // 而非序号切片——因为序号可能与实际位置不一致。 let 始 = 普K序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(&self.文.中.标的K线)); - let 终 = 普K序列 - .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(&self.武.中.标的K线)); + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(&*self.文.中.标的K线.read().unwrap())); + let 终 = 普K序列.iter().position(|k| { + Arc::as_ptr(k) == Arc::as_ptr(&*self.武.read().unwrap().中.标的K线.read().unwrap()) + }); match (始, 终) { (Some(s), Some(e)) if s <= e => 普K序列[s..=e].to_vec(), _ => { // 指针查找失败时回退到序号方式 println!("[警告]虚线.获取普K序列 <指针查找失败时回退到序号方式>"); let 始 = self.文.中.原始起始序号 as usize; - let 终 = self.武.中.原始结束序号 as usize; + let 终 = self + .武 + .read() + .unwrap() + .中 + .原始结束序号 + .load(Ordering::Relaxed) as usize; if 始 < 普K序列.len() && 终 < 普K序列.len() && 始 <= 终 { 普K序列[始..=终].to_vec() } else { @@ -181,36 +211,43 @@ impl 虚线 { } /// 获取该虚线范围内的缠K序列 - pub fn 获取缠K序列(&self, 缠K序列: &[Rc<缠论K线>]) -> Vec> { - 缠论K线::截取(缠K序列, &self.文.中, &self.武.中).unwrap_or_default() + pub fn 获取缠K序列(&self, 缠K序列: &[Arc<缠论K线>]) -> Vec> { + 缠论K线::截取(缠K序列, &self.文.中, &self.武.read().unwrap().中).unwrap_or_default() } /// 获取_武 — 递归获取虚线的终点分型(笔直接返回武,线段递归到底层笔的武) - pub fn 获取_武(&self) -> Rc<分型> { - if self.标识 == "笔" { - return Rc::clone(&self.武); + pub fn 获取_武(&self) -> Arc<分型> { + if *self.标识.read().unwrap() == "笔" { + return self.武.read().unwrap().clone(); } - let mut current: &虚线 = self; - while current.标识 != "笔" { - current = &*current.基础序列.last().unwrap(); + let mut current_rc = Arc::clone(self.基础序列.read().unwrap().last().unwrap()); + loop { + if *current_rc.标识.read().unwrap() == "笔" { + return current_rc.武.read().unwrap().clone(); + } + let next = Arc::clone(current_rc.基础序列.read().unwrap().last().unwrap()); + current_rc = next; } - Rc::clone(¤t.武) } /// 获取数据文本(用于保存/调试) pub fn 获取数据文本(&self) -> String { use crate::utils::format_f64_g; - if self.标识 == "笔" { + if *self.标识.read().unwrap() == "笔" { return format!( "{}, {}, {}, 文:({},{}), 武:({},{}), {}", - self.标识, - self.序号, - self.级别, + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed), + self.级别.load(Ordering::Relaxed), self.文.时间戳, format_f64_g(self.文.分型特征值), - self.武.时间戳, - format_f64_g(self.武.分型特征值), - if self.有效性 { "True" } else { "False" }, + self.武.read().unwrap().时间戳, + format_f64_g(self.武.read().unwrap().分型特征值), + if self.有效性.load(Ordering::Relaxed) { + "True" + } else { + "False" + }, ); } @@ -225,11 +262,11 @@ impl 虚线 { } }; - let 前一缺口_str = match &self.前一缺口 { + let 前一缺口_str = match &*self.前一缺口.read().unwrap() { Some(g) => format!("{}", g), None => "None".to_string(), }; - let 前一结束位置_str = match &self.前一结束位置 { + let 前一结束位置_str = match &*self.前一结束位置.read().unwrap() { Some(d) => format!("{}", d), None => "None".to_string(), }; @@ -238,6 +275,8 @@ impl 虚线 { let 实_str = format!( "[{}]", self.实_中枢序列 + .read() + .unwrap() .iter() .map(|h| format!("{}", h)) .collect::>() @@ -246,6 +285,8 @@ impl 虚线 { let 虚_str = format!( "[{}]", self.虚_中枢序列 + .read() + .unwrap() .iter() .map(|h| format!("{}", h)) .collect::>() @@ -254,6 +295,8 @@ impl 虚线 { let 合_str = format!( "[{}]", self.合_中枢序列 + .read() + .unwrap() .iter() .map(|h| format!("{}", h)) .collect::>() @@ -284,15 +327,15 @@ impl 虚线 { format!( "{}, {}, {}, 文:({},{}), 武:({},{}), {}, {}, ({}, {}, {}), (前: {}, 后: {}, 三: {}, 伤: {}), 实: {}, 虚: {}, 合: {}, {}, {}, {}, {}", - self.标识, - self.序号, - self.级别, + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed), + self.级别.load(Ordering::Relaxed), self.文.时间戳, format_f64_g(self.文.分型特征值), - self.武.时间戳, - format_f64_g(self.武.分型特征值), - if self.有效性 { "True" } else { "False" }, - self.基础序列.len(), + self.武.read().unwrap().时间戳, + format_f64_g(self.武.read().unwrap().分型特征值), + if self.有效性.load(Ordering::Relaxed) { "True" } else { "False" }, + self.基础序列.read().unwrap().len(), 特征_bool(特征_a), 特征_bool(特征_b), 特征_bool(特征_c), @@ -303,33 +346,39 @@ impl 虚线 { 实_str, 虚_str, 合_str, - self.模式, + self.模式.read().unwrap(), 前一缺口_str, 前一结束位置_str, - if self.短路修正 { "True" } else { "False" }, + if self.短路修正.load(Ordering::Relaxed) { "True" } else { "False" }, ) } // ---- 关联函数(静态工厂方法) ---- /// 创建笔 - pub fn 创建笔(文: Rc<分型>, 武: Rc<分型>, 有效性: bool) -> Self { + pub fn 创建笔(文: Arc<分型>, 武: Arc<分型>, 有效性: bool) -> Self { Self::new(0, "笔".into(), 文, 武, 1, 有效性) } /// 创建线段 - pub fn 创建线段(虚线序列: &[Rc<虚线>]) -> Self { - let 文 = Rc::clone(&虚线序列[0].文); - let 武 = Rc::clone(&虚线序列[虚线序列.len() - 1].武); - let 标识 = if 虚线序列[0].标识 == "笔" { + pub fn 创建线段(虚线序列: &[Arc<虚线>]) -> Self { + let 文 = Arc::clone(&虚线序列[0].文); + let 武 = Arc::clone(&*虚线序列[虚线序列.len() - 1].武.read().unwrap()); + assert!( + 文.结构 != 武.结构, + "创建线段: 文.结构 == 武.结构 文={}, 武={}", + 文, + 武 + ); + let 标识: String = if *虚线序列[0].标识.read().unwrap() == "笔" { "线段".into() } else { - format!("线段<{}>", 虚线序列[0].标识) + format!("线段<{}>", 虚线序列[0].标识.read().unwrap()) }; - let 级别 = 虚线序列[0].级别 + 1; - let mut 段 = Self::new(0, 标识, 文, 武, 级别, true); - 段.基础序列 = 虚线序列.to_vec(); - 段.模式 = "文武".into(); + let 级别 = 虚线序列[0].级别.load(Ordering::Relaxed) + 1; + let 段 = Self::new(0, 标识, 文, 武, 级别, true); + *段.基础序列.write().unwrap() = 虚线序列.to_vec(); + *段.模式.write().unwrap() = "文武".into(); 段 } @@ -383,8 +432,12 @@ impl 虚线 { // ---- MACD柱子均值计算 ---- /// 计算MACD柱子均值 — 虚线范围内所有MACD柱的绝对值均值 - pub fn 计算MACD柱子均值(普K序列: &[Rc], 实线: &虚线) -> f64 { - let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线); + pub fn 计算MACD柱子均值(普K序列: &[Arc], 实线: &虚线) -> f64 { + let K线序列 = K线::截取rc( + 普K序列, + &*实线.文.中.标的K线.read().unwrap(), + &*实线.武.read().unwrap().中.标的K线.read().unwrap(), + ); if K线序列.is_empty() { return 0.0; } @@ -397,8 +450,12 @@ impl 虚线 { } /// 计算MACD柱子均值_阴 — 负柱的绝对值均值 - pub fn 计算MACD柱子均值_阴(普K序列: &[Rc], 实线: &虚线) -> Option { - let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线); + pub fn 计算MACD柱子均值_阴(普K序列: &[Arc], 实线: &虚线) -> Option { + let K线序列 = K线::截取rc( + 普K序列, + &*实线.文.中.标的K线.read().unwrap(), + &*实线.武.read().unwrap().中.标的K线.read().unwrap(), + ); let 总: Vec = K线序列 .iter() .filter_map(|k| k.macd.as_ref()) @@ -413,8 +470,12 @@ impl 虚线 { } /// 计算MACD柱子均值_阳 — 正柱的绝对值均值 - pub fn 计算MACD柱子均值_阳(普K序列: &[Rc], 实线: &虚线) -> Option { - let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线); + pub fn 计算MACD柱子均值_阳(普K序列: &[Arc], 实线: &虚线) -> Option { + let K线序列 = K线::截取rc( + 普K序列, + &*实线.文.中.标的K线.read().unwrap(), + &*实线.武.read().unwrap().中.标的K线.read().unwrap(), + ); let 总: Vec = K线序列 .iter() .filter_map(|k| k.macd.as_ref()) @@ -431,8 +492,10 @@ impl 虚线 { // ---- 武之MACD比较 ---- /// 武之全量MACD均值 — 武端MACD柱是否小于均值(背驰) - pub fn 武之全量MACD均值(普K序列: &[Rc], 实线: &虚线) -> bool { - let 武_MACD = match &实线.武.中.标的K线.macd { + pub fn 武之全量MACD均值(普K序列: &[Arc], 实线: &虚线) -> bool { + let 武_ref = 实线.武.read().unwrap(); + let 标 = 武_ref.中.标的K线.read().unwrap(); + let 武_MACD = match 标.macd.as_ref() { Some(m) => m.MACD柱.abs(), None => return false, }; @@ -440,7 +503,7 @@ impl 虚线 { } /// 武之MACD均值 — 按方向选择阴/阳均值比对 - pub fn 武之MACD均值(普K序列: &[Rc], 实线: &虚线) -> bool { + pub fn 武之MACD均值(普K序列: &[Arc], 实线: &虚线) -> bool { if 实线.方向() == 相对方向::向上 { Self::武之MACD均值_阳(普K序列, 实线) } else { @@ -449,8 +512,10 @@ impl 虚线 { } /// 武之MACD均值_阴 — 武端负柱是否小于阴均值 - pub fn 武之MACD均值_阴(普K序列: &[Rc], 实线: &虚线) -> bool { - let 武_MACD = match &实线.武.中.标的K线.macd { + pub fn 武之MACD均值_阴(普K序列: &[Arc], 实线: &虚线) -> bool { + let 武_ref = 实线.武.read().unwrap(); + let 标 = 武_ref.中.标的K线.read().unwrap(); + let 武_MACD = match 标.macd.as_ref() { Some(m) => m.MACD柱.abs(), None => return false, }; @@ -461,8 +526,10 @@ impl 虚线 { } /// 武之MACD均值_阳 — 武端正柱是否小于阳均值 - pub fn 武之MACD均值_阳(普K序列: &[Rc], 实线: &虚线) -> bool { - let 武_MACD = match &实线.武.中.标的K线.macd { + pub fn 武之MACD均值_阳(普K序列: &[Arc], 实线: &虚线) -> bool { + let 武_ref = 实线.武.read().unwrap(); + let 标 = 武_ref.中.标的K线.read().unwrap(); + let 武_MACD = match 标.macd.as_ref() { Some(m) => m.MACD柱.abs(), None => return false, }; @@ -473,12 +540,18 @@ impl 虚线 { } /// 武之MACD极值 — 武端MACD柱是否为区间极值 - pub fn 武之MACD极值(普K序列: &[Rc], 实线: &虚线) -> bool { - let 武_MACD = match &实线.武.中.标的K线.macd { + pub fn 武之MACD极值(普K序列: &[Arc], 实线: &虚线) -> bool { + let 武_ref = 实线.武.read().unwrap(); + let 标 = 武_ref.中.标的K线.read().unwrap(); + let 武_MACD = match 标.macd.as_ref() { Some(m) => m.MACD柱, None => return false, }; - let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线); + let K线序列 = K线::截取rc( + 普K序列, + &*实线.文.中.标的K线.read().unwrap(), + &*实线.武.read().unwrap().中.标的K线.read().unwrap(), + ); let 所有柱子: Vec = K线序列 .iter() .filter_map(|k| k.macd.as_ref()) @@ -500,7 +573,7 @@ impl 虚线 { /// 计算K线序列MACD趋向背驰 — 分析 MACD柱/DIF/DEA 三项背驰信号 pub fn 计算K线序列MACD趋向背驰( - 普K序列: &[Rc], 方向: 相对方向 + 普K序列: &[Arc], 方向: 相对方向 ) -> [bool; 3] { if 普K序列.is_empty() { return [false, false, false]; @@ -508,7 +581,7 @@ impl 虚线 { let 最后 = &普K序列[普K序列.len() - 1]; if 方向 == 相对方向::向上 { - let 柱子序列: Vec<&Rc> = 普K序列 + let 柱子序列: Vec<&Arc> = 普K序列 .iter() .filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 > 0.0)) .collect(); @@ -530,7 +603,7 @@ impl 虚线 { .unwrap_or(std::cmp::Ordering::Equal) }) .unwrap(); - let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::clone(最后)]; + let mut 柱对 = vec![Arc::clone(*最高柱子), Arc::clone(最后)]; 柱对.sort_by_key(|k| k.时间戳); if let (Some(m0), Some(m1)) = (柱对[0].macd.as_ref(), 柱对[1].macd.as_ref()) { if m0.MACD柱 > m1.MACD柱 && 柱对[0].高 < 柱对[1].高 { @@ -574,7 +647,7 @@ impl 虚线 { 结果 } else { - let 柱子序列: Vec<&Rc> = 普K序列 + let 柱子序列: Vec<&Arc> = 普K序列 .iter() .filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 < 0.0)) .collect(); @@ -597,7 +670,7 @@ impl 虚线 { .unwrap_or(std::cmp::Ordering::Equal) }) .unwrap(); - let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::clone(最后)]; + let mut 柱对 = vec![Arc::clone(*最高柱子), Arc::clone(最后)]; 柱对.sort_by_key(|k| k.时间戳); if let (Some(m0), Some(m1)) = (柱对[0].macd.as_ref(), 柱对[1].macd.as_ref()) { if m0.MACD柱 < m1.MACD柱 && 柱对[0].低 > 柱对[1].低 { @@ -646,7 +719,7 @@ impl 虚线 { // ---- MACD柱子分段 ---- /// 计算MACD柱子分段 — 按正负号将MACD柱子分段 - pub fn 计算MACD柱子分段(k线序列: &[Rc]) -> Vec> { + pub fn 计算MACD柱子分段(k线序列: &[Arc]) -> Vec> { if k线序列.is_empty() { return Vec::new(); } @@ -729,7 +802,7 @@ impl 虚线 { /// 统计MACD行为 — 分析DIF/DEA穿零轴和金叉死叉 pub fn 统计MACD行为( - 普K序列: &[Rc], + 普K序列: &[Arc], 最大间隔: usize, 最少交叉数: usize, ) -> MACD行为统计 { @@ -820,34 +893,39 @@ impl 虚线 { let 普K序列 = &观察员.普通K线序列; let 配置 = &观察员.配置; - if 实线.标识 != "笔" && 实线.标识 != "线段" && !实线.标识.starts_with("线段<") + if *实线.标识.read().unwrap() != "笔" + && *实线.标识.read().unwrap() != "线段" + && !实线.标识.read().unwrap().starts_with("线段<") { return (false, "标识不在范围内".into()); } // KDJ指标完整性检查 - match &实线.武.中.标的K线.kdj { + let 武_ref = 实线.武.read().unwrap(); + let 标 = 武_ref.中.标的K线.read().unwrap(); + match 标.kdj.as_ref() { Some(kdj) if kdj.K.is_some() && kdj.D.is_some() && kdj.J.is_some() => {} _ => return (false, "KDJ指标不完整".into()), } - let 意义 = Self::缠K买卖点模式(&配置.买卖点_指标模式, &实线.武.中, 配置); + let 意义 = + Self::缠K买卖点模式(&配置.买卖点_指标模式, &实线.武.read().unwrap().中, 配置); let 结果 = false; - let 背驰过: Vec> = if 实线.标识 == "笔" { + let 背驰过: Vec> = if *实线.标识.read().unwrap() == "笔" { crate::algorithm::bi::笔::是否背驰过(实线, 观察员) } else { crate::algorithm::segment::线段::是否背驰过(实线, 观察员) }; if 意义 { - if 实线.标识 == "笔" { + if *实线.标识.read().unwrap() == "笔" { if Self::武之MACD均值(普K序列, 实线) { return (true, "武之MACD均值".into()); } if Self::武之MACD极值(普K序列, 实线) && !背驰过.is_empty() { return (true, "背驰过且极值".into()); - } else if 实线.武.与MACD柱子分型匹配() { + } else if 实线.武.read().unwrap().与MACD柱子分型匹配() { return ( true, format!( @@ -862,14 +940,14 @@ impl 虚线 { ); } } - if 实线.标识 != "笔" + if *实线.标识.read().unwrap() != "笔" && crate::algorithm::segment::线段::判断线段内部是否背驰(实线, 观察员) { return (true, "线段内部背驰".into()); } } - if !结果 && 意义 && 实线.武.中.与MACD柱子匹配() { + if !结果 && 意义 && 实线.武.read().unwrap().中.与MACD柱子匹配() { if Self::武之MACD极值(普K序列, 实线) && 背驰过.len() > 2 { return (true, "没结果, 极值, 柱子分型匹配, 背驰过大于2次".into()); } @@ -879,18 +957,300 @@ impl 虚线 { } } +#[cfg(test)] +mod tests { + use super::*; + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + use crate::types::分型结构; + + /// 辅助:创建一根最小化的原始K线 + fn 辅助_创建K线(时间戳: i64, 高: f64, 低: f64, 开: f64, 收: f64) -> K线 { + let mut k = K线::default(); + k.时间戳 = 时间戳; + k.高 = 高; + k.低 = 低; + k.开盘价 = 开; + k.收盘价 = 收; + k + } + + /// 辅助:创建一根缠论K线 + fn 辅助_创建缠K( + 时间戳: i64, + 高: f64, + 低: f64, + 方向: 相对方向, + 结构: Option<分型结构>, + 序号: i64, + ) -> Arc<缠论K线> { + let 普K = Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)); + let 缠K = 缠论K线::创建缠K(时间戳, 高, 低, 方向, 结构, 序号, 普K, None); + Arc::new(缠K) + } + + /// 辅助:创建顶分型 + fn 辅助_创建顶分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 - 2.0, + 低 - 2.0, + 相对方向::向上, + Some(分型结构::上), + 序号 - 2, + ); + let 中 = 辅助_创建缠K(时间戳, 高, 低, 相对方向::向上, Some(分型结构::顶), 序号); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 - 1.0, + 低 - 1.0, + 相对方向::向下, + Some(分型结构::下), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + /// 辅助:创建底分型 + fn 辅助_创建底分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 + 2.0, + 低 + 2.0, + 相对方向::向下, + Some(分型结构::下), + 序号 - 2, + ); + let 中 = 缠论K线::创建缠K( + 时间戳, + 高, + 低, + 相对方向::向下, + Some(分型结构::底), + 序号, + Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)), + None, + ); + 中.分型特征值.set(低); + let 中 = Arc::new(中); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 + 1.0, + 低 + 1.0, + 相对方向::向上, + Some(分型结构::上), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + // ============================================================ + // Cell 字段读写测试 + // ============================================================ + + #[test] + fn test_Cell字段读写一致性() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔 = 虚线::创建笔(顶, 底, true); + + assert_eq!(笔.序号.load(Ordering::Relaxed), 0); + assert!(笔.有效性.load(Ordering::Relaxed)); + assert!(!笔.短路修正.load(Ordering::Relaxed)); + assert!(笔.前一缺口.read().unwrap().is_none()); + + // 修改 Cell 字段 + 笔.序号.store(42, Ordering::Relaxed); + 笔.有效性.store(false, Ordering::Relaxed); + 笔.短路修正.store(true, Ordering::Relaxed); + *笔.前一缺口.write().unwrap() = Some(缺口::new(200.0, 100.0)); + + assert_eq!(笔.序号.load(Ordering::Relaxed), 42); + assert!(!笔.有效性.load(Ordering::Relaxed)); + assert!(笔.短路修正.load(Ordering::Relaxed)); + let qk = 笔.前一缺口.read().unwrap().unwrap(); + assert!((qk.高 - 200.0).abs() < 0.01); + assert!((qk.低 - 100.0).abs() < 0.01); + } + + // ============================================================ + // RefCell 字段读写测试 + // ============================================================ + + #[test] + fn test_RefCell字段读写一致性() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔 = 虚线::创建笔(顶, 底, true); + + // 标识 + assert_eq!(*笔.标识.read().unwrap(), "笔"); + *笔.标识.write().unwrap() = "测试标识".into(); + assert_eq!(*笔.标识.read().unwrap(), "测试标识"); + + // 模式 + assert_eq!(*笔.模式.read().unwrap(), "文武"); + *笔.模式.write().unwrap() = "全量".into(); + assert_eq!(*笔.模式.read().unwrap(), "全量"); + + // 基础序列 + assert!(笔.基础序列.read().unwrap().is_empty()); + let 另一底 = 辅助_创建底分型(300, 20.0, 10.0, 15); + let 笔2 = 虚线::创建笔(Arc::clone(&*笔.武.read().unwrap()), 另一底, true); + 笔.基础序列.write().unwrap().push(Arc::new(笔2)); + assert_eq!(笔.基础序列.read().unwrap().len(), 1); + + // 武 - Replace with new 分型 + let 新底 = 辅助_创建底分型(400, 15.0, 5.0, 20); + let 新底_ptr = Arc::as_ptr(&新底); + *笔.武.write().unwrap() = Arc::clone(&新底); + assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), 新底_ptr); + } + + // ============================================================ + // Clone 后 Rc 指针身份一致 + // ============================================================ + + #[test] + fn test_虚线Clone后文Rc指针一致() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底), true); + + let 克隆笔 = 笔.clone(); + + // 文 Rc 指针应一致 + assert_eq!(Arc::as_ptr(&笔.文), Arc::as_ptr(&顶)); + assert_eq!(Arc::as_ptr(&克隆笔.文), Arc::as_ptr(&笔.文)); + + // 武 Rc 指针应一致 + assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), Arc::as_ptr(&底)); + assert_eq!( + Arc::as_ptr(&*克隆笔.武.read().unwrap()), + Arc::as_ptr(&*笔.武.read().unwrap()) + ); + } + + #[test] + fn test_虚线Clone是深拷贝Cell值而非共享() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔 = 虚线::创建笔(顶, 底, true); + 笔.序号.store(10, Ordering::Relaxed); + + let 克隆笔 = 笔.clone(); + // Clone 后序号应独立(deep copy for Cell) + 克隆笔.序号.store(99, Ordering::Relaxed); + assert_eq!(笔.序号.load(Ordering::Relaxed), 10); + assert_eq!(克隆笔.序号.load(Ordering::Relaxed), 99); + + // Rc 指针仍应一致(文/武 共享) + assert_eq!(Arc::as_ptr(&笔.文), Arc::as_ptr(&克隆笔.文)); + } + + // ============================================================ + // 多 Rc 共享下 Cell/RefCell 修改可见性 + // ============================================================ + + #[test] + fn test_多Rc共享下Cell修改对所有引用可见() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔_rc1 = Arc::new(虚线::创建笔(顶, 底, true)); + let 笔_rc2 = Arc::clone(&笔_rc1); + + // 通过 rc1 修改 Cell + 笔_rc1.序号.store(77, Ordering::Relaxed); + // rc2 应能看到 + assert_eq!(笔_rc2.序号.load(Ordering::Relaxed), 77); + + // 通过 rc1 修改 RefCell + *笔_rc1.模式.write().unwrap() = "配置".into(); + assert_eq!(*笔_rc2.模式.read().unwrap(), "配置"); + + // 通过 rc1 修改 武 + let 新底 = 辅助_创建底分型(400, 15.0, 5.0, 20); + let 新底_ptr = Arc::as_ptr(&新底); + *笔_rc1.武.write().unwrap() = Arc::clone(&新底); + assert_eq!(Arc::as_ptr(&*笔_rc2.武.read().unwrap()), 新底_ptr); + } + + // ============================================================ + // 获取_武 递归正确性 + // ============================================================ + + #[test] + fn test_获取武_笔级别直接返回武() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底), true); + + let wu = 笔.获取_武(); + assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), Arc::as_ptr(&wu)); + assert_eq!(Arc::as_ptr(&wu), Arc::as_ptr(&底)); + } + + #[test] + fn test_获取武_线段级别递归到底层笔() { + let 顶1 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底1 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 顶2 = 辅助_创建顶分型(300, 55.0, 45.0, 15); + let 底2 = 辅助_创建底分型(400, 25.0, 15.0, 20); + + let 笔1 = Arc::new(虚线::创建笔(Arc::clone(&顶1), Arc::clone(&底1), true)); + let 笔2 = Arc::new(虚线::创建笔(Arc::clone(&底1), Arc::clone(&顶2), true)); + let 笔3 = Arc::new(虚线::创建笔(Arc::clone(&顶2), Arc::clone(&底2), true)); + + let 段 = 虚线::创建线段(&[Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)]); + + // 线段的 获取_武 应返回底层最后一笔的武(底2) + let wu = 段.获取_武(); + assert_eq!(Arc::as_ptr(&wu), Arc::as_ptr(&底2)); + + // 笔1 的 获取_武 应返回底1 + let wu1 = 笔1.获取_武(); + assert_eq!(Arc::as_ptr(&wu1), Arc::as_ptr(&底1)); + } + + // ============================================================ + // 虚线 字段原子性 - 修改不影响文(不可变字段) + // ============================================================ + + #[test] + fn test_修改武不影响文Rc指针() { + let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5); + let 底1 = 辅助_创建底分型(200, 30.0, 20.0, 10); + let 底2 = 辅助_创建底分型(300, 25.0, 15.0, 15); + + let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底1), true); + let 文_ptr_before = Arc::as_ptr(&笔.文); + + // 修改武 + *笔.武.write().unwrap() = Arc::clone(&底2); + + // 文指针不变 + assert_eq!(Arc::as_ptr(&笔.文), 文_ptr_before); + + // 但方向变了(因为武从底1变成底2) + let 新武耗时 = 笔.武.read().unwrap().时间戳; + assert_eq!(新武耗时, 300); + } +} + impl std::fmt::Display for 虚线 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.标识 == "笔" { + if *self.标识.read().unwrap() == "笔" { write!( f, "笔({}, {}, {}, {}, 周期: {}, 数量: {})", - self.序号, + self.序号.load(Ordering::Relaxed), self.方向(), self.文, - self.武, + self.武.read().unwrap(), self.文.中.周期, - self.武.中.序号 - self.文.中.序号 + 1 + self.武.read().unwrap().中.序号.load(Ordering::Relaxed) + - self.文.中.序号.load(Ordering::Relaxed) + + 1 ) } else { let 四象 = crate::algorithm::segment::线段::四象(self); @@ -899,20 +1259,20 @@ impl std::fmt::Display for 虚线 { Some(g) => format!("{}", g), None => "None".to_string(), }; - let 确认K线_str = match &self.确认K线 { + let 确认K线_str = match &*self.确认K线.read().unwrap() { Some(k) => format!("{}", k), None => "None".to_string(), }; write!( f, "{}<{}, {}, {}, {}, {}, 数量: {}, 缺口: {}, {}>", - self.标识, - self.序号, + self.标识.read().unwrap(), + self.序号.load(Ordering::Relaxed), 四象, self.方向(), self.文, - self.武, - self.基础序列.len(), + self.武.read().unwrap(), + self.基础序列.read().unwrap().len(), 缺口_str, 确认K线_str, ) diff --git a/chanlun/src/structure/feat_fractal.rs b/chanlun/src/structure/feat_fractal.rs index 6a65634..f25949f 100644 --- a/chanlun/src/structure/feat_fractal.rs +++ b/chanlun/src/structure/feat_fractal.rs @@ -24,20 +24,20 @@ use crate::structure::segment_feat::线段特征; use crate::types::分型结构; -use std::rc::Rc; +use std::sync::Arc; /// 特征分型 — 由三个线段特征元素构成的分型 #[derive(Debug, Clone)] pub struct 特征分型 { - pub 左: Rc<线段特征>, - pub 中: Rc<线段特征>, - pub 右: Rc<线段特征>, + pub 左: Arc<线段特征>, + pub 中: Arc<线段特征>, + pub 右: Arc<线段特征>, pub 结构: 分型结构, } impl 特征分型 { pub fn new( - 左: Rc<线段特征>, 中: Rc<线段特征>, 右: Rc<线段特征>, 结构: 分型结构 + 左: Arc<线段特征>, 中: Arc<线段特征>, 右: Arc<线段特征>, 结构: 分型结构 ) -> Self { Self { 左, 中, 右, 结构 diff --git a/chanlun/src/structure/fractal_obj.rs b/chanlun/src/structure/fractal_obj.rs index a6a1783..d8774a6 100644 --- a/chanlun/src/structure/fractal_obj.rs +++ b/chanlun/src/structure/fractal_obj.rs @@ -25,14 +25,15 @@ use crate::kline::chan_kline::缠论K线; use crate::types::分型结构; use crate::types::相对方向; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; /// 分型 — 由三根缠K构成(可能缺左或右) #[derive(Debug, Clone)] pub struct 分型 { - pub 左: Option>, - pub 中: Rc<缠论K线>, - pub 右: Option>, + pub 左: Option>, + pub 中: Arc<缠论K线>, + pub 右: Option>, pub 结构: 分型结构, pub 时间戳: i64, pub 分型特征值: f64, @@ -40,11 +41,11 @@ pub struct 分型 { impl 分型 { pub fn new( - 左: Option>, 中: Rc<缠论K线>, 右: Option> + 左: Option>, 中: Arc<缠论K线>, 右: Option> ) -> Self { - let 结构 = 中.分型.unwrap_or(分型结构::散); - let 时间戳 = 中.时间戳; - let 分型特征值 = 中.分型特征值; + let 结构 = 中.分型.read().unwrap().unwrap_or(分型结构::散); + let 时间戳 = 中.时间戳.load(Ordering::Relaxed); + let 分型特征值 = 中.分型特征值.get(); Self { 左, 中, @@ -60,9 +61,9 @@ impl 分型 { let 左 = self.左.as_ref()?; let 右 = self.右.as_ref()?; Some(( - 相对方向::分析(左.高, 左.低, self.中.高, self.中.低), - 相对方向::分析(self.中.高, self.中.低, 右.高, 右.低), - 相对方向::分析(左.高, 左.低, 右.高, 右.低), + 相对方向::分析(左.高.get(), 左.低.get(), self.中.高.get(), self.中.低.get()), + 相对方向::分析(self.中.高.get(), self.中.低.get(), 右.高.get(), 右.低.get()), + 相对方向::分析(左.高.get(), 左.低.get(), 右.高.get(), 右.低.get()), )) } @@ -97,17 +98,19 @@ impl 分型 { if let (Some(ref 左), Some(ref 右)) = (&self.左, &self.右) { if self.结构 == 分型结构::底 { - if 右.标的K线.收盘价 > 左.标的K线.高 { + if 右.标的K线.read().unwrap().收盘价 > 左.标的K线.read().unwrap().高 { return "强"; - } else if 右.标的K线.收盘价 > self.中.标的K线.高 { + } else if 右.标的K线.read().unwrap().收盘价 > self.中.标的K线.read().unwrap().高 + { return "中"; } else { return "弱"; } } else if self.结构 == 分型结构::顶 { - if 右.标的K线.收盘价 < 左.标的K线.低 { + if 右.标的K线.read().unwrap().收盘价 < 左.标的K线.read().unwrap().低 { return "强"; - } else if 右.标的K线.收盘价 < self.中.标的K线.低 { + } else if 右.标的K线.read().unwrap().收盘价 < self.中.标的K线.read().unwrap().低 + { return "中"; } else { return "弱"; @@ -121,15 +124,21 @@ impl 分型 { pub fn 与MACD柱子分型匹配(&self) -> bool { if let (Some(ref 左), Some(ref 右)) = (&self.左, &self.右) { if self.结构 == 分型结构::底 { + let 左_k = 左.标的K线.read().unwrap(); + let 中_k = self.中.标的K线.read().unwrap(); + let 右_k = 右.标的K线.read().unwrap(); if let (Some(ref 左macd), Some(ref 中macd), Some(ref 右macd)) = - (&左.标的K线.macd, &self.中.标的K线.macd, &右.标的K线.macd) + (&左_k.macd, &中_k.macd, &右_k.macd) { return 左macd.MACD柱 > 中macd.MACD柱 && 中macd.MACD柱 < 右macd.MACD柱; } } if self.结构 == 分型结构::顶 { + let 左_k = 左.标的K线.read().unwrap(); + let 中_k = self.中.标的K线.read().unwrap(); + let 右_k = 右.标的K线.read().unwrap(); if let (Some(ref 左macd), Some(ref 中macd), Some(ref 右macd)) = - (&左.标的K线.macd, &self.中.标的K线.macd, &右.标的K线.macd) + (&左_k.macd, &中_k.macd, &右_k.macd) { return 左macd.MACD柱 < 中macd.MACD柱 && 中macd.MACD柱 > 右macd.MACD柱; } @@ -139,35 +148,36 @@ impl 分型 { } /// 判断两个分型是否匹配 - pub fn 判断分型(左: &Rc<分型>, 右: &Rc<分型>, 模式: &str) -> bool { + pub fn 判断分型(左: &Arc<分型>, 右: &Arc<分型>, 模式: &str) -> bool { match 模式 { - "中" => Rc::as_ptr(左) == Rc::as_ptr(右), + "中" => Arc::as_ptr(左) == Arc::as_ptr(右), _ => false, } } /// 从缠K序列中获取以指定缠K为中元素的分型 pub fn 从缠K序列中获取分型( - K线序列: &[Rc<缠论K线>], 中: &Rc<缠论K线> + K线序列: &[Arc<缠论K线>], + 中: &Arc<缠论K线>, ) -> Option { let idx = K线序列 .iter() - .position(|k| Rc::as_ptr(k) == Rc::as_ptr(中))?; + .position(|k| Arc::as_ptr(k) == Arc::as_ptr(中))?; let 左 = if idx > 0 { - Some(Rc::clone(&K线序列[idx - 1])) + Some(Arc::clone(&K线序列[idx - 1])) } else { None }; let 右 = if idx + 1 < K线序列.len() { - Some(Rc::clone(&K线序列[idx + 1])) + Some(Arc::clone(&K线序列[idx + 1])) } else { None }; - Some(Self::new(左, Rc::clone(中), 右)) + Some(Self::new(左, Arc::clone(中), 右)) } /// 向分型序列中添加新分型 - pub fn 向序列中添加(分型序列: &mut Vec>, 当前分型: Rc<分型>) { + pub fn 向序列中添加(分型序列: &mut Vec>, 当前分型: Arc<分型>) { if 分型序列.is_empty() { if 当前分型.结构 != 分型结构::顶 && 当前分型.结构 != 分型结构::底 { @@ -188,10 +198,10 @@ impl 分型 { impl crate::types::fractal::有高低 for 分型 { fn 高(&self) -> f64 { - self.中.高 + self.中.高.get() } fn 低(&self) -> f64 { - self.中.低 + self.中.低.get() } } @@ -200,7 +210,11 @@ impl std::fmt::Display for 分型 { write!( f, "{}<{}, {}, None: {}, None: {}>", - self.中.分型.unwrap_or(crate::types::分型结构::散), + self.中 + .分型 + .read() + .unwrap() + .unwrap_or(crate::types::分型结构::散), self.时间戳, crate::utils::format_f64_g(self.分型特征值), if self.左.is_none() { "True" } else { "False" }, diff --git a/chanlun/src/structure/segment_feat.rs b/chanlun/src/structure/segment_feat.rs index 325ef87..2edcc9b 100644 --- a/chanlun/src/structure/segment_feat.rs +++ b/chanlun/src/structure/segment_feat.rs @@ -26,7 +26,8 @@ use crate::structure::dash_line::虚线; use crate::structure::feat_fractal::特征分型; use crate::structure::fractal_obj::分型; use crate::types::{分型结构, 相对方向}; -use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; /// 线段特征 — 特征序列元素(内部是虚线的集合) #[derive(Debug, Clone)] @@ -34,11 +35,11 @@ pub struct 线段特征 { pub 序号: i64, pub 标识: String, pub 线段方向: 相对方向, - pub 元素: Vec>, + pub 元素: Vec>, } impl 线段特征 { - pub fn new(标识: String, 基础序列: Vec>, 线段方向: 相对方向) -> Self { + pub fn new(标识: String, 基础序列: Vec>, 线段方向: 相对方向) -> Self { Self { 序号: 0, 标识, @@ -53,7 +54,7 @@ impl 线段特征 { /// 文 — 取特征序列元素中分型特征值最大/最小的文分型 /// tiebreaker: later时间戳 wins when特征值 equal (matches Python) - pub fn 文(&self) -> Rc<分型> { + pub fn 文(&self) -> Arc<分型> { if self.线段方向.是否向上() { self.元素 .iter() @@ -64,8 +65,8 @@ impl 线段特征 { .unwrap_or(std::cmp::Ordering::Equal) .then_with(|| a.文.时间戳.cmp(&b.文.时间戳)) }) - .map(|x| Rc::clone(&x.文)) - .unwrap_or_else(|| Rc::clone(&self.元素[0].文)) + .map(|x| Arc::clone(&x.文)) + .unwrap_or_else(|| Arc::clone(&self.元素[0].文)) } else { self.元素 .iter() @@ -76,38 +77,54 @@ impl 线段特征 { .unwrap_or(std::cmp::Ordering::Equal) .then_with(|| b.文.时间戳.cmp(&a.文.时间戳)) }) - .map(|x| Rc::clone(&x.文)) - .unwrap_or_else(|| Rc::clone(&self.元素[0].文)) + .map(|x| Arc::clone(&x.文)) + .unwrap_or_else(|| Arc::clone(&self.元素[0].文)) } } /// 武 — 取特征序列元素中分型特征值最大/最小的武分型 /// tiebreaker: later时间戳 wins when特征值 equal (matches Python) - pub fn 武(&self) -> Rc<分型> { + pub fn 武(&self) -> Arc<分型> { if self.线段方向.是否向上() { self.元素 .iter() .max_by(|a, b| { a.武 + .read() + .unwrap() .分型特征值 - .partial_cmp(&b.武.分型特征值) + .partial_cmp(&b.武.read().unwrap().分型特征值) .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| a.武.时间戳.cmp(&b.武.时间戳)) + .then_with(|| { + a.武 + .read() + .unwrap() + .时间戳 + .cmp(&b.武.read().unwrap().时间戳) + }) }) - .map(|x| Rc::clone(&x.武)) - .unwrap_or_else(|| Rc::clone(&self.元素[0].武)) + .map(|x| x.武.read().unwrap().clone()) + .unwrap_or_else(|| self.元素[0].武.read().unwrap().clone()) } else { self.元素 .iter() .min_by(|a, b| { a.武 + .read() + .unwrap() .分型特征值 - .partial_cmp(&b.武.分型特征值) + .partial_cmp(&b.武.read().unwrap().分型特征值) .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| b.武.时间戳.cmp(&a.武.时间戳)) + .then_with(|| { + b.武 + .read() + .unwrap() + .时间戳 + .cmp(&a.武.read().unwrap().时间戳) + }) }) - .map(|x| Rc::clone(&x.武)) - .unwrap_or_else(|| Rc::clone(&self.元素[0].武)) + .map(|x| x.武.read().unwrap().clone()) + .unwrap_or_else(|| self.元素[0].武.read().unwrap().clone()) } } @@ -129,7 +146,7 @@ impl 线段特征 { } /// 向特征序列元素中添加虚线 - pub fn 添加(&mut self, 待添加虚线: Rc<虚线>) -> Result<(), String> { + pub fn 添加(&mut self, 待添加虚线: Arc<虚线>) -> Result<(), String> { if 待添加虚线.方向() == self.线段方向 { return Err("添加方向与线段方向相同".into()); } @@ -138,14 +155,14 @@ impl 线段特征 { } /// 从特征序列元素中删除虚线 - pub fn 删除(&mut self, 待删除虚线: &Rc<虚线>) -> Result<(), String> { + pub fn 删除(&mut self, 待删除虚线: &Arc<虚线>) -> Result<(), String> { if 待删除虚线.方向() == self.方向() { return Err("删除方向与特征序列方向相同".into()); } if let Some(pos) = self .元素 .iter() - .position(|x| Rc::as_ptr(x) == Rc::as_ptr(待删除虚线)) + .position(|x| Arc::as_ptr(x) == Arc::as_ptr(待删除虚线)) { self.元素.remove(pos); Ok(()) @@ -155,19 +172,19 @@ impl 线段特征 { } /// 新建特征序列元素 - pub fn 新建(虚线序列: Vec>, 线段方向: 相对方向) -> Self { + pub fn 新建(虚线序列: Vec>, 线段方向: 相对方向) -> Self { let 标识 = format!("特征<虚线>"); Self::new(标识, 虚线序列, 线段方向) } /// 静态分析 — 从虚线序列生成特征序列元素列表 pub fn 静态分析( - 虚线序列: &[Rc<虚线>], + 虚线序列: &[Arc<虚线>], 线段方向: 相对方向, 四象: &str, 是否忽视: bool, - ) -> Vec> { - let mut 结果: Vec> = Vec::new(); + ) -> Vec> { + let mut 结果: Vec> = Vec::new(); // 需要被合并的方向集合 let 需要合并: Vec<相对方向> = match 四象 { @@ -179,9 +196,9 @@ impl 线段特征 { // 情况1:方向相同(可能触发分型替换) if 虚线.方向() == 线段方向 { if 结果.len() >= 3 { - let 左 = Rc::clone(&结果[结果.len() - 3]); - let 中 = Rc::clone(&结果[结果.len() - 2]); - let 右 = Rc::clone(&结果[结果.len() - 1]); + let 左 = Arc::clone(&结果[结果.len() - 3]); + let 中 = Arc::clone(&结果[结果.len() - 2]); + let 右 = Arc::clone(&结果[结果.len() - 1]); if let Some(结构) = 分型结构::分析(&*左, &*中, &*右, true, true) { let 应替换 = (线段方向 == 相对方向::向上 @@ -192,16 +209,24 @@ impl 线段特征 { && 虚线.低() < 中.低()); if 应替换 { - let 小号虚线 = 中.元素.iter().min_by_key(|o| o.序号).unwrap(); - let 大号虚线 = 右.元素.iter().max_by_key(|o| o.序号).unwrap(); + let 小号虚线 = 中 + .元素 + .iter() + .min_by_key(|o| o.序号.load(Ordering::Relaxed)) + .unwrap(); + let 大号虚线 = 右 + .元素 + .iter() + .max_by_key(|o| o.序号.load(Ordering::Relaxed)) + .unwrap(); let fake = 虚线::创建笔( - Rc::clone(&小号虚线.文), - Rc::clone(&大号虚线.武), + Arc::clone(&小号虚线.文), + 大号虚线.武.read().unwrap().clone(), false, ); 结果.pop(); let idx = 结果.len() - 1; - 结果[idx] = Rc::new(Self::新建(vec![Rc::new(fake)], 线段方向)); + 结果[idx] = Arc::new(Self::新建(vec![Arc::new(fake)], 线段方向)); } } } @@ -210,7 +235,7 @@ impl 线段特征 { // 情况2:方向不同(执行特征序列的合并/添加) if 结果.is_empty() { - 结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向))); + 结果.push(Arc::new(Self::新建(vec![Arc::clone(虚线)], 线段方向))); continue; } @@ -225,10 +250,10 @@ impl 线段特征 { )) { // Clone-modify-replace let mut 新特征 = (*结果[最后_idx]).clone(); - let _ = 新特征.添加(Rc::clone(虚线)); - 结果[最后_idx] = Rc::new(新特征); + let _ = 新特征.添加(Arc::clone(虚线)); + 结果[最后_idx] = Arc::new(新特征); } else { - 结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向))); + 结果.push(Arc::new(Self::新建(vec![Arc::clone(虚线)], 线段方向))); } } @@ -236,15 +261,15 @@ impl 线段特征 { } /// 获取分型序列 - pub fn 获取分型序列(特征序列: &[Rc<线段特征>]) -> Vec<特征分型> { + pub fn 获取分型序列(特征序列: &[Arc<线段特征>]) -> Vec<特征分型> { let mut 结果 = Vec::new(); if 特征序列.len() < 3 { return 结果; } for i in 2..特征序列.len() { - let 左 = Rc::clone(&特征序列[i - 2]); - let 中 = Rc::clone(&特征序列[i - 1]); - let 右 = Rc::clone(&特征序列[i]); + let 左 = Arc::clone(&特征序列[i - 2]); + let 中 = Arc::clone(&特征序列[i - 1]); + let 右 = Arc::clone(&特征序列[i]); let 结构 = 分型结构::分析_对象( &*左 as &dyn crate::types::fractal::有高低, @@ -285,3 +310,273 @@ impl std::fmt::Display for 线段特征 { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::kline::bar::K线; + use crate::kline::chan_kline::缠论K线; + use crate::structure::fractal_obj::分型; + use crate::types::分型结构; + + fn 辅助_创建K线(时间戳: i64, 高: f64, 低: f64, 开: f64, 收: f64) -> K线 { + let mut k = K线::default(); + k.时间戳 = 时间戳; + k.高 = 高; + k.低 = 低; + k.开盘价 = 开; + k.收盘价 = 收; + k + } + + fn 辅助_创建缠K( + 时间戳: i64, + 高: f64, + 低: f64, + 方向: 相对方向, + 结构: Option<分型结构>, + 序号: i64, + ) -> Arc<缠论K线> { + let 普K = Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)); + Arc::new(缠论K线::创建缠K( + 时间戳, 高, 低, 方向, 结构, 序号, 普K, None, + )) + } + + fn 辅助_创建顶分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 - 2.0, + 低 - 2.0, + 相对方向::向上, + Some(分型结构::上), + 序号 - 2, + ); + let 中 = 辅助_创建缠K(时间戳, 高, 低, 相对方向::向上, Some(分型结构::顶), 序号); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 - 1.0, + 低 - 1.0, + 相对方向::向下, + Some(分型结构::下), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + fn 辅助_创建底分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> { + let 左 = 辅助_创建缠K( + 时间戳 - 2, + 高 + 2.0, + 低 + 2.0, + 相对方向::向下, + Some(分型结构::下), + 序号 - 2, + ); + let 中 = 缠论K线::创建缠K( + 时间戳, + 高, + 低, + 相对方向::向下, + Some(分型结构::底), + 序号, + Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)), + None, + ); + 中.分型特征值.set(低); + let 中 = Arc::new(中); + let 右 = 辅助_创建缠K( + 时间戳 + 2, + 高 + 1.0, + 低 + 1.0, + 相对方向::向上, + Some(分型结构::上), + 序号 + 2, + ); + Arc::new(分型::new(Some(左), 中, Some(右))) + } + + fn 辅助_创建笔( + 文时间戳: i64, + 文高: f64, + 文低: f64, + 武时间戳: i64, + 武高: f64, + 武低: f64, + ) -> Arc<虚线> { + let 顶 = 辅助_创建顶分型(文时间戳, 文高, 文低, 1); + let 底 = 辅助_创建底分型(武时间戳, 武高, 武低, 2); + Arc::new(虚线::创建笔(顶, 底, true)) + } + + // ============================================================ + // 文 — 取特征值最大/最小的分型 + // 特征序列元素方向与线段方向相反: + // 向上线段 → 元素为向下笔(顶→底) → 文=顶分型 → 取max + // 向下线段 → 元素为向上笔(底→顶) → 文=底分型 → 取min + // ============================================================ + + #[test] + fn test_文_向上线段取最大特征值分型() { + // 向上线段,元素用向下笔(顶→底),文=顶分型 + // 笔1: 顶(特征值=100)→底(80), 文=顶(100) + let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0); + // 笔2: 顶(特征值=110)→底(90), 文=顶(110) + let 笔2 = 辅助_创建笔(200, 110.0, 100.0, 300, 90.0, 80.0); + + let feat = 线段特征::new( + "测试".into(), + vec![Arc::clone(&笔1), Arc::clone(&笔2)], + 相对方向::向上, + ); + + // 向上取max → 笔2.文=110 + let 文 = feat.文(); + assert!((文.分型特征值 - 110.0).abs() < 0.01); + } + + #[test] + fn test_文_向下线段取最小特征值分型() { + // 向下线段,元素用向上笔(底→顶),文=底分型 + // 笔1: 底(特征值=80)→顶(100), 文=底(80) + let 底1 = 辅助_创建底分型(100, 90.0, 80.0, 5); + let 顶1 = 辅助_创建顶分型(200, 100.0, 90.0, 10); + let 笔1 = Arc::new(虚线::创建笔(底1, 顶1, true)); + + // 笔2: 底(特征值=70)→顶(95), 文=底(70) + let 底2 = 辅助_创建底分型(200, 80.0, 70.0, 15); + let 顶2 = 辅助_创建顶分型(300, 95.0, 85.0, 20); + let 笔2 = Arc::new(虚线::创建笔(底2, 顶2, true)); + + let feat = 线段特征::new( + "测试".into(), + vec![Arc::clone(&笔1), Arc::clone(&笔2)], + 相对方向::向下, + ); + + // 向下取min → 笔2.文=70 + let 文 = feat.文(); + assert!((文.分型特征值 - 70.0).abs() < 0.01); + } + + // ============================================================ + // 武 — 取特征值最大/最小的分型 + // 向上线段 → 元素为向下笔 → 武=底分型 → 取max + // 向下线段 → 元素为向上笔 → 武=顶分型 → 取min + // ============================================================ + + #[test] + fn test_武_向上线段取最大特征值分型() { + // 向上线段,元素用向下笔(顶→底),武=底分型 + // 笔1: 顶(100)→底(特征值=80), 武=底(80) + let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0); + // 笔2: 顶(110)→底(特征值=90), 武=底(90) + let 笔2 = 辅助_创建笔(200, 110.0, 100.0, 300, 100.0, 90.0); + + let feat = 线段特征::new( + "测试".into(), + vec![Arc::clone(&笔1), Arc::clone(&笔2)], + 相对方向::向上, + ); + + // 向上取max → 笔2.武=90 + let 武 = feat.武(); + assert!((武.分型特征值 - 90.0).abs() < 0.01); + } + + #[test] + fn test_武_向下线段取最小特征值分型() { + // 向下线段,元素用向上笔(底→顶),武=顶分型 + // 笔1: 底(80)→顶(特征值=100), 武=顶(100) + let 底1 = 辅助_创建底分型(100, 90.0, 80.0, 5); + let 顶1 = 辅助_创建顶分型(200, 100.0, 90.0, 10); + let 笔1 = Arc::new(虚线::创建笔(底1, 顶1, true)); + + // 笔2: 底(60)→顶(特征值=85), 武=顶(85) + let 底2 = 辅助_创建底分型(200, 70.0, 60.0, 15); + let 顶2 = 辅助_创建顶分型(300, 85.0, 75.0, 20); + let 笔2 = Arc::new(虚线::创建笔(底2, 顶2, true)); + + let feat = 线段特征::new( + "测试".into(), + vec![Arc::clone(&笔1), Arc::clone(&笔2)], + 相对方向::向下, + ); + + // 向下取min → 笔2.武=85 + let 武 = feat.武(); + assert!((武.分型特征值 - 85.0).abs() < 0.01); + } + + // ============================================================ + // 文/武 tiebreaker — 同特征值取后时间戳 + // ============================================================ + + #[test] + fn test_文_同特征值取后时间戳() { + // 两个笔的文特征值相同=100,但时间戳不同 + let 顶1 = 辅助_创建顶分型(100, 100.0, 90.0, 5); + let 底1 = 辅助_创建底分型(200, 90.0, 80.0, 10); + let 笔1 = Arc::new(虚线::创建笔(顶1, 底1, true)); + + let 顶2 = 辅助_创建顶分型(300, 100.0, 90.0, 15); // 同特征值,后时间戳 + let 底2 = 辅助_创建底分型(400, 80.0, 70.0, 20); + let 笔2 = Arc::new(虚线::创建笔(顶2, 底2, true)); + + let feat = 线段特征::new("测试".into(), vec![笔1, 笔2], 相对方向::向上); + + let 文 = feat.文(); + // 向上取最大特征值:都是100 → tiebreaker取后时间戳 → 笔2.文(300) + assert_eq!(文.时间戳, 300); + } + + #[test] + fn test_武_同特征值取后时间戳_向上() { + let 顶1 = 辅助_创建顶分型(100, 100.0, 90.0, 5); + let 底1 = 辅助_创建底分型(200, 80.0, 70.0, 10); // 特征值80 + let 笔1 = Arc::new(虚线::创建笔(顶1, 底1, true)); + + let 顶2 = 辅助_创建顶分型(300, 80.0, 70.0, 15); // 特征值80 + let 底2 = 辅助_创建底分型(400, 80.0, 70.0, 20); // 特征值80 + let 笔2 = Arc::new(虚线::创建笔(顶2, 底2, true)); + + let feat = 线段特征::new("测试".into(), vec![笔1, 笔2], 相对方向::向上); + + let 武 = feat.武(); + // 向上取最大特征值:都是80 → tiebreaker取后时间戳 → 笔2.武(400) + assert_eq!(武.时间戳, 400); + } + + // ============================================================ + // 添加/删除 操作 + // ============================================================ + + #[test] + fn test_添加方向与线段方向相反的虚线可成功() { + // 向下笔(顶→底,方向=向下) 添加到 向上线段(方向=向上) → 方向不同, 可添加 + let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0); + let mut feat = 线段特征::new("测试".into(), vec![], 相对方向::向上); + + let result = feat.添加(Arc::clone(&笔1)); + assert!(result.is_ok()); + } + + #[test] + fn test_添加方向与线段方向相同的虚线应报错() { + // 向下笔(顶→底,方向=向下) 添加到 向下线段(方向=向下) → 方向相同, 应报错 + let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0); + let mut feat = 线段特征::new("测试".into(), vec![], 相对方向::向下); + + let result = feat.添加(Arc::clone(&笔1)); + assert!(result.is_err()); + } + + #[test] + fn test_空线段特征文返回第一个元素的文() { + let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0); + let feat = 线段特征::new("测试".into(), vec![Arc::clone(&笔1)], 相对方向::向上); + + let 文 = feat.文(); + assert_eq!(Arc::as_ptr(&文), Arc::as_ptr(&笔1.文)); + } +} diff --git a/chanlun/src/types/mod.rs b/chanlun/src/types/mod.rs index c01614f..40a68a5 100644 --- a/chanlun/src/types/mod.rs +++ b/chanlun/src/types/mod.rs @@ -26,8 +26,10 @@ pub mod bsp_type; pub mod direction; pub mod fractal; pub mod gap; +pub mod sync_f64; pub use bsp_type::买卖点类型; pub use direction::相对方向; pub use fractal::分型结构; pub use gap::缺口; +pub use sync_f64::SyncF64; diff --git a/chanlun/src/types/sync_f64.rs b/chanlun/src/types/sync_f64.rs new file mode 100644 index 0000000..7adfe8b --- /dev/null +++ b/chanlun/src/types/sync_f64.rs @@ -0,0 +1,25 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + +/// f64 原子类型 — 基于 AtomicU64 + 位转换,API 与 `Cell` 一致。 +#[derive(Debug, Default)] +pub struct SyncF64(AtomicU64); + +impl SyncF64 { + pub fn new(v: f64) -> Self { + Self(AtomicU64::new(v.to_bits())) + } + + pub fn get(&self) -> f64 { + f64::from_bits(self.0.load(Ordering::Relaxed)) + } + + pub fn set(&self, v: f64) { + self.0.store(v.to_bits(), Ordering::Relaxed); + } +} + +impl Clone for SyncF64 { + fn clone(&self) -> Self { + Self(AtomicU64::new(self.0.load(Ordering::Relaxed))) + } +} diff --git a/chanlun/src/utils/format.rs b/chanlun/src/utils/format.rs index cafb651..81696a6 100644 --- a/chanlun/src/utils/format.rs +++ b/chanlun/src/utils/format.rs @@ -22,6 +22,7 @@ * SOFTWARE. */ +/// 将 f64 格式化为与 Python `:g` (6 位有效数字) 兼容的字符串。 pub fn format_f64_g(value: f64) -> String { if value.is_nan() { return "nan".to_string(); @@ -33,9 +34,61 @@ pub fn format_f64_g(value: f64) -> String { "-inf".to_string() }; } + if value == 0.0 { + return "0".to_string(); + } - // Use high precision then trim trailing zeros - let s = format!("{:.15}", value); - let s = s.trim_end_matches('0'); - s.trim_end_matches('.').to_string() + let abs = value.abs(); + let exp = abs.log10().floor() as i32; + + // Python :g 科学计数法边界: exp < -4 或 exp >= p (=6) + if exp < -4 || exp >= 6 { + let significand = value / 10_f64.powi(exp); + let s = format!("{:.5}", significand); + let s = s.trim_end_matches('0').trim_end_matches('.'); + return format!("{}e{:+03}", s, exp); + } + + // 定点表示 + if abs >= 1.0 { + let int_digits = exp as usize + 1; + if int_digits >= 6 { + return format!("{:.0}", value); + } + let s = format!("{:.prec$}", value, prec = 6 - int_digits); + let s = s.trim_end_matches('0'); + return s.trim_end_matches('.').to_string(); + } else { + let leading_zeros = (-exp) as usize; + let s = format!("{:.prec$}", value, prec = leading_zeros + 5); + let s = s.trim_end_matches('0'); + return s.trim_end_matches('.').to_string(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_format_large() { + assert_eq!(format_f64_g(82833.0), "82833"); + assert_eq!(format_f64_g(74192.2), "74192.2"); + assert_eq!(format_f64_g(100.0), "100"); + assert_eq!(format_f64_g(0.0), "0"); + assert_eq!(format_f64_g(12345.6789), "12345.7"); + } + + #[test] + fn test_format_small() { + assert_eq!(format_f64_g(0.001234), "0.001234"); + assert_eq!(format_f64_g(0.1), "0.1"); + assert_eq!(format_f64_g(0.001), "0.001"); + } + + #[test] + fn test_format_extreme() { + assert_eq!(format_f64_g(1e7), "1e+07"); + assert_eq!(format_f64_g(1e-5), "1e-05"); + } }