全量支持 观察者在python端的重写机制
This commit is contained in:
@@ -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,6 +1,6 @@
|
||||
[package]
|
||||
name = "chanlun-py"
|
||||
version = "26.5.102"
|
||||
version = "26.5.103"
|
||||
edition = "2021"
|
||||
description = "缠论技术分析库 — Rust 高性能 Python 绑定"
|
||||
authors = ["YuYuKunKun"]
|
||||
|
||||
@@ -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 配置: 缠论配置
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user