全量支持 观察者在python端的重写机制

This commit is contained in:
YuWuKunCheng
2026-05-30 15:35:48 +08:00
parent af3ebf13c8
commit bd4fceab02
6 changed files with 65 additions and 41 deletions
+5 -5
View File
@@ -5243,12 +5243,12 @@ class 观察者:
buffer = f.read()
size = struct.calcsize(">6d")
for i in range(len(buffer) // size):
时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量 = struct.unpack(">6d", buffer[i * size: i * size + size])
时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量 = struct.unpack(">6d", buffer[i * size : i * size + size])
self.投喂原始数据(转化为时间戳(int(时间戳)), 开盘价, 最高价, 最低价, 收盘价, 成交量)
@classmethod
def 读取数据文件(cls,观察员:"观察者", 文件路径: str, 配置=缠论配置()) -> Self:
""" 加载数据文件
def 读取数据文件(cls, 观察员: "观察者", 文件路径: str, 配置=缠论配置()) -> Self:
"""加载数据文件
:param 观察员: 观察者
:param 文件路径: 数据文件路径 格式如: btcusd-300-1631772074-1632222374.nb
:param 配置: 缠论配置
@@ -5513,7 +5513,7 @@ class 立体分析器:
print(f"多级别数据拆分保存完成,目录:{保存路径.resolve()}")
def 测试_读取数据(观察员: 观察者, 配置: 缠论配置)-> Callable[[], "观察者"]:
def 测试_读取数据(观察员: 观察者, 配置: 缠论配置) -> Callable[[], "观察者"]:
"""测试_读取数据
:param 观察员: 观察者
:param 配置: 缠论配置
@@ -5563,5 +5563,5 @@ if __name__ == "__main__":
当前配置 = 缠论配置.不推送()
当前配置.加载文件路径 = str(Path(__file__).parent / "btcusd-300-1761327300-1776327900.nb")
观察员 = 观察者("", 0, 当前配置)
测试_读取数据(观察员,当前配置)()# .测试_保存数据()
测试_读取数据(观察员, 当前配置)() # .测试_保存数据()
# 测试_周期合成(当前配置)().测试_保存数据()
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "chanlun-py"
version = "26.5.102"
version = "26.5.103"
edition = "2021"
description = "缠论技术分析库 — Rust 高性能 Python 绑定"
authors = ["YuYuKunKun"]
+4 -4
View File
@@ -5243,12 +5243,12 @@ class 观察者:
buffer = f.read()
size = struct.calcsize(">6d")
for i in range(len(buffer) // size):
时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量 = struct.unpack(">6d", buffer[i * size: i * size + size])
时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量 = struct.unpack(">6d", buffer[i * size : i * size + size])
self.投喂原始数据(转化为时间戳(int(时间戳)), 开盘价, 最高价, 最低价, 收盘价, 成交量)
@classmethod
def 读取数据文件(cls,观察员:"观察者", 文件路径: str, 配置=缠论配置()) -> Self:
""" 加载数据文件
def 读取数据文件(cls, 观察员: "观察者", 文件路径: str, 配置=缠论配置()) -> Self:
"""加载数据文件
:param 观察员: 观察者
:param 文件路径: 数据文件路径 格式如: btcusd-300-1631772074-1632222374.nb
:param 配置: 缠论配置
@@ -5513,7 +5513,7 @@ class 立体分析器:
print(f"多级别数据拆分保存完成,目录:{保存路径.resolve()}")
def 测试_读取数据(观察员: 观察者, 配置: 缠论配置)-> Callable[()]:
def 测试_读取数据(观察员: 观察者, 配置: 缠论配置) -> Callable[()]:
"""测试_读取数据
:param 观察员: 观察者
:param 配置: 缠论配置
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "chanlun"
version = "2605.102"
version = "2605.103"
description = "缠论技术分析库 — Rust 高性能实现"
readme = { file = "README.md", content-type = "text/markdown" }
license = { file = "LICENSE", content-type = "text/plain" }
+25 -6
View File
@@ -560,18 +560,37 @@ impl 观察者Py {
self.obs_mut().K线((*K.borrow().inner).clone());
}
/// 投喂原始数据 — 便捷入口,直接从 OHLCV 创建 K线 并投喂
/// 投喂原始数据 — 便捷入口,直接从 OHLCV 创建 K线 并通过 Python 分发 增加原始K线,
/// 确保子类重写的 增加原始K线 被正确调用。
fn (
&mut self, : i64, : f64, : f64, : f64, : f64, : f64
) {
self.obs_mut().(, , , , , );
slf: &Bound<'_, Self>,
: i64,
: f64,
: f64,
: f64,
: f64,
: f64,
) -> PyResult<()> {
let (, ) = {
let me = slf.borrow();
let obs = me.obs();
(obs..clone(), obs.)
};
let kline = K线Py {
inner: Arc::new(chanlun::kline::bar::K线::K(
&, , , , , , , 0, ,
)),
};
let kline_py = Py::new(slf.py(), kline)?;
slf.call_method1("增加原始K线", (kline_py,))?;
Ok(())
}
/// 加载本地数据 — 从 .nb 文件加载K线数据(先重置,再通过 Python dispatch 逐根投喂,
/// 确保子类重写的 增加原始K线 被正确调用)。
fn (slf: &Bound<'_, Self>, : &str) -> PyResult<()> {
// 重置基础序列
slf.borrow_mut().obs_mut().();
// 重置基础序列(通过 Python 分发,支持子类重写)
slf.call_method1("重置基础序列", ())?;
// 读取文件,通过 Python dispatch 逐根投喂(支持子类重写 增加原始K线)
let data = std::fs::read()
+29 -24
View File
@@ -347,15 +347,11 @@ impl K线Py {
#[pyclass(name = "缠论K线", module = "chanlun._chanlun", from_py_object)]
pub struct K线Py {
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::sync::Arc<chanlun::kline::chan_kline::K线>) -> Self {
Self {
inner,
bsp_set: std::sync::RwLock::new(None),
}
Self { inner }
}
}
@@ -366,6 +362,9 @@ thread_local! {
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());
/// 买卖点信息缓存 — 按 Arc 指针全局共享,确保所有 wrapper 看到同一 PySet
static BSP_CACHE: RwLock<HashMap<usize, Py<pyo3::types::PySet>>> = RwLock::new(HashMap::new());
}
/// 将 Rc<K线> 转为 Py<K线Py>,确保同一 Rc 地址总是返回同一 Python 对象
@@ -408,7 +407,6 @@ impl Clone for 缠论K线Py {
fn clone(&self) -> Self {
Self {
inner: std::sync::Arc::clone(&self.inner),
bsp_set: std::sync::RwLock::new(None),
}
}
}
@@ -530,16 +528,23 @@ impl 缠论K线Py {
#[getter]
/// 创建当前缠K的浅拷贝副本
fn (&self, py: Python<'_>) -> Self {
let mut mirror = Self {
let mirror = Self {
inner: std::sync::Arc::new(self.inner.()),
bsp_set: std::sync::RwLock::new(None),
};
if let Some(ref src_set) = *self.bsp_set.read().unwrap() {
// 复制买卖点信息到镜像
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)));
if let Some(cached_src) = cached_src {
if let Ok(new_set) = pyo3::types::PySet::empty(py) {
for item in src_set.bind(py).iter() {
for item in cached_src.bind(py).iter() {
let _ = new_set.add(item);
}
mirror.bsp_set = std::sync::RwLock::new(Some(new_set.into()));
let py_set: Py<pyo3::types::PySet> = new_set.into();
BSP_CACHE.with(|c| {
c.write().unwrap().insert(dst_key, py_set);
});
}
}
mirror
@@ -565,20 +570,20 @@ impl 缠论K线Py {
#[getter]
fn (&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
if self.bsp_set.read().unwrap().is_none() {
let set = pyo3::types::PySet::empty(py)?;
for s in self.inner..read().unwrap().iter() {
set.add(s.clone())?;
}
*self.bsp_set.write().unwrap() = Some(set.into());
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)));
if let Some(set) = cached {
return Ok(set.into_any());
}
Ok(self
.bsp_set
.read()
.unwrap()
.as_ref()
.unwrap()
.clone_ref(py)
// 创建新的 PySet 并存入全局缓存
let set = pyo3::types::PySet::empty(py)?;
BSP_CACHE.with(|c| {
c.write().unwrap().insert(key, set.into());
});
// 重新读取并返回(无法从 insert 获取 Py 引用,需要重新读)
Ok(BSP_CACHE
.with(|c| c.read().unwrap().get(&key).unwrap().clone_ref(py))
.into_any())
}