use crate::algorithm::bi::笔;
use crate::algorithm::hub::中枢;
use crate::algorithm::segment::线段;
use crate::config::缠论配置;
use crate::kline::bar::K线;
use crate::kline::chan_kline::缠论K线;
use crate::structure::dash_line::虚线;
use crate::structure::fractal_obj::分型;
use crate::types::相对方向;
use crate::utils::datetime;
use std::sync::atomic::Ordering;
use std::sync::{Arc, RwLock};
pub struct 观察者 {
pub 符号: String,
pub 周期: i64,
pub 配置: 缠论配置,
pub 普通K线序列: Vec<Arc<K线>>,
pub 基础缠K序列: Vec<Arc<缠论K线>>,
pub 缠论K线序列: Vec<Arc<缠论K线>>,
pub 分型序列: Vec<Arc<分型>>,
pub 笔序列: Vec<Arc<虚线>>,
pub 笔_中枢序列: Vec<Arc<中枢>>,
pub 线段序列: Vec<Arc<虚线>>,
pub 中枢序列: Vec<Arc<中枢>>,
pub 扩展线段序列: Vec<Arc<虚线>>,
pub 扩展中枢序列: Vec<Arc<中枢>>,
pub 扩展线段序列_线段: Vec<Arc<虚线>>,
pub 扩展中枢序列_线段: Vec<Arc<中枢>>,
pub 线段_线段序列: Vec<Arc<虚线>>,
pub 线段_中枢序列: Vec<Arc<中枢>>,
pub 扩展线段序列_扩展线段: Vec<Arc<虚线>>,
pub 扩展中枢序列_扩展线段: Vec<Arc<中枢>>,
终止时间戳: Option<i64>,
}
impl 观察者 {
pub fn new(符号: String, 周期: i64, 配置: 缠论配置) -> Arc<RwLock<Self>> {
let 终止时间戳 = if 配置.手动终止 != "1970-01-01 00:00:00" && !配置.手动终止.is_empty()
{
datetime::转化为时间戳(&配置.手动终止)
} else {
None
};
let mut instance = Self {
符号: 符号.clone(),
周期,
配置,
普通K线序列: Vec::new(),
基础缠K序列: Vec::new(),
缠论K线序列: Vec::new(),
分型序列: Vec::new(),
笔序列: Vec::new(),
笔_中枢序列: Vec::new(),
线段序列: Vec::new(),
中枢序列: Vec::new(),
扩展线段序列: Vec::new(),
扩展中枢序列: Vec::new(),
扩展线段序列_线段: Vec::new(),
扩展中枢序列_线段: Vec::new(),
线段_线段序列: Vec::new(),
线段_中枢序列: Vec::new(),
扩展线段序列_扩展线段: Vec::new(),
扩展中枢序列_扩展线段: Vec::new(),
终止时间戳,
};
instance.配置.标识 = 符号;
Arc::new(RwLock::new(instance))
}
pub fn 标识(&self) -> String {
format!("{}:{}", self.符号, self.周期)
}
pub fn 当前K线(&self) -> Option<&Arc<K线>> {
self.普通K线序列.last()
}
pub fn 当前缠K(&self) -> Option<&Arc<缠论K线>> {
self.缠论K线序列.last()
}
pub fn 重置基础序列(&mut self) {
self.普通K线序列.clear();
self.基础缠K序列.clear();
self.缠论K线序列.clear();
self.分型序列.clear();
self.笔序列.clear();
self.笔_中枢序列.clear();
self.线段序列.clear();
self.中枢序列.clear();
self.扩展线段序列.clear();
self.扩展中枢序列.clear();
self.扩展线段序列_线段.clear();
self.扩展中枢序列_线段.clear();
self.线段_线段序列.clear();
self.线段_中枢序列.clear();
self.扩展线段序列_扩展线段.clear();
self.扩展中枢序列_扩展线段.clear();
}
pub fn 增加原始K线(&mut self, 普K: K线) {
if let Some(终止) = self.终止时间戳 {
if 普K.时间戳 > 终止 {
return;
}
}
self.__处理数据(普K);
}
fn __处理数据(&mut self, 普K: K线) {
let (_, 当前分型) = 缠论K线::分析(
普K,
&mut self.缠论K线序列,
&mut self.普通K线序列,
&self.配置,
);
let 当前分型 = match 当前分型 {
Some(fx) => fx,
None => return,
};
if self.配置.分析笔 {
笔::分析(
当前分型,
&mut self.分型序列,
&mut self.笔序列,
&self.缠论K线序列,
&self.普通K线序列,
0,
&self.配置,
);
}
if self.分型序列.is_empty() {
return;
}
if self.配置.分析笔中枢 {
中枢::分析(&self.笔序列, &mut self.笔_中枢序列, true, "", 0);
}
if self.笔序列.is_empty() {
return;
}
if self.配置.分析线段 {
线段::分析(
&self.笔序列,
&mut self.线段序列,
&self.配置,
0,
&[相对方向::向上, 相对方向::向下],
);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.线段序列, &mut self.中枢序列, true, "", 0);
}
if self.配置.分析扩展线段 {
线段::扩展分析(&self.笔序列, &mut self.扩展线段序列, &self.配置);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.扩展线段序列, &mut self.扩展中枢序列, true, "", 0);
}
if self.配置.分析扩展线段 {
线段::扩展分析(&self.线段序列, &mut self.扩展线段序列_线段, &self.配置);
}
if self.配置.分析线段中枢 {
中枢::分析(
&self.扩展线段序列_线段,
&mut self.扩展中枢序列_线段,
true,
"",
0,
);
}
if self.配置.分析线段 {
线段::分析(
&self.线段序列,
&mut self.线段_线段序列,
&self.配置,
0,
&[相对方向::向上, 相对方向::向下],
);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.线段_线段序列, &mut self.线段_中枢序列, true, "", 0);
}
if self.配置.分析扩展线段 {
线段::扩展分析(
&self.扩展线段序列,
&mut self.扩展线段序列_扩展线段,
&self.配置,
);
}
if self.配置.分析线段中枢 {
中枢::分析(
&self.扩展线段序列_扩展线段,
&mut self.扩展中枢序列_扩展线段,
true,
"",
0,
);
}
}
pub fn 静态重新分析(&mut self) {
self.分型序列.clear();
self.笔序列.clear();
self.笔_中枢序列.clear();
self.线段序列.clear();
self.中枢序列.clear();
self.扩展线段序列.clear();
self.扩展中枢序列.clear();
self.扩展线段序列_线段.clear();
self.扩展中枢序列_线段.clear();
self.线段_线段序列.clear();
self.线段_中枢序列.clear();
self.扩展线段序列_扩展线段.clear();
self.扩展中枢序列_扩展线段.clear();
for i in 1..self.缠论K线序列.len() - 1 {
let 当前分型 = 分型::new(
Some(Arc::clone(&self.缠论K线序列[i - 1])),
Arc::clone(&self.缠论K线序列[i]),
Some(Arc::clone(&self.缠论K线序列[i + 1])),
);
笔::分析(
Arc::new(当前分型),
&mut self.分型序列,
&mut self.笔序列,
&self.缠论K线序列,
&self.普通K线序列,
0,
&self.配置,
);
}
if self.配置.分析笔中枢 {
中枢::分析(&self.笔序列, &mut self.笔_中枢序列, true, "", 0);
}
if self.配置.分析线段 {
线段::分析(
&self.笔序列,
&mut self.线段序列,
&self.配置,
0,
&[相对方向::向上, 相对方向::向下],
);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.线段序列, &mut self.中枢序列, true, "", 0);
}
if self.配置.分析扩展线段 {
线段::扩展分析(&self.笔序列, &mut self.扩展线段序列, &self.配置);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.扩展线段序列, &mut self.扩展中枢序列, true, "", 0);
}
if self.配置.分析扩展线段 {
线段::扩展分析(&self.线段序列, &mut self.扩展线段序列_线段, &self.配置);
}
if self.配置.分析线段中枢 {
中枢::分析(
&self.扩展线段序列_线段,
&mut self.扩展中枢序列_线段,
true,
"",
0,
);
}
if self.配置.分析线段 {
线段::分析(
&self.线段序列,
&mut self.线段_线段序列,
&self.配置,
0,
&[相对方向::向上, 相对方向::向下],
);
}
if self.配置.分析线段中枢 {
中枢::分析(&self.线段_线段序列, &mut self.线段_中枢序列, true, "", 0);
}
}
pub fn 测试_保存数据(&self, root: Option<&str>) {
let 笔序列_文本数据: Vec<String> = self.笔序列.iter().map(|b| b.获取数据文本()).collect();
let 线段序列_文本数据: Vec<String> =
self.线段序列.iter().map(|s| s.获取数据文本()).collect();
let 扩展线段序列_数据文本: Vec<String> =
self.扩展线段序列.iter().map(|s| s.获取数据文本()).collect();
let 扩展线段序列_线段_数据文本: Vec<String> = self
.扩展线段序列_线段
.iter()
.map(|s| s.获取数据文本())
.collect();
let 线段_线段序列_数据文本: Vec<String> = self
.线段_线段序列
.iter()
.map(|s| s.获取数据文本())
.collect();
let 扩展线段序列_扩展线段_数据文本: Vec<String> = self
.扩展线段序列_扩展线段
.iter()
.map(|s| s.获取数据文本())
.collect();
let 笔_中枢序列_数据文本: Vec<String> =
self.笔_中枢序列.iter().map(|h| h.获取数据文本()).collect();
let 中枢序列_数据文本: Vec<String> =
self.中枢序列.iter().map(|h| h.获取数据文本()).collect();
let 扩展中枢序列_数据文本: Vec<String> =
self.扩展中枢序列.iter().map(|h| h.获取数据文本()).collect();
let 扩展中枢序列_线段_数据文本: Vec<String> = self
.扩展中枢序列_线段
.iter()
.map(|h| h.获取数据文本())
.collect();
let 线段_中枢序列_数据文本: Vec<String> = self
.线段_中枢序列
.iter()
.map(|h| h.获取数据文本())
.collect();
let 扩展中枢序列_扩展线段_数据文本: Vec<String> = self
.扩展中枢序列_扩展线段
.iter()
.map(|h| h.获取数据文本())
.collect();
let 根目录 = match root {
Some(r) => std::path::PathBuf::from(r),
None => std::env::var("CHANLUN_DATA_DIR")
.map(std::path::PathBuf::from)
.unwrap_or_else(|_| std::env::temp_dir()),
};
let 起始时间 = self.普通K线序列.first().map(|k| k.时间戳).unwrap_or(0);
let 结束时间 = self.普通K线序列.last().map(|k| k.时间戳).unwrap_or(0);
let 目录标识 = format!("Rust_{}:{}_{}_{}", self.符号, self.周期, 起始时间, 结束时间);
let 保存路径 = 根目录.join(&目录标识);
if let Err(e) = std::fs::create_dir_all(&保存路径) {
eprintln!("创建目录失败: {} -> {}", 保存路径.display(), e);
return;
}
let 缠K序列_数据文本: Vec<String> = self
.缠论K线序列
.iter()
.map(|ck| {
format!(
"缠K, {}, {}, {:?}, {}, {}, {}, {}, {}",
ck.序号.load(Ordering::Relaxed),
ck.时间戳.load(Ordering::Relaxed),
ck.分型,
*ck.方向.read().unwrap(),
ck.高.get(),
ck.低.get(),
ck.原始起始序号,
ck.原始结束序号.load(Ordering::Relaxed)
)
})
.collect();
let 分型序列_数据文本: Vec<String> = self
.分型序列
.iter()
.enumerate()
.map(|(i, fx)| {
format!(
"分型, {}, {}, {:?}, {}, {}, {}",
i,
fx.时间戳(),
fx.结构,
fx.分型特征值,
fx.中.时间戳.load(Ordering::Relaxed),
fx.中.低.get(),
)
})
.collect();
let 数据映射: Vec<(&str, &[String])> = vec![
("笔序列_文本数据", &笔序列_文本数据),
("线段序列_文本数据", &线段序列_文本数据),
("扩展线段序列_数据文本", &扩展线段序列_数据文本),
("扩展线段序列_线段_数据文本", &扩展线段序列_线段_数据文本),
("线段_线段序列_数据文本", &线段_线段序列_数据文本),
(
"扩展线段序列_扩展线段_数据文本",
&扩展线段序列_扩展线段_数据文本,
),
("笔_中枢序列_数据文本", &笔_中枢序列_数据文本),
("中枢序列_数据文本", &中枢序列_数据文本),
("扩展中枢序列_数据文本", &扩展中枢序列_数据文本),
("扩展中枢序列_线段_数据文本", &扩展中枢序列_线段_数据文本),
("线段_中枢序列_数据文本", &线段_中枢序列_数据文本),
(
"扩展中枢序列_扩展线段_数据文本",
&扩展中枢序列_扩展线段_数据文本,
),
("缠K序列_数据文本", &缠K序列_数据文本),
("分型序列_数据文本", &分型序列_数据文本),
];
for (文件名, 数据列表) in &数据映射 {
let 文件路径 = 保存路径.join(format!("{}.txt", 文件名));
let 内容 = 数据列表.join("\n") + "\n";
if let Err(e) = std::fs::write(&文件路径, &内容) {
eprintln!("写入文件失败: {} -> {}", 文件路径.display(), e);
}
}
println!("全部数据拆分保存完成,目录:{}", 保存路径.display());
}
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)
}
pub fn 加载本地数据(&mut self, 文件路径: &str) -> Result<(), String> {
self.重置基础序列();
let bars = self.解析本地数据(文件路径)?;
for k线 in bars {
self.增加原始K线(k线);
}
Ok(())
}
pub fn 读取数据文件(
文件路径: &str,
配置: Option<缠论配置>,
) -> Result<Arc<RwLock<Self>>, String> {
let 配置 = 配置.unwrap_or_default();
let path = std::path::Path::new(文件路径);
let name = path
.file_stem()
.and_then(|n| n.to_str())
.ok_or("invalid filename")?;
let parts: Vec<&str> = name.split('-').collect();
if parts.len() < 4 {
return Err(format!("invalid filename format: {}", name));
}
let 符号 = parts[0].to_string();
let 周期: i64 = 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; 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(实例)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::缠论配置;
const TEST_DATA_PATH: &str = "/home/moscow/chanlun.rs/btcusd-300-1777649100-1778398800.nb";
#[test]
fn test_普k序列指针一致性() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for (i, bi) in obs_ref.笔序列.iter().enumerate() {
let pu_seq = bi.获取普K序列(&obs_ref.普通K线序列);
if pu_seq.is_empty() {
println!("笔 {}: 获取普K序列 返回空 (fallback failed)", i);
println!(" 文.中.标的K线 原始起始序号: {}", bi.文.中.原始起始序号);
println!(
" 武.中.标的K线 原始结束序号: {}",
bi.武
.read()
.unwrap()
.中
.原始结束序号
.load(Ordering::Relaxed)
);
println!(" 普通K线序列.len: {}", obs_ref.普通K线序列.len());
} else {
let first_ptr = Arc::as_ptr(&pu_seq[0]);
let found = obs_ref
.普通K线序列
.iter()
.any(|k| Arc::as_ptr(k) == first_ptr);
if !found {
println!("笔 {}: 获取普K序列[0] 的 Rc 指针不在 普通K线序列 中!", i);
let wen_ptr = Arc::as_ptr(&*bi.文.中.标的K线.read().unwrap());
let wen_found = obs_ref
.普通K线序列
.iter()
.any(|k| Arc::as_ptr(k) == wen_ptr);
println!(" 文.中.标的K线 在序列中: {}", wen_found);
} else {
println!("笔 {}: OK, 获取普K序列[0] 在序列中找到", i);
}
}
}
}
#[test]
fn test_pyo3_flow_pointer_consistency() {
let config = 缠论配置::default();
let obs_ref = 观察者::new("btcusd".into(), 300, config);
let data = std::fs::read(TEST_DATA_PATH).unwrap();
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], 300, "btcusd") {
let _k线_py_inner = Arc::new(k线.clone());
obs_ref.write().unwrap().增加原始K线(k线);
}
}
let obs = obs_ref.read().unwrap();
println!("普通K线序列.len: {}", obs.普通K线序列.len());
println!("笔序列.len: {}", obs.笔序列.len());
for (i, bi) in obs.笔序列.iter().enumerate() {
let pu_seq = bi.获取普K序列(&obs.普通K线序列);
if pu_seq.is_empty() {
println!("笔 {}: 获取普K序列 返回空!", i);
} else {
let first_ptr = Arc::as_ptr(&pu_seq[0]);
let found = obs.普通K线序列.iter().any(|k| Arc::as_ptr(k) == first_ptr);
if !found {
println!("笔 {}: 获取普K序列[0] 指针不在序列中!", i);
}
if i < 5 {
println!("笔 {}: OK, len={}", i, pu_seq.len());
}
}
}
}
#[test]
fn test_分型到笔的文武Rc指针一致性() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for (i, bi) in obs_ref.笔序列.iter().enumerate() {
let 文_ptr = Arc::as_ptr(&bi.文);
let 文_found = obs_ref.分型序列.iter().any(|f| Arc::as_ptr(f) == 文_ptr);
if !文_found {
println!("笔 {}: 文(时间戳={}) 不在分型序列中!", i, bi.文.时间戳());
}
let 武_ptr = Arc::as_ptr(&*bi.武.read().unwrap());
let 武_found = obs_ref.分型序列.iter().any(|f| Arc::as_ptr(f) == 武_ptr);
if !武_found {
println!(
"笔 {}: 武(时间戳={}) 不在分型序列中!",
i,
bi.武.read().unwrap().时间戳()
);
}
}
}
#[test]
fn test_笔到线段的基础序列Rc指针一致性() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for (i, seg) in obs_ref.线段序列.iter().enumerate() {
for (j, bi_in_seg) in seg.基础序列.read().unwrap().iter().enumerate() {
let bi_ptr = Arc::as_ptr(bi_in_seg);
let found = obs_ref.笔序列.iter().any(|b| Arc::as_ptr(b) == bi_ptr);
if !found {
println!("线段 {} 的基础序列[{}] 不在笔序列中!", i, j);
}
}
}
}
#[test]
fn test_中枢基础序列与笔序列Rc指针一致() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for (i, hub) in obs_ref.笔_中枢序列.iter().enumerate() {
for (j, bi_in_hub) in hub.基础序列.read().unwrap().iter().enumerate() {
let bi_ptr = Arc::as_ptr(bi_in_hub);
let found = obs_ref.笔序列.iter().any(|b| Arc::as_ptr(b) == bi_ptr);
if !found {
println!("笔中枢 {} 的基础序列[{}] 不在笔序列中!", i, j);
}
}
}
for (i, hub) in obs_ref.中枢序列.iter().enumerate() {
for (j, seg_in_hub) in hub.基础序列.read().unwrap().iter().enumerate() {
let seg_ptr = Arc::as_ptr(seg_in_hub);
let found = obs_ref.线段序列.iter().any(|s| Arc::as_ptr(s) == seg_ptr);
if !found {
println!("线段中枢 {} 的基础序列[{}] 不在线段序列中!", i, j);
}
}
}
}
#[test]
fn test_重复计算后结果一致() {
let data = std::fs::read(TEST_DATA_PATH).unwrap();
let size = 48;
let 计算 = || {
let config = 缠论配置::default();
let obs_ref = 观察者::new("btcusd".into(), 300, config);
for i in 0..data.len() / size {
let offset = i * size;
if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") {
obs_ref.write().unwrap().增加原始K线(k线);
}
}
let obs = obs_ref.read().unwrap();
(
obs.笔序列.len(),
obs.线段序列.len(),
obs.中枢序列.len(),
obs.笔_中枢序列.len(),
)
};
let (笔数1, 段数1, 中枢1, 笔中枢1) = 计算();
let (笔数2, 段数2, 中枢2, 笔中枢2) = 计算();
assert_eq!(笔数1, 笔数2, "重复计算笔数不一致");
assert_eq!(段数1, 段数2, "重复计算线段数不一致");
assert_eq!(中枢1, 中枢2, "重复计算中枢数不一致");
assert_eq!(笔中枢1, 笔中枢2, "重复计算笔中枢数不一致");
println!(
"两次计算结果一致: 笔={}, 线段={}, 中枢={}, 笔中枢={}",
笔数1, 段数1, 中枢1, 笔中枢1
);
}
#[test]
fn test_重置后重新投喂数据一致() {
let config = 缠论配置::default();
let obs_ref = 观察者::new("btcusd".into(), 300, config);
let data = std::fs::read(TEST_DATA_PATH).unwrap();
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], 300, "btcusd") {
obs_ref.write().unwrap().增加原始K线(k线);
}
}
let 第一次笔数 = obs_ref.read().unwrap().笔序列.len();
let 第一次段数 = obs_ref.read().unwrap().线段序列.len();
obs_ref.write().unwrap().重置基础序列();
assert_eq!(obs_ref.read().unwrap().笔序列.len(), 0);
assert_eq!(obs_ref.read().unwrap().线段序列.len(), 0);
for i in 0..data.len() / size {
let offset = i * size;
if let Some(k线) = K线::from_bytes(&data[offset..offset + size], 300, "btcusd") {
obs_ref.write().unwrap().增加原始K线(k线);
}
}
let 第二次笔数 = obs_ref.read().unwrap().笔序列.len();
let 第二次段数 = obs_ref.read().unwrap().线段序列.len();
assert_eq!(第一次笔数, 第二次笔数, "重置后重新投喂笔数不一致");
assert_eq!(第一次段数, 第二次段数, "重置后重新投喂线段数不一致");
println!("重置后重投一致: 笔={}, 线段={}", 第一次笔数, 第一次段数);
}
#[test]
fn test_RefCell借用安全性_连续读取不panic() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for _ in 0..100 {
for bi in &obs_ref.笔序列 {
let _标识 = bi.标识.read().unwrap().clone();
let _wu = bi.武.read().unwrap().clone();
let _基础序列 = bi.基础序列.read().unwrap().len();
let _特征序列 = bi.特征序列.read().unwrap().len();
let _模式 = bi.模式.read().unwrap().clone();
let _实中枢 = bi.实_中枢序列.read().unwrap().len();
let _虚中枢 = bi.虚_中枢序列.read().unwrap().len();
let _合中枢 = bi.合_中枢序列.read().unwrap().len();
let _确认K = bi.确认K线.read().unwrap().is_some();
let _序号 = bi.序号.load(Ordering::Relaxed);
let _有效性 = bi.有效性.load(Ordering::Relaxed);
let _短路 = bi.短路修正.load(Ordering::Relaxed);
let _前一缺口 = *bi.前一缺口.read().unwrap();
}
for seg in &obs_ref.线段序列 {
let _ = seg.标识.read().unwrap().clone();
let _ = seg.基础序列.read().unwrap().len();
}
}
}
#[test]
fn test_RefCell借用安全性_交替读写不panic() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
if !obs_ref.笔序列.is_empty() {
let bi = &obs_ref.笔序列[0];
let old_mode = bi.模式.read().unwrap().clone();
*bi.模式.write().unwrap() = "测试模式".into();
let new_mode = bi.模式.read().unwrap().clone();
assert_eq!(new_mode, "测试模式");
*bi.模式.write().unwrap() = old_mode;
let old_wu = bi.武.read().unwrap().clone();
assert!(Arc::as_ptr(&old_wu) == Arc::as_ptr(&old_wu));
}
}
#[test]
fn test_缠K到分型的Rc指针一致性() {
let config = 缠论配置::default();
let obs = 观察者::读取数据文件(TEST_DATA_PATH, Some(config)).unwrap();
let obs_ref = obs.read().unwrap();
for (i, f) in obs_ref.分型序列.iter().enumerate() {
let 中_ptr = Arc::as_ptr(&f.中);
let 中_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 中_ptr);
if !中_found {
println!("分型 {} 的 中(时间戳={}) 不在缠论K线序列中!", i, f.时间戳);
}
if let Some(ref 左) = f.左 {
let 左_ptr = Arc::as_ptr(左);
let 左_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 左_ptr);
if !左_found {
println!("分型 {} 的 左 不在缠论K线序列中!", i);
}
}
if let Some(ref 右) = f.右 {
let 右_ptr = Arc::as_ptr(右);
let 右_found = obs_ref.缠论K线序列.iter().any(|k| Arc::as_ptr(k) == 右_ptr);
if !右_found {
println!("分型 {} 的 右 不在缠论K线序列中!", i);
}
}
}
}
#[allow(dead_code)]
fn 断言_Send_Sync_编译期检查() {
fn _需要_Send<T: Send>() {}
fn _需要_Sync<T: Sync>() {}
fn _需要_Send_Sync<T: Send + Sync>() {}
_需要_Send::<crate::kline::chan_kline::缠论K线>();
_需要_Send::<crate::structure::dash_line::虚线>();
_需要_Send::<crate::algorithm::hub::中枢>();
_需要_Send_Sync::<crate::kline::chan_kline::缠论K线>();
_需要_Send_Sync::<crate::structure::dash_line::虚线>();
_需要_Send_Sync::<crate::algorithm::hub::中枢>();
_需要_Send::<Arc<crate::kline::chan_kline::缠论K线>>();
_需要_Send::<Arc<crate::structure::dash_line::虚线>>();
_需要_Send::<Arc<crate::algorithm::hub::中枢>>();
_需要_Send::<crate::business::observer::观察者>();
}
#[test]
fn test_跨线程_缠论K线_Send() {
use crate::kline::bar::K线;
use crate::kline::chan_kline::缠论K线;
let 普k = Arc::new(K线::创建普K(
"test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300,
));
let ck = 缠论K线::创建缠K(
1000,
110.0,
90.0,
crate::types::相对方向::向上,
None,
1,
普k,
None,
);
let arc_ck = Arc::new(ck);
let arc_ck2 = Arc::clone(&arc_ck);
let handle = std::thread::spawn(move || {
let _ = arc_ck2;
42
});
assert_eq!(handle.join().unwrap(), 42);
assert!((arc_ck.高.get() - 110.0).abs() < 0.01);
}
#[test]
fn test_跨线程_虚线_Send() {
use crate::kline::bar::K线;
use crate::kline::chan_kline::缠论K线;
use crate::structure::dash_line::虚线;
use crate::structure::fractal_obj::分型;
let 普k = Arc::new(K线::创建普K(
"test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300,
));
let ck = Arc::new(缠论K线::创建缠K(
1000,
110.0,
90.0,
crate::types::相对方向::向上,
None,
1,
普k,
None,
));
let frac = Arc::new(分型::new(None, Arc::clone(&ck), None));
let frac2 = Arc::new(分型::new(None, ck, None));
let dash = Arc::new(虚线::创建笔(frac, frac2, true));
let dash2 = Arc::clone(&dash);
let handle = std::thread::spawn(move || {
let _ = Arc::as_ptr(&dash2.文);
99
});
assert_eq!(handle.join().unwrap(), 99);
assert_eq!(dash.标识.read().unwrap().as_str(), "笔");
}
#[test]
fn test_跨线程_中枢_Send() {
let hub = crate::algorithm::hub::中枢::new(1, "test".into(), 1, vec![]);
let arc_hub = Arc::new(hub);
let arc_hub2 = Arc::clone(&arc_hub);
let handle = std::thread::spawn(move || {
let _ = arc_hub2.序号.load(Ordering::Relaxed);
77
});
assert_eq!(handle.join().unwrap(), 77);
assert_eq!(arc_hub.序号.load(Ordering::Relaxed), 1);
}
#[test]
fn test_跨线程_观察者_多线程读取() {
let obs = 观察者::new("btcusd".into(), 86400, Default::default());
let obs2 = Arc::clone(&obs);
let obs3 = Arc::clone(&obs);
let h1 = std::thread::spawn(move || {
let guard = obs2.read().unwrap();
guard.符号.clone()
});
let h2 = std::thread::spawn(move || {
let guard = obs3.read().unwrap();
guard.周期
});
assert_eq!(h1.join().unwrap(), "btcusd");
assert_eq!(h2.join().unwrap(), 86400);
}
#[test]
fn test_跨线程_Cell字段_并发读写() {
use crate::kline::bar::K线;
use crate::kline::chan_kline::缠论K线;
let 普k = Arc::new(K线::创建普K(
"test", 1000, 100.0, 110.0, 90.0, 95.0, 1000.0, 0, 300,
));
let ck = Arc::new(缠论K线::创建缠K(
1000,
110.0,
90.0,
crate::types::相对方向::向上,
None,
1,
普k,
None,
));
let ck2 = Arc::clone(&ck);
let handle = std::thread::spawn(move || {
let 序号 = ck2.序号.load(Ordering::Relaxed);
let 高 = ck2.高.get();
(序号, 高)
});
let (序号, 高) = handle.join().unwrap();
assert_eq!(序号, 0); assert!((高 - 110.0).abs() < 0.01);
ck.序号.store(2, Ordering::Relaxed);
assert_eq!(ck.序号.load(Ordering::Relaxed), 2);
}
#[test]
fn test_跨线程_观察者_所有权转移() {
let obs = 观察者::new("ethusd".into(), 7200, Default::default());
let handle = std::thread::spawn(move || {
let guard = obs.read().unwrap();
(guard.符号.clone(), guard.周期)
});
let (符号, 周期) = handle.join().unwrap();
assert_eq!(符号, "ethusd");
assert_eq!(周期, 7200);
}
}