第八版

This commit is contained in:
YuWuKunCheng
2026-05-29 03:55:22 +08:00
parent ae57090d7f
commit 5c3179eec8
31 changed files with 4111 additions and 1730 deletions
+2 -2
View File
@@ -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"
-1
View File
@@ -16,7 +16,6 @@ __all__ = [
"基础买卖点",
"平滑异同移动平均线",
"指标",
"测试_读取数据",
"特征分型",
"相对强弱指数",
"相对方向",
-1
View File
@@ -11,7 +11,6 @@ __all__ = [
"基础买卖点",
"平滑异同移动平均线",
"指标",
"测试_读取数据",
"特征分型",
"相对强弱指数",
"相对方向",
-1
View File
@@ -16,7 +16,6 @@ __all__ = [
"基础买卖点",
"平滑异同移动平均线",
"指标",
"测试_读取数据",
"特征分型",
"相对强弱指数",
"相对方向",
+1 -1
View File
@@ -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" }
+177 -148
View File
@@ -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<HashMap<usize, Py<Py>>> = RwLock::new(HashMap::new());
}
pub(crate) fn hub_to_py(
py: Python<'_>, inner: Arc<chanlun::algorithm::hub::>
) -> 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<Rc<chanlun::kline::bar::K线>> = K线序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K线序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -107,7 +135,7 @@ impl 背驰分析Py {
K序列: Vec<Py<K线Py>>,
py: Python<'_>,
) -> bool {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -127,7 +155,7 @@ impl 背驰分析Py {
K序列: Vec<Py<K线Py>>,
py: Python<'_>,
) -> bool {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -148,7 +176,7 @@ impl 背驰分析Py {
: &Bound<'_, Py>,
py: Python<'_>,
) -> PyResult<bool> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -170,7 +198,7 @@ impl 背驰分析Py {
K序列: Vec<Py<K线Py>>,
py: Python<'_>,
) -> bool {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -192,7 +220,7 @@ impl 背驰分析Py {
: &str,
py: Python<'_>,
) -> PyResult<bool> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -234,13 +262,13 @@ impl 笔Py {
: &Bound<'_, Py>,
py: Python<'_>,
) -> PyResult<usize> {
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Rc<chanlun::structure::dash_line::线>> =
let bi_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Py<crate::kline_py::K线Py>>,
: bool,
py: Python<'_>,
) -> Option<crate::kline_py::K线Py> {
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
) -> Option<Py<crate::kline_py::K线Py>> {
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Py<crate::kline_py::K线Py>>,
: bool,
py: Python<'_>,
) -> Option<crate::kline_py::K线Py> {
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
) -> Option<Py<crate::kline_py::K线Py>> {
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Py<crate::kline_py::K线Py>>,
: bool,
py: Python<'_>,
) -> Option<crate::kline_py::K线Py> {
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
) -> Option<Py<crate::kline_py::K线Py>> {
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Py<crate::kline_py::K线Py>>,
: bool,
py: Python<'_>,
) -> Option<crate::kline_py::K线Py> {
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
) -> Option<Py<crate::kline_py::K线Py>> {
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Rc<chanlun::structure::dash_line::线>> =
let bi_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Rc<chanlun::structure::dash_line::线>> =
let bi_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Rc<chanlun::structure::dash_line::线>> =
let bi_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<i64> {
let _ = ; // Python API 兼容参数,核心从0开始计数
let _rc = .map(|f| Rc::clone(&f.borrow().inner));
let mut fr_seq: Vec<Rc<chanlun::structure::fractal_obj::>> =
let _rc = .map(|f| Arc::clone(&f.borrow().inner));
let mut fr_seq: Vec<Arc<chanlun::structure::fractal_obj::>> =
.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<Rc<chanlun::structure::dash_line::线>> =
let mut bi_seq: Vec<Arc<chanlun::structure::dash_line::线>> =
.iter()
.map(|d| Rc::clone(&d.bind(py).borrow().inner))
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
.collect();
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let bar_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -435,25 +463,25 @@ impl 笔Py {
: &Bound<'_, Py>,
py: Python<'_>,
) -> PyResult<i64> {
let mut fr_seq: Vec<Rc<chanlun::structure::fractal_obj::>> =
let mut fr_seq: Vec<Arc<chanlun::structure::fractal_obj::>> =
.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<Rc<chanlun::structure::dash_line::线>> =
let mut bi_seq: Vec<Arc<chanlun::structure::dash_line::线>> =
.iter()
.map(|d| Rc::clone(&d.bind(py).borrow().inner))
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
.collect();
let ck_list: Vec<Rc<chanlun::kline::chan_kline::K线>> = K序列
let ck_list: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let bar_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Py<K线Py>> {
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<Rc<chanlun::structure::dash_line::线>> =
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Rc<chanlun::structure::dash_line::线>> =
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Option<Rc<chanlun::structure::segment_feat::线>>> = if .is_none() {
let seq: Vec<Option<Arc<chanlun::structure::segment_feat::线>>> = if .is_none()
{
vec![]
} else if let Ok(list) = .downcast::<pyo3::types::PyList>() {
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::<PyRefMut<'_, Py>>() {
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<Rc<chanlun::structure::dash_line::线>>| -> PyResult<Vec<Py<线Py>>> {
let wrap = |v: Vec<Arc<chanlun::structure::dash_line::线>>| -> PyResult<Vec<Py<线Py>>> {
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<Rc<chanlun::algorithm::hub::>>| -> PyResult<Py<PyAny>> {
let pk_list = |v: Vec<Arc<chanlun::algorithm::hub::>>| -> PyResult<Py<PyAny>> {
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<Rc<chanlun::structure::dash_line::线>> = vec![];
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 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<Option<线Py>> {
let config = .borrow().to_rust_config(py)?;
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = vec![];
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 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<bool> {
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<bool> {
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<bool> {
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<bool> {
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Vec<Py>>,
py: Python<'_>,
) -> PyResult<()> {
let bi_list: Vec<Rc<chanlun::structure::dash_line::线>> =
let bi_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Option<线Py>> {
let mut seg_seq: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::structure::dash_line::线>> = 线
let dash_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::structure::dash_line::线>> = 线
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Py<K线Py>> {
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<chanlun::algorithm::hub::>,
pub(crate) inner: Arc<chanlun::algorithm::hub::>,
}
#[pymethods]
@@ -1105,12 +1137,12 @@ impl 中枢Py {
fn new(
: i64, : String, : i64, : Vec<Py<线Py>>, py: Python<'_>
) -> Self {
let rc_list: Vec<Rc<chanlun::structure::dash_line::线>> =
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Py<PyAny>> {
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<Py<线Py>> {
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<Py<线Py>> {
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<Rc<chanlun::structure::dash_line::线>> =
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Rc<chanlun::algorithm::hub::>> =
let mut hub_seq: Vec<Arc<chanlun::algorithm::hub::>> =
.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::<PyRef<'_, Self>>() {
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<Self> {
let rc_list: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::structure::dash_line::线>> = 线
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::algorithm::hub::>> =
let mut hub_seq: Vec<Arc<chanlun::algorithm::hub::>> =
.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(())
+99 -94
View File
@@ -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<K线Py> {
bar_to_py(py, self.inner.K线.clone())
}
#[getter]
fn K线(&self) -> Option<K线Py> {
self.inner.K线.as_ref().map(|k| K线Py {
inner: Rc::clone(k),
})
fn K线(&self, py: Python<'_>) -> Option<Py<K线Py>> {
self.inner
.K线
.as_ref()
.map(|k| bar_to_py(py, Arc::clone(k)))
}
#[getter]
fn K线(&self) -> Option<K线Py> {
self.inner.K线.as_ref().map(|k| K线Py {
inner: Rc::clone(k),
})
fn K线(&self, py: Python<'_>) -> Option<Py<K线Py>> {
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<Rc<RefCell<chanlun::business::observer::>>>,
pub(crate) inner: Option<Arc<RwLock<chanlun::business::observer::>>>,
}
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<K线Py> {
self.obs().K线().map(|k| K线Py {
inner: Rc::clone(k),
})
fn K线(&self, py: Python<'_>) -> Option<Py<K线Py>> {
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<Py<K线Py>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<K线Py> {
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::,
}
+98 -9
View File
@@ -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<Self> {
let path = path.unwrap_or("缠论配置.json");
#[pyo3(signature = (path = "缠论配置.json"))]
fn (_cls: &Bound<'_, PyType>, py: Python<'_>, path: &str) -> PyResult<Self> {
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 {
+104 -94
View File
@@ -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<chanlun::kline::bar::K线>,
pub(crate) inner: Arc<chanlun::kline::bar::K线>,
}
#[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::<PyRef<'_, Self>>() {
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<i64>,
) -> 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<Self> {
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<Vec<Py<Self>>> {
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<chanlun::kline::chan_kline::K线>,
bsp_set: std::cell::RefCell<Option<Py<pyo3::types::PySet>>>,
pub(crate) inner: std::sync::Arc<chanlun::kline::chan_kline::K线>,
bsp_set: std::sync::RwLock<Option<Py<pyo3::types::PySet>>>,
}
impl K线Py {
pub(crate) fn from_rc(inner: std::rc::Rc<chanlun::kline::chan_kline::K线>) -> Self {
pub(crate) fn from_rc(inner: std::sync::Arc<chanlun::kline::chan_kline::K线>) -> 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<HashMap<usize, Py<K线Py>>> = RwLock::new(HashMap::new());
static KLINE_IDENTITY: RwLock<HashMap<usize, Py<K线Py>>> = RwLock::new(HashMap::new());
}
/// 将 Rc<K线> 转为 Py<K线Py>,确保同一 Rc 地址总是返回同一 Python 对象
pub(crate) fn bar_to_py(
py: Python<'_>,
inner: std::sync::Arc<chanlun::kline::bar::K线>,
) -> Py<K线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<chanlun::kline::chan_kline::K线>,
) -> 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<crate::types_py::Py> {
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<K线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::<PyRef<'_, Self>>() {
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<Py<PyAny>> {
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<Self> {
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<Self>, Option<String>)> {
) -> PyResult<(Option<Py<Self>>, Option<String>)> {
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<Vec<Py<Self>>> {
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 {
+233 -185
View File
@@ -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<HashMap<usize, Py<Py>>> = RwLock::new(HashMap::new());
static DASHED_IDENTITY: RwLock<HashMap<usize, Py<线Py>>> = RwLock::new(HashMap::new());
static SEGFEAT_IDENTITY: RwLock<HashMap<usize, Py<线Py>>> = RwLock::new(HashMap::new());
static FEATFRAC_IDENTITY: RwLock<HashMap<usize, Py<Py>>> = RwLock::new(HashMap::new());
}
pub(crate) fn fractal_to_py(
py: Python<'_>,
inner: Arc<chanlun::structure::fractal_obj::>,
) -> 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<chanlun::structure::dash_line::线>,
) -> 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<chanlun::structure::segment_feat::线>,
) -> 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<chanlun::structure::feat_fractal::>,
) -> 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<chanlun::structure::fractal_obj::>,
pub(crate) inner: Arc<chanlun::structure::fractal_obj::>,
}
#[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<Py<K线Py>> {
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<Py<K线Py>> {
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::<PyRef<'_, Self>>() {
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<Self> {
let ck_seq: Vec<Rc<chanlun::kline::chan_kline::K线>> = K线序列
let ck_seq: Vec<Arc<chanlun::kline::chan_kline::K线>> = 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<chanlun::structure::dash_line::线>,
pub(crate) inner: Arc<chanlun::structure::dash_line::线>,
}
#[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<Py<PyAny>> {
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<Py<K线Py>> {
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> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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<Py<PyAny>> {
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::<PyRef<'_, Self>>() {
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<Self>>, py: Python<'_>) -> Self {
let rc_list: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -720,7 +803,7 @@ impl 虚线Py {
线: &Bound<'_, Self>,
py: Python<'_>,
) -> Option<f64> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -738,7 +821,7 @@ impl 虚线Py {
线: &Bound<'_, Self>,
py: Python<'_>,
) -> Option<f64> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = K序列
.iter()
.map(|k| k.bind(py).borrow().inner.clone())
.collect();
@@ -803,7 +886,7 @@ impl 虚线Py {
k线序列: Vec<Py<K线Py>>,
py: Python<'_>,
) -> Vec<Vec<f64>> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = k线序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<Py<PyAny>> {
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K序列
let rc_list: Vec<Arc<chanlun::kline::bar::K线>> = 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<chanlun::structure::segment_feat::线>,
pub(crate) inner: Arc<chanlun::structure::segment_feat::线>,
}
#[pymethods]
@@ -918,12 +998,12 @@ impl 线段特征Py {
线: &Bound<'_, Py>,
py: Python<'_>,
) -> Self {
let rc_list: Vec<Rc<chanlun::structure::dash_line::线>> =
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> =
.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<Py<PyAny>> {
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<PyAny> = Py::new(
py,
线Py {
inner: Rc::clone(dash),
},
)?
.into();
let obj: Py<PyAny> = dashed_to_py(py, Arc::clone(dash)).into();
Ok(obj)
}
fn __iter__(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
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::<PyRef<'_, Self>>() {
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<Rc<chanlun::structure::dash_line::线>> = 线
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Self> {
let rc_list: Vec<Rc<chanlun::structure::dash_line::线>> = 线
let rc_list: Vec<Arc<chanlun::structure::dash_line::线>> = 线
.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<Self>>,
py: Python<'_>,
) -> Vec<Py> {
let rc_list: Vec<Rc<chanlun::structure::segment_feat::线>> =
) -> Vec<Py<Py>> {
let rc_list: Vec<Arc<chanlun::structure::segment_feat::线>> =
.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<chanlun::structure::feat_fractal::>,
pub(crate) inner: Arc<chanlun::structure::feat_fractal::>,
}
#[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::<PyRef<'_, Self>>() {
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
}
}
+5 -7
View File
@@ -286,17 +286,15 @@ impl 分型结构Py {
/// 返回:
/// 分型结构 或 None — 无法判定时返回 None
#[classmethod]
#[pyo3(signature = (左, 中, 右, 可以逆序包含 = false, 忽视顺序包含 = false))]
fn (
_cls: &Bound<'_, PyType>,
: &Bound<'_, PyAny>,
: &Bound<'_, PyAny>,
: &Bound<'_, PyAny>,
: Option<bool>,
: Option<bool>,
: bool,
: bool,
) -> PyResult<Option<Self>> {
let = .unwrap_or(false);
let = .unwrap_or(false);
let get_hl = |obj: &Bound<'_, PyAny>| -> PyResult<(f64, f64)> {
Ok((
obj.getattr("")?.extract::<f64>()?,
@@ -456,13 +454,13 @@ impl 缺口Py {
/// 返回:
/// 缺口 或 None — 起点==终点时返回 None
#[classmethod]
#[pyo3(signature = (起点, 终点, 比例 = 0.15))]
fn (
_cls: &Bound<'_, PyType>,
: f64,
: f64,
: Option<f64>,
: f64,
) -> Option<Self> {
let = .unwrap_or(0.15);
chanlun::types::::(, , ).map(|inner| Self { inner })
}
}
+267
View File
@@ -0,0 +1,267 @@
#!/usr/bin/env python3
"""
对象标识测试验证同一 Rc 底层数据通过不同路径访问时
Python 侧始终返回相同的 PyObject`is` 比较为 True
涉及的 Rc 包装类型
- K线 (Rc<K线>) 原始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
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "chanlun"
version = "26.5.2"
version = "26.5.3"
edition = "2021"
rust-version = "1.70"
license = "MIT"
+223 -159
View File
@@ -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<Rc<K线>> {
pub fn (K序列: &[Arc<K线>], : bool) -> Option<Arc<K线>> {
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<Rc<K线>> {
pub fn (K序列: &[Arc<K线>], : bool) -> Option<Arc<K线>> {
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<Rc<K线>> {
pub fn (K序列: &[Arc<K线>], : bool) -> Option<Arc<K线>> {
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<Rc<K线>> {
pub fn (K序列: &[Arc<K线>], : bool) -> Option<Arc<K线>> {
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<Rc<线>> {
pub fn (: &[Arc<线>], : &Arc<>) -> Option<Arc<线>> {
.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<Rc<线>> {
pub fn (: &[Arc<线>], : &Arc<>) -> Option<Arc<线>> {
.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<Rc<线>> {
) -> Option<Arc<线>> {
// 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<Rc<>>, : &mut Vec<Rc<线>>) {
fn (: &mut Vec<Arc<>>, : &mut Vec<Arc<线>>) {
.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<Rc<>>,
: &mut Vec<Rc<线>>,
K序列: &[Rc<K线>],
_普K序列: &[Rc<K线>],
: Arc<>,
: &mut Vec<Arc<>>,
: &mut Vec<Arc<线>>,
K序列: &[Arc<K线>],
_普K序列: &[Arc<K线>],
: &,
) -> 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<Rc<>> = Vec::new();
let mut : Vec<Arc<>> = 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<Rc<>>,
: &mut Vec<Rc<线>>,
K序列: &[Rc<K线>],
_普K序列: &[Rc<K线>],
: Arc<>,
: &mut Vec<Arc<>>,
: &mut Vec<Arc<线>>,
K序列: &[Arc<K线>],
_普K序列: &[Arc<K线>],
: 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<Rc<>>,
: &mut Vec<Rc<线>>,
: Rc<>,
mut : Rc<线>,
: &mut Vec<Arc<>>,
: &mut Vec<Arc<线>>,
: 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<Rc<K线>> {
pub fn (: &线, : &) -> Vec<Arc<K线>> {
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().));
}
}
+32 -22
View File
@@ -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<K线>], : &str
: &线, : &线, K线序列: &[Arc<K线>], : &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<K线>]) -> bool {
pub fn (: &线, : &线, K序列: &[Arc<K线>]) -> bool {
Self::MACD背驰(, , K序列, "")
&& Self::(, )
&& Self::(, )
}
/// 任意背驰 — 任一条件满足即可
pub fn (: &线, : &线, K序列: &[Rc<K线>]) -> bool {
pub fn (: &线, : &线, K序列: &[Arc<K线>]) -> bool {
Self::MACD背驰(, , K序列, "")
|| Self::(, )
|| Self::(, )
@@ -119,7 +125,7 @@ impl 背驰分析 {
pub fn (
: &线,
: &线,
K序列: &[Rc<K线>],
K序列: &[Arc<K线>],
: &,
) -> bool {
match (
@@ -152,7 +158,7 @@ impl 背驰分析 {
}
/// 任选背驰 — 至少两个条件满足(多数投票)
pub fn (: &线, : &线, K序列: &[Rc<K线>]) -> bool {
pub fn (: &线, : &线, K序列: &[Arc<K线>]) -> bool {
let = [
Self::MACD背驰(, , K序列, ""),
Self::(, ),
@@ -165,7 +171,7 @@ impl 背驰分析 {
pub fn (
: &线,
: &线,
K序列: &[Rc<K线>],
K序列: &[Arc<K线>],
: &,
: &str,
) -> bool {
@@ -180,9 +186,13 @@ impl 背驰分析 {
// ---- 内部辅助 ----
fn _获取MACD面积(K线序列: &[Rc<K线>], : &Rc<K线>, : &Rc<K线>) -> 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<K线>], : &Arc<K线>, : &Arc<K线>) -> 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;
+475 -124
View File
@@ -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<Rc<线>>,
pub 线: Option<Rc<线>>,
pub _第三买卖线: Option<Rc<线>>,
pub : AtomicI64,
pub : RwLock<String>,
pub : AtomicI64,
pub : RwLock<Vec<Arc<线>>>,
pub 线: RwLock<Option<Arc<线>>>,
pub _第三买卖线: RwLock<Option<Arc<线>>>,
}
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<Rc<线>>) -> Self {
pub fn new(: i64, : String, : i64, : Vec<Arc<线>>) -> 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<Rc<线>> {
let mut : Vec<Rc<线>> = self..clone();
if let Some(ref ) = self.线 {
.push(Rc::clone());
pub fn (&self) -> Vec<Arc<线>> {
let mut : Vec<Arc<线>> = 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<Rc<线>> = 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<Arc<线>> = 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<Rc<>>, : &crate::config::
&self,
: &mut Vec<Arc<>>,
: &crate::config::,
) {
if self..len() >= 9 {
let mut 线: Vec<Rc<线>> = Vec::new();
crate::algorithm::segment::线::(&self., &mut 线, );
if self..read().unwrap().len() >= 9 {
let mut 线: Vec<Arc<线>> = 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<Rc<>> {
) -> Option<Arc<>> {
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<Rc<>>, mut : Rc<>
: &mut Vec<Arc<>>, 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<>>,
: &Rc<>,
) -> Option<Rc<>> {
if .last().map(|x| Rc::as_ptr(x)) == Some(Rc::as_ptr()) {
: &mut Vec<Arc<>>,
: &Arc<>,
) -> Option<Arc<>> {
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<Rc<>>,
线: &[Arc<线>],
: &mut Vec<Arc<>>,
: 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<Rc<线>> = Vec::new();
let mut : Vec<Arc<线>> = 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::<Vec<_>>()
@@ -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.(),
File diff suppressed because it is too large Load Diff
+27 -26
View File
@@ -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<K线>,
pub K线: Option<Rc<K线>>,
pub K线: Option<Rc<K线>>,
pub : Arc<>,
pub K线: Arc<K线>,
pub K线: Arc<K线>,
pub K线: Option<Arc<K线>>,
pub K线: Option<Arc<K线>>,
pub : f64,
pub : Option<>,
}
@@ -46,12 +47,12 @@ pub struct 基础买卖点 {
impl {
pub fn new(
: ,
K线: Rc<K线>,
: Rc<>,
K线: Arc<K线>,
: 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<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &str,
: String,
: f64,
@@ -122,8 +123,8 @@ impl 买卖点 {
}
pub fn (
: Rc<>,
K线: Rc<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &str,
: String,
: f64,
@@ -132,8 +133,8 @@ impl 买卖点 {
}
pub fn (
: Rc<>,
K线: Rc<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &str,
: String,
: f64,
@@ -142,8 +143,8 @@ impl 买卖点 {
}
pub fn (
: Rc<>,
K线: Rc<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &str,
: String,
: f64,
@@ -152,8 +153,8 @@ impl 买卖点 {
}
pub fn (
: Rc<>,
K线: Rc<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &str,
: String,
: f64,
@@ -162,8 +163,8 @@ impl 买卖点 {
}
pub fn (
: Rc<>,
K线: Rc<K线>,
: Arc<>,
K线: Arc<K线>,
_标识: &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 (, ) {
("", "") => ::,
+11 -10
View File
@@ -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>,
: i64,
K线合成器: K线合成器,
: HashMap<i64, Rc<RefCell<>>>,
: HashMap<i64, Arc<RwLock<>>>,
}
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<Rc<RefCell<>>> {
pub fn (&self, : i64) -> Option<Arc<RwLock<>>> {
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()));
}
}
+508 -80
View File
@@ -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<Rc<K线>>,
pub K线序列: Vec<Rc<K线>>,
pub K线序列: Vec<Arc<K线>>,
pub K序列: Vec<Arc<K线>>,
pub K线序列: Vec<Arc<K线>>,
// 分型与笔
pub : Vec<Rc<>>,
pub : Vec<Rc<线>>,
pub _中枢序列: Vec<Rc<>>,
pub : Vec<Arc<>>,
pub : Vec<Arc<线>>,
pub _中枢序列: Vec<Arc<>>,
// 线段
pub 线: Vec<Rc<线>>,
pub : Vec<Rc<>>,
pub 线: Vec<Arc<线>>,
pub : Vec<Arc<>>,
// 扩展线段(笔级)
pub 线: Vec<Rc<线>>,
pub : Vec<Rc<>>,
pub 线: Vec<Arc<线>>,
pub : Vec<Arc<>>,
// 扩展线段(线段级)
pub 线_线段: Vec<Rc<线>>,
pub _线段: Vec<Rc<>>,
pub 线_线段: Vec<Arc<线>>,
pub _线段: Vec<Arc<>>,
// 线段之线段
pub 线_线段序列: Vec<Rc<线>>,
pub 线_中枢序列: Vec<Rc<>>,
pub 线_线段序列: Vec<Arc<线>>,
pub 线_中枢序列: Vec<Arc<>>,
// 扩展线段之扩展线段
pub 线_扩展线段: Vec<Rc<线>>,
pub _扩展线段: Vec<Rc<>>,
pub 线_扩展线段: Vec<Arc<线>>,
pub _扩展线段: Vec<Arc<>>,
// 终止时间戳
: Option<i64>,
}
impl {
pub fn new(: String, : i64, : ) -> Rc<RefCell<Self>> {
pub fn new(: String, : i64, : ) -> Arc<RwLock<Self>> {
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<K线>> {
pub fn K线(&self) -> Option<&Arc<K线>> {
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<Rc<RefCell<Self>>, String> {
) -> Result<Arc<RwLock<Self>>, 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<T: Send>() {}
fn _需要_Sync<T: Sync>() {}
fn _需要_Send_Sync<T: Send + Sync>() {}
// 核心数据结构
_需要_Send::<crate::kline::chan_kline::K线>();
_需要_Send::<crate::structure::dash_line::线>();
_需要_Send::<crate::algorithm::hub::>();
_需要_Send_Sync::<crate::kline::chan_kline::K线>();
_需要_Send_Sync::<crate::structure::dash_line::线>();
_需要_Send_Sync::<crate::algorithm::hub::>();
// Arc 包装后的 Send 检查
_需要_Send::<Arc<crate::kline::chan_kline::K线>>();
_需要_Send::<Arc<crate::structure::dash_line::线>>();
_需要_Send::<Arc<crate::algorithm::hub::>>();
// 观察者
_需要_Send::<crate::business::observer::>();
}
/// 测试: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);
}
}
+90 -1
View File
@@ -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<String, D::Error>
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<String, D::Error>
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<String, D::Error>
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();
+7 -7
View File
@@ -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<K线>序列中从始到终的片段
pub fn rc(: &[Rc<Self>], : &Rc<Self>, : &Rc<Self>) -> Vec<Rc<Self>> {
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<K线>序列中从始到终的片段
pub fn rc(: &[Arc<Self>], : &Arc<Self>, : &Arc<Self>) -> Vec<Arc<Self>> {
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(),
+194 -164
View File
@@ -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<Option<>>,
pub : i64,
pub : String,
pub : f64,
pub : SyncF64,
pub : i64,
pub : i64,
pub K线: Rc<K线>,
pub : std::cell::RefCell<Vec<String>>,
pub : AtomicI64,
pub K线: RwLock<Arc<K线>>,
pub : RwLock<Vec<String>>,
}
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线>,
k: Arc<K线>,
: 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线,
K: &Arc<K线>,
: &,
) -> (Option<Rc<K线>>, Option<String>) {
let = ::(K., K., K., K.);
) -> (Option<Arc<K线>>, Option<String>) {
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<Rc<K线>>,
K序列: &mut Vec<Rc<K线>>,
K序列: &mut Vec<Arc<K线>>,
K序列: &mut Vec<Arc<K线>>,
: &,
) -> (String, Option<Rc<>>) {
) -> (String, Option<Arc<>>) {
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线> = K序列.last().unwrap();
let K线_ref: &Arc<K线> = 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<Vec<Rc<K线>>> {
: &[Arc<K线>],
: &K线,
: &K线,
) -> Option<Vec<Arc<K线>>> {
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]
+2 -2
View File
@@ -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,
+495 -135
View File
@@ -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<Rc<线>>,
pub : Vec<Option<Rc<线>>>,
pub _中枢序列: Vec<Rc<>>,
pub _中枢序列: Vec<Rc<>>,
pub _中枢序列: Vec<Rc<>>,
pub K线: Option<Rc<K线>>,
pub : String,
pub _特征序列_显示: bool,
pub : Option<>,
pub : Option<Rc<线>>,
pub : bool,
pub : RwLock<String>,
pub : AtomicI64,
pub : AtomicI64,
pub : Arc<>,
pub : RwLock<Arc<>>,
pub : AtomicBool,
pub : RwLock<Vec<Arc<线>>>,
pub : RwLock<Vec<Option<Arc<线>>>>,
pub _中枢序列: RwLock<Vec<Arc<>>>,
pub _中枢序列: RwLock<Vec<Arc<>>>,
pub _中枢序列: RwLock<Vec<Arc<>>>,
pub K线: RwLock<Option<Arc<K线>>>,
pub : RwLock<String>,
pub _特征序列_显示: AtomicBool,
pub : RwLock<Option<>>,
pub : RwLock<Option<Arc<线>>>,
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<Rc<线>> {
&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<K线>]) -> Vec<Rc<K线>> {
pub fn K序列(&self, K序列: &[Arc<K线>]) -> Vec<Arc<K线>> {
// 使用指针查找(与 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<Rc<K线>> {
K线::(K序列, &self.., &self..).unwrap_or_default()
pub fn K序列(&self, K序列: &[Arc<K线>]) -> Vec<Arc<K线>> {
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(&current.)
}
/// 获取数据文本(用于保存/调试)
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::<Vec<_>>()
@@ -246,6 +285,8 @@ impl 虚线 {
let _str = format!(
"[{}]",
self._中枢序列
.read()
.unwrap()
.iter()
.map(|h| format!("{}", h))
.collect::<Vec<_>>()
@@ -254,6 +295,8 @@ impl 虚线 {
let _str = format!(
"[{}]",
self._中枢序列
.read()
.unwrap()
.iter()
.map(|h| format!("{}", h))
.collect::<Vec<_>>()
@@ -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<K线>], 线: &线) -> f64 {
let K线序列 = K线::rc(K序列, &线...K线, &线...K线);
pub fn MACD柱子均值(K序列: &[Arc<K线>], 线: &线) -> 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<K线>], 线: &线) -> Option<f64> {
let K线序列 = K线::rc(K序列, &线...K线, &线...K线);
pub fn MACD柱子均值_阴(K序列: &[Arc<K线>], 线: &线) -> Option<f64> {
let K线序列 = K线::rc(
K序列,
&*线...K线.read().unwrap(),
&*线..read().unwrap()..K线.read().unwrap(),
);
let : Vec<f64> = K线序列
.iter()
.filter_map(|k| k.macd.as_ref())
@@ -413,8 +470,12 @@ impl 虚线 {
}
/// 计算MACD柱子均值_阳 — 正柱的绝对值均值
pub fn MACD柱子均值_阳(K序列: &[Rc<K线>], 线: &线) -> Option<f64> {
let K线序列 = K线::rc(K序列, &线...K线, &线...K线);
pub fn MACD柱子均值_阳(K序列: &[Arc<K线>], 线: &线) -> Option<f64> {
let K线序列 = K线::rc(
K序列,
&*线...K线.read().unwrap(),
&*线..read().unwrap()..K线.read().unwrap(),
);
let : Vec<f64> = K线序列
.iter()
.filter_map(|k| k.macd.as_ref())
@@ -431,8 +492,10 @@ impl 虚线 {
// ---- 武之MACD比较 ----
/// 武之全量MACD均值 — 武端MACD柱是否小于均值(背驰)
pub fn MACD均值(K序列: &[Rc<K线>], 线: &线) -> bool {
let _MACD = match &线...K线.macd {
pub fn MACD均值(K序列: &[Arc<K线>], 线: &线) -> 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<K线>], 线: &线) -> bool {
pub fn MACD均值(K序列: &[Arc<K线>], 线: &线) -> bool {
if 线.() == :: {
Self::MACD均值_阳(K序列, 线)
} else {
@@ -449,8 +512,10 @@ impl 虚线 {
}
/// 武之MACD均值_阴 — 武端负柱是否小于阴均值
pub fn MACD均值_阴(K序列: &[Rc<K线>], 线: &线) -> bool {
let _MACD = match &线...K线.macd {
pub fn MACD均值_阴(K序列: &[Arc<K线>], 线: &线) -> 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<K线>], 线: &线) -> bool {
let _MACD = match &线...K线.macd {
pub fn MACD均值_阳(K序列: &[Arc<K线>], 线: &线) -> 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<K线>], 线: &线) -> bool {
let _MACD = match &线...K线.macd {
pub fn MACD极值(K序列: &[Arc<K线>], 线: &线) -> 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<f64> = 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线>], :
K序列: &[Arc<K线>], :
) -> [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线>> = K序列
let : Vec<&Arc<K线>> = 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线>> = K序列
let : Vec<&Arc<K线>> = 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<K线>]) -> Vec<Vec<f64>> {
pub fn MACD柱子分段(k线序列: &[Arc<K线>]) -> Vec<Vec<f64>> {
if k线序列.is_empty() {
return Vec::new();
}
@@ -729,7 +802,7 @@ impl 虚线 {
/// 统计MACD行为 — 分析DIF/DEA穿零轴和金叉死叉
pub fn MACD行为(
K序列: &[Rc<K线>],
K序列: &[Arc<K线>],
: 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<Rc<K线>> = if 线. == "" {
let : Vec<Arc<K线>> = 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,
)
+5 -5
View File
@@ -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 {
, , ,
+42 -28
View File
@@ -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<Rc<K线>>,
pub : Rc<K线>,
pub : Option<Rc<K线>>,
pub : Option<Arc<K线>>,
pub : Arc<K线>,
pub : Option<Arc<K线>>,
pub : ,
pub : i64,
pub : f64,
@@ -40,11 +41,11 @@ pub struct 分型 {
impl {
pub fn new(
: Option<Rc<K线>>, : Rc<K线>, : Option<Rc<K线>>
: Option<Arc<K线>>, : Arc<K线>, : Option<Arc<K线>>
) -> 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<Self> {
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<>>, : Rc<>) {
pub fn (: &mut Vec<Arc<>>, : 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" },
+335 -40
View File
@@ -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<Rc<线>>,
pub : Vec<Arc<线>>,
}
impl 线 {
pub fn new(: String, : Vec<Rc<线>>, 线: ) -> Self {
pub fn new(: String, : Vec<Arc<线>>, 线: ) -> 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<Rc<线>>, 线: ) -> Self {
pub fn (线: Vec<Arc<线>>, 线: ) -> Self {
let = format!("特征<虚线>");
Self::new(, 线, 线)
}
/// 静态分析 — 从虚线序列生成特征序列元素列表
pub fn (
线: &[Rc<线>],
线: &[Arc<线>],
线: ,
: &str,
: bool,
) -> Vec<Rc<线>> {
let mut : Vec<Rc<线>> = Vec::new();
) -> Vec<Arc<线>> {
let mut : Vec<Arc<线>> = 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.));
}
}
+2
View File
@@ -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;
+25
View File
@@ -0,0 +1,25 @@
use std::sync::atomic::{AtomicU64, Ordering};
/// f64 原子类型 — 基于 AtomicU64 + 位转换,API 与 `Cell<f64>` 一致。
#[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)))
}
}
+57 -4
View File
@@ -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");
}
}