添加 原始chan到模块

修复 相对方向的一致性
添加 观察者.投喂原始数据
This commit is contained in:
YuWuKunCheng
2026-05-30 11:26:59 +08:00
parent 14279f3df6
commit 1e6025a968
15 changed files with 333 additions and 243 deletions
+71 -58
View File
@@ -155,6 +155,14 @@ impl 观察者 {
self.__处理数据(K);
}
/// 投喂原始数据 — 便捷入口,直接从 OHLCV 创建 K线 并投喂
pub fn (
&mut self, : i64, : f64, : f64, : f64, : f64, : f64
) {
let K = K线::K(&self., , , , , , , 0, self.);
self.K线(K);
}
/// 核心数据处理管道
fn __处理数据(&mut self, K: K线) {
// Step 1: 缠论K线分析 (普K is consumed by 分析 as &mut)
@@ -479,39 +487,26 @@ impl 观察者 {
println!("全部数据拆分保存完成,目录:{}", .display());
}
/// 解析本地数据文件 — 从 .nb 文件读取并解析所有 K线
pub fn (&self, : &str) -> Result<Vec<K线>, String> {
let data = std::fs::read().map_err(|e| format!("read file: {}", e))?;
let mut bars = Vec::new();
let size = 48;
for i in 0..data.len() / size {
let offset = i * size;
if let Some(k线) = K线::from_bytes(&data[offset..offset + size], self., &self.)
{
bars.push(k线);
}
}
Ok(bars)
}
/// 加载本地数据 — 从 .nb 文件加载数据到当前观察者(先重置再投喂)
pub fn (&mut self, : &str) -> Result<(), String> {
self.();
let bars = self.()?;
for k线 in bars {
self.K线(k线);
let data = std::fs::read().map_err(|e| format!("read file: {}", e))?;
let size = 48;
for i in 0..data.len() / size {
let offset = i * size;
if let Some((, , , , , )) =
K线::(&data[offset..offset + size])
{
self.(, , , , , );
}
}
Ok(())
}
/// 读取数据文件 — .nb 文件加载数据
/// 读取数据文件 — 更新当前观察者并加载 .nb 文件
pub fn (
: &str,
: Option<>,
) -> Result<Arc<RwLock<Self>>, String> {
let = .unwrap_or_default();
// Parse filename: btcusd-300-1631772074-1632222374.nb
&mut self, : &str, :
) -> Result<(), String> {
let path = std::path::Path::new();
let name = path
.file_stem()
@@ -521,23 +516,12 @@ impl 观察者 {
if parts.len() < 4 {
return Err(format!("invalid filename format: {}", name));
}
let = parts[0].to_string();
let : i64 = parts[1]
self. = parts[0].to_string();
self. = parts[1]
.parse()
.map_err(|e| format!("parse period: {}", e))?;
let = Self::new(, , );
let data = std::fs::read().map_err(|e| format!("read file: {}", e))?;
let size = 48; // 6 × 8 bytes (big-endian double)
for i in 0..data.len() / size {
let offset = i * size;
if let Some(k线) = K线::from_bytes(&data[offset..offset + size], , "nb") {
.write().unwrap().K线(k线);
}
}
Ok()
self. = ;
self.()
}
}
@@ -546,12 +530,23 @@ mod tests {
use super::*;
use crate::config::;
const TEST_DATA_PATH: &str = "/home/moscow/chanlun.rs/btcusd-300-1777649100-1778398800.nb";
fn test_data_path() -> String {
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
manifest
.parent()
.unwrap()
.join("btcusd-300-1777649100-1778398800.nb")
.to_string_lossy()
.to_string()
}
#[test]
fn test_普k序列指针一致性() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
for (i, bi) in obs_ref..iter().enumerate() {
@@ -595,7 +590,7 @@ mod tests {
let config = ::default();
let obs_ref = ::new("btcusd".into(), 300, config);
let data = std::fs::read(TEST_DATA_PATH).unwrap();
let data = std::fs::read(&test_data_path()).unwrap();
let size = 48;
for i in 0..data.len() / size {
@@ -633,8 +628,11 @@ mod tests {
#[test]
fn test_分型到笔的文武Rc指针一致性() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
// 每个笔的文/武 分型 Rc 指针必须在 分型序列 中
@@ -663,8 +661,11 @@ mod tests {
#[test]
fn test_笔到线段的基础序列Rc指针一致性() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
// 每个线段的基础序列中的笔 Rc 指针必须在 笔序列 中
@@ -685,8 +686,11 @@ mod tests {
#[test]
fn test_中枢基础序列与笔序列Rc指针一致() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
for (i, hub) in obs_ref._中枢序列.iter().enumerate() {
@@ -716,7 +720,7 @@ mod tests {
#[test]
fn test_重复计算后结果一致() {
let data = std::fs::read(TEST_DATA_PATH).unwrap();
let data = std::fs::read(&test_data_path()).unwrap();
let size = 48;
let = || {
@@ -760,7 +764,7 @@ mod tests {
let config = ::default();
let obs_ref = ::new("btcusd".into(), 300, config);
let data = std::fs::read(TEST_DATA_PATH).unwrap();
let data = std::fs::read(&test_data_path()).unwrap();
let size = 48;
for i in 0..data.len() / size {
@@ -800,8 +804,11 @@ mod tests {
#[test]
fn test_RefCell借用安全性_连续读取不panic() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
// 连续大量读取所有 RefCell 字段,不应 panic
@@ -831,8 +838,11 @@ mod tests {
#[test]
fn test_RefCell借用安全性_交替读写不panic() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
// 交替读写 RefCell 字段 — 先读再写同字段,分离 borrow 作用域
@@ -860,8 +870,11 @@ mod tests {
#[test]
fn test_缠K到分型的Rc指针一致性() {
let config = ::default();
let obs = ::(TEST_DATA_PATH, Some(config)).unwrap();
let obs = ::new("btcusd".into(), 300, Default::default());
obs.write()
.unwrap()
.(&test_data_path(), Default::default())
.unwrap();
let obs_ref = obs.read().unwrap();
// 每个分型的左/中/右 缠K 指针必须在 缠论K线序列 中
+15
View File
@@ -125,6 +125,21 @@ impl K线 {
Self::from_bytes(, , )
}
/// 解析原始数据 — 只提取时间戳+OHLCV,不构造 K线
pub fn (: &[u8]) -> Option<(i64, f64, f64, f64, f64, f64)> {
if .len() < 48 {
return None;
}
let mut reader = &[..48];
let = reader.read_f64::<BigEndian>().ok()? as i64;
let = reader.read_f64::<BigEndian>().ok()?;
let = reader.read_f64::<BigEndian>().ok()?;
let = reader.read_f64::<BigEndian>().ok()?;
let = reader.read_f64::<BigEndian>().ok()?;
let = reader.read_f64::<BigEndian>().ok()?;
Some((, , , , , ))
}
/// 创建普通K线
pub fn K(
: &str,
+29 -31
View File
@@ -77,38 +77,36 @@ fn 测试_读取数据(文件路径: &str) {
let = Instant::now();
let = ::default().();
match ::(, Some()) {
Ok() => {
let = .read().unwrap();
let = .elapsed();
println!(
"测试_读取数据 耗时 {:.2?} 普K数量 {}",
,
.K线序列.len()
);
println!("符号: {}", .);
println!("周期: {}", .);
println!("缠K数量: {}", .K线序列.len());
println!("分型数量: {}", ..len());
println!("笔数量: {}", ..len());
println!("笔中枢数量: {}", ._中枢序列.len());
println!("线段数量: {}", .线.len());
println!("中枢数量: {}", ..len());
println!("扩展线段数量: {}", .线.len());
println!("线段_线段序列数量: {}", .线_线段序列.len());
println!(
"扩展线段_扩展线段数量: {}",
.线_扩展线段.len()
);
let = ::new("".into(), 0, ::default());
.write()
.unwrap()
.(, )
.expect("读取数据文件失败");
let = .read().unwrap();
let = .elapsed();
println!(
"测试_读取数据 耗时 {:.2?} 普K数量 {}",
,
.K线序列.len()
);
println!("符号: {}", .);
println!("周期: {}", .);
println!("缠K数量: {}", .K线序列.len());
println!("分型数量: {}", ..len());
println!("数量: {}", ..len());
println!("笔中枢数量: {}", ._中枢序列.len());
println!("线段数量: {}", .线.len());
println!("中枢数量: {}", ..len());
println!("扩展线段数量: {}", .线.len());
println!("线段_线段序列数量: {}", .线_线段序列.len());
println!(
"扩展线段_扩展线段数量: {}",
.线_扩展线段.len()
);
println!("\n===== 保存分析数据 =====\n");
._保存数据(None);
}
Err(e) => {
eprintln!("读取失败: {}", e);
std::process::exit(1);
}
}
println!("\n===== 保存分析数据 =====\n");
._保存数据(None);
}
/// 测试_周期合成 — 多周期合成分析
+24
View File
@@ -1,3 +1,27 @@
/*
* MIT License
*
* Copyright (c) 2026 YuYuKunKun
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use std::sync::atomic::{AtomicU64, Ordering};
/// f64 原子类型 — 基于 AtomicU64 + 位转换,API 与 `Cell<f64>` 一致。