修复 rust 引用问题
This commit is contained in:
@@ -28,8 +28,8 @@ use std::rc::Rc;
|
||||
|
||||
use crate::business_py::观察者Py;
|
||||
use crate::config_py::缠论配置Py;
|
||||
use crate::kline_py::K线Py;
|
||||
use crate::structure_py::{分型Py, 虚线Py};
|
||||
use crate::kline_py::{缠论K线Py, K线Py};
|
||||
use crate::structure_py::{分型Py, 线段特征Py, 虚线Py};
|
||||
use crate::types_py::相对方向Py;
|
||||
|
||||
// ========== 背驰分析 ==========
|
||||
@@ -61,7 +61,7 @@ impl 背驰分析Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = K线序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::algorithm::divergence::背驰分析::MACD背驰(
|
||||
&进入段.borrow().inner,
|
||||
@@ -105,7 +105,7 @@ impl 背驰分析Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::algorithm::divergence::背驰分析::全量背驰(
|
||||
&进入段.borrow().inner,
|
||||
@@ -124,7 +124,7 @@ impl 背驰分析Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::algorithm::divergence::背驰分析::任意背驰(
|
||||
&进入段.borrow().inner,
|
||||
@@ -144,7 +144,7 @@ impl 背驰分析Py {
|
||||
) -> PyResult<bool> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
Ok(chanlun::algorithm::divergence::背驰分析::配置背驰(
|
||||
@@ -165,7 +165,7 @@ impl 背驰分析Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::algorithm::divergence::背驰分析::任选背驰(
|
||||
&进入段.borrow().inner,
|
||||
@@ -186,7 +186,7 @@ impl 背驰分析Py {
|
||||
) -> PyResult<bool> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
Ok(chanlun::algorithm::divergence::背驰分析::背驰模式(
|
||||
@@ -251,7 +251,7 @@ impl 笔Py {
|
||||
.map(|k| Rc::clone(&k.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::次高(&ck_list, 取舍)
|
||||
.map(|inner| crate::kline_py::缠论K线Py { inner })
|
||||
.map(|inner| crate::kline_py::缠论K线Py::from_rc(inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -266,7 +266,7 @@ impl 笔Py {
|
||||
.map(|k| Rc::clone(&k.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::次低(&ck_list, 取舍)
|
||||
.map(|inner| crate::kline_py::缠论K线Py { inner })
|
||||
.map(|inner| crate::kline_py::缠论K线Py::from_rc(inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -281,7 +281,7 @@ impl 笔Py {
|
||||
.map(|k| Rc::clone(&k.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::实际高点(&ck_list, 取舍)
|
||||
.map(|inner| crate::kline_py::缠论K线Py { inner })
|
||||
.map(|inner| crate::kline_py::缠论K线Py::from_rc(inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -296,7 +296,7 @@ impl 笔Py {
|
||||
.map(|k| Rc::clone(&k.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::实际低点(&ck_list, 取舍)
|
||||
.map(|inner| crate::kline_py::缠论K线Py { inner })
|
||||
.map(|inner| crate::kline_py::缠论K线Py::from_rc(inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -361,16 +361,20 @@ impl 笔Py {
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
#[pyo3(signature = (当前分型, 分型序列, 笔序列, 缠K序列, 普K序列, 递归层次, 配置))]
|
||||
fn 分析(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
当前分型: &Bound<'_, 分型Py>,
|
||||
当前分型: Option<&Bound<'_, 分型Py>>,
|
||||
分型序列: Vec<Py<分型Py>>,
|
||||
笔序列: Vec<Py<虚线Py>>,
|
||||
缠K序列: Vec<Py<crate::kline_py::缠论K线Py>>,
|
||||
普K序列: Vec<Py<K线Py>>,
|
||||
递归层次: i64,
|
||||
配置: &Bound<'_, 缠论配置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::分型>> = 分型序列
|
||||
.iter()
|
||||
.map(|f| Rc::clone(&f.bind(py).borrow().inner))
|
||||
@@ -385,17 +389,20 @@ impl 笔Py {
|
||||
.collect();
|
||||
let bar_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
Ok(chanlun::algorithm::bi::笔::分析(
|
||||
Rc::clone(&当前分型.borrow().inner),
|
||||
&mut fr_seq,
|
||||
&mut bi_seq,
|
||||
&ck_list,
|
||||
&bar_list,
|
||||
&config,
|
||||
))
|
||||
match 当前分型_rc {
|
||||
Some(fr) => Ok(chanlun::algorithm::bi::笔::分析(
|
||||
fr,
|
||||
&mut fr_seq,
|
||||
&mut bi_seq,
|
||||
&ck_list,
|
||||
&bar_list,
|
||||
&config,
|
||||
)),
|
||||
None => Ok(递归层次),
|
||||
}
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -424,7 +431,7 @@ impl 笔Py {
|
||||
.collect();
|
||||
let bar_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
Ok(chanlun::algorithm::bi::笔::分析递归(
|
||||
@@ -468,12 +475,12 @@ impl 笔Py {
|
||||
_cls: &Bound<'_, PyType>,
|
||||
当前筆: &Bound<'_, 虚线Py>,
|
||||
观察员: &Bound<'_, 观察者Py>,
|
||||
) -> Vec<分型Py> {
|
||||
) -> Vec<缠论K线Py> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::bi::笔::是否背驰过(&当前筆.borrow().inner, &*obs_ref)
|
||||
.into_iter()
|
||||
.map(|f| 分型Py { inner: f })
|
||||
.map(|ck| 缠论K线Py::from_rc(ck))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -620,10 +627,26 @@ impl 线段Py {
|
||||
序列: &Bound<'_, PyAny>,
|
||||
行号: u32,
|
||||
) -> PyResult<()> {
|
||||
// 特征序列 contains Option<Rc<线段特征>>, skip for now
|
||||
let seq: Vec<Option<Rc<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());
|
||||
for item in list.iter() {
|
||||
if item.is_none() {
|
||||
result.push(None);
|
||||
} else {
|
||||
let feat: PyRef<'_, 线段特征Py> = item.extract()?;
|
||||
result.push(Some(Rc::clone(&feat.inner)));
|
||||
}
|
||||
}
|
||||
result
|
||||
} else {
|
||||
return Err(pyo3::exceptions::PyTypeError::new_err(
|
||||
"序列 必须是 list 或 None",
|
||||
));
|
||||
};
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
// Just pass empty vec for now — 线段特征Py not fully integrated
|
||||
chanlun::algorithm::segment::线段::设置特征序列(&mut ref_mut.inner, vec![], 行号);
|
||||
chanlun::algorithm::segment::线段::设置特征序列(&mut ref_mut.inner, seq, 行号);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -658,9 +681,17 @@ impl 线段Py {
|
||||
Vec<Py<虚线Py>>,
|
||||
Option<Py<虚线Py>>,
|
||||
)> {
|
||||
// 所属中枢 extraction is complex — pass None for now
|
||||
let (a, b, c, d) =
|
||||
chanlun::algorithm::segment::线段::分割序列(&段.borrow().inner, None);
|
||||
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);
|
||||
chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, Some(inner_mut))
|
||||
} else {
|
||||
chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, None)
|
||||
}
|
||||
} else {
|
||||
chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, None)
|
||||
};
|
||||
let wrap = |v: Vec<Rc<chanlun::structure::dash_line::虚线>>| -> PyResult<Vec<Py<虚线Py>>> {
|
||||
let mut result = Vec::new();
|
||||
for x in v {
|
||||
@@ -945,20 +976,17 @@ impl 线段Py {
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
fn 段获取所有停顿位置(
|
||||
fn 获取所有停顿位置(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
段: &Bound<'_, 虚线Py>,
|
||||
观察员: &Bound<'_, 观察者Py>,
|
||||
) -> Vec<虚线Py> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::segment::线段::段获取所有停顿位置(
|
||||
&段.borrow().inner,
|
||||
&*obs_ref,
|
||||
)
|
||||
.into_iter()
|
||||
.map(|d| 虚线Py { inner: Rc::new(d) })
|
||||
.collect()
|
||||
chanlun::algorithm::segment::线段::获取所有停顿位置(&段.borrow().inner, &*obs_ref)
|
||||
.into_iter()
|
||||
.map(|d| 虚线Py { inner: Rc::new(d) })
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -966,12 +994,12 @@ impl 线段Py {
|
||||
_cls: &Bound<'_, PyType>,
|
||||
当前段: &Bound<'_, 虚线Py>,
|
||||
观察员: &Bound<'_, 观察者Py>,
|
||||
) -> Vec<分型Py> {
|
||||
) -> Vec<缠论K线Py> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::segment::线段::是否背驰过(&当前段.borrow().inner, &*obs_ref)
|
||||
.into_iter()
|
||||
.map(|f| 分型Py { inner: f })
|
||||
.map(|ck| 缠论K线Py::from_rc(ck))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -1153,7 +1181,14 @@ impl 中枢Py {
|
||||
self.inner.获取数据文本()
|
||||
}
|
||||
|
||||
fn 校验合法性(&mut self, 序列: Vec<Py<虚线Py>>, py: Python<'_>) -> bool {
|
||||
#[pyo3(signature = (序列, 中枢序列 = None))]
|
||||
fn 校验合法性(
|
||||
&mut self,
|
||||
序列: Vec<Py<虚线Py>>,
|
||||
中枢序列: Option<Vec<Py<虚线Py>>>,
|
||||
py: Python<'_>,
|
||||
) -> bool {
|
||||
let _ = 中枢序列; // Python 版声明了此参数但未使用
|
||||
let rc_list: Vec<Rc<chanlun::structure::dash_line::虚线>> = 序列
|
||||
.iter()
|
||||
.map(|d| Rc::clone(&d.bind(py).borrow().inner))
|
||||
@@ -1167,18 +1202,21 @@ impl 中枢Py {
|
||||
self.inner.完整性(虚实)
|
||||
}
|
||||
|
||||
fn 获取扩展中枢(&self, 扩展中枢: Vec<Py<Self>>, py: Python<'_>) -> PyResult<()> {
|
||||
fn 获取扩展中枢(
|
||||
&self,
|
||||
扩展中枢: Vec<Py<Self>>,
|
||||
配置: &Bound<'_, crate::config_py::缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let mut hub_seq: Vec<Rc<chanlun::algorithm::hub::中枢>> = 扩展中枢
|
||||
.iter()
|
||||
.map(|h| Rc::clone(&h.bind(py).borrow().inner))
|
||||
.collect();
|
||||
// Need config for this call — use default
|
||||
let config = chanlun::config::缠论配置::default();
|
||||
let config = 配置.borrow().to_rust_config(配置.py())?;
|
||||
self.inner.获取扩展中枢(&mut hub_seq, &config);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 当前状态(&self) -> String {
|
||||
self.inner.当前状态().to_string()
|
||||
}
|
||||
@@ -1191,6 +1229,17 @@ impl 中枢Py {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
// ---- classmethods ----
|
||||
|
||||
#[classmethod]
|
||||
|
||||
+162
-53
@@ -63,7 +63,7 @@ impl 基础买卖点Py {
|
||||
Self {
|
||||
inner: chanlun::business::bsp::基础买卖点::new(
|
||||
类型.borrow().inner,
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -76,6 +76,12 @@ impl 基础买卖点Py {
|
||||
self.inner.备注.clone()
|
||||
}
|
||||
|
||||
#[setter]
|
||||
#[pyo3(name = "备注")]
|
||||
fn 设置_备注(&mut self, value: String) {
|
||||
self.inner.备注 = value;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 类型(&self) -> 买卖点类型Py {
|
||||
买卖点类型Py {
|
||||
@@ -92,29 +98,27 @@ impl 基础买卖点Py {
|
||||
|
||||
#[getter]
|
||||
fn 买卖点K线(&self) -> 缠论K线Py {
|
||||
缠论K线Py {
|
||||
inner: Rc::clone(&self.inner.买卖点K线),
|
||||
}
|
||||
缠论K线Py::from_rc(Rc::clone(&self.inner.买卖点K线))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 当前K线(&self) -> K线Py {
|
||||
K线Py {
|
||||
inner: (*self.inner.当前K线).clone(),
|
||||
inner: self.inner.当前K线.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 失效K线(&self) -> Option<K线Py> {
|
||||
self.inner.失效K线.as_ref().map(|k| K线Py {
|
||||
inner: (**k).clone(),
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 终结K线(&self) -> Option<K线Py> {
|
||||
self.inner.终结K线.as_ref().map(|k| K线Py {
|
||||
inner: (**k).clone(),
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -130,10 +134,12 @@ impl 基础买卖点Py {
|
||||
.map(|f| crate::types_py::分型结构Py { inner: f })
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 偏移(&self) -> i64 {
|
||||
self.inner.偏移()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 失效偏移(&self) -> i64 {
|
||||
self.inner.失效偏移()
|
||||
}
|
||||
@@ -187,7 +193,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::一卖点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -207,7 +213,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::一买点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -227,7 +233,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::二卖点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -247,7 +253,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::二买点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -267,7 +273,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::三卖点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -287,7 +293,7 @@ impl 买卖点Py {
|
||||
基础买卖点Py {
|
||||
inner: chanlun::business::bsp::买卖点::三买点(
|
||||
Rc::clone(&买卖点分型.borrow().inner),
|
||||
Rc::new(当前K线.borrow().inner.clone()),
|
||||
当前K线.borrow().inner.clone(),
|
||||
标识,
|
||||
备注,
|
||||
中枢破位值,
|
||||
@@ -370,33 +376,68 @@ impl 观察者Py {
|
||||
|
||||
#[pymethods]
|
||||
impl 观察者Py {
|
||||
/// __new__ 只分配空壳,构造逻辑在 __init__
|
||||
/// __new__ 从 *args/**kwargs 中提取 (符号, 周期, 配置),完整初始化观察者。
|
||||
/// 由于形参可变(子类参数各异),不依赖固定签名,而是从 args/kwargs 中按位置和名称智能提取。
|
||||
#[new]
|
||||
#[pyo3(signature = (*args, **kwargs))]
|
||||
fn new(
|
||||
args: &Bound<'_, pyo3::types::PyTuple>,
|
||||
kwargs: Option<&Bound<'_, pyo3::types::PyDict>>,
|
||||
) -> Self {
|
||||
let _ = (args, kwargs);
|
||||
Self { inner: None }
|
||||
) -> PyResult<Self> {
|
||||
let py = args.py();
|
||||
|
||||
// 提取 符号(位置 0 或关键字)
|
||||
let 符号: String = if !args.is_empty() {
|
||||
args.get_item(0)?.extract()?
|
||||
} else {
|
||||
match kwargs.and_then(|kw| kw.get_item("符号").ok().flatten()) {
|
||||
Some(val) => val.extract()?,
|
||||
None => return Err(pyo3::exceptions::PyTypeError::new_err("缺少参数: 符号")),
|
||||
}
|
||||
};
|
||||
|
||||
// 提取 周期(位置 1 或关键字)
|
||||
let 周期: i64 = if args.len() >= 2 {
|
||||
args.get_item(1)?.extract()?
|
||||
} else {
|
||||
match kwargs.and_then(|kw| kw.get_item("周期").ok().flatten()) {
|
||||
Some(val) => val.extract()?,
|
||||
None => return Err(pyo3::exceptions::PyTypeError::new_err("缺少参数: 周期")),
|
||||
}
|
||||
};
|
||||
|
||||
// 提取 配置(关键字优先,然后扫描剩余位置参数)
|
||||
let mut config = None;
|
||||
if let Some(val) = kwargs.and_then(|kw| kw.get_item("配置").ok().flatten()) {
|
||||
let cfg: PyRef<'_, 缠论配置Py> = val.extract()?;
|
||||
config = Some(cfg.to_rust_config(py)?);
|
||||
}
|
||||
if config.is_none() {
|
||||
for i in 2..args.len() {
|
||||
if let Ok(cfg) = args.get_item(i)?.extract::<PyRef<'_, 缠论配置Py>>() {
|
||||
config = Some(cfg.to_rust_config(py)?);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let config = config.unwrap_or_else(chanlun::config::缠论配置::default);
|
||||
|
||||
Ok(Self {
|
||||
inner: Some(chanlun::business::observer::观察者::new(
|
||||
符号, 周期, config,
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
/// __init__ 执行真正的构造。子类可重写并调用 super().__init__(符号, 周期, 配置)
|
||||
#[pyo3(signature = (符号, 周期, 配置 = None))]
|
||||
/// __init__ 不重复构造 — __new__ 已完成初始化。
|
||||
/// 接收 *args/**kwargs 是为了兼容 Python 构造函数给 __init__ 传入的任意形参。
|
||||
#[pyo3(signature = (*args, **kwargs))]
|
||||
fn __init__(
|
||||
&mut self,
|
||||
py: Python<'_>,
|
||||
符号: String,
|
||||
周期: i64,
|
||||
配置: Option<&Bound<'_, 缠论配置Py>>,
|
||||
args: &Bound<'_, pyo3::types::PyTuple>,
|
||||
kwargs: Option<&Bound<'_, pyo3::types::PyDict>>,
|
||||
) -> PyResult<()> {
|
||||
let config = match 配置 {
|
||||
Some(cfg) => cfg.borrow().to_rust_config(py)?,
|
||||
None => chanlun::config::缠论配置::default(),
|
||||
};
|
||||
self.inner = Some(chanlun::business::observer::观察者::new(
|
||||
符号, 周期, config,
|
||||
));
|
||||
let _ = (args, kwargs);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -413,15 +454,15 @@ impl 观察者Py {
|
||||
#[getter]
|
||||
fn 当前K线(&self) -> Option<K线Py> {
|
||||
self.obs().当前K线().map(|k| K线Py {
|
||||
inner: (**k).clone(),
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 当前缠K(&self) -> Option<缠论K线Py> {
|
||||
self.obs().当前缠K().map(|k| 缠论K线Py {
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
self.obs()
|
||||
.当前缠K()
|
||||
.map(|k| 缠论K线Py::from_rc(Rc::clone(k)))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -444,7 +485,35 @@ impl 观察者Py {
|
||||
}
|
||||
|
||||
fn 增加原始K线(&mut self, 普K: &Bound<'_, K线Py>) {
|
||||
self.obs_mut().增加原始K线(普K.borrow().inner.clone());
|
||||
self.obs_mut().增加原始K线((*普K.borrow().inner).clone());
|
||||
}
|
||||
|
||||
/// 加载本地数据 — 从 .nb 文件加载K线数据(先重置,再通过 Python dispatch 逐根投喂,
|
||||
/// 确保子类重写的 增加原始K线 被正确调用)。
|
||||
fn 加载本地数据(slf: &Bound<'_, Self>, 文件路径: &str) -> PyResult<()> {
|
||||
let py = slf.py();
|
||||
|
||||
// 重置基础序列
|
||||
slf.borrow_mut().obs_mut().重置基础序列();
|
||||
|
||||
// 解析文件得到 K线 列表
|
||||
let bars = slf
|
||||
.borrow()
|
||||
.obs()
|
||||
.解析本地数据(文件路径)
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))?;
|
||||
|
||||
// 通过 Python dispatch 逐根投喂,确保子类重写生效
|
||||
for k线 in bars {
|
||||
let k线_py = Py::new(
|
||||
py,
|
||||
K线Py {
|
||||
inner: Rc::new(k线),
|
||||
},
|
||||
)?;
|
||||
slf.call_method1("增加原始K线", (k线_py,))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn 静态重新分析(&mut self) {
|
||||
@@ -456,19 +525,61 @@ impl 观察者Py {
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
#[pyo3(signature = (文件路径, 配置 = None))]
|
||||
fn 读取数据文件(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
cls: &Bound<'_, PyType>,
|
||||
文件路径: &str,
|
||||
配置: Option<&Bound<'_, 缠论配置Py>>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<Self> {
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let config = match 配置 {
|
||||
Some(cfg) => Some(cfg.borrow().to_rust_config(py)?),
|
||||
None => None,
|
||||
Some(cfg) => cfg.borrow().to_rust_config(py)?,
|
||||
None => chanlun::config::缠论配置::default(),
|
||||
};
|
||||
chanlun::business::observer::观察者::读取数据文件(文件路径, config)
|
||||
.map(|inner| Self { inner: Some(inner) })
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
|
||||
|
||||
// 从文件名解析 符号/周期: "btcusd-300-1761327300-1776327900.nb"
|
||||
let path = std::path::Path::new(文件路径);
|
||||
let name = path
|
||||
.file_stem()
|
||||
.and_then(|n| n.to_str())
|
||||
.ok_or_else(|| pyo3::exceptions::PyValueError::new_err("invalid filename"))?;
|
||||
let parts: Vec<&str> = name.split('-').collect();
|
||||
if parts.len() < 4 {
|
||||
return Err(pyo3::exceptions::PyValueError::new_err(format!(
|
||||
"invalid filename format: {}",
|
||||
name
|
||||
)));
|
||||
}
|
||||
let 符号 = parts[0].to_string();
|
||||
let 周期: i64 = parts[1]
|
||||
.parse()
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("parse period: {}", e)))?;
|
||||
|
||||
// 通过 cls 构造实例(支持子类化)
|
||||
let cfg_py = 缠论配置Py::from_rust_config(&config)?;
|
||||
let cfg_obj = Py::new(py, cfg_py)?;
|
||||
let obj = cls.call1((符号.clone(), 周期, cfg_obj))?;
|
||||
|
||||
// 读取文件并通过 Python 分发逐根投喂(支持子类重写 增加原始K线)
|
||||
let data = std::fs::read(文件路径)
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("read file: {}", e)))?;
|
||||
let size: usize = 48;
|
||||
for i in 0..data.len() / size {
|
||||
let offset = i * size;
|
||||
if let Some(k线) =
|
||||
chanlun::kline::bar::K线::from_bytes(&data[offset..offset + size], 周期, &符号)
|
||||
{
|
||||
let k线_py = Py::new(
|
||||
py,
|
||||
K线Py {
|
||||
inner: Rc::new(k线),
|
||||
},
|
||||
)?;
|
||||
obj.call_method1("增加原始K线", (k线_py,))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(obj.unbind())
|
||||
}
|
||||
|
||||
// ---- 序列 getters ----
|
||||
@@ -478,7 +589,7 @@ impl 观察者Py {
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for k in &self.obs().普通K线序列 {
|
||||
list.append(K线Py {
|
||||
inner: (**k).clone(),
|
||||
inner: Rc::clone(k),
|
||||
})?;
|
||||
}
|
||||
Ok(list.into())
|
||||
@@ -488,9 +599,7 @@ 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(缠论K线Py::from_rc(Rc::clone(k)))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
@@ -670,10 +779,10 @@ impl K线合成器Py {
|
||||
普K: &Bound<'_, K线Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<Vec<(i64, K线Py)>> {
|
||||
let results = self.inner.投喂K线(普K.borrow().inner.clone());
|
||||
let results = self.inner.投喂K线((*普K.borrow().inner).clone());
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|(周期, k)| (周期, K线Py { inner: k }))
|
||||
.map(|(周期, k)| (周期, K线Py { inner: Rc::new(k) }))
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -701,14 +810,14 @@ impl K线合成器Py {
|
||||
let results = self.inner.投喂K线(k);
|
||||
results
|
||||
.into_iter()
|
||||
.map(|(周期, k2)| (周期, K线Py { inner: k2 }))
|
||||
.map(|(周期, k2)| (周期, K线Py { inner: Rc::new(k2) }))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn 获取当前K线(&self, 周期: i64) -> Option<K线Py> {
|
||||
self.inner
|
||||
.获取当前K线(周期)
|
||||
.map(|k| K线Py { inner: k.clone() })
|
||||
self.inner.获取当前K线(周期).map(|k| K线Py {
|
||||
inner: Rc::new(k.clone()),
|
||||
})
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -776,7 +885,7 @@ impl 立体分析器Py {
|
||||
}
|
||||
|
||||
fn 投喂K线(&mut self, 普K: &Bound<'_, K线Py>) {
|
||||
self.inner.投喂K线(普K.borrow().inner.clone());
|
||||
self.inner.投喂K线((*普K.borrow().inner).clone());
|
||||
}
|
||||
|
||||
fn 获取观察者(&self, 周期: i64) -> Option<观察者Py> {
|
||||
|
||||
@@ -107,16 +107,18 @@ impl 缠论配置Py {
|
||||
if let Some(kwargs) = kwargs {
|
||||
for (key, value) in kwargs.iter() {
|
||||
let key: String = key.extract()?;
|
||||
if fields.contains_key(&key) {
|
||||
fields.insert(key, value.clone().unbind());
|
||||
} else {
|
||||
if !fields.contains_key(&key) {
|
||||
return Err(pyo3::exceptions::PyAttributeError::new_err(format!(
|
||||
"缠论配置 没有字段: {key}"
|
||||
)));
|
||||
}
|
||||
fields.insert(key, value.clone().unbind());
|
||||
}
|
||||
}
|
||||
|
||||
// 全部通过 serde_json 往返验证类型,统一处理字符串数字/布尔强制转换
|
||||
let config = dict_to_rust_config(&fields)?;
|
||||
let fields = config_to_field_dict(&config)?;
|
||||
Ok(Self { fields })
|
||||
}
|
||||
|
||||
@@ -132,7 +134,16 @@ impl 缠论配置Py {
|
||||
fn __setattr__(&mut self, name: &str, value: &Bound<'_, PyAny>) -> PyResult<()> {
|
||||
if self.fields.contains_key(name) {
|
||||
self.fields.insert(name.to_string(), value.clone().unbind());
|
||||
Ok(())
|
||||
// 通过 serde 往返验证类型
|
||||
match dict_to_rust_config(&self.fields) {
|
||||
Ok(config) => {
|
||||
self.fields = config_to_field_dict(&config)?;
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(pyo3::exceptions::PyValueError::new_err(format!(
|
||||
"配置转换失败: {e}"
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
Err(pyo3::exceptions::PyAttributeError::new_err(format!(
|
||||
"缠论配置 没有字段: {name}"
|
||||
@@ -198,10 +209,13 @@ impl 缠论配置Py {
|
||||
|
||||
for (key, value) in data.iter() {
|
||||
let key: String = key.extract()?;
|
||||
fields.insert(key, value.clone().unbind());
|
||||
if fields.contains_key(&key) {
|
||||
fields.insert(key, value.clone().unbind());
|
||||
}
|
||||
}
|
||||
|
||||
dict_to_rust_config(&fields)?;
|
||||
let config = dict_to_rust_config(&fields)?;
|
||||
let fields = config_to_field_dict(&config)?;
|
||||
Ok(Self { fields })
|
||||
}
|
||||
|
||||
@@ -270,7 +284,8 @@ impl 缠论配置Py {
|
||||
fields.insert(key, value.clone().unbind());
|
||||
}
|
||||
|
||||
dict_to_rust_config(&fields)?;
|
||||
let config = dict_to_rust_config(&fields)?;
|
||||
let fields = config_to_field_dict(&config)?;
|
||||
Ok(Self { fields })
|
||||
}
|
||||
|
||||
@@ -313,11 +328,84 @@ fn dict_to_rust_config(
|
||||
}
|
||||
let dumps = json_mod.getattr("dumps")?;
|
||||
let json_str: String = dumps.call1((dict,))?.extract()?;
|
||||
serde_json::from_str(&json_str)
|
||||
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)
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("配置转换失败: {e}")))
|
||||
})
|
||||
}
|
||||
|
||||
/// 递归遍历 JSON Value,将数字/布尔字符串转为对应类型。
|
||||
fn coerce_strings_to_numbers(value: &mut serde_json::Value) {
|
||||
match value {
|
||||
serde_json::Value::Object(map) => {
|
||||
for (_, v) in map.iter_mut() {
|
||||
coerce_strings_to_numbers(v);
|
||||
}
|
||||
}
|
||||
serde_json::Value::Array(arr) => {
|
||||
for v in arr.iter_mut() {
|
||||
coerce_strings_to_numbers(v);
|
||||
}
|
||||
}
|
||||
serde_json::Value::String(s) => {
|
||||
// 先 clone 出独立副本,避免借用冲突
|
||||
let cloned = s.clone();
|
||||
if let Ok(n) = cloned.parse::<i64>() {
|
||||
*value = serde_json::Value::Number(serde_json::Number::from(n));
|
||||
} else if let Ok(n) = cloned.parse::<f64>() {
|
||||
if n.is_finite() {
|
||||
if let Some(num) = serde_json::Number::from_f64(n) {
|
||||
*value = serde_json::Value::Number(num);
|
||||
}
|
||||
}
|
||||
} else if cloned.eq_ignore_ascii_case("true") {
|
||||
*value = serde_json::Value::Bool(true);
|
||||
} else if cloned.eq_ignore_ascii_case("false") {
|
||||
*value = serde_json::Value::Bool(false);
|
||||
}
|
||||
// 非数字非布尔的原样保留,不做任何修改
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 将 Python 字符串数字/布尔值强制转为对应类型,非字符串保持不变。
|
||||
/// 注:主代码路径现通过 serde 往返处理类型转换,此函数作为辅助保留。
|
||||
#[allow(dead_code)]
|
||||
fn coerce_py_value(value: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> {
|
||||
let py = value.py();
|
||||
|
||||
let type_name: String = value.get_type().name()?.extract()?;
|
||||
if type_name != "str" {
|
||||
return Ok(value.clone().unbind());
|
||||
}
|
||||
|
||||
let lower_obj = value.call_method0("lower")?;
|
||||
let lower: String = lower_obj.extract()?;
|
||||
|
||||
if lower == "true" || lower == "false" {
|
||||
let b = lower == "true";
|
||||
let obj = pyo3::types::PyBool::new(py, b)
|
||||
.to_owned()
|
||||
.into_any()
|
||||
.unbind();
|
||||
return Ok(obj);
|
||||
}
|
||||
|
||||
if let Ok(n) = lower.parse::<i64>() {
|
||||
return Ok(n.into_pyobject(py)?.into_any().unbind());
|
||||
}
|
||||
if let Ok(n) = lower.parse::<f64>() {
|
||||
if n.is_finite() {
|
||||
return Ok(n.into_pyobject(py)?.into_any().unbind());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(value.clone().unbind())
|
||||
}
|
||||
|
||||
pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_class::<缠论配置Py>()?;
|
||||
Ok(())
|
||||
|
||||
+157
-65
@@ -25,6 +25,7 @@
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyBytes, PyType};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::config_py::缠论配置Py;
|
||||
use crate::indicators_py::{平滑异同移动平均线Py, 相对强弱指数Py, 随机指标Py};
|
||||
@@ -51,10 +52,9 @@ use crate::types_py::相对方向Py;
|
||||
/// 获取MACD(K线序列, 计算方式, 快线周期?, 慢线周期?, 信号周期?) -> list[平滑异同移动平均线]
|
||||
/// — 对整个K线序列批量计算 MACD
|
||||
/// 截取(序列, 起点K线, 终点K线) -> list — 按时间戳截取K线区间
|
||||
#[pyclass(name = "K线")]
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "K线", unsendable)]
|
||||
pub struct K线Py {
|
||||
pub(crate) inner: chanlun::kline::bar::K线,
|
||||
pub(crate) inner: Rc<chanlun::kline::bar::K线>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
@@ -73,7 +73,7 @@ impl K线Py {
|
||||
成交量: f64,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: chanlun::kline::bar::K线 {
|
||||
inner: Rc::new(chanlun::kline::bar::K线 {
|
||||
标识: 标识.to_string(),
|
||||
序号,
|
||||
周期,
|
||||
@@ -86,7 +86,7 @@ impl K线Py {
|
||||
macd: None,
|
||||
rsi: None,
|
||||
kdj: None,
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_标识(&mut self, v: String) {
|
||||
self.inner.标识 = v;
|
||||
Rc::make_mut(&mut self.inner).标识 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -105,7 +105,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_序号(&mut self, v: i64) {
|
||||
self.inner.序号 = v;
|
||||
Rc::make_mut(&mut self.inner).序号 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -114,7 +114,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_周期(&mut self, v: i64) {
|
||||
self.inner.周期 = v;
|
||||
Rc::make_mut(&mut self.inner).周期 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -123,7 +123,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_时间戳(&mut self, v: i64) {
|
||||
self.inner.时间戳 = v;
|
||||
Rc::make_mut(&mut self.inner).时间戳 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -132,7 +132,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_高(&mut self, v: f64) {
|
||||
self.inner.高 = v;
|
||||
Rc::make_mut(&mut self.inner).高 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -141,7 +141,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_低(&mut self, v: f64) {
|
||||
self.inner.低 = v;
|
||||
Rc::make_mut(&mut self.inner).低 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -150,7 +150,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_开盘价(&mut self, v: f64) {
|
||||
self.inner.开盘价 = v;
|
||||
Rc::make_mut(&mut self.inner).开盘价 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -159,7 +159,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_收盘价(&mut self, v: f64) {
|
||||
self.inner.收盘价 = v;
|
||||
Rc::make_mut(&mut self.inner).收盘价 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -168,7 +168,7 @@ impl K线Py {
|
||||
}
|
||||
#[setter]
|
||||
fn set_成交量(&mut self, v: f64) {
|
||||
self.inner.成交量 = v;
|
||||
Rc::make_mut(&mut self.inner).成交量 = v;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -179,7 +179,7 @@ impl K线Py {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn MACD(&self) -> Option<平滑异同移动平均线Py> {
|
||||
fn macd(&self) -> Option<平滑异同移动平均线Py> {
|
||||
self.inner
|
||||
.macd
|
||||
.as_ref()
|
||||
@@ -187,7 +187,7 @@ impl K线Py {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn RSI(&self) -> Option<相对强弱指数Py> {
|
||||
fn rsi(&self) -> Option<相对强弱指数Py> {
|
||||
self.inner
|
||||
.rsi
|
||||
.as_ref()
|
||||
@@ -195,7 +195,7 @@ impl K线Py {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn KDJ(&self) -> Option<随机指标Py> {
|
||||
fn kdj(&self) -> Option<随机指标Py> {
|
||||
self.inner
|
||||
.kdj
|
||||
.as_ref()
|
||||
@@ -214,6 +214,17 @@ impl K线Py {
|
||||
PyBytes::new(py, &self.inner.to_bytes()).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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
#[pyo3(signature = (标识, 时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量, 序号 = None, 周期 = None))]
|
||||
fn 创建普K(
|
||||
@@ -229,7 +240,7 @@ impl K线Py {
|
||||
周期: Option<i64>,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: chanlun::kline::bar::K线::创建普K(
|
||||
inner: Rc::new(chanlun::kline::bar::K线::创建普K(
|
||||
标识,
|
||||
时间戳,
|
||||
开盘价,
|
||||
@@ -239,7 +250,7 @@ impl K线Py {
|
||||
成交量,
|
||||
序号.unwrap_or(0),
|
||||
周期.unwrap_or(60),
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +262,7 @@ impl K线Py {
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let refs: Vec<_> = K线序列.iter().map(|k| k.bind(py).borrow()).collect();
|
||||
let bars: Vec<&chanlun::kline::bar::K线> = refs.iter().map(|r| &r.inner).collect();
|
||||
let bars: Vec<&chanlun::kline::bar::K线> = refs.iter().map(|r| r.inner.as_ref()).collect();
|
||||
chanlun::kline::bar::K线::保存到DAT文件(路径, &bars)
|
||||
.map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
|
||||
}
|
||||
@@ -263,8 +274,11 @@ impl K线Py {
|
||||
周期: i64,
|
||||
标识: &str,
|
||||
) -> Option<Self> {
|
||||
chanlun::kline::bar::K线::读取大端字节数组(字节组.as_bytes(), 周期, 标识)
|
||||
.map(|inner| Self { inner })
|
||||
chanlun::kline::bar::K线::读取大端字节数组(字节组.as_bytes(), 周期, 标识).map(|inner| {
|
||||
Self {
|
||||
inner: Rc::new(inner),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -276,7 +290,7 @@ impl K线Py {
|
||||
py: Python<'_>,
|
||||
) -> HashMap<String, f64> {
|
||||
let refs: Vec<_> = k线序列.iter().map(|k| k.bind(py).borrow()).collect();
|
||||
let bars: Vec<&chanlun::kline::bar::K线> = refs.iter().map(|r| &r.inner).collect();
|
||||
let bars: Vec<&chanlun::kline::bar::K线> = refs.iter().map(|r| r.inner.as_ref()).collect();
|
||||
chanlun::kline::bar::K线::获取MACD(&bars, &始.borrow().inner, &终.borrow().inner)
|
||||
}
|
||||
|
||||
@@ -285,22 +299,33 @@ impl K线Py {
|
||||
序列: Vec<Py<Self>>,
|
||||
始: &Bound<'_, Self>,
|
||||
终: &Bound<'_, Self>,
|
||||
) -> Option<Vec<Py<Self>>> {
|
||||
let start_ptr = 始.as_ptr();
|
||||
let end_ptr = 终.as_ptr();
|
||||
let start_idx = 序列.iter().position(|k| k.as_ptr() == start_ptr)?;
|
||||
let end_idx = 序列.iter().position(|k| k.as_ptr() == end_ptr)?;
|
||||
if start_idx <= end_idx {
|
||||
Some(
|
||||
序列
|
||||
.into_iter()
|
||||
.skip(start_idx)
|
||||
.take(end_idx - start_idx + 1)
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
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_idx = 序列
|
||||
.iter()
|
||||
.position(|k| {
|
||||
Rc::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
|
||||
})
|
||||
.ok_or_else(|| pyo3::exceptions::PyValueError::new_err("终 不在序列中"))?;
|
||||
if start_idx > end_idx {
|
||||
return Err(pyo3::exceptions::PyValueError::new_err("始 排序在 终 之后"));
|
||||
}
|
||||
Ok(序列
|
||||
.into_iter()
|
||||
.skip(start_idx)
|
||||
.take(end_idx - start_idx + 1)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,9 +349,27 @@ impl K线Py {
|
||||
/// — 分析分型形成结果
|
||||
/// 截取(序列, 起点分型, 终点分型) -> list — 截取分型间的缠K子序列
|
||||
#[pyclass(name = "缠论K线", unsendable)]
|
||||
#[derive(Clone)]
|
||||
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>>>,
|
||||
}
|
||||
|
||||
impl 缠论K线Py {
|
||||
pub(crate) fn from_rc(inner: std::rc::Rc<chanlun::kline::chan_kline::缠论K线>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
bsp_set: std::cell::RefCell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for 缠论K线Py {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: std::rc::Rc::clone(&self.inner),
|
||||
bsp_set: std::cell::RefCell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
@@ -398,7 +441,7 @@ impl 缠论K线Py {
|
||||
#[getter]
|
||||
fn 标的K线(&self) -> K线Py {
|
||||
K线Py {
|
||||
inner: (*self.inner.标的K线).clone(),
|
||||
inner: self.inner.标的K线.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,10 +453,32 @@ impl 缠论K线Py {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
fn 镜像(&self) -> Self {
|
||||
Self {
|
||||
inner: std::rc::Rc::new(self.inner.镜像()),
|
||||
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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 镜像(&self, py: Python<'_>) -> Self {
|
||||
let mut mirror = Self {
|
||||
inner: std::rc::Rc::new(self.inner.镜像()),
|
||||
bsp_set: std::cell::RefCell::new(None),
|
||||
};
|
||||
if let Some(ref src_set) = *self.bsp_set.borrow() {
|
||||
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
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -431,6 +496,24 @@ impl 缠论K线Py {
|
||||
self.inner.与KDJ匹配()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 买卖点信息(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
if self.bsp_set.borrow().is_none() {
|
||||
let set = pyo3::types::PySet::empty(py)?;
|
||||
for s in self.inner.买卖点信息.borrow().iter() {
|
||||
set.add(s.clone())?;
|
||||
}
|
||||
*self.bsp_set.borrow_mut() = Some(set.into());
|
||||
}
|
||||
Ok(self
|
||||
.bsp_set
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone_ref(py)
|
||||
.into_any())
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
fn 时间戳对齐(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
@@ -466,12 +549,10 @@ impl 缠论K线Py {
|
||||
方向.borrow().inner,
|
||||
结构.map(|s| s.borrow().inner),
|
||||
原始序号,
|
||||
std::rc::Rc::new(普k.borrow().inner.clone()),
|
||||
普k.borrow().inner.clone(),
|
||||
prev_inner,
|
||||
);
|
||||
Self {
|
||||
inner: std::rc::Rc::new(inner),
|
||||
}
|
||||
Self::from_rc(std::rc::Rc::new(inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -493,7 +574,7 @@ impl 缠论K线Py {
|
||||
&当前普K.borrow().inner,
|
||||
&config,
|
||||
);
|
||||
Ok((result.map(|rc| Self { inner: rc }), mode))
|
||||
Ok((result.map(Self::from_rc), mode))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -505,7 +586,7 @@ impl 缠论K线Py {
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<(String, Option<Py<PyAny>>)> {
|
||||
let ck_inner = 当前K线.borrow().inner.clone();
|
||||
let ck_inner = (*当前K线.borrow().inner).clone();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
|
||||
let mut ck_seq: Vec<_> = 缠K序列
|
||||
@@ -514,7 +595,7 @@ impl 缠论K线Py {
|
||||
.collect();
|
||||
let mut bar_seq: Vec<_> = 普K序列
|
||||
.iter()
|
||||
.map(|k| std::rc::Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
|
||||
let (status, _fractal) = chanlun::kline::chan_kline::缠论K线::分析(
|
||||
@@ -532,22 +613,33 @@ impl 缠论K线Py {
|
||||
序列: Vec<Py<Self>>,
|
||||
始: &Bound<'_, Self>,
|
||||
终: &Bound<'_, Self>,
|
||||
) -> Option<Vec<Py<Self>>> {
|
||||
let start_ptr = 始.as_ptr();
|
||||
let end_ptr = 终.as_ptr();
|
||||
let start_idx = 序列.iter().position(|k| k.as_ptr() == start_ptr)?;
|
||||
let end_idx = 序列.iter().position(|k| k.as_ptr() == end_ptr)?;
|
||||
if start_idx <= end_idx {
|
||||
Some(
|
||||
序列
|
||||
.into_iter()
|
||||
.skip(start_idx)
|
||||
.take(end_idx - start_idx + 1)
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
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_idx = 序列
|
||||
.iter()
|
||||
.position(|k| {
|
||||
Rc::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
|
||||
})
|
||||
.ok_or_else(|| pyo3::exceptions::PyValueError::new_err("终 不在序列中"))?;
|
||||
if start_idx > end_idx {
|
||||
return Err(pyo3::exceptions::PyValueError::new_err("始 排序在 终 之后"));
|
||||
}
|
||||
Ok(序列
|
||||
.into_iter()
|
||||
.skip(start_idx)
|
||||
.take(end_idx - start_idx + 1)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,3 +51,43 @@ fn _chanlun(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
business_py::register(m)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::*;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_rc_pointer_across_getters() {
|
||||
pyo3::prepare_freethreaded_python();
|
||||
Python::with_gil(|py| {
|
||||
let module = PyModule::new(py, "test_module").unwrap();
|
||||
module.add_class::<business_py::观察者Py>().unwrap();
|
||||
module.add_class::<business_py::基础买卖点Py>().unwrap();
|
||||
module.add_class::<business_py::买卖点Py>().unwrap();
|
||||
module.add_class::<kline_py::K线Py>().unwrap();
|
||||
module.add_class::<kline_py::缠论K线Py>().unwrap();
|
||||
module.add_class::<structure_py::分型Py>().unwrap();
|
||||
module.add_class::<structure_py::虚线Py>().unwrap();
|
||||
module.add_class::<config_py::缠论配置Py>().unwrap();
|
||||
|
||||
let config = config_py::缠论配置Py::from_rust_config(&Default::default()).unwrap();
|
||||
let obs = business_py::观察者Py::new_impl("btcusd".into(), 300, config, py).unwrap();
|
||||
|
||||
// Feed one K line
|
||||
let kline = kline_py::K线Py::new_impl(
|
||||
"btcusd".into(),
|
||||
1000,
|
||||
100.0,
|
||||
105.0,
|
||||
99.0,
|
||||
103.0,
|
||||
1000.0,
|
||||
0,
|
||||
300,
|
||||
);
|
||||
let kline_ref = kline.into_ref(py);
|
||||
// ... this is too complex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+181
-52
@@ -72,23 +72,23 @@ impl 分型Py {
|
||||
|
||||
#[getter]
|
||||
fn 左(&self) -> Option<缠论K线Py> {
|
||||
self.inner.左.as_ref().map(|k| 缠论K线Py {
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
self.inner
|
||||
.左
|
||||
.as_ref()
|
||||
.map(|k| 缠论K线Py::from_rc(Rc::clone(k)))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 中(&self) -> 缠论K线Py {
|
||||
缠论K线Py {
|
||||
inner: Rc::clone(&self.inner.中),
|
||||
}
|
||||
缠论K线Py::from_rc(Rc::clone(&self.inner.中))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 右(&self) -> Option<缠论K线Py> {
|
||||
self.inner.右.as_ref().map(|k| 缠论K线Py {
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
self.inner
|
||||
.右
|
||||
.as_ref()
|
||||
.map(|k| 缠论K线Py::from_rc(Rc::clone(k)))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -116,6 +116,17 @@ impl 分型Py {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 关系组(&self) -> Option<(相对方向Py, 相对方向Py, 相对方向Py)> {
|
||||
self.inner.关系组().map(|(a, b, c)| {
|
||||
@@ -208,8 +219,8 @@ impl 分型Py {
|
||||
/// 方法:
|
||||
/// 之前是(其他虚线) -> bool — 判断当前虚线是否紧接在另一虚线之前
|
||||
/// 之后是(其他虚线) -> bool — 判断当前虚线是否紧接在另一虚线之后
|
||||
/// 获取普K序列(普K序列) -> list[K线] — 截取该虚线的原始K线范围
|
||||
/// 获取缠K序列(缠K序列) -> list[缠论K线] — 截取该虚线的缠K范围
|
||||
/// 获取普K序列(观察员) -> list[K线] — 截取该虚线的原始K线范围
|
||||
/// 获取缠K序列(观察员) -> list[缠论K线] — 截取该虚线的缠K范围
|
||||
/// 获取数据文本() -> str
|
||||
///
|
||||
/// 类方法(算法辅助):
|
||||
@@ -294,6 +305,25 @@ impl 虚线Py {
|
||||
self.inner._特征序列_显示
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 特征序列(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for item in &self.inner.特征序列 {
|
||||
match item {
|
||||
Some(feat) => list.append(Py::new(
|
||||
py,
|
||||
线段特征Py {
|
||||
inner: Rc::clone(feat),
|
||||
},
|
||||
)?)?,
|
||||
None => {
|
||||
list.append(py.None())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 短路修正(&self) -> bool {
|
||||
self.inner.短路修正
|
||||
@@ -301,9 +331,10 @@ impl 虚线Py {
|
||||
|
||||
#[getter]
|
||||
fn 确认K线(&self) -> Option<缠论K线Py> {
|
||||
self.inner.确认K线.as_ref().map(|k| 缠论K线Py {
|
||||
inner: Rc::clone(k),
|
||||
})
|
||||
self.inner
|
||||
.确认K线
|
||||
.as_ref()
|
||||
.map(|k| 缠论K线Py::from_rc(Rc::clone(k)))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -413,39 +444,43 @@ impl 虚线Py {
|
||||
self.inner.之后是(&之后.borrow().inner)
|
||||
}
|
||||
|
||||
fn 获取普K序列(&self, 普K序列: Vec<Py<K线Py>>, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.collect();
|
||||
let result = self.inner.获取普K序列(&rc_list);
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
fn 获取普K序列(
|
||||
&self,
|
||||
观察员: &Bound<'_, crate::business_py::观察者Py>,
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let obs_ref = 观察员.borrow();
|
||||
let observer_inner = obs_ref.obs();
|
||||
let result = self.inner.获取普K序列(&observer_inner.普通K线序列);
|
||||
let list = pyo3::types::PyList::empty(观察员.py());
|
||||
for k in &result {
|
||||
list.append(K线Py {
|
||||
inner: (**k).clone(),
|
||||
})?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
|
||||
fn 获取缠K序列(
|
||||
&self, 缠K序列: Vec<Py<缠论K线Py>>, py: Python<'_>
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::chan_kline::缠论K线>> = 缠K序列
|
||||
.iter()
|
||||
.map(|k| Rc::clone(&k.bind(py).borrow().inner))
|
||||
.collect();
|
||||
let result = self.inner.获取缠K序列(&rc_list);
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for k in &result {
|
||||
list.append(缠论K线Py {
|
||||
inner: Rc::clone(k),
|
||||
})?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 获取缠K序列(
|
||||
&self,
|
||||
观察员: &Bound<'_, crate::business_py::观察者Py>,
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let obs_ref = 观察员.borrow();
|
||||
let observer_inner = obs_ref.obs();
|
||||
let result = self.inner.获取缠K序列(&observer_inner.缠论K线序列);
|
||||
let list = pyo3::types::PyList::empty(观察员.py());
|
||||
for k in &result {
|
||||
list.append(缠论K线Py::from_rc(Rc::clone(k)))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
fn 获取_武(_cls: &Bound<'_, PyType>, 实线: &Bound<'_, Self>) -> 分型Py {
|
||||
分型Py {
|
||||
inner: 实线.borrow().inner.获取_武(),
|
||||
}
|
||||
}
|
||||
|
||||
fn 获取数据文本(&self) -> String {
|
||||
self.inner.获取数据文本()
|
||||
}
|
||||
@@ -458,6 +493,17 @@ impl 虚线Py {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
// ---- 静态工厂方法 ----
|
||||
|
||||
#[classmethod]
|
||||
@@ -547,7 +593,7 @@ impl 虚线Py {
|
||||
) -> f64 {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::计算MACD柱子均值(
|
||||
&rc_list,
|
||||
@@ -564,7 +610,7 @@ impl 虚线Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::武之全量MACD均值(
|
||||
&rc_list,
|
||||
@@ -581,7 +627,7 @@ impl 虚线Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::武之MACD均值(&rc_list, &实线.borrow().inner)
|
||||
}
|
||||
@@ -595,7 +641,7 @@ impl 虚线Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::武之MACD极值(&rc_list, &实线.borrow().inner)
|
||||
}
|
||||
@@ -609,7 +655,7 @@ impl 虚线Py {
|
||||
) -> Option<f64> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::计算MACD柱子均值_阴(
|
||||
&rc_list,
|
||||
@@ -626,7 +672,7 @@ impl 虚线Py {
|
||||
) -> Option<f64> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::计算MACD柱子均值_阳(
|
||||
&rc_list,
|
||||
@@ -643,7 +689,7 @@ impl 虚线Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::武之MACD均值_阴(&rc_list, &实线.borrow().inner)
|
||||
}
|
||||
@@ -657,7 +703,7 @@ impl 虚线Py {
|
||||
) -> bool {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::武之MACD均值_阳(&rc_list, &实线.borrow().inner)
|
||||
}
|
||||
@@ -671,7 +717,7 @@ impl 虚线Py {
|
||||
) -> [bool; 3] {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::计算K线序列MACD趋向背驰(
|
||||
&rc_list,
|
||||
@@ -687,7 +733,7 @@ impl 虚线Py {
|
||||
) -> Vec<Vec<f64>> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = k线序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::计算MACD柱子分段(&rc_list)
|
||||
}
|
||||
@@ -713,12 +759,37 @@ impl 虚线Py {
|
||||
最大间隔: usize,
|
||||
最少交叉数: usize,
|
||||
py: Python<'_>,
|
||||
) -> HashMap<String, String> {
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let rc_list: Vec<Rc<chanlun::kline::bar::K线>> = 普K序列
|
||||
.iter()
|
||||
.map(|k| Rc::new(k.bind(py).borrow().inner.clone()))
|
||||
.map(|k| k.bind(py).borrow().inner.clone())
|
||||
.collect();
|
||||
chanlun::structure::dash_line::虚线::统计MACD行为(&rc_list, 最大间隔, 最少交叉数)
|
||||
let result =
|
||||
chanlun::structure::dash_line::虚线::统计MACD行为(&rc_list, 最大间隔, 最少交叉数);
|
||||
let dict = pyo3::types::PyDict::new(py);
|
||||
dict.set_item("DIF上穿0", result.DIF上穿0)?;
|
||||
dict.set_item("DIF下穿0", result.DIF下穿0)?;
|
||||
dict.set_item("DEA上穿0", result.DEA上穿0)?;
|
||||
dict.set_item("DEA下穿0", result.DEA下穿0)?;
|
||||
dict.set_item("金叉次数", result.金叉次数)?;
|
||||
dict.set_item("死叉次数", result.死叉次数)?;
|
||||
let 密集区: Vec<Py<PyAny>> = result
|
||||
.密集交叉区域
|
||||
.iter()
|
||||
.map(|(a, b, c)| {
|
||||
let tup = pyo3::types::PyTuple::new(
|
||||
py,
|
||||
[
|
||||
(*a).into_pyobject(py)?.into_any().unbind(),
|
||||
(*b).into_pyobject(py)?.into_any().unbind(),
|
||||
(*c).into_pyobject(py)?.into_any().unbind(),
|
||||
],
|
||||
)?;
|
||||
Ok(tup.into_any().unbind())
|
||||
})
|
||||
.collect::<PyResult<Vec<_>>>()?;
|
||||
dict.set_item("密集交叉区域", 密集区)?;
|
||||
Ok(dict.into())
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -821,6 +892,53 @@ impl 线段特征Py {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
fn __len__(&self) -> usize {
|
||||
self.inner.元素.len()
|
||||
}
|
||||
|
||||
fn __getitem__(&self, index: isize, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let len = self.inner.元素.len() as isize;
|
||||
let idx = if index < 0 { index + len } else { index };
|
||||
if idx < 0 || idx >= len {
|
||||
return Err(pyo3::exceptions::PyIndexError::new_err(format!(
|
||||
"线段特征 index {index} out of range (len={len})"
|
||||
)));
|
||||
}
|
||||
let dash = &self.inner.元素[idx as usize];
|
||||
let obj: Py<PyAny> = Py::new(
|
||||
py,
|
||||
虚线Py {
|
||||
inner: Rc::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.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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
|
||||
// ---- instance methods ----
|
||||
|
||||
#[getter]
|
||||
@@ -1004,6 +1122,17 @@ impl 特征分型Py {
|
||||
fn __repr__(&self) -> String {
|
||||
self.__str__()
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn __hash__(&self) -> u64 {
|
||||
Rc::as_ptr(&self.inner) as u64
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
|
||||
@@ -135,27 +135,22 @@ impl 相对方向Py {
|
||||
}
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 是否向上(&self) -> bool {
|
||||
self.inner.是否向上()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 是否向下(&self) -> bool {
|
||||
self.inner.是否向下()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 是否包含(&self) -> bool {
|
||||
self.inner.是否包含()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 是否缺口(&self) -> bool {
|
||||
self.inner.是否缺口()
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 是否衔接(&self) -> bool {
|
||||
self.inner.是否衔接()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user