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