第八版
This commit is contained in:
+495
-135
@@ -29,30 +29,32 @@ use crate::kline::chan_kline::缠论K线;
|
||||
use crate::structure::fractal_obj::分型;
|
||||
use crate::structure::segment_feat::线段特征;
|
||||
use crate::types::{分型结构, 相对方向, 缺口};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
/// 虚线 — 笔和线段的通用数据结构
|
||||
///
|
||||
/// 笔和线段共享此 struct,通过 `标识` 字段区分 ("笔"/"线段"/"扩展线段"等)
|
||||
#[derive(Debug, Clone)]
|
||||
/// 可变字段使用 Cell/RefCell 实现内部可变性,确保 Rc 指针身份一致
|
||||
#[derive(Debug)]
|
||||
pub struct 虚线 {
|
||||
pub 标识: String,
|
||||
pub 序号: i64,
|
||||
pub 级别: i64,
|
||||
pub 文: Rc<分型>,
|
||||
pub 武: Rc<分型>,
|
||||
pub 有效性: bool,
|
||||
pub 基础序列: Vec<Rc<虚线>>,
|
||||
pub 特征序列: Vec<Option<Rc<线段特征>>>,
|
||||
pub 实_中枢序列: Vec<Rc<中枢>>,
|
||||
pub 虚_中枢序列: Vec<Rc<中枢>>,
|
||||
pub 合_中枢序列: Vec<Rc<中枢>>,
|
||||
pub 确认K线: Option<Rc<缠论K线>>,
|
||||
pub 模式: String,
|
||||
pub _特征序列_显示: bool,
|
||||
pub 前一缺口: Option<缺口>,
|
||||
pub 前一结束位置: Option<Rc<虚线>>,
|
||||
pub 短路修正: bool,
|
||||
pub 标识: RwLock<String>,
|
||||
pub 序号: AtomicI64,
|
||||
pub 级别: AtomicI64,
|
||||
pub 文: Arc<分型>,
|
||||
pub 武: RwLock<Arc<分型>>,
|
||||
pub 有效性: AtomicBool,
|
||||
pub 基础序列: RwLock<Vec<Arc<虚线>>>,
|
||||
pub 特征序列: RwLock<Vec<Option<Arc<线段特征>>>>,
|
||||
pub 实_中枢序列: RwLock<Vec<Arc<中枢>>>,
|
||||
pub 虚_中枢序列: RwLock<Vec<Arc<中枢>>>,
|
||||
pub 合_中枢序列: RwLock<Vec<Arc<中枢>>>,
|
||||
pub 确认K线: RwLock<Option<Arc<缠论K线>>>,
|
||||
pub 模式: RwLock<String>,
|
||||
pub _特征序列_显示: AtomicBool,
|
||||
pub 前一缺口: RwLock<Option<缺口>>,
|
||||
pub 前一结束位置: RwLock<Option<Arc<虚线>>>,
|
||||
pub 短路修正: AtomicBool,
|
||||
}
|
||||
|
||||
/// MACD行为统计 — 统计MACD行为 方法的返回类型
|
||||
@@ -67,51 +69,73 @@ pub struct MACD行为统计 {
|
||||
pub 密集交叉区域: Vec<(usize, usize, usize)>,
|
||||
}
|
||||
|
||||
impl Clone for 虚线 {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
标识: RwLock::new(self.标识.read().unwrap().clone()),
|
||||
序号: AtomicI64::new(self.序号.load(Ordering::Relaxed)),
|
||||
级别: AtomicI64::new(self.级别.load(Ordering::Relaxed)),
|
||||
文: Arc::clone(&self.文),
|
||||
武: RwLock::new(Arc::clone(&self.武.read().unwrap())),
|
||||
有效性: AtomicBool::new(self.有效性.load(Ordering::Relaxed)),
|
||||
基础序列: RwLock::new(self.基础序列.read().unwrap().clone()),
|
||||
特征序列: RwLock::new(self.特征序列.read().unwrap().clone()),
|
||||
实_中枢序列: RwLock::new(self.实_中枢序列.read().unwrap().clone()),
|
||||
虚_中枢序列: RwLock::new(self.虚_中枢序列.read().unwrap().clone()),
|
||||
合_中枢序列: RwLock::new(self.合_中枢序列.read().unwrap().clone()),
|
||||
确认K线: RwLock::new(self.确认K线.read().unwrap().clone()),
|
||||
模式: RwLock::new(self.模式.read().unwrap().clone()),
|
||||
_特征序列_显示: AtomicBool::new(self._特征序列_显示.load(Ordering::Relaxed)),
|
||||
前一缺口: RwLock::new(*self.前一缺口.read().unwrap()),
|
||||
前一结束位置: RwLock::new(self.前一结束位置.read().unwrap().clone()),
|
||||
短路修正: AtomicBool::new(self.短路修正.load(Ordering::Relaxed)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl 虚线 {
|
||||
pub fn new(
|
||||
序号: i64,
|
||||
标识: String,
|
||||
文: Rc<分型>,
|
||||
武: Rc<分型>,
|
||||
文: Arc<分型>,
|
||||
武: Arc<分型>,
|
||||
级别: i64,
|
||||
有效性: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
序号,
|
||||
标识,
|
||||
级别,
|
||||
序号: AtomicI64::new(序号),
|
||||
标识: RwLock::new(标识),
|
||||
级别: AtomicI64::new(级别),
|
||||
文,
|
||||
武,
|
||||
有效性,
|
||||
基础序列: Vec::new(),
|
||||
特征序列: Vec::new(),
|
||||
实_中枢序列: Vec::new(),
|
||||
虚_中枢序列: Vec::new(),
|
||||
合_中枢序列: Vec::new(),
|
||||
确认K线: None,
|
||||
模式: "文武".into(),
|
||||
_特征序列_显示: false,
|
||||
前一缺口: None,
|
||||
前一结束位置: None,
|
||||
短路修正: false,
|
||||
武: RwLock::new(武),
|
||||
有效性: AtomicBool::new(有效性),
|
||||
基础序列: RwLock::new(Vec::new()),
|
||||
特征序列: RwLock::new(Vec::new()),
|
||||
实_中枢序列: RwLock::new(Vec::new()),
|
||||
虚_中枢序列: RwLock::new(Vec::new()),
|
||||
合_中枢序列: RwLock::new(Vec::new()),
|
||||
确认K线: RwLock::new(None),
|
||||
模式: RwLock::new("文武".into()),
|
||||
_特征序列_显示: AtomicBool::new(false),
|
||||
前一缺口: RwLock::new(None),
|
||||
前一结束位置: RwLock::new(None),
|
||||
短路修正: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// 笔序列(基础序列的别名)
|
||||
pub fn 笔序列(&self) -> &Vec<Rc<虚线>> {
|
||||
&self.基础序列
|
||||
}
|
||||
|
||||
pub fn 图表标题(&self) -> String {
|
||||
format!(
|
||||
"{}:{}:{}:{}",
|
||||
self.文.中.标识, self.文.中.周期, self.标识, self.序号
|
||||
self.文.中.标识,
|
||||
self.文.中.周期,
|
||||
self.标识.read().unwrap(),
|
||||
self.序号.load(Ordering::Relaxed)
|
||||
)
|
||||
}
|
||||
|
||||
/// 方向 — 文到武的方向
|
||||
pub fn 方向(&self) -> 相对方向 {
|
||||
match (self.文.结构, self.武.结构) {
|
||||
match (self.文.结构, self.武.read().unwrap().结构) {
|
||||
(分型结构::顶, 分型结构::底) => 相对方向::向下,
|
||||
(分型结构::顶, 分型结构::下) => 相对方向::向下,
|
||||
(分型结构::上, 分型结构::底) => 相对方向::向下,
|
||||
@@ -123,54 +147,60 @@ impl 虚线 {
|
||||
/// 虚线高
|
||||
pub fn 高(&self) -> f64 {
|
||||
if self.方向() == 相对方向::向下 {
|
||||
self.文.中.高
|
||||
self.文.中.高.get()
|
||||
} else {
|
||||
self.武.中.高
|
||||
self.武.read().unwrap().中.高.get()
|
||||
}
|
||||
}
|
||||
|
||||
/// 虚线低
|
||||
pub fn 低(&self) -> f64 {
|
||||
if self.方向() == 相对方向::向下 {
|
||||
self.武.中.低
|
||||
self.武.read().unwrap().中.低.get()
|
||||
} else {
|
||||
self.文.中.低
|
||||
self.文.中.低.get()
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断两个虚线是否首尾相连
|
||||
pub fn 之前是(&self, 之前: &虚线) -> bool {
|
||||
if self.标识 != 之前.标识 {
|
||||
if *self.标识.read().unwrap() != *之前.标识.read().unwrap() {
|
||||
return false;
|
||||
}
|
||||
Rc::as_ptr(&之前.武) == Rc::as_ptr(&self.文)
|
||||
Arc::as_ptr(&*之前.武.read().unwrap()) == Arc::as_ptr(&self.文)
|
||||
}
|
||||
|
||||
/// 判断两个虚线是否首尾相连
|
||||
pub fn 之后是(&self, 之后: &虚线) -> bool {
|
||||
if self.标识 != 之后.标识 {
|
||||
if *self.标识.read().unwrap() != *之后.标识.read().unwrap() {
|
||||
return false;
|
||||
}
|
||||
Rc::as_ptr(&self.武) == Rc::as_ptr(&之后.文)
|
||||
Arc::as_ptr(&*self.武.read().unwrap()) == Arc::as_ptr(&之后.文)
|
||||
}
|
||||
|
||||
/// 获取该虚线范围内的普K序列
|
||||
pub fn 获取普K序列(&self, 普K序列: &[Rc<K线>]) -> Vec<Rc<K线>> {
|
||||
pub fn 获取普K序列(&self, 普K序列: &[Arc<K线>]) -> Vec<Arc<K线>> {
|
||||
// 使用指针查找(与 Python list.index 身份匹配行为一致),
|
||||
// 而非序号切片——因为序号可能与实际位置不一致。
|
||||
let 始 = 普K序列
|
||||
.iter()
|
||||
.position(|k| Rc::as_ptr(k) == Rc::as_ptr(&self.文.中.标的K线));
|
||||
let 终 = 普K序列
|
||||
.iter()
|
||||
.position(|k| Rc::as_ptr(k) == Rc::as_ptr(&self.武.中.标的K线));
|
||||
.position(|k| Arc::as_ptr(k) == Arc::as_ptr(&*self.文.中.标的K线.read().unwrap()));
|
||||
let 终 = 普K序列.iter().position(|k| {
|
||||
Arc::as_ptr(k) == Arc::as_ptr(&*self.武.read().unwrap().中.标的K线.read().unwrap())
|
||||
});
|
||||
match (始, 终) {
|
||||
(Some(s), Some(e)) if s <= e => 普K序列[s..=e].to_vec(),
|
||||
_ => {
|
||||
// 指针查找失败时回退到序号方式
|
||||
println!("[警告]虚线.获取普K序列 <指针查找失败时回退到序号方式>");
|
||||
let 始 = self.文.中.原始起始序号 as usize;
|
||||
let 终 = self.武.中.原始结束序号 as usize;
|
||||
let 终 = self
|
||||
.武
|
||||
.read()
|
||||
.unwrap()
|
||||
.中
|
||||
.原始结束序号
|
||||
.load(Ordering::Relaxed) as usize;
|
||||
if 始 < 普K序列.len() && 终 < 普K序列.len() && 始 <= 终 {
|
||||
普K序列[始..=终].to_vec()
|
||||
} else {
|
||||
@@ -181,36 +211,43 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 获取该虚线范围内的缠K序列
|
||||
pub fn 获取缠K序列(&self, 缠K序列: &[Rc<缠论K线>]) -> Vec<Rc<缠论K线>> {
|
||||
缠论K线::截取(缠K序列, &self.文.中, &self.武.中).unwrap_or_default()
|
||||
pub fn 获取缠K序列(&self, 缠K序列: &[Arc<缠论K线>]) -> Vec<Arc<缠论K线>> {
|
||||
缠论K线::截取(缠K序列, &self.文.中, &self.武.read().unwrap().中).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// 获取_武 — 递归获取虚线的终点分型(笔直接返回武,线段递归到底层笔的武)
|
||||
pub fn 获取_武(&self) -> Rc<分型> {
|
||||
if self.标识 == "笔" {
|
||||
return Rc::clone(&self.武);
|
||||
pub fn 获取_武(&self) -> Arc<分型> {
|
||||
if *self.标识.read().unwrap() == "笔" {
|
||||
return self.武.read().unwrap().clone();
|
||||
}
|
||||
let mut current: &虚线 = self;
|
||||
while current.标识 != "笔" {
|
||||
current = &*current.基础序列.last().unwrap();
|
||||
let mut current_rc = Arc::clone(self.基础序列.read().unwrap().last().unwrap());
|
||||
loop {
|
||||
if *current_rc.标识.read().unwrap() == "笔" {
|
||||
return current_rc.武.read().unwrap().clone();
|
||||
}
|
||||
let next = Arc::clone(current_rc.基础序列.read().unwrap().last().unwrap());
|
||||
current_rc = next;
|
||||
}
|
||||
Rc::clone(¤t.武)
|
||||
}
|
||||
|
||||
/// 获取数据文本(用于保存/调试)
|
||||
pub fn 获取数据文本(&self) -> String {
|
||||
use crate::utils::format_f64_g;
|
||||
if self.标识 == "笔" {
|
||||
if *self.标识.read().unwrap() == "笔" {
|
||||
return format!(
|
||||
"{}, {}, {}, 文:({},{}), 武:({},{}), {}",
|
||||
self.标识,
|
||||
self.序号,
|
||||
self.级别,
|
||||
self.标识.read().unwrap(),
|
||||
self.序号.load(Ordering::Relaxed),
|
||||
self.级别.load(Ordering::Relaxed),
|
||||
self.文.时间戳,
|
||||
format_f64_g(self.文.分型特征值),
|
||||
self.武.时间戳,
|
||||
format_f64_g(self.武.分型特征值),
|
||||
if self.有效性 { "True" } else { "False" },
|
||||
self.武.read().unwrap().时间戳,
|
||||
format_f64_g(self.武.read().unwrap().分型特征值),
|
||||
if self.有效性.load(Ordering::Relaxed) {
|
||||
"True"
|
||||
} else {
|
||||
"False"
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -225,11 +262,11 @@ impl 虚线 {
|
||||
}
|
||||
};
|
||||
|
||||
let 前一缺口_str = match &self.前一缺口 {
|
||||
let 前一缺口_str = match &*self.前一缺口.read().unwrap() {
|
||||
Some(g) => format!("{}", g),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
let 前一结束位置_str = match &self.前一结束位置 {
|
||||
let 前一结束位置_str = match &*self.前一结束位置.read().unwrap() {
|
||||
Some(d) => format!("{}", d),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
@@ -238,6 +275,8 @@ impl 虚线 {
|
||||
let 实_str = format!(
|
||||
"[{}]",
|
||||
self.实_中枢序列
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|h| format!("{}", h))
|
||||
.collect::<Vec<_>>()
|
||||
@@ -246,6 +285,8 @@ impl 虚线 {
|
||||
let 虚_str = format!(
|
||||
"[{}]",
|
||||
self.虚_中枢序列
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|h| format!("{}", h))
|
||||
.collect::<Vec<_>>()
|
||||
@@ -254,6 +295,8 @@ impl 虚线 {
|
||||
let 合_str = format!(
|
||||
"[{}]",
|
||||
self.合_中枢序列
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|h| format!("{}", h))
|
||||
.collect::<Vec<_>>()
|
||||
@@ -284,15 +327,15 @@ impl 虚线 {
|
||||
|
||||
format!(
|
||||
"{}, {}, {}, 文:({},{}), 武:({},{}), {}, {}, ({}, {}, {}), (前: {}, 后: {}, 三: {}, 伤: {}), 实: {}, 虚: {}, 合: {}, {}, {}, {}, {}",
|
||||
self.标识,
|
||||
self.序号,
|
||||
self.级别,
|
||||
self.标识.read().unwrap(),
|
||||
self.序号.load(Ordering::Relaxed),
|
||||
self.级别.load(Ordering::Relaxed),
|
||||
self.文.时间戳,
|
||||
format_f64_g(self.文.分型特征值),
|
||||
self.武.时间戳,
|
||||
format_f64_g(self.武.分型特征值),
|
||||
if self.有效性 { "True" } else { "False" },
|
||||
self.基础序列.len(),
|
||||
self.武.read().unwrap().时间戳,
|
||||
format_f64_g(self.武.read().unwrap().分型特征值),
|
||||
if self.有效性.load(Ordering::Relaxed) { "True" } else { "False" },
|
||||
self.基础序列.read().unwrap().len(),
|
||||
特征_bool(特征_a),
|
||||
特征_bool(特征_b),
|
||||
特征_bool(特征_c),
|
||||
@@ -303,33 +346,39 @@ impl 虚线 {
|
||||
实_str,
|
||||
虚_str,
|
||||
合_str,
|
||||
self.模式,
|
||||
self.模式.read().unwrap(),
|
||||
前一缺口_str,
|
||||
前一结束位置_str,
|
||||
if self.短路修正 { "True" } else { "False" },
|
||||
if self.短路修正.load(Ordering::Relaxed) { "True" } else { "False" },
|
||||
)
|
||||
}
|
||||
|
||||
// ---- 关联函数(静态工厂方法) ----
|
||||
|
||||
/// 创建笔
|
||||
pub fn 创建笔(文: Rc<分型>, 武: Rc<分型>, 有效性: bool) -> Self {
|
||||
pub fn 创建笔(文: Arc<分型>, 武: Arc<分型>, 有效性: bool) -> Self {
|
||||
Self::new(0, "笔".into(), 文, 武, 1, 有效性)
|
||||
}
|
||||
|
||||
/// 创建线段
|
||||
pub fn 创建线段(虚线序列: &[Rc<虚线>]) -> Self {
|
||||
let 文 = Rc::clone(&虚线序列[0].文);
|
||||
let 武 = Rc::clone(&虚线序列[虚线序列.len() - 1].武);
|
||||
let 标识 = if 虚线序列[0].标识 == "笔" {
|
||||
pub fn 创建线段(虚线序列: &[Arc<虚线>]) -> Self {
|
||||
let 文 = Arc::clone(&虚线序列[0].文);
|
||||
let 武 = Arc::clone(&*虚线序列[虚线序列.len() - 1].武.read().unwrap());
|
||||
assert!(
|
||||
文.结构 != 武.结构,
|
||||
"创建线段: 文.结构 == 武.结构 文={}, 武={}",
|
||||
文,
|
||||
武
|
||||
);
|
||||
let 标识: String = if *虚线序列[0].标识.read().unwrap() == "笔" {
|
||||
"线段".into()
|
||||
} else {
|
||||
format!("线段<{}>", 虚线序列[0].标识)
|
||||
format!("线段<{}>", 虚线序列[0].标识.read().unwrap())
|
||||
};
|
||||
let 级别 = 虚线序列[0].级别 + 1;
|
||||
let mut 段 = Self::new(0, 标识, 文, 武, 级别, true);
|
||||
段.基础序列 = 虚线序列.to_vec();
|
||||
段.模式 = "文武".into();
|
||||
let 级别 = 虚线序列[0].级别.load(Ordering::Relaxed) + 1;
|
||||
let 段 = Self::new(0, 标识, 文, 武, 级别, true);
|
||||
*段.基础序列.write().unwrap() = 虚线序列.to_vec();
|
||||
*段.模式.write().unwrap() = "文武".into();
|
||||
段
|
||||
}
|
||||
|
||||
@@ -383,8 +432,12 @@ impl 虚线 {
|
||||
// ---- MACD柱子均值计算 ----
|
||||
|
||||
/// 计算MACD柱子均值 — 虚线范围内所有MACD柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值(普K序列: &[Rc<K线>], 实线: &虚线) -> f64 {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
pub fn 计算MACD柱子均值(普K序列: &[Arc<K线>], 实线: &虚线) -> f64 {
|
||||
let K线序列 = K线::截取rc(
|
||||
普K序列,
|
||||
&*实线.文.中.标的K线.read().unwrap(),
|
||||
&*实线.武.read().unwrap().中.标的K线.read().unwrap(),
|
||||
);
|
||||
if K线序列.is_empty() {
|
||||
return 0.0;
|
||||
}
|
||||
@@ -397,8 +450,12 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 计算MACD柱子均值_阴 — 负柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值_阴(普K序列: &[Rc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
pub fn 计算MACD柱子均值_阴(普K序列: &[Arc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(
|
||||
普K序列,
|
||||
&*实线.文.中.标的K线.read().unwrap(),
|
||||
&*实线.武.read().unwrap().中.标的K线.read().unwrap(),
|
||||
);
|
||||
let 总: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
@@ -413,8 +470,12 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 计算MACD柱子均值_阳 — 正柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值_阳(普K序列: &[Rc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
pub fn 计算MACD柱子均值_阳(普K序列: &[Arc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(
|
||||
普K序列,
|
||||
&*实线.文.中.标的K线.read().unwrap(),
|
||||
&*实线.武.read().unwrap().中.标的K线.read().unwrap(),
|
||||
);
|
||||
let 总: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
@@ -431,8 +492,10 @@ impl 虚线 {
|
||||
// ---- 武之MACD比较 ----
|
||||
|
||||
/// 武之全量MACD均值 — 武端MACD柱是否小于均值(背驰)
|
||||
pub fn 武之全量MACD均值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
pub fn 武之全量MACD均值(普K序列: &[Arc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_ref = 实线.武.read().unwrap();
|
||||
let 标 = 武_ref.中.标的K线.read().unwrap();
|
||||
let 武_MACD = match 标.macd.as_ref() {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
@@ -440,7 +503,7 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 武之MACD均值 — 按方向选择阴/阳均值比对
|
||||
pub fn 武之MACD均值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
pub fn 武之MACD均值(普K序列: &[Arc<K线>], 实线: &虚线) -> bool {
|
||||
if 实线.方向() == 相对方向::向上 {
|
||||
Self::武之MACD均值_阳(普K序列, 实线)
|
||||
} else {
|
||||
@@ -449,8 +512,10 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 武之MACD均值_阴 — 武端负柱是否小于阴均值
|
||||
pub fn 武之MACD均值_阴(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
pub fn 武之MACD均值_阴(普K序列: &[Arc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_ref = 实线.武.read().unwrap();
|
||||
let 标 = 武_ref.中.标的K线.read().unwrap();
|
||||
let 武_MACD = match 标.macd.as_ref() {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
@@ -461,8 +526,10 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 武之MACD均值_阳 — 武端正柱是否小于阳均值
|
||||
pub fn 武之MACD均值_阳(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
pub fn 武之MACD均值_阳(普K序列: &[Arc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_ref = 实线.武.read().unwrap();
|
||||
let 标 = 武_ref.中.标的K线.read().unwrap();
|
||||
let 武_MACD = match 标.macd.as_ref() {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
@@ -473,12 +540,18 @@ impl 虚线 {
|
||||
}
|
||||
|
||||
/// 武之MACD极值 — 武端MACD柱是否为区间极值
|
||||
pub fn 武之MACD极值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
pub fn 武之MACD极值(普K序列: &[Arc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_ref = 实线.武.read().unwrap();
|
||||
let 标 = 武_ref.中.标的K线.read().unwrap();
|
||||
let 武_MACD = match 标.macd.as_ref() {
|
||||
Some(m) => m.MACD柱,
|
||||
None => return false,
|
||||
};
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
let K线序列 = K线::截取rc(
|
||||
普K序列,
|
||||
&*实线.文.中.标的K线.read().unwrap(),
|
||||
&*实线.武.read().unwrap().中.标的K线.read().unwrap(),
|
||||
);
|
||||
let 所有柱子: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
@@ -500,7 +573,7 @@ impl 虚线 {
|
||||
|
||||
/// 计算K线序列MACD趋向背驰 — 分析 MACD柱/DIF/DEA 三项背驰信号
|
||||
pub fn 计算K线序列MACD趋向背驰(
|
||||
普K序列: &[Rc<K线>], 方向: 相对方向
|
||||
普K序列: &[Arc<K线>], 方向: 相对方向
|
||||
) -> [bool; 3] {
|
||||
if 普K序列.is_empty() {
|
||||
return [false, false, false];
|
||||
@@ -508,7 +581,7 @@ impl 虚线 {
|
||||
let 最后 = &普K序列[普K序列.len() - 1];
|
||||
|
||||
if 方向 == 相对方向::向上 {
|
||||
let 柱子序列: Vec<&Rc<K线>> = 普K序列
|
||||
let 柱子序列: Vec<&Arc<K线>> = 普K序列
|
||||
.iter()
|
||||
.filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 > 0.0))
|
||||
.collect();
|
||||
@@ -530,7 +603,7 @@ impl 虚线 {
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::clone(最后)];
|
||||
let mut 柱对 = vec![Arc::clone(*最高柱子), Arc::clone(最后)];
|
||||
柱对.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对[0].macd.as_ref(), 柱对[1].macd.as_ref()) {
|
||||
if m0.MACD柱 > m1.MACD柱 && 柱对[0].高 < 柱对[1].高 {
|
||||
@@ -574,7 +647,7 @@ impl 虚线 {
|
||||
|
||||
结果
|
||||
} else {
|
||||
let 柱子序列: Vec<&Rc<K线>> = 普K序列
|
||||
let 柱子序列: Vec<&Arc<K线>> = 普K序列
|
||||
.iter()
|
||||
.filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 < 0.0))
|
||||
.collect();
|
||||
@@ -597,7 +670,7 @@ impl 虚线 {
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::clone(最后)];
|
||||
let mut 柱对 = vec![Arc::clone(*最高柱子), Arc::clone(最后)];
|
||||
柱对.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对[0].macd.as_ref(), 柱对[1].macd.as_ref()) {
|
||||
if m0.MACD柱 < m1.MACD柱 && 柱对[0].低 > 柱对[1].低 {
|
||||
@@ -646,7 +719,7 @@ impl 虚线 {
|
||||
// ---- MACD柱子分段 ----
|
||||
|
||||
/// 计算MACD柱子分段 — 按正负号将MACD柱子分段
|
||||
pub fn 计算MACD柱子分段(k线序列: &[Rc<K线>]) -> Vec<Vec<f64>> {
|
||||
pub fn 计算MACD柱子分段(k线序列: &[Arc<K线>]) -> Vec<Vec<f64>> {
|
||||
if k线序列.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
@@ -729,7 +802,7 @@ impl 虚线 {
|
||||
|
||||
/// 统计MACD行为 — 分析DIF/DEA穿零轴和金叉死叉
|
||||
pub fn 统计MACD行为(
|
||||
普K序列: &[Rc<K线>],
|
||||
普K序列: &[Arc<K线>],
|
||||
最大间隔: usize,
|
||||
最少交叉数: usize,
|
||||
) -> MACD行为统计 {
|
||||
@@ -820,34 +893,39 @@ impl 虚线 {
|
||||
let 普K序列 = &观察员.普通K线序列;
|
||||
let 配置 = &观察员.配置;
|
||||
|
||||
if 实线.标识 != "笔" && 实线.标识 != "线段" && !实线.标识.starts_with("线段<")
|
||||
if *实线.标识.read().unwrap() != "笔"
|
||||
&& *实线.标识.read().unwrap() != "线段"
|
||||
&& !实线.标识.read().unwrap().starts_with("线段<")
|
||||
{
|
||||
return (false, "标识不在范围内".into());
|
||||
}
|
||||
|
||||
// KDJ指标完整性检查
|
||||
match &实线.武.中.标的K线.kdj {
|
||||
let 武_ref = 实线.武.read().unwrap();
|
||||
let 标 = 武_ref.中.标的K线.read().unwrap();
|
||||
match 标.kdj.as_ref() {
|
||||
Some(kdj) if kdj.K.is_some() && kdj.D.is_some() && kdj.J.is_some() => {}
|
||||
_ => return (false, "KDJ指标不完整".into()),
|
||||
}
|
||||
|
||||
let 意义 = Self::缠K买卖点模式(&配置.买卖点_指标模式, &实线.武.中, 配置);
|
||||
let 意义 =
|
||||
Self::缠K买卖点模式(&配置.买卖点_指标模式, &实线.武.read().unwrap().中, 配置);
|
||||
let 结果 = false;
|
||||
|
||||
let 背驰过: Vec<Rc<缠论K线>> = if 实线.标识 == "笔" {
|
||||
let 背驰过: Vec<Arc<缠论K线>> = if *实线.标识.read().unwrap() == "笔" {
|
||||
crate::algorithm::bi::笔::是否背驰过(实线, 观察员)
|
||||
} else {
|
||||
crate::algorithm::segment::线段::是否背驰过(实线, 观察员)
|
||||
};
|
||||
|
||||
if 意义 {
|
||||
if 实线.标识 == "笔" {
|
||||
if *实线.标识.read().unwrap() == "笔" {
|
||||
if Self::武之MACD均值(普K序列, 实线) {
|
||||
return (true, "武之MACD均值".into());
|
||||
}
|
||||
if Self::武之MACD极值(普K序列, 实线) && !背驰过.is_empty() {
|
||||
return (true, "背驰过且极值".into());
|
||||
} else if 实线.武.与MACD柱子分型匹配() {
|
||||
} else if 实线.武.read().unwrap().与MACD柱子分型匹配() {
|
||||
return (
|
||||
true,
|
||||
format!(
|
||||
@@ -862,14 +940,14 @@ impl 虚线 {
|
||||
);
|
||||
}
|
||||
}
|
||||
if 实线.标识 != "笔"
|
||||
if *实线.标识.read().unwrap() != "笔"
|
||||
&& crate::algorithm::segment::线段::判断线段内部是否背驰(实线, 观察员)
|
||||
{
|
||||
return (true, "线段内部背驰".into());
|
||||
}
|
||||
}
|
||||
|
||||
if !结果 && 意义 && 实线.武.中.与MACD柱子匹配() {
|
||||
if !结果 && 意义 && 实线.武.read().unwrap().中.与MACD柱子匹配() {
|
||||
if Self::武之MACD极值(普K序列, 实线) && 背驰过.len() > 2 {
|
||||
return (true, "没结果, 极值, 柱子分型匹配, 背驰过大于2次".into());
|
||||
}
|
||||
@@ -879,18 +957,300 @@ impl 虚线 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::kline::bar::K线;
|
||||
use crate::kline::chan_kline::缠论K线;
|
||||
use crate::types::分型结构;
|
||||
|
||||
/// 辅助:创建一根最小化的原始K线
|
||||
fn 辅助_创建K线(时间戳: i64, 高: f64, 低: f64, 开: f64, 收: f64) -> K线 {
|
||||
let mut k = K线::default();
|
||||
k.时间戳 = 时间戳;
|
||||
k.高 = 高;
|
||||
k.低 = 低;
|
||||
k.开盘价 = 开;
|
||||
k.收盘价 = 收;
|
||||
k
|
||||
}
|
||||
|
||||
/// 辅助:创建一根缠论K线
|
||||
fn 辅助_创建缠K(
|
||||
时间戳: i64,
|
||||
高: f64,
|
||||
低: f64,
|
||||
方向: 相对方向,
|
||||
结构: Option<分型结构>,
|
||||
序号: i64,
|
||||
) -> Arc<缠论K线> {
|
||||
let 普K = Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高));
|
||||
let 缠K = 缠论K线::创建缠K(时间戳, 高, 低, 方向, 结构, 序号, 普K, None);
|
||||
Arc::new(缠K)
|
||||
}
|
||||
|
||||
/// 辅助:创建顶分型
|
||||
fn 辅助_创建顶分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> {
|
||||
let 左 = 辅助_创建缠K(
|
||||
时间戳 - 2,
|
||||
高 - 2.0,
|
||||
低 - 2.0,
|
||||
相对方向::向上,
|
||||
Some(分型结构::上),
|
||||
序号 - 2,
|
||||
);
|
||||
let 中 = 辅助_创建缠K(时间戳, 高, 低, 相对方向::向上, Some(分型结构::顶), 序号);
|
||||
let 右 = 辅助_创建缠K(
|
||||
时间戳 + 2,
|
||||
高 - 1.0,
|
||||
低 - 1.0,
|
||||
相对方向::向下,
|
||||
Some(分型结构::下),
|
||||
序号 + 2,
|
||||
);
|
||||
Arc::new(分型::new(Some(左), 中, Some(右)))
|
||||
}
|
||||
|
||||
/// 辅助:创建底分型
|
||||
fn 辅助_创建底分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> {
|
||||
let 左 = 辅助_创建缠K(
|
||||
时间戳 - 2,
|
||||
高 + 2.0,
|
||||
低 + 2.0,
|
||||
相对方向::向下,
|
||||
Some(分型结构::下),
|
||||
序号 - 2,
|
||||
);
|
||||
let 中 = 缠论K线::创建缠K(
|
||||
时间戳,
|
||||
高,
|
||||
低,
|
||||
相对方向::向下,
|
||||
Some(分型结构::底),
|
||||
序号,
|
||||
Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)),
|
||||
None,
|
||||
);
|
||||
中.分型特征值.set(低);
|
||||
let 中 = Arc::new(中);
|
||||
let 右 = 辅助_创建缠K(
|
||||
时间戳 + 2,
|
||||
高 + 1.0,
|
||||
低 + 1.0,
|
||||
相对方向::向上,
|
||||
Some(分型结构::上),
|
||||
序号 + 2,
|
||||
);
|
||||
Arc::new(分型::new(Some(左), 中, Some(右)))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Cell 字段读写测试
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_Cell字段读写一致性() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔 = 虚线::创建笔(顶, 底, true);
|
||||
|
||||
assert_eq!(笔.序号.load(Ordering::Relaxed), 0);
|
||||
assert!(笔.有效性.load(Ordering::Relaxed));
|
||||
assert!(!笔.短路修正.load(Ordering::Relaxed));
|
||||
assert!(笔.前一缺口.read().unwrap().is_none());
|
||||
|
||||
// 修改 Cell 字段
|
||||
笔.序号.store(42, Ordering::Relaxed);
|
||||
笔.有效性.store(false, Ordering::Relaxed);
|
||||
笔.短路修正.store(true, Ordering::Relaxed);
|
||||
*笔.前一缺口.write().unwrap() = Some(缺口::new(200.0, 100.0));
|
||||
|
||||
assert_eq!(笔.序号.load(Ordering::Relaxed), 42);
|
||||
assert!(!笔.有效性.load(Ordering::Relaxed));
|
||||
assert!(笔.短路修正.load(Ordering::Relaxed));
|
||||
let qk = 笔.前一缺口.read().unwrap().unwrap();
|
||||
assert!((qk.高 - 200.0).abs() < 0.01);
|
||||
assert!((qk.低 - 100.0).abs() < 0.01);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// RefCell 字段读写测试
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_RefCell字段读写一致性() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔 = 虚线::创建笔(顶, 底, true);
|
||||
|
||||
// 标识
|
||||
assert_eq!(*笔.标识.read().unwrap(), "笔");
|
||||
*笔.标识.write().unwrap() = "测试标识".into();
|
||||
assert_eq!(*笔.标识.read().unwrap(), "测试标识");
|
||||
|
||||
// 模式
|
||||
assert_eq!(*笔.模式.read().unwrap(), "文武");
|
||||
*笔.模式.write().unwrap() = "全量".into();
|
||||
assert_eq!(*笔.模式.read().unwrap(), "全量");
|
||||
|
||||
// 基础序列
|
||||
assert!(笔.基础序列.read().unwrap().is_empty());
|
||||
let 另一底 = 辅助_创建底分型(300, 20.0, 10.0, 15);
|
||||
let 笔2 = 虚线::创建笔(Arc::clone(&*笔.武.read().unwrap()), 另一底, true);
|
||||
笔.基础序列.write().unwrap().push(Arc::new(笔2));
|
||||
assert_eq!(笔.基础序列.read().unwrap().len(), 1);
|
||||
|
||||
// 武 - Replace with new 分型
|
||||
let 新底 = 辅助_创建底分型(400, 15.0, 5.0, 20);
|
||||
let 新底_ptr = Arc::as_ptr(&新底);
|
||||
*笔.武.write().unwrap() = Arc::clone(&新底);
|
||||
assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), 新底_ptr);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Clone 后 Rc 指针身份一致
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_虚线Clone后文Rc指针一致() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底), true);
|
||||
|
||||
let 克隆笔 = 笔.clone();
|
||||
|
||||
// 文 Rc 指针应一致
|
||||
assert_eq!(Arc::as_ptr(&笔.文), Arc::as_ptr(&顶));
|
||||
assert_eq!(Arc::as_ptr(&克隆笔.文), Arc::as_ptr(&笔.文));
|
||||
|
||||
// 武 Rc 指针应一致
|
||||
assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), Arc::as_ptr(&底));
|
||||
assert_eq!(
|
||||
Arc::as_ptr(&*克隆笔.武.read().unwrap()),
|
||||
Arc::as_ptr(&*笔.武.read().unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_虚线Clone是深拷贝Cell值而非共享() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔 = 虚线::创建笔(顶, 底, true);
|
||||
笔.序号.store(10, Ordering::Relaxed);
|
||||
|
||||
let 克隆笔 = 笔.clone();
|
||||
// Clone 后序号应独立(deep copy for Cell)
|
||||
克隆笔.序号.store(99, Ordering::Relaxed);
|
||||
assert_eq!(笔.序号.load(Ordering::Relaxed), 10);
|
||||
assert_eq!(克隆笔.序号.load(Ordering::Relaxed), 99);
|
||||
|
||||
// Rc 指针仍应一致(文/武 共享)
|
||||
assert_eq!(Arc::as_ptr(&笔.文), Arc::as_ptr(&克隆笔.文));
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 多 Rc 共享下 Cell/RefCell 修改可见性
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_多Rc共享下Cell修改对所有引用可见() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔_rc1 = Arc::new(虚线::创建笔(顶, 底, true));
|
||||
let 笔_rc2 = Arc::clone(&笔_rc1);
|
||||
|
||||
// 通过 rc1 修改 Cell
|
||||
笔_rc1.序号.store(77, Ordering::Relaxed);
|
||||
// rc2 应能看到
|
||||
assert_eq!(笔_rc2.序号.load(Ordering::Relaxed), 77);
|
||||
|
||||
// 通过 rc1 修改 RefCell
|
||||
*笔_rc1.模式.write().unwrap() = "配置".into();
|
||||
assert_eq!(*笔_rc2.模式.read().unwrap(), "配置");
|
||||
|
||||
// 通过 rc1 修改 武
|
||||
let 新底 = 辅助_创建底分型(400, 15.0, 5.0, 20);
|
||||
let 新底_ptr = Arc::as_ptr(&新底);
|
||||
*笔_rc1.武.write().unwrap() = Arc::clone(&新底);
|
||||
assert_eq!(Arc::as_ptr(&*笔_rc2.武.read().unwrap()), 新底_ptr);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 获取_武 递归正确性
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_获取武_笔级别直接返回武() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底), true);
|
||||
|
||||
let wu = 笔.获取_武();
|
||||
assert_eq!(Arc::as_ptr(&*笔.武.read().unwrap()), Arc::as_ptr(&wu));
|
||||
assert_eq!(Arc::as_ptr(&wu), Arc::as_ptr(&底));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_获取武_线段级别递归到底层笔() {
|
||||
let 顶1 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底1 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 顶2 = 辅助_创建顶分型(300, 55.0, 45.0, 15);
|
||||
let 底2 = 辅助_创建底分型(400, 25.0, 15.0, 20);
|
||||
|
||||
let 笔1 = Arc::new(虚线::创建笔(Arc::clone(&顶1), Arc::clone(&底1), true));
|
||||
let 笔2 = Arc::new(虚线::创建笔(Arc::clone(&底1), Arc::clone(&顶2), true));
|
||||
let 笔3 = Arc::new(虚线::创建笔(Arc::clone(&顶2), Arc::clone(&底2), true));
|
||||
|
||||
let 段 = 虚线::创建线段(&[Arc::clone(&笔1), Arc::clone(&笔2), Arc::clone(&笔3)]);
|
||||
|
||||
// 线段的 获取_武 应返回底层最后一笔的武(底2)
|
||||
let wu = 段.获取_武();
|
||||
assert_eq!(Arc::as_ptr(&wu), Arc::as_ptr(&底2));
|
||||
|
||||
// 笔1 的 获取_武 应返回底1
|
||||
let wu1 = 笔1.获取_武();
|
||||
assert_eq!(Arc::as_ptr(&wu1), Arc::as_ptr(&底1));
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 虚线 字段原子性 - 修改不影响文(不可变字段)
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_修改武不影响文Rc指针() {
|
||||
let 顶 = 辅助_创建顶分型(100, 50.0, 40.0, 5);
|
||||
let 底1 = 辅助_创建底分型(200, 30.0, 20.0, 10);
|
||||
let 底2 = 辅助_创建底分型(300, 25.0, 15.0, 15);
|
||||
|
||||
let 笔 = 虚线::创建笔(Arc::clone(&顶), Arc::clone(&底1), true);
|
||||
let 文_ptr_before = Arc::as_ptr(&笔.文);
|
||||
|
||||
// 修改武
|
||||
*笔.武.write().unwrap() = Arc::clone(&底2);
|
||||
|
||||
// 文指针不变
|
||||
assert_eq!(Arc::as_ptr(&笔.文), 文_ptr_before);
|
||||
|
||||
// 但方向变了(因为武从底1变成底2)
|
||||
let 新武耗时 = 笔.武.read().unwrap().时间戳;
|
||||
assert_eq!(新武耗时, 300);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 虚线 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.标识 == "笔" {
|
||||
if *self.标识.read().unwrap() == "笔" {
|
||||
write!(
|
||||
f,
|
||||
"笔({}, {}, {}, {}, 周期: {}, 数量: {})",
|
||||
self.序号,
|
||||
self.序号.load(Ordering::Relaxed),
|
||||
self.方向(),
|
||||
self.文,
|
||||
self.武,
|
||||
self.武.read().unwrap(),
|
||||
self.文.中.周期,
|
||||
self.武.中.序号 - self.文.中.序号 + 1
|
||||
self.武.read().unwrap().中.序号.load(Ordering::Relaxed)
|
||||
- self.文.中.序号.load(Ordering::Relaxed)
|
||||
+ 1
|
||||
)
|
||||
} else {
|
||||
let 四象 = crate::algorithm::segment::线段::四象(self);
|
||||
@@ -899,20 +1259,20 @@ impl std::fmt::Display for 虚线 {
|
||||
Some(g) => format!("{}", g),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
let 确认K线_str = match &self.确认K线 {
|
||||
let 确认K线_str = match &*self.确认K线.read().unwrap() {
|
||||
Some(k) => format!("{}", k),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{}<{}, {}, {}, {}, {}, 数量: {}, 缺口: {}, {}>",
|
||||
self.标识,
|
||||
self.序号,
|
||||
self.标识.read().unwrap(),
|
||||
self.序号.load(Ordering::Relaxed),
|
||||
四象,
|
||||
self.方向(),
|
||||
self.文,
|
||||
self.武,
|
||||
self.基础序列.len(),
|
||||
self.武.read().unwrap(),
|
||||
self.基础序列.read().unwrap().len(),
|
||||
缺口_str,
|
||||
确认K线_str,
|
||||
)
|
||||
|
||||
@@ -24,20 +24,20 @@
|
||||
|
||||
use crate::structure::segment_feat::线段特征;
|
||||
use crate::types::分型结构;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 特征分型 — 由三个线段特征元素构成的分型
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct 特征分型 {
|
||||
pub 左: Rc<线段特征>,
|
||||
pub 中: Rc<线段特征>,
|
||||
pub 右: Rc<线段特征>,
|
||||
pub 左: Arc<线段特征>,
|
||||
pub 中: Arc<线段特征>,
|
||||
pub 右: Arc<线段特征>,
|
||||
pub 结构: 分型结构,
|
||||
}
|
||||
|
||||
impl 特征分型 {
|
||||
pub fn new(
|
||||
左: Rc<线段特征>, 中: Rc<线段特征>, 右: Rc<线段特征>, 结构: 分型结构
|
||||
左: Arc<线段特征>, 中: Arc<线段特征>, 右: Arc<线段特征>, 结构: 分型结构
|
||||
) -> Self {
|
||||
Self {
|
||||
左, 中, 右, 结构
|
||||
|
||||
@@ -25,14 +25,15 @@
|
||||
use crate::kline::chan_kline::缠论K线;
|
||||
use crate::types::分型结构;
|
||||
use crate::types::相对方向;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 分型 — 由三根缠K构成(可能缺左或右)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct 分型 {
|
||||
pub 左: Option<Rc<缠论K线>>,
|
||||
pub 中: Rc<缠论K线>,
|
||||
pub 右: Option<Rc<缠论K线>>,
|
||||
pub 左: Option<Arc<缠论K线>>,
|
||||
pub 中: Arc<缠论K线>,
|
||||
pub 右: Option<Arc<缠论K线>>,
|
||||
pub 结构: 分型结构,
|
||||
pub 时间戳: i64,
|
||||
pub 分型特征值: f64,
|
||||
@@ -40,11 +41,11 @@ pub struct 分型 {
|
||||
|
||||
impl 分型 {
|
||||
pub fn new(
|
||||
左: Option<Rc<缠论K线>>, 中: Rc<缠论K线>, 右: Option<Rc<缠论K线>>
|
||||
左: Option<Arc<缠论K线>>, 中: Arc<缠论K线>, 右: Option<Arc<缠论K线>>
|
||||
) -> Self {
|
||||
let 结构 = 中.分型.unwrap_or(分型结构::散);
|
||||
let 时间戳 = 中.时间戳;
|
||||
let 分型特征值 = 中.分型特征值;
|
||||
let 结构 = 中.分型.read().unwrap().unwrap_or(分型结构::散);
|
||||
let 时间戳 = 中.时间戳.load(Ordering::Relaxed);
|
||||
let 分型特征值 = 中.分型特征值.get();
|
||||
Self {
|
||||
左,
|
||||
中,
|
||||
@@ -60,9 +61,9 @@ impl 分型 {
|
||||
let 左 = self.左.as_ref()?;
|
||||
let 右 = self.右.as_ref()?;
|
||||
Some((
|
||||
相对方向::分析(左.高, 左.低, self.中.高, self.中.低),
|
||||
相对方向::分析(self.中.高, self.中.低, 右.高, 右.低),
|
||||
相对方向::分析(左.高, 左.低, 右.高, 右.低),
|
||||
相对方向::分析(左.高.get(), 左.低.get(), self.中.高.get(), self.中.低.get()),
|
||||
相对方向::分析(self.中.高.get(), self.中.低.get(), 右.高.get(), 右.低.get()),
|
||||
相对方向::分析(左.高.get(), 左.低.get(), 右.高.get(), 右.低.get()),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -97,17 +98,19 @@ impl 分型 {
|
||||
|
||||
if let (Some(ref 左), Some(ref 右)) = (&self.左, &self.右) {
|
||||
if self.结构 == 分型结构::底 {
|
||||
if 右.标的K线.收盘价 > 左.标的K线.高 {
|
||||
if 右.标的K线.read().unwrap().收盘价 > 左.标的K线.read().unwrap().高 {
|
||||
return "强";
|
||||
} else if 右.标的K线.收盘价 > self.中.标的K线.高 {
|
||||
} else if 右.标的K线.read().unwrap().收盘价 > self.中.标的K线.read().unwrap().高
|
||||
{
|
||||
return "中";
|
||||
} else {
|
||||
return "弱";
|
||||
}
|
||||
} else if self.结构 == 分型结构::顶 {
|
||||
if 右.标的K线.收盘价 < 左.标的K线.低 {
|
||||
if 右.标的K线.read().unwrap().收盘价 < 左.标的K线.read().unwrap().低 {
|
||||
return "强";
|
||||
} else if 右.标的K线.收盘价 < self.中.标的K线.低 {
|
||||
} else if 右.标的K线.read().unwrap().收盘价 < self.中.标的K线.read().unwrap().低
|
||||
{
|
||||
return "中";
|
||||
} else {
|
||||
return "弱";
|
||||
@@ -121,15 +124,21 @@ impl 分型 {
|
||||
pub fn 与MACD柱子分型匹配(&self) -> bool {
|
||||
if let (Some(ref 左), Some(ref 右)) = (&self.左, &self.右) {
|
||||
if self.结构 == 分型结构::底 {
|
||||
let 左_k = 左.标的K线.read().unwrap();
|
||||
let 中_k = self.中.标的K线.read().unwrap();
|
||||
let 右_k = 右.标的K线.read().unwrap();
|
||||
if let (Some(ref 左macd), Some(ref 中macd), Some(ref 右macd)) =
|
||||
(&左.标的K线.macd, &self.中.标的K线.macd, &右.标的K线.macd)
|
||||
(&左_k.macd, &中_k.macd, &右_k.macd)
|
||||
{
|
||||
return 左macd.MACD柱 > 中macd.MACD柱 && 中macd.MACD柱 < 右macd.MACD柱;
|
||||
}
|
||||
}
|
||||
if self.结构 == 分型结构::顶 {
|
||||
let 左_k = 左.标的K线.read().unwrap();
|
||||
let 中_k = self.中.标的K线.read().unwrap();
|
||||
let 右_k = 右.标的K线.read().unwrap();
|
||||
if let (Some(ref 左macd), Some(ref 中macd), Some(ref 右macd)) =
|
||||
(&左.标的K线.macd, &self.中.标的K线.macd, &右.标的K线.macd)
|
||||
(&左_k.macd, &中_k.macd, &右_k.macd)
|
||||
{
|
||||
return 左macd.MACD柱 < 中macd.MACD柱 && 中macd.MACD柱 > 右macd.MACD柱;
|
||||
}
|
||||
@@ -139,35 +148,36 @@ impl 分型 {
|
||||
}
|
||||
|
||||
/// 判断两个分型是否匹配
|
||||
pub fn 判断分型(左: &Rc<分型>, 右: &Rc<分型>, 模式: &str) -> bool {
|
||||
pub fn 判断分型(左: &Arc<分型>, 右: &Arc<分型>, 模式: &str) -> bool {
|
||||
match 模式 {
|
||||
"中" => Rc::as_ptr(左) == Rc::as_ptr(右),
|
||||
"中" => Arc::as_ptr(左) == Arc::as_ptr(右),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 从缠K序列中获取以指定缠K为中元素的分型
|
||||
pub fn 从缠K序列中获取分型(
|
||||
K线序列: &[Rc<缠论K线>], 中: &Rc<缠论K线>
|
||||
K线序列: &[Arc<缠论K线>],
|
||||
中: &Arc<缠论K线>,
|
||||
) -> Option<Self> {
|
||||
let idx = K线序列
|
||||
.iter()
|
||||
.position(|k| Rc::as_ptr(k) == Rc::as_ptr(中))?;
|
||||
.position(|k| Arc::as_ptr(k) == Arc::as_ptr(中))?;
|
||||
let 左 = if idx > 0 {
|
||||
Some(Rc::clone(&K线序列[idx - 1]))
|
||||
Some(Arc::clone(&K线序列[idx - 1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let 右 = if idx + 1 < K线序列.len() {
|
||||
Some(Rc::clone(&K线序列[idx + 1]))
|
||||
Some(Arc::clone(&K线序列[idx + 1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some(Self::new(左, Rc::clone(中), 右))
|
||||
Some(Self::new(左, Arc::clone(中), 右))
|
||||
}
|
||||
|
||||
/// 向分型序列中添加新分型
|
||||
pub fn 向序列中添加(分型序列: &mut Vec<Rc<分型>>, 当前分型: Rc<分型>) {
|
||||
pub fn 向序列中添加(分型序列: &mut Vec<Arc<分型>>, 当前分型: Arc<分型>) {
|
||||
if 分型序列.is_empty() {
|
||||
if 当前分型.结构 != 分型结构::顶 && 当前分型.结构 != 分型结构::底
|
||||
{
|
||||
@@ -188,10 +198,10 @@ impl 分型 {
|
||||
|
||||
impl crate::types::fractal::有高低 for 分型 {
|
||||
fn 高(&self) -> f64 {
|
||||
self.中.高
|
||||
self.中.高.get()
|
||||
}
|
||||
fn 低(&self) -> f64 {
|
||||
self.中.低
|
||||
self.中.低.get()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +210,11 @@ impl std::fmt::Display for 分型 {
|
||||
write!(
|
||||
f,
|
||||
"{}<{}, {}, None: {}, None: {}>",
|
||||
self.中.分型.unwrap_or(crate::types::分型结构::散),
|
||||
self.中
|
||||
.分型
|
||||
.read()
|
||||
.unwrap()
|
||||
.unwrap_or(crate::types::分型结构::散),
|
||||
self.时间戳,
|
||||
crate::utils::format_f64_g(self.分型特征值),
|
||||
if self.左.is_none() { "True" } else { "False" },
|
||||
|
||||
@@ -26,7 +26,8 @@ use crate::structure::dash_line::虚线;
|
||||
use crate::structure::feat_fractal::特征分型;
|
||||
use crate::structure::fractal_obj::分型;
|
||||
use crate::types::{分型结构, 相对方向};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 线段特征 — 特征序列元素(内部是虚线的集合)
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -34,11 +35,11 @@ pub struct 线段特征 {
|
||||
pub 序号: i64,
|
||||
pub 标识: String,
|
||||
pub 线段方向: 相对方向,
|
||||
pub 元素: Vec<Rc<虚线>>,
|
||||
pub 元素: Vec<Arc<虚线>>,
|
||||
}
|
||||
|
||||
impl 线段特征 {
|
||||
pub fn new(标识: String, 基础序列: Vec<Rc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
pub fn new(标识: String, 基础序列: Vec<Arc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
Self {
|
||||
序号: 0,
|
||||
标识,
|
||||
@@ -53,7 +54,7 @@ impl 线段特征 {
|
||||
|
||||
/// 文 — 取特征序列元素中分型特征值最大/最小的文分型
|
||||
/// tiebreaker: later时间戳 wins when特征值 equal (matches Python)
|
||||
pub fn 文(&self) -> Rc<分型> {
|
||||
pub fn 文(&self) -> Arc<分型> {
|
||||
if self.线段方向.是否向上() {
|
||||
self.元素
|
||||
.iter()
|
||||
@@ -64,8 +65,8 @@ impl 线段特征 {
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
.then_with(|| a.文.时间戳.cmp(&b.文.时间戳))
|
||||
})
|
||||
.map(|x| Rc::clone(&x.文))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].文))
|
||||
.map(|x| Arc::clone(&x.文))
|
||||
.unwrap_or_else(|| Arc::clone(&self.元素[0].文))
|
||||
} else {
|
||||
self.元素
|
||||
.iter()
|
||||
@@ -76,38 +77,54 @@ impl 线段特征 {
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
.then_with(|| b.文.时间戳.cmp(&a.文.时间戳))
|
||||
})
|
||||
.map(|x| Rc::clone(&x.文))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].文))
|
||||
.map(|x| Arc::clone(&x.文))
|
||||
.unwrap_or_else(|| Arc::clone(&self.元素[0].文))
|
||||
}
|
||||
}
|
||||
|
||||
/// 武 — 取特征序列元素中分型特征值最大/最小的武分型
|
||||
/// tiebreaker: later时间戳 wins when特征值 equal (matches Python)
|
||||
pub fn 武(&self) -> Rc<分型> {
|
||||
pub fn 武(&self) -> Arc<分型> {
|
||||
if self.线段方向.是否向上() {
|
||||
self.元素
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
a.武
|
||||
.read()
|
||||
.unwrap()
|
||||
.分型特征值
|
||||
.partial_cmp(&b.武.分型特征值)
|
||||
.partial_cmp(&b.武.read().unwrap().分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
.then_with(|| a.武.时间戳.cmp(&b.武.时间戳))
|
||||
.then_with(|| {
|
||||
a.武
|
||||
.read()
|
||||
.unwrap()
|
||||
.时间戳
|
||||
.cmp(&b.武.read().unwrap().时间戳)
|
||||
})
|
||||
})
|
||||
.map(|x| Rc::clone(&x.武))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].武))
|
||||
.map(|x| x.武.read().unwrap().clone())
|
||||
.unwrap_or_else(|| self.元素[0].武.read().unwrap().clone())
|
||||
} else {
|
||||
self.元素
|
||||
.iter()
|
||||
.min_by(|a, b| {
|
||||
a.武
|
||||
.read()
|
||||
.unwrap()
|
||||
.分型特征值
|
||||
.partial_cmp(&b.武.分型特征值)
|
||||
.partial_cmp(&b.武.read().unwrap().分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
.then_with(|| b.武.时间戳.cmp(&a.武.时间戳))
|
||||
.then_with(|| {
|
||||
b.武
|
||||
.read()
|
||||
.unwrap()
|
||||
.时间戳
|
||||
.cmp(&a.武.read().unwrap().时间戳)
|
||||
})
|
||||
})
|
||||
.map(|x| Rc::clone(&x.武))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].武))
|
||||
.map(|x| x.武.read().unwrap().clone())
|
||||
.unwrap_or_else(|| self.元素[0].武.read().unwrap().clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +146,7 @@ impl 线段特征 {
|
||||
}
|
||||
|
||||
/// 向特征序列元素中添加虚线
|
||||
pub fn 添加(&mut self, 待添加虚线: Rc<虚线>) -> Result<(), String> {
|
||||
pub fn 添加(&mut self, 待添加虚线: Arc<虚线>) -> Result<(), String> {
|
||||
if 待添加虚线.方向() == self.线段方向 {
|
||||
return Err("添加方向与线段方向相同".into());
|
||||
}
|
||||
@@ -138,14 +155,14 @@ impl 线段特征 {
|
||||
}
|
||||
|
||||
/// 从特征序列元素中删除虚线
|
||||
pub fn 删除(&mut self, 待删除虚线: &Rc<虚线>) -> Result<(), String> {
|
||||
pub fn 删除(&mut self, 待删除虚线: &Arc<虚线>) -> Result<(), String> {
|
||||
if 待删除虚线.方向() == self.方向() {
|
||||
return Err("删除方向与特征序列方向相同".into());
|
||||
}
|
||||
if let Some(pos) = self
|
||||
.元素
|
||||
.iter()
|
||||
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(待删除虚线))
|
||||
.position(|x| Arc::as_ptr(x) == Arc::as_ptr(待删除虚线))
|
||||
{
|
||||
self.元素.remove(pos);
|
||||
Ok(())
|
||||
@@ -155,19 +172,19 @@ impl 线段特征 {
|
||||
}
|
||||
|
||||
/// 新建特征序列元素
|
||||
pub fn 新建(虚线序列: Vec<Rc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
pub fn 新建(虚线序列: Vec<Arc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
let 标识 = format!("特征<虚线>");
|
||||
Self::new(标识, 虚线序列, 线段方向)
|
||||
}
|
||||
|
||||
/// 静态分析 — 从虚线序列生成特征序列元素列表
|
||||
pub fn 静态分析(
|
||||
虚线序列: &[Rc<虚线>],
|
||||
虚线序列: &[Arc<虚线>],
|
||||
线段方向: 相对方向,
|
||||
四象: &str,
|
||||
是否忽视: bool,
|
||||
) -> Vec<Rc<线段特征>> {
|
||||
let mut 结果: Vec<Rc<线段特征>> = Vec::new();
|
||||
) -> Vec<Arc<线段特征>> {
|
||||
let mut 结果: Vec<Arc<线段特征>> = Vec::new();
|
||||
|
||||
// 需要被合并的方向集合
|
||||
let 需要合并: Vec<相对方向> = match 四象 {
|
||||
@@ -179,9 +196,9 @@ impl 线段特征 {
|
||||
// 情况1:方向相同(可能触发分型替换)
|
||||
if 虚线.方向() == 线段方向 {
|
||||
if 结果.len() >= 3 {
|
||||
let 左 = Rc::clone(&结果[结果.len() - 3]);
|
||||
let 中 = Rc::clone(&结果[结果.len() - 2]);
|
||||
let 右 = Rc::clone(&结果[结果.len() - 1]);
|
||||
let 左 = Arc::clone(&结果[结果.len() - 3]);
|
||||
let 中 = Arc::clone(&结果[结果.len() - 2]);
|
||||
let 右 = Arc::clone(&结果[结果.len() - 1]);
|
||||
|
||||
if let Some(结构) = 分型结构::分析(&*左, &*中, &*右, true, true) {
|
||||
let 应替换 = (线段方向 == 相对方向::向上
|
||||
@@ -192,16 +209,24 @@ impl 线段特征 {
|
||||
&& 虚线.低() < 中.低());
|
||||
|
||||
if 应替换 {
|
||||
let 小号虚线 = 中.元素.iter().min_by_key(|o| o.序号).unwrap();
|
||||
let 大号虚线 = 右.元素.iter().max_by_key(|o| o.序号).unwrap();
|
||||
let 小号虚线 = 中
|
||||
.元素
|
||||
.iter()
|
||||
.min_by_key(|o| o.序号.load(Ordering::Relaxed))
|
||||
.unwrap();
|
||||
let 大号虚线 = 右
|
||||
.元素
|
||||
.iter()
|
||||
.max_by_key(|o| o.序号.load(Ordering::Relaxed))
|
||||
.unwrap();
|
||||
let fake = 虚线::创建笔(
|
||||
Rc::clone(&小号虚线.文),
|
||||
Rc::clone(&大号虚线.武),
|
||||
Arc::clone(&小号虚线.文),
|
||||
大号虚线.武.read().unwrap().clone(),
|
||||
false,
|
||||
);
|
||||
结果.pop();
|
||||
let idx = 结果.len() - 1;
|
||||
结果[idx] = Rc::new(Self::新建(vec![Rc::new(fake)], 线段方向));
|
||||
结果[idx] = Arc::new(Self::新建(vec![Arc::new(fake)], 线段方向));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +235,7 @@ impl 线段特征 {
|
||||
|
||||
// 情况2:方向不同(执行特征序列的合并/添加)
|
||||
if 结果.is_empty() {
|
||||
结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向)));
|
||||
结果.push(Arc::new(Self::新建(vec![Arc::clone(虚线)], 线段方向)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -225,10 +250,10 @@ impl 线段特征 {
|
||||
)) {
|
||||
// Clone-modify-replace
|
||||
let mut 新特征 = (*结果[最后_idx]).clone();
|
||||
let _ = 新特征.添加(Rc::clone(虚线));
|
||||
结果[最后_idx] = Rc::new(新特征);
|
||||
let _ = 新特征.添加(Arc::clone(虚线));
|
||||
结果[最后_idx] = Arc::new(新特征);
|
||||
} else {
|
||||
结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向)));
|
||||
结果.push(Arc::new(Self::新建(vec![Arc::clone(虚线)], 线段方向)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,15 +261,15 @@ impl 线段特征 {
|
||||
}
|
||||
|
||||
/// 获取分型序列
|
||||
pub fn 获取分型序列(特征序列: &[Rc<线段特征>]) -> Vec<特征分型> {
|
||||
pub fn 获取分型序列(特征序列: &[Arc<线段特征>]) -> Vec<特征分型> {
|
||||
let mut 结果 = Vec::new();
|
||||
if 特征序列.len() < 3 {
|
||||
return 结果;
|
||||
}
|
||||
for i in 2..特征序列.len() {
|
||||
let 左 = Rc::clone(&特征序列[i - 2]);
|
||||
let 中 = Rc::clone(&特征序列[i - 1]);
|
||||
let 右 = Rc::clone(&特征序列[i]);
|
||||
let 左 = Arc::clone(&特征序列[i - 2]);
|
||||
let 中 = Arc::clone(&特征序列[i - 1]);
|
||||
let 右 = Arc::clone(&特征序列[i]);
|
||||
|
||||
let 结构 = 分型结构::分析_对象(
|
||||
&*左 as &dyn crate::types::fractal::有高低,
|
||||
@@ -285,3 +310,273 @@ impl std::fmt::Display for 线段特征 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::kline::bar::K线;
|
||||
use crate::kline::chan_kline::缠论K线;
|
||||
use crate::structure::fractal_obj::分型;
|
||||
use crate::types::分型结构;
|
||||
|
||||
fn 辅助_创建K线(时间戳: i64, 高: f64, 低: f64, 开: f64, 收: f64) -> K线 {
|
||||
let mut k = K线::default();
|
||||
k.时间戳 = 时间戳;
|
||||
k.高 = 高;
|
||||
k.低 = 低;
|
||||
k.开盘价 = 开;
|
||||
k.收盘价 = 收;
|
||||
k
|
||||
}
|
||||
|
||||
fn 辅助_创建缠K(
|
||||
时间戳: i64,
|
||||
高: f64,
|
||||
低: f64,
|
||||
方向: 相对方向,
|
||||
结构: Option<分型结构>,
|
||||
序号: i64,
|
||||
) -> Arc<缠论K线> {
|
||||
let 普K = Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高));
|
||||
Arc::new(缠论K线::创建缠K(
|
||||
时间戳, 高, 低, 方向, 结构, 序号, 普K, None,
|
||||
))
|
||||
}
|
||||
|
||||
fn 辅助_创建顶分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> {
|
||||
let 左 = 辅助_创建缠K(
|
||||
时间戳 - 2,
|
||||
高 - 2.0,
|
||||
低 - 2.0,
|
||||
相对方向::向上,
|
||||
Some(分型结构::上),
|
||||
序号 - 2,
|
||||
);
|
||||
let 中 = 辅助_创建缠K(时间戳, 高, 低, 相对方向::向上, Some(分型结构::顶), 序号);
|
||||
let 右 = 辅助_创建缠K(
|
||||
时间戳 + 2,
|
||||
高 - 1.0,
|
||||
低 - 1.0,
|
||||
相对方向::向下,
|
||||
Some(分型结构::下),
|
||||
序号 + 2,
|
||||
);
|
||||
Arc::new(分型::new(Some(左), 中, Some(右)))
|
||||
}
|
||||
|
||||
fn 辅助_创建底分型(时间戳: i64, 高: f64, 低: f64, 序号: i64) -> Arc<分型> {
|
||||
let 左 = 辅助_创建缠K(
|
||||
时间戳 - 2,
|
||||
高 + 2.0,
|
||||
低 + 2.0,
|
||||
相对方向::向下,
|
||||
Some(分型结构::下),
|
||||
序号 - 2,
|
||||
);
|
||||
let 中 = 缠论K线::创建缠K(
|
||||
时间戳,
|
||||
高,
|
||||
低,
|
||||
相对方向::向下,
|
||||
Some(分型结构::底),
|
||||
序号,
|
||||
Arc::new(辅助_创建K线(时间戳, 高, 低, 低, 高)),
|
||||
None,
|
||||
);
|
||||
中.分型特征值.set(低);
|
||||
let 中 = Arc::new(中);
|
||||
let 右 = 辅助_创建缠K(
|
||||
时间戳 + 2,
|
||||
高 + 1.0,
|
||||
低 + 1.0,
|
||||
相对方向::向上,
|
||||
Some(分型结构::上),
|
||||
序号 + 2,
|
||||
);
|
||||
Arc::new(分型::new(Some(左), 中, Some(右)))
|
||||
}
|
||||
|
||||
fn 辅助_创建笔(
|
||||
文时间戳: i64,
|
||||
文高: f64,
|
||||
文低: f64,
|
||||
武时间戳: i64,
|
||||
武高: f64,
|
||||
武低: f64,
|
||||
) -> Arc<虚线> {
|
||||
let 顶 = 辅助_创建顶分型(文时间戳, 文高, 文低, 1);
|
||||
let 底 = 辅助_创建底分型(武时间戳, 武高, 武低, 2);
|
||||
Arc::new(虚线::创建笔(顶, 底, true))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 文 — 取特征值最大/最小的分型
|
||||
// 特征序列元素方向与线段方向相反:
|
||||
// 向上线段 → 元素为向下笔(顶→底) → 文=顶分型 → 取max
|
||||
// 向下线段 → 元素为向上笔(底→顶) → 文=底分型 → 取min
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_文_向上线段取最大特征值分型() {
|
||||
// 向上线段,元素用向下笔(顶→底),文=顶分型
|
||||
// 笔1: 顶(特征值=100)→底(80), 文=顶(100)
|
||||
let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0);
|
||||
// 笔2: 顶(特征值=110)→底(90), 文=顶(110)
|
||||
let 笔2 = 辅助_创建笔(200, 110.0, 100.0, 300, 90.0, 80.0);
|
||||
|
||||
let feat = 线段特征::new(
|
||||
"测试".into(),
|
||||
vec![Arc::clone(&笔1), Arc::clone(&笔2)],
|
||||
相对方向::向上,
|
||||
);
|
||||
|
||||
// 向上取max → 笔2.文=110
|
||||
let 文 = feat.文();
|
||||
assert!((文.分型特征值 - 110.0).abs() < 0.01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_文_向下线段取最小特征值分型() {
|
||||
// 向下线段,元素用向上笔(底→顶),文=底分型
|
||||
// 笔1: 底(特征值=80)→顶(100), 文=底(80)
|
||||
let 底1 = 辅助_创建底分型(100, 90.0, 80.0, 5);
|
||||
let 顶1 = 辅助_创建顶分型(200, 100.0, 90.0, 10);
|
||||
let 笔1 = Arc::new(虚线::创建笔(底1, 顶1, true));
|
||||
|
||||
// 笔2: 底(特征值=70)→顶(95), 文=底(70)
|
||||
let 底2 = 辅助_创建底分型(200, 80.0, 70.0, 15);
|
||||
let 顶2 = 辅助_创建顶分型(300, 95.0, 85.0, 20);
|
||||
let 笔2 = Arc::new(虚线::创建笔(底2, 顶2, true));
|
||||
|
||||
let feat = 线段特征::new(
|
||||
"测试".into(),
|
||||
vec![Arc::clone(&笔1), Arc::clone(&笔2)],
|
||||
相对方向::向下,
|
||||
);
|
||||
|
||||
// 向下取min → 笔2.文=70
|
||||
let 文 = feat.文();
|
||||
assert!((文.分型特征值 - 70.0).abs() < 0.01);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 武 — 取特征值最大/最小的分型
|
||||
// 向上线段 → 元素为向下笔 → 武=底分型 → 取max
|
||||
// 向下线段 → 元素为向上笔 → 武=顶分型 → 取min
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_武_向上线段取最大特征值分型() {
|
||||
// 向上线段,元素用向下笔(顶→底),武=底分型
|
||||
// 笔1: 顶(100)→底(特征值=80), 武=底(80)
|
||||
let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0);
|
||||
// 笔2: 顶(110)→底(特征值=90), 武=底(90)
|
||||
let 笔2 = 辅助_创建笔(200, 110.0, 100.0, 300, 100.0, 90.0);
|
||||
|
||||
let feat = 线段特征::new(
|
||||
"测试".into(),
|
||||
vec![Arc::clone(&笔1), Arc::clone(&笔2)],
|
||||
相对方向::向上,
|
||||
);
|
||||
|
||||
// 向上取max → 笔2.武=90
|
||||
let 武 = feat.武();
|
||||
assert!((武.分型特征值 - 90.0).abs() < 0.01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_武_向下线段取最小特征值分型() {
|
||||
// 向下线段,元素用向上笔(底→顶),武=顶分型
|
||||
// 笔1: 底(80)→顶(特征值=100), 武=顶(100)
|
||||
let 底1 = 辅助_创建底分型(100, 90.0, 80.0, 5);
|
||||
let 顶1 = 辅助_创建顶分型(200, 100.0, 90.0, 10);
|
||||
let 笔1 = Arc::new(虚线::创建笔(底1, 顶1, true));
|
||||
|
||||
// 笔2: 底(60)→顶(特征值=85), 武=顶(85)
|
||||
let 底2 = 辅助_创建底分型(200, 70.0, 60.0, 15);
|
||||
let 顶2 = 辅助_创建顶分型(300, 85.0, 75.0, 20);
|
||||
let 笔2 = Arc::new(虚线::创建笔(底2, 顶2, true));
|
||||
|
||||
let feat = 线段特征::new(
|
||||
"测试".into(),
|
||||
vec![Arc::clone(&笔1), Arc::clone(&笔2)],
|
||||
相对方向::向下,
|
||||
);
|
||||
|
||||
// 向下取min → 笔2.武=85
|
||||
let 武 = feat.武();
|
||||
assert!((武.分型特征值 - 85.0).abs() < 0.01);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 文/武 tiebreaker — 同特征值取后时间戳
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_文_同特征值取后时间戳() {
|
||||
// 两个笔的文特征值相同=100,但时间戳不同
|
||||
let 顶1 = 辅助_创建顶分型(100, 100.0, 90.0, 5);
|
||||
let 底1 = 辅助_创建底分型(200, 90.0, 80.0, 10);
|
||||
let 笔1 = Arc::new(虚线::创建笔(顶1, 底1, true));
|
||||
|
||||
let 顶2 = 辅助_创建顶分型(300, 100.0, 90.0, 15); // 同特征值,后时间戳
|
||||
let 底2 = 辅助_创建底分型(400, 80.0, 70.0, 20);
|
||||
let 笔2 = Arc::new(虚线::创建笔(顶2, 底2, true));
|
||||
|
||||
let feat = 线段特征::new("测试".into(), vec![笔1, 笔2], 相对方向::向上);
|
||||
|
||||
let 文 = feat.文();
|
||||
// 向上取最大特征值:都是100 → tiebreaker取后时间戳 → 笔2.文(300)
|
||||
assert_eq!(文.时间戳, 300);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_武_同特征值取后时间戳_向上() {
|
||||
let 顶1 = 辅助_创建顶分型(100, 100.0, 90.0, 5);
|
||||
let 底1 = 辅助_创建底分型(200, 80.0, 70.0, 10); // 特征值80
|
||||
let 笔1 = Arc::new(虚线::创建笔(顶1, 底1, true));
|
||||
|
||||
let 顶2 = 辅助_创建顶分型(300, 80.0, 70.0, 15); // 特征值80
|
||||
let 底2 = 辅助_创建底分型(400, 80.0, 70.0, 20); // 特征值80
|
||||
let 笔2 = Arc::new(虚线::创建笔(顶2, 底2, true));
|
||||
|
||||
let feat = 线段特征::new("测试".into(), vec![笔1, 笔2], 相对方向::向上);
|
||||
|
||||
let 武 = feat.武();
|
||||
// 向上取最大特征值:都是80 → tiebreaker取后时间戳 → 笔2.武(400)
|
||||
assert_eq!(武.时间戳, 400);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 添加/删除 操作
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_添加方向与线段方向相反的虚线可成功() {
|
||||
// 向下笔(顶→底,方向=向下) 添加到 向上线段(方向=向上) → 方向不同, 可添加
|
||||
let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0);
|
||||
let mut feat = 线段特征::new("测试".into(), vec![], 相对方向::向上);
|
||||
|
||||
let result = feat.添加(Arc::clone(&笔1));
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_添加方向与线段方向相同的虚线应报错() {
|
||||
// 向下笔(顶→底,方向=向下) 添加到 向下线段(方向=向下) → 方向相同, 应报错
|
||||
let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0);
|
||||
let mut feat = 线段特征::new("测试".into(), vec![], 相对方向::向下);
|
||||
|
||||
let result = feat.添加(Arc::clone(&笔1));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_空线段特征文返回第一个元素的文() {
|
||||
let 笔1 = 辅助_创建笔(100, 100.0, 90.0, 200, 90.0, 80.0);
|
||||
let feat = 线段特征::new("测试".into(), vec![Arc::clone(&笔1)], 相对方向::向上);
|
||||
|
||||
let 文 = feat.文();
|
||||
assert_eq!(Arc::as_ptr(&文), Arc::as_ptr(&笔1.文));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user