1. thread_local! 导致跨线程缓存不可见(主要问题)
kline_py.rs 中 BSP_CACHE、KLINE_IDENTITY、BAR_IDENTITY 使用了 thread_local!。主线程调用 识别买卖点() → 买卖点信息.add() 写入的是主线程的 PySet,backtrader 策略线程读取的是自己线程独立的空 PySet。 修复:将三个缓存从 thread_local! 改为全局 static + std::sync::LazyLock<RwLock<HashMap<...>>> 影响分析 这些身份缓存的影响与 KLINE_IDENTITY/BAR_IDENTITY 不同——它们只影响 Python 对象身份(is 比较),不直接影响数据内容(因为 Rust 数据通过 Arc 共享,读写都是同一份)。 具体后果: - 不同线程访问同一个 Rust Arc 会得到不同的 Python wrapper 对象 - a is b 跨线程比较返回 False,哪怕它们包装同一个底层 Rust 对象 - 每个线程维护一份独立缓存,内存浪费(不过 wrapper 很小)
This commit is contained in:
@@ -31,26 +31,28 @@ 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());
|
||||
}
|
||||
// 使用全局 static 而非 thread_local!,保证跨线程对象标识一致性
|
||||
static HUB_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<中枢Py>>>> =
|
||||
std::sync::LazyLock::new(|| 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)))
|
||||
if let Some(cached) = HUB_IDENTITY
|
||||
.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);
|
||||
});
|
||||
HUB_IDENTITY
|
||||
.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));
|
||||
});
|
||||
HUB_IDENTITY.write().unwrap().insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -362,13 +364,13 @@ impl 笔Py {
|
||||
笔序列: Vec<Py<虚线Py>>,
|
||||
文: &Bound<'_, 分型Py>,
|
||||
py: Python<'_>,
|
||||
) -> Option<虚线Py> {
|
||||
) -> Option<Py<虚线Py>> {
|
||||
let bi_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 笔序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::以文会友(&bi_list, &文.borrow().inner)
|
||||
.map(|inner| 虚线Py { inner })
|
||||
.map(|inner| dashed_to_py(py, inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -378,13 +380,13 @@ impl 笔Py {
|
||||
笔序列: Vec<Py<虚线Py>>,
|
||||
武: &Bound<'_, 分型Py>,
|
||||
py: Python<'_>,
|
||||
) -> Option<虚线Py> {
|
||||
) -> Option<Py<虚线Py>> {
|
||||
let bi_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 笔序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::以武会友(&bi_list, &武.borrow().inner)
|
||||
.map(|inner| 虚线Py { inner })
|
||||
.map(|inner| dashed_to_py(py, inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -396,13 +398,13 @@ impl 笔Py {
|
||||
缠K: &Bound<'_, crate::kline_py::缠论K线Py>,
|
||||
偏移: i64,
|
||||
py: Python<'_>,
|
||||
) -> Option<虚线Py> {
|
||||
) -> Option<Py<虚线Py>> {
|
||||
let bi_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 笔序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::bi::笔::根据缠K找笔(&bi_list, &缠K.borrow().inner, 偏移)
|
||||
.map(|inner| 虚线Py { inner })
|
||||
.map(|inner| dashed_to_py(py, inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -501,7 +503,7 @@ impl 笔Py {
|
||||
) -> bool {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::bi::笔::自检(&筆.borrow().inner, &*obs_ref)
|
||||
chanlun::algorithm::bi::笔::自检(&筆.borrow().inner, &obs_ref)
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -510,12 +512,13 @@ impl 笔Py {
|
||||
_cls: &Bound<'_, PyType>,
|
||||
筆: &Bound<'_, 虚线Py>,
|
||||
观察员: &Bound<'_, 观察者Py>,
|
||||
) -> Vec<虚线Py> {
|
||||
py: Python<'_>,
|
||||
) -> Vec<Py<虚线Py>> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::bi::笔::获取所有停顿位置(&筆.borrow().inner, &*obs_ref)
|
||||
chanlun::algorithm::bi::笔::获取所有停顿位置(&筆.borrow().inner, &obs_ref)
|
||||
.into_iter()
|
||||
.map(|d| 虚线Py { inner: Arc::new(d) })
|
||||
.map(|d| dashed_to_py(py, Arc::new(d)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -529,7 +532,7 @@ impl 笔Py {
|
||||
) -> Vec<Py<缠论K线Py>> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::bi::笔::是否背驰过(&当前筆.borrow().inner, &*obs_ref)
|
||||
chanlun::algorithm::bi::笔::是否背驰过(&当前筆.borrow().inner, &obs_ref)
|
||||
.into_iter()
|
||||
.map(|ck| chan_kline_to_py(py, ck))
|
||||
.collect()
|
||||
@@ -569,8 +572,8 @@ impl 线段Py {
|
||||
筆: &Bound<'_, 虚线Py>,
|
||||
) -> PyResult<()> {
|
||||
let bi_rc = Arc::clone(&筆.borrow().inner);
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::添加虚线(&mut ref_mut.inner, bi_rc);
|
||||
let ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::添加虚线(&ref_mut.inner, bi_rc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -582,9 +585,9 @@ impl 线段Py {
|
||||
武: &Bound<'_, 分型Py>,
|
||||
行号: u32,
|
||||
) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::武斗(
|
||||
&mut ref_mut.inner,
|
||||
&ref_mut.inner,
|
||||
&Arc::clone(&武.borrow().inner),
|
||||
行号,
|
||||
);
|
||||
@@ -594,8 +597,8 @@ impl 线段Py {
|
||||
#[classmethod]
|
||||
/// 武终
|
||||
fn 武终(_cls: &Bound<'_, PyType>, 段: &Bound<'_, 虚线Py>, 行号: u32) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::武终(&mut ref_mut.inner, 行号);
|
||||
let ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::武终(&ref_mut.inner, 行号);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -607,12 +610,12 @@ impl 线段Py {
|
||||
序列: Vec<Py<虚线Py>>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
let rc_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::segment::线段::验证序列(&mut ref_mut.inner, &rc_list);
|
||||
chanlun::algorithm::segment::线段::验证序列(&ref_mut.inner, &rc_list);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -624,12 +627,12 @@ impl 线段Py {
|
||||
序列: Vec<Py<虚线Py>>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
let rc_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
.collect();
|
||||
chanlun::algorithm::segment::线段::序列重置(&mut ref_mut.inner, &rc_list);
|
||||
chanlun::algorithm::segment::线段::序列重置(&ref_mut.inner, &rc_list);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -692,7 +695,7 @@ impl 线段Py {
|
||||
let seq: Vec<Option<Arc<chanlun::structure::segment_feat::线段特征>>> = if 序列.is_none()
|
||||
{
|
||||
vec![]
|
||||
} else if let Ok(list) = 序列.downcast::<pyo3::types::PyList>() {
|
||||
} else if let Ok(list) = 序列.cast::<pyo3::types::PyList>() {
|
||||
let mut result = Vec::with_capacity(list.len());
|
||||
for item in list.iter() {
|
||||
if item.is_none() {
|
||||
@@ -708,8 +711,8 @@ impl 线段Py {
|
||||
"序列 必须是 list 或 None",
|
||||
));
|
||||
};
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::设置特征序列(&mut ref_mut.inner, seq, 行号);
|
||||
let ref_mut = 段.borrow_mut();
|
||||
chanlun::algorithm::segment::线段::设置特征序列(&ref_mut.inner, seq, 行号);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -721,22 +724,26 @@ impl 线段Py {
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
chanlun::algorithm::segment::线段::刷新特征序列(&mut ref_mut.inner, &config);
|
||||
chanlun::algorithm::segment::线段::刷新特征序列(&ref_mut.inner, &config);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
/// 查找贯穿伤
|
||||
fn 查找贯穿伤(_cls: &Bound<'_, PyType>, 段: &Bound<'_, 虚线Py>) -> Option<虚线Py> {
|
||||
fn 查找贯穿伤(
|
||||
_cls: &Bound<'_, PyType>, 段: &Bound<'_, 虚线Py>
|
||||
) -> Option<Py<虚线Py>> {
|
||||
let py = _cls.py();
|
||||
chanlun::algorithm::segment::线段::查找贯穿伤(&段.borrow().inner)
|
||||
.map(|inner| 虚线Py { inner })
|
||||
.map(|inner| dashed_to_py(py, inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
#[pyo3(signature = (段, 所属中枢 = None))]
|
||||
/// 将线段基础序列分割为前/后/第三买卖/贯穿伤四部分
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn 分割序列(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
段: &Bound<'_, 虚线Py>,
|
||||
@@ -761,19 +768,10 @@ impl 线段Py {
|
||||
} else {
|
||||
chanlun::algorithm::segment::线段::分割序列(&borrowed.inner, None)
|
||||
};
|
||||
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 })?);
|
||||
}
|
||||
Ok(result)
|
||||
let wrap = |v: Vec<Arc<chanlun::structure::dash_line::虚线>>| -> Vec<Py<虚线Py>> {
|
||||
v.into_iter().map(|x| dashed_to_py(py, x)).collect()
|
||||
};
|
||||
Ok((
|
||||
wrap(a)?,
|
||||
wrap(b)?,
|
||||
wrap(c)?,
|
||||
d.map(|x| Py::new(py, 虚线Py { inner: x })).transpose()?,
|
||||
))
|
||||
Ok((wrap(a), wrap(b), wrap(c), d.map(|x| dashed_to_py(py, x))))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -784,9 +782,9 @@ impl 线段Py {
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<()> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
chanlun::algorithm::segment::线段::刷新(&mut ref_mut.inner, &config);
|
||||
chanlun::algorithm::segment::线段::刷新(&ref_mut.inner, &config);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -798,16 +796,14 @@ impl 线段Py {
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<(Py<PyAny>, Py<PyAny>, Py<PyAny>)> {
|
||||
let mut ref_mut = 段.borrow_mut();
|
||||
let ref_mut = 段.borrow_mut();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
let (a, b, c) = chanlun::algorithm::segment::线段::获取内部中枢序列(
|
||||
&mut ref_mut.inner,
|
||||
&config,
|
||||
);
|
||||
let (a, b, c) =
|
||||
chanlun::algorithm::segment::线段::获取内部中枢序列(&ref_mut.inner, &config);
|
||||
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 })?)?;
|
||||
list.append(hub_to_py(py, h))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
};
|
||||
@@ -818,7 +814,7 @@ impl 线段Py {
|
||||
/// 内部方法:向线段序列添加新线段
|
||||
fn _添加线段(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
线段序列: &Bound<'_, PyAny>,
|
||||
_线段序列: &Bound<'_, PyAny>,
|
||||
待添加线段: &Bound<'_, 虚线Py>,
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
行号: String,
|
||||
@@ -839,12 +835,12 @@ impl 线段Py {
|
||||
/// 内部方法:从线段序列弹出最后一个线段
|
||||
fn _弹出线段(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
线段序列: &Bound<'_, PyAny>,
|
||||
_线段序列: &Bound<'_, PyAny>,
|
||||
待弹出线段: &Bound<'_, 虚线Py>,
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
行号: String,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<Option<虚线Py>> {
|
||||
) -> PyResult<Option<Py<虚线Py>>> {
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::虚线>> = vec![];
|
||||
let result = chanlun::algorithm::segment::线段::_弹出线段(
|
||||
@@ -853,7 +849,7 @@ impl 线段Py {
|
||||
&config,
|
||||
行号,
|
||||
);
|
||||
Ok(result.map(|inner| 虚线Py { inner }))
|
||||
Ok(result.map(|inner| dashed_to_py(py, inner)))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -1007,7 +1003,7 @@ impl 线段Py {
|
||||
待弹出线段: &Bound<'_, 虚线Py>,
|
||||
行号: u32,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<Option<虚线Py>> {
|
||||
) -> PyResult<Option<Py<虚线Py>>> {
|
||||
let mut seg_seq: Vec<Arc<chanlun::structure::dash_line::虚线>> = 线段序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
@@ -1017,7 +1013,7 @@ impl 线段Py {
|
||||
&Arc::clone(&待弹出线段.borrow().inner),
|
||||
行号,
|
||||
);
|
||||
Ok(result.map(|inner| 虚线Py { inner }))
|
||||
Ok(result.map(|inner| dashed_to_py(py, inner)))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -1053,7 +1049,7 @@ impl 线段Py {
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::segment::线段::判断线段内部是否背驰(
|
||||
&当前段.borrow().inner,
|
||||
&*obs_ref,
|
||||
&obs_ref,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1063,12 +1059,13 @@ impl 线段Py {
|
||||
_cls: &Bound<'_, PyType>,
|
||||
段: &Bound<'_, 虚线Py>,
|
||||
观察员: &Bound<'_, 观察者Py>,
|
||||
) -> Vec<虚线Py> {
|
||||
py: Python<'_>,
|
||||
) -> Vec<Py<虚线Py>> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::segment::线段::获取所有停顿位置(&段.borrow().inner, &*obs_ref)
|
||||
chanlun::algorithm::segment::线段::获取所有停顿位置(&段.borrow().inner, &obs_ref)
|
||||
.into_iter()
|
||||
.map(|d| 虚线Py { inner: Arc::new(d) })
|
||||
.map(|d| dashed_to_py(py, Arc::new(d)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -1082,7 +1079,7 @@ impl 线段Py {
|
||||
) -> Vec<Py<缠论K线Py>> {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::algorithm::segment::线段::是否背驰过(&当前段.borrow().inner, &*obs_ref)
|
||||
chanlun::algorithm::segment::线段::是否背驰过(&当前段.borrow().inner, &obs_ref)
|
||||
.into_iter()
|
||||
.map(|ck| chan_kline_to_py(py, ck))
|
||||
.collect()
|
||||
@@ -1264,7 +1261,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 { inner: d })?;
|
||||
list.append(dashed_to_py(py, d))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
@@ -1381,16 +1378,15 @@ impl 中枢Py {
|
||||
右: &Bound<'_, 虚线Py>,
|
||||
级别: i64,
|
||||
标识: &str,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(chanlun::algorithm::hub::中枢::创建(
|
||||
Arc::clone(&左.borrow().inner),
|
||||
Arc::clone(&中.borrow().inner),
|
||||
Arc::clone(&右.borrow().inner),
|
||||
级别,
|
||||
标识,
|
||||
)),
|
||||
}
|
||||
) -> Py<中枢Py> {
|
||||
let inner = Arc::new(chanlun::algorithm::hub::中枢::创建(
|
||||
Arc::clone(&左.borrow().inner),
|
||||
Arc::clone(&中.borrow().inner),
|
||||
Arc::clone(&右.borrow().inner),
|
||||
级别,
|
||||
标识,
|
||||
));
|
||||
hub_to_py(_cls.py(), inner)
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -1401,7 +1397,7 @@ impl 中枢Py {
|
||||
起始方向: &Bound<'_, 相对方向Py>,
|
||||
标识: &str,
|
||||
py: Python<'_>,
|
||||
) -> Option<Self> {
|
||||
) -> Option<Py<中枢Py>> {
|
||||
let rc_list: Vec<Arc<chanlun::structure::dash_line::虚线>> = 虚线序列
|
||||
.iter()
|
||||
.map(|d| Arc::clone(&d.bind(py).borrow().inner))
|
||||
@@ -1411,7 +1407,7 @@ impl 中枢Py {
|
||||
起始方向.borrow().inner,
|
||||
标识,
|
||||
)
|
||||
.map(|inner| Self { inner })
|
||||
.map(|inner| hub_to_py(py, inner))
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
@@ -1421,8 +1417,9 @@ impl 中枢Py {
|
||||
中枢序列: &Bound<'_, PyAny>,
|
||||
待添加中枢: &Bound<'_, Self>,
|
||||
) -> PyResult<()> {
|
||||
let py = 中枢序列.py();
|
||||
let inner = Arc::clone(&待添加中枢.borrow().inner);
|
||||
let wrapper = Py::new(中枢序列.py(), Self { inner })?;
|
||||
let wrapper = hub_to_py(py, inner);
|
||||
中枢序列.call_method1("append", (wrapper,))?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1432,7 +1429,7 @@ impl 中枢Py {
|
||||
fn 从中枢序列尾部弹出(
|
||||
_cls: &Bound<'_, PyType>,
|
||||
中枢序列: &Bound<'_, PyAny>,
|
||||
待弹出中枢: &Bound<'_, Self>,
|
||||
_待弹出中枢: &Bound<'_, Self>,
|
||||
) -> PyResult<Option<Self>> {
|
||||
let result = 中枢序列.call_method1("pop", ())?;
|
||||
if result.is_none() {
|
||||
|
||||
@@ -28,14 +28,12 @@ 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 crate::structure_py::{dashed_to_py, fractal_to_py, 分型Py};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::algorithm_py::中枢Py;
|
||||
use crate::config_py::缠论配置Py;
|
||||
use crate::kline_py::{缠论K线Py, K线Py};
|
||||
use crate::structure_py::{分型Py, 虚线Py};
|
||||
use crate::types_py::买卖点类型Py;
|
||||
|
||||
// ========== 基础买卖点 ==========
|
||||
@@ -100,10 +98,8 @@ impl 基础买卖点Py {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 买卖点分型(&self) -> 分型Py {
|
||||
分型Py {
|
||||
inner: Arc::clone(&self.inner.买卖点分型),
|
||||
}
|
||||
fn 买卖点分型(&self, py: Python<'_>) -> Py<分型Py> {
|
||||
fractal_to_py(py, Arc::clone(&self.inner.买卖点分型))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -576,13 +572,13 @@ impl 观察者Py {
|
||||
let obs = me.obs();
|
||||
(obs.符号.clone(), obs.周期)
|
||||
};
|
||||
let kline = K线Py {
|
||||
inner: Arc::new(chanlun::kline::bar::K线::创建普K(
|
||||
let kline = bar_to_py(
|
||||
slf.py(),
|
||||
Arc::new(chanlun::kline::bar::K线::创建普K(
|
||||
&符号, 时间戳, 开, 高, 低, 收, 量, 0, 周期,
|
||||
)),
|
||||
};
|
||||
let kline_py = Py::new(slf.py(), kline)?;
|
||||
slf.call_method1("增加原始K线", (kline_py,))?;
|
||||
);
|
||||
slf.call_method1("增加原始K线", (kline,))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -860,11 +856,11 @@ impl K线合成器Py {
|
||||
&mut self,
|
||||
普K: &Bound<'_, K线Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<Vec<(i64, K线Py)>> {
|
||||
) -> PyResult<Vec<(i64, Py<K线Py>)>> {
|
||||
let results = self.inner.投喂K线((*普K.borrow().inner).clone());
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|(周期, k)| (周期, K线Py { inner: Arc::new(k) }))
|
||||
.map(|(周期, k)| (周期, bar_to_py(py, Arc::new(k))))
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -877,7 +873,8 @@ impl K线合成器Py {
|
||||
低: f64,
|
||||
收: f64,
|
||||
量: f64,
|
||||
) -> Vec<(i64, K线Py)> {
|
||||
py: Python<'_>,
|
||||
) -> Vec<(i64, Py<K线Py>)> {
|
||||
let min_cycle = self.inner.周期组.iter().copied().min().unwrap_or(1);
|
||||
let k = chanlun::kline::bar::K线::创建普K(
|
||||
&self.inner.标识,
|
||||
@@ -893,22 +890,15 @@ impl K线合成器Py {
|
||||
let results = self.inner.投喂K线(k);
|
||||
results
|
||||
.into_iter()
|
||||
.map(|(周期, k2)| {
|
||||
(
|
||||
周期,
|
||||
K线Py {
|
||||
inner: Arc::new(k2),
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|(周期, k2)| (周期, bar_to_py(py, Arc::new(k2))))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 获取指定周期当前正在合成的K线
|
||||
fn 获取当前K线(&self, 周期: i64) -> Option<K线Py> {
|
||||
self.inner.获取当前K线(周期).map(|k| K线Py {
|
||||
inner: Arc::new(k.clone()),
|
||||
})
|
||||
fn 获取当前K线(&self, 周期: i64, py: Python<'_>) -> Option<Py<K线Py>> {
|
||||
self.inner
|
||||
.获取当前K线(周期)
|
||||
.map(|k| bar_to_py(py, Arc::new(k.clone())))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -957,7 +947,7 @@ impl 立体分析器Py {
|
||||
};
|
||||
let cfg_map: Option<HashMap<i64, chanlun::config::缠论配置>> = match 配置组 {
|
||||
Some(dict_any) => {
|
||||
let dict = dict_any.downcast::<pyo3::types::PyDict>()?;
|
||||
let dict = dict_any.cast::<pyo3::types::PyDict>()?;
|
||||
let mut map = HashMap::new();
|
||||
for (key, value) in dict.iter() {
|
||||
let period: i64 = key.extract()?;
|
||||
|
||||
@@ -239,7 +239,7 @@ impl 缠论配置Py {
|
||||
) -> PyResult<Py<PyDict>> {
|
||||
let py = 原始字典.py();
|
||||
let result = PyDict::new(py);
|
||||
if let Ok(default_dict) = 默认配置.downcast::<PyDict>() {
|
||||
if let Ok(default_dict) = 默认配置.cast::<PyDict>() {
|
||||
for (key, value) in default_dict.iter() {
|
||||
if 原始字典.contains(&key)? {
|
||||
result.set_item(key.clone(), 原始字典.get_item(&key)?)?;
|
||||
@@ -252,6 +252,7 @@ impl 缠论配置Py {
|
||||
}
|
||||
|
||||
/// 比较当前配置与另一个配置的差异
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn 对比(
|
||||
&self,
|
||||
py: Python<'_>,
|
||||
@@ -290,7 +291,10 @@ impl 缠论配置Py {
|
||||
Ok(Self { fields })
|
||||
}
|
||||
|
||||
pub(crate) fn to_rust_config(&self, py: Python<'_>) -> PyResult<chanlun::config::缠论配置> {
|
||||
pub(crate) fn to_rust_config(
|
||||
&self,
|
||||
_py: Python<'_>,
|
||||
) -> PyResult<chanlun::config::缠论配置> {
|
||||
dict_to_rust_config(&self.fields)
|
||||
}
|
||||
|
||||
|
||||
+40
-31
@@ -355,17 +355,18 @@ impl 缠论K线Py {
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// 对象标识缓存:Rc 地址 → 规范 Python 对象
|
||||
/// 确保同一底层 Rc 指针在 Python 侧始终映射到同一 PyObject
|
||||
/// 对象标识缓存:Arc 地址 → 规范 Python 对象
|
||||
/// 确保同一底层 Arc 指针在 Python 侧始终映射到同一 PyObject
|
||||
/// 使用全局 static 而非 thread_local!,保证跨线程对象标识和买卖点信息一致性
|
||||
static BAR_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<K线Py>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
static BAR_IDENTITY: RwLock<HashMap<usize, Py<K线Py>>> = RwLock::new(HashMap::new());
|
||||
static KLINE_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<缠论K线Py>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
static KLINE_IDENTITY: RwLock<HashMap<usize, Py<缠论K线Py>>> = RwLock::new(HashMap::new());
|
||||
|
||||
/// 买卖点信息缓存 — 按 Arc 指针全局共享,确保所有 wrapper 看到同一 PySet
|
||||
static BSP_CACHE: RwLock<HashMap<usize, Py<pyo3::types::PySet>>> = RwLock::new(HashMap::new());
|
||||
}
|
||||
/// 买卖点信息缓存 — 按 Arc 指针全局共享,确保所有 wrapper 看到同一 PySet
|
||||
static BSP_CACHE: std::sync::LazyLock<RwLock<HashMap<usize, Py<pyo3::types::PySet>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
/// 将 Rc<K线> 转为 Py<K线Py>,确保同一 Rc 地址总是返回同一 Python 对象
|
||||
pub(crate) fn bar_to_py(
|
||||
@@ -373,15 +374,16 @@ pub(crate) fn bar_to_py(
|
||||
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)))
|
||||
if let Some(cached) = BAR_IDENTITY
|
||||
.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));
|
||||
});
|
||||
BAR_IDENTITY.write().unwrap().insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -391,15 +393,19 @@ pub(crate) fn chan_kline_to_py(
|
||||
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)))
|
||||
if let Some(cached) = KLINE_IDENTITY
|
||||
.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));
|
||||
});
|
||||
KLINE_IDENTITY
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -534,17 +540,18 @@ impl 缠论K线Py {
|
||||
// 复制买卖点信息到镜像
|
||||
let src_key = Arc::as_ptr(&self.inner) as usize;
|
||||
let dst_key = Arc::as_ptr(&mirror.inner) as usize;
|
||||
let cached_src =
|
||||
BSP_CACHE.with(|c| c.read().unwrap().get(&src_key).map(|p| p.clone_ref(py)));
|
||||
let cached_src = BSP_CACHE
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&src_key)
|
||||
.map(|p| p.clone_ref(py));
|
||||
if let Some(cached_src) = cached_src {
|
||||
if let Ok(new_set) = pyo3::types::PySet::empty(py) {
|
||||
for item in cached_src.bind(py).iter() {
|
||||
let _ = new_set.add(item);
|
||||
}
|
||||
let py_set: Py<pyo3::types::PySet> = new_set.into();
|
||||
BSP_CACHE.with(|c| {
|
||||
c.write().unwrap().insert(dst_key, py_set);
|
||||
});
|
||||
BSP_CACHE.write().unwrap().insert(dst_key, py_set);
|
||||
}
|
||||
}
|
||||
mirror
|
||||
@@ -572,18 +579,20 @@ impl 缠论K线Py {
|
||||
fn 买卖点信息(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let key = Arc::as_ptr(&self.inner) as usize;
|
||||
// 检查全局缓存
|
||||
let cached = BSP_CACHE.with(|c| c.read().unwrap().get(&key).map(|p| p.clone_ref(py)));
|
||||
let cached = BSP_CACHE.read().unwrap().get(&key).map(|p| p.clone_ref(py));
|
||||
if let Some(set) = cached {
|
||||
return Ok(set.into_any());
|
||||
}
|
||||
// 创建新的 PySet 并存入全局缓存
|
||||
let set = pyo3::types::PySet::empty(py)?;
|
||||
BSP_CACHE.with(|c| {
|
||||
c.write().unwrap().insert(key, set.into());
|
||||
});
|
||||
BSP_CACHE.write().unwrap().insert(key, set.into());
|
||||
// 重新读取并返回(无法从 insert 获取 Py 引用,需要重新读)
|
||||
Ok(BSP_CACHE
|
||||
.with(|c| c.read().unwrap().get(&key).unwrap().clone_ref(py))
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&key)
|
||||
.unwrap()
|
||||
.clone_ref(py)
|
||||
.into_any())
|
||||
}
|
||||
|
||||
@@ -642,13 +651,13 @@ impl 缠论K线Py {
|
||||
配置: &Bound<'_, 缠论配置Py>,
|
||||
py: Python<'_>,
|
||||
) -> PyResult<(Option<Py<Self>>, Option<String>)> {
|
||||
let mut ck_inner = (*当前缠K.borrow().inner).clone();
|
||||
let ck_inner = (*当前缠K.borrow().inner).clone();
|
||||
let config = 配置.borrow().to_rust_config(py)?;
|
||||
let prev_ref = 之前缠K.map(|prev| prev.borrow());
|
||||
let prev_inner = prev_ref.as_ref().map(|r| r.inner.as_ref());
|
||||
let (result, mode) = chanlun::kline::chan_kline::缠论K线::兼并(
|
||||
prev_inner,
|
||||
&mut ck_inner,
|
||||
&ck_inner,
|
||||
&当前普K.borrow().inner,
|
||||
&config,
|
||||
);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#![allow(non_snake_case, clippy::too_many_arguments)]
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
||||
@@ -29,37 +29,45 @@ use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use crate::algorithm_py::{hub_to_py, 中枢Py};
|
||||
use crate::algorithm_py::hub_to_py;
|
||||
use crate::config_py::缠论配置Py;
|
||||
use crate::kline_py::{缠论K线Py, K线Py};
|
||||
use crate::kline_py::{bar_to_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());
|
||||
}
|
||||
// 使用全局 static 而非 thread_local!,保证跨线程对象标识一致性
|
||||
static FRACTAL_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<分型Py>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
static DASHED_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<虚线Py>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
static SEGFEAT_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<线段特征Py>>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
static FEATFRAC_IDENTITY: std::sync::LazyLock<RwLock<HashMap<usize, Py<特征分型Py>>>> =
|
||||
std::sync::LazyLock::new(|| 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)))
|
||||
if let Some(cached) = FRACTAL_IDENTITY
|
||||
.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);
|
||||
});
|
||||
FRACTAL_IDENTITY
|
||||
.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));
|
||||
});
|
||||
FRACTAL_IDENTITY
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -68,18 +76,23 @@ pub(crate) fn dashed_to_py(
|
||||
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)))
|
||||
if let Some(cached) = DASHED_IDENTITY
|
||||
.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);
|
||||
});
|
||||
DASHED_IDENTITY
|
||||
.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));
|
||||
});
|
||||
DASHED_IDENTITY
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -88,18 +101,23 @@ pub(crate) fn segfeat_to_py(
|
||||
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)))
|
||||
if let Some(cached) = SEGFEAT_IDENTITY
|
||||
.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);
|
||||
});
|
||||
SEGFEAT_IDENTITY
|
||||
.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));
|
||||
});
|
||||
SEGFEAT_IDENTITY
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
|
||||
@@ -108,18 +126,23 @@ pub(crate) fn featfrac_to_py(
|
||||
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)))
|
||||
if let Some(cached) = FEATFRAC_IDENTITY
|
||||
.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);
|
||||
});
|
||||
FEATFRAC_IDENTITY
|
||||
.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));
|
||||
});
|
||||
FEATFRAC_IDENTITY
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(key, obj.clone_ref(py));
|
||||
obj
|
||||
}
|
||||
use crate::types_py::{分型结构Py, 相对方向Py, 缺口Py};
|
||||
@@ -469,15 +492,13 @@ impl 虚线Py {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn 前一结束位置(&self) -> Option<Self> {
|
||||
fn 前一结束位置(&self, py: Python<'_>) -> Option<Py<虚线Py>> {
|
||||
self.inner
|
||||
.前一结束位置
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|d| Self {
|
||||
inner: Arc::clone(d),
|
||||
})
|
||||
.map(|d| dashed_to_py(py, Arc::clone(d)))
|
||||
}
|
||||
|
||||
// ---- 序列 getters ----
|
||||
@@ -486,12 +507,7 @@ impl 虚线Py {
|
||||
fn 基础序列(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for d in self.inner.基础序列.read().unwrap().iter() {
|
||||
list.append(Py::new(
|
||||
py,
|
||||
Self {
|
||||
inner: Arc::clone(d),
|
||||
},
|
||||
)?)?;
|
||||
list.append(dashed_to_py(py, Arc::clone(d)))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
@@ -530,12 +546,7 @@ impl 虚线Py {
|
||||
fn 笔序列(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for d in self.inner.基础序列.read().unwrap().iter() {
|
||||
list.append(Py::new(
|
||||
py,
|
||||
Self {
|
||||
inner: Arc::clone(d),
|
||||
},
|
||||
)?)?;
|
||||
list.append(dashed_to_py(py, Arc::clone(d)))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
@@ -582,11 +593,10 @@ impl 虚线Py {
|
||||
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());
|
||||
let py = 观察员.py();
|
||||
let list = pyo3::types::PyList::empty(py);
|
||||
for k in &result {
|
||||
list.append(K线Py {
|
||||
inner: Arc::clone(k),
|
||||
})?;
|
||||
list.append(bar_to_py(py, Arc::clone(k)))?;
|
||||
}
|
||||
Ok(list.into())
|
||||
}
|
||||
@@ -973,7 +983,7 @@ impl 虚线Py {
|
||||
) -> (bool, String) {
|
||||
let obs = 观察员.borrow();
|
||||
let obs_ref = obs.obs();
|
||||
chanlun::structure::dash_line::虚线::买卖意义(&实线.borrow().inner, &*obs_ref)
|
||||
chanlun::structure::dash_line::虚线::买卖意义(&实线.borrow().inner, &obs_ref)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,7 +1158,7 @@ impl 线段特征Py {
|
||||
let inner = Arc::make_mut(&mut self.inner);
|
||||
inner
|
||||
.添加(Arc::clone(&待添加虚线.borrow().inner))
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
|
||||
.map_err(pyo3::exceptions::PyValueError::new_err)
|
||||
}
|
||||
|
||||
/// :param 待删除虚线: 待删除的虚线
|
||||
@@ -1156,7 +1166,7 @@ impl 线段特征Py {
|
||||
let inner = Arc::make_mut(&mut self.inner);
|
||||
inner
|
||||
.删除(&Arc::clone(&待删除虚线.borrow().inner))
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
|
||||
.map_err(pyo3::exceptions::PyValueError::new_err)
|
||||
}
|
||||
|
||||
// ---- classmethods ----
|
||||
|
||||
@@ -545,7 +545,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
// 买卖点类型 class attributes (singleton instances)
|
||||
let py = m.py();
|
||||
let bsp_class = m.getattr("买卖点类型")?;
|
||||
let bsp_class = bsp_class.downcast_into::<PyType>()?;
|
||||
let bsp_class = bsp_class.cast_into::<PyType>()?;
|
||||
|
||||
let variants: &[(&str, chanlun::types::买卖点类型)] = &[
|
||||
("一买", chanlun::types::买卖点类型::一买),
|
||||
@@ -568,7 +568,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
("T3B卖", chanlun::types::买卖点类型::T3B卖),
|
||||
];
|
||||
|
||||
let mut bsp_members = PyDict::new(py);
|
||||
let bsp_members = PyDict::new(py);
|
||||
for (name, value) in variants {
|
||||
let instance = Py::new(py, 买卖点类型Py { inner: *value })?;
|
||||
bsp_class.setattr(*name, instance.clone_ref(py))?;
|
||||
@@ -577,7 +577,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
bsp_class.setattr("__members__", bsp_members)?;
|
||||
|
||||
// 相对方向 class attributes
|
||||
let dir_class = m.getattr("相对方向")?.downcast_into::<PyType>()?.clone();
|
||||
let dir_class = m.getattr("相对方向")?.cast_into::<PyType>()?.clone();
|
||||
let dir_variants: &[(&str, chanlun::types::相对方向)] = &[
|
||||
("向上", chanlun::types::相对方向::向上),
|
||||
("向下", chanlun::types::相对方向::向下),
|
||||
@@ -590,7 +590,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
("同", chanlun::types::相对方向::同),
|
||||
];
|
||||
|
||||
let mut dir_members = PyDict::new(py);
|
||||
let dir_members = PyDict::new(py);
|
||||
for (name, value) in dir_variants {
|
||||
let instance = Py::new(py, 相对方向Py { inner: *value })?;
|
||||
dir_class.setattr(*name, instance.clone_ref(py))?;
|
||||
@@ -599,7 +599,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
dir_class.setattr("__members__", dir_members)?;
|
||||
|
||||
// 分型结构 class attributes
|
||||
let frac_class = m.getattr("分型结构")?.downcast_into::<PyType>()?.clone();
|
||||
let frac_class = m.getattr("分型结构")?.cast_into::<PyType>()?.clone();
|
||||
let frac_variants: &[(&str, chanlun::types::分型结构)] = &[
|
||||
("上", chanlun::types::分型结构::上),
|
||||
("下", chanlun::types::分型结构::下),
|
||||
@@ -608,7 +608,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
("散", chanlun::types::分型结构::散),
|
||||
];
|
||||
|
||||
let mut frac_members = PyDict::new(py);
|
||||
let frac_members = PyDict::new(py);
|
||||
for (name, value) in frac_variants {
|
||||
let instance = Py::new(py, 分型结构Py { inner: *value })?;
|
||||
frac_class.setattr(*name, instance.clone_ref(py))?;
|
||||
|
||||
Reference in New Issue
Block a user