第二版
This commit is contained in:
+167
-63
@@ -12,7 +12,11 @@ pub struct 笔;
|
||||
|
||||
impl 笔 {
|
||||
/// 获取可成笔的缠K数量(考虑弱化模式)
|
||||
pub fn 获取缠K数量(缠K序列: &[Rc<缠论K线>], 笔序列: &[Rc<虚线>], 配置: &缠论配置) -> usize {
|
||||
pub fn 获取缠K数量(
|
||||
缠K序列: &[Rc<缠论K线>],
|
||||
笔序列: &[Rc<虚线>],
|
||||
配置: &缠论配置,
|
||||
) -> usize {
|
||||
let 实际数量 = 缠K序列.len();
|
||||
if 实际数量 >= 配置.笔内元素数量 as usize {
|
||||
return 实际数量;
|
||||
@@ -31,13 +35,19 @@ impl 笔 {
|
||||
|
||||
if !笔序列.is_empty() {
|
||||
// Try both high and low points (Python: 根据缠K找笔(笔序列, 实际高点) or 根据缠K找笔(笔序列, 实际低点))
|
||||
let 筆 = 实际高点.as_ref()
|
||||
let 筆 = 实际高点
|
||||
.as_ref()
|
||||
.and_then(|h| Self::根据缠K找笔(笔序列, h, 1))
|
||||
.or_else(|| 实际低点.as_ref().and_then(|l| Self::根据缠K找笔(笔序列, l, 1)));
|
||||
.or_else(|| {
|
||||
实际低点
|
||||
.as_ref()
|
||||
.and_then(|l| Self::根据缠K找笔(笔序列, l, 1))
|
||||
});
|
||||
|
||||
if let Some(ref 筆) = 筆 {
|
||||
if let (Some(ref 高_k), Some(ref 低_k)) = (&实际高点, &实际低点) {
|
||||
let 原始数量 = 1 + (低_k.标的K线.序号 - 高_k.标的K线.序号).unsigned_abs() as usize;
|
||||
let 原始数量 =
|
||||
1 + (低_k.标的K线.序号 - 高_k.标的K线.序号).unsigned_abs() as usize;
|
||||
// 向上笔
|
||||
if 筆.方向().是否向上() && 低_k.低 < 筆.低() {
|
||||
if 原始数量 >= 配置.笔弱化_原始数量 as usize {
|
||||
@@ -62,15 +72,25 @@ impl 笔 {
|
||||
if 缠K序列.len() < 2 {
|
||||
return 缠K序列.first().cloned();
|
||||
}
|
||||
let max_高 = 缠K序列.iter().map(|k| k.高).fold(f64::NEG_INFINITY, f64::max);
|
||||
let max_高 = 缠K序列
|
||||
.iter()
|
||||
.map(|k| k.高)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
// 排除最高值
|
||||
let filtered: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.高 != max_高).collect();
|
||||
if filtered.is_empty() {
|
||||
return 缠K序列.first().cloned();
|
||||
}
|
||||
// 筛选次高值
|
||||
let second_高 = filtered.iter().map(|k| k.高).fold(f64::NEG_INFINITY, f64::max);
|
||||
let mut candidates: Vec<&Rc<缠论K线>> = filtered.iter().filter(|k| k.高 == second_高).copied().collect();
|
||||
let second_高 = filtered
|
||||
.iter()
|
||||
.map(|k| k.高)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
let mut candidates: Vec<&Rc<缠论K线>> = filtered
|
||||
.iter()
|
||||
.filter(|k| k.高 == second_高)
|
||||
.copied()
|
||||
.collect();
|
||||
// 按时间戳排序
|
||||
candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳));
|
||||
if 取舍 {
|
||||
@@ -93,7 +113,11 @@ impl 笔 {
|
||||
}
|
||||
// 筛选次低值
|
||||
let second_低 = filtered.iter().map(|k| k.低).fold(f64::INFINITY, f64::min);
|
||||
let mut candidates: Vec<&Rc<缠论K线>> = filtered.iter().filter(|k| k.低 == second_低).copied().collect();
|
||||
let mut candidates: Vec<&Rc<缠论K线>> = filtered
|
||||
.iter()
|
||||
.filter(|k| k.低 == second_低)
|
||||
.copied()
|
||||
.collect();
|
||||
// 按时间戳排序
|
||||
candidates.sort_by(|a, b| a.时间戳.cmp(&b.时间戳));
|
||||
if 取舍 {
|
||||
@@ -108,7 +132,10 @@ impl 笔 {
|
||||
if 缠K序列.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let max_高 = 缠K序列.iter().map(|k| k.高).fold(f64::NEG_INFINITY, f64::max);
|
||||
let max_高 = 缠K序列
|
||||
.iter()
|
||||
.map(|k| k.高)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
let mut candidates: Vec<&Rc<缠论K线>> = 缠K序列.iter().filter(|k| k.高 == max_高).collect();
|
||||
if candidates.is_empty() {
|
||||
return Some(Rc::clone(&缠K序列[0]));
|
||||
@@ -142,30 +169,84 @@ impl 笔 {
|
||||
}
|
||||
|
||||
/// 判断笔的相对关系是否合理
|
||||
pub fn 相对关系(筆: &虚线, _配置: &缠论配置) -> bool {
|
||||
let 文 = &筆.文;
|
||||
let 武 = &筆.武;
|
||||
pub fn 相对关系(筆: &虚线, 配置: &缠论配置) -> bool {
|
||||
let 文分型 = &筆.文;
|
||||
let 武分型 = &筆.武;
|
||||
|
||||
// 向上笔:文(底)低 → 武(顶)高
|
||||
if 筆.方向().是否向上() {
|
||||
return 武.分型特征值 > 文.分型特征值;
|
||||
let 相对关系 = if 配置.笔内起始分型包含整笔 {
|
||||
let 文中_rc = Rc::clone(&文分型.中);
|
||||
let 武中_rc = Rc::clone(&武分型.中);
|
||||
let 文_元素: [Option<&Rc<缠论K线>>; 3] =
|
||||
[文分型.左.as_ref(), Some(&文中_rc), 文分型.右.as_ref()];
|
||||
let 有效序列: Vec<&Rc<缠论K线>> = 文_元素.iter().filter_map(|x| *x).collect();
|
||||
let 文高 = 有效序列
|
||||
.iter()
|
||||
.map(|k| k.高)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
let 文低 = 有效序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min);
|
||||
|
||||
let 武_右: Option<&Rc<缠论K线>> = if 配置.笔内起始分型包含整笔_包括右 {
|
||||
武分型.右.as_ref()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let 武_元素: [Option<&Rc<缠论K线>>; 3] = [武分型.左.as_ref(), Some(&武中_rc), 武_右];
|
||||
let 有效序列: Vec<&Rc<缠论K线>> = 武_元素.iter().filter_map(|x| *x).collect();
|
||||
let 武高 = 有效序列
|
||||
.iter()
|
||||
.map(|k| k.高)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
let 武低 = 有效序列.iter().map(|k| k.低).fold(f64::INFINITY, f64::min);
|
||||
|
||||
crate::types::相对方向::分析(文高, 文低, 武高, 武低)
|
||||
} else {
|
||||
let 相对关系 = crate::types::相对方向::分析(
|
||||
文分型.中.高,
|
||||
文分型.中.低,
|
||||
武分型.中.高,
|
||||
武分型.中.低,
|
||||
);
|
||||
if 配置.笔内原始K线包含整笔 {
|
||||
let 文标的 = &文分型.中.标的K线;
|
||||
let 武标的 = &武分型.中.标的K线;
|
||||
if crate::types::相对方向::分析(文标的.高, 文标的.低, 武标的.高, 武标的.低)
|
||||
.是否包含()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
相对关系
|
||||
};
|
||||
|
||||
if 筆.方向() == crate::types::相对方向::向下 {
|
||||
return 相对关系.是否向下();
|
||||
}
|
||||
// 向下笔:文(顶)高 → 武(底)低
|
||||
武.分型特征值 < 文.分型特征值
|
||||
相对关系.是否向上()
|
||||
}
|
||||
|
||||
/// 以文会友 — 根据起点分型找笔
|
||||
pub fn 以文会友(笔序列: &[Rc<虚线>], 文: &Rc<分型>) -> Option<Rc<虚线>> {
|
||||
笔序列.iter().find(|b| Rc::as_ptr(&b.文) == Rc::as_ptr(文)).cloned()
|
||||
笔序列
|
||||
.iter()
|
||||
.find(|b| Rc::as_ptr(&b.文) == Rc::as_ptr(文))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// 以武会友 — 根据终点分型找笔
|
||||
pub fn 以武会友(笔序列: &[Rc<虚线>], 武: &Rc<分型>) -> Option<Rc<虚线>> {
|
||||
笔序列.iter().find(|b| Rc::as_ptr(&b.武) == Rc::as_ptr(武)).cloned()
|
||||
笔序列
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|b| Rc::as_ptr(&b.武) == Rc::as_ptr(武))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// 根据缠K找对应的笔
|
||||
pub fn 根据缠K找笔(笔序列: &[Rc<虚线>], 缠K: &Rc<缠论K线>, 偏移: i64) -> Option<Rc<虚线>> {
|
||||
pub fn 根据缠K找笔(
|
||||
笔序列: &[Rc<虚线>],
|
||||
缠K: &Rc<缠论K线>,
|
||||
偏移: i64,
|
||||
) -> Option<Rc<虚线>> {
|
||||
// Python iterates in reverse: for 筆 in 笔序列[::-1]
|
||||
for b in 笔序列.iter().rev() {
|
||||
// Python: 筆.文.中.序号 - 偏移 <= 缠K.序号 <= 筆.武.中.序号
|
||||
@@ -282,7 +363,8 @@ impl 笔 {
|
||||
let 之前分型 = Rc::clone(分型序列.last().unwrap());
|
||||
|
||||
// Python line 2338: 时序检查 — skip out-of-order fractals
|
||||
if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1 {
|
||||
if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -310,8 +392,12 @@ impl 笔 {
|
||||
|
||||
// Python line 2350: 分型结构相反 → 可能成笔
|
||||
if 之前分型.结构 != 当前分型.结构 {
|
||||
let 文_idx = 缠K序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(&之前分型.中));
|
||||
let 武_idx = 缠K序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(&当前分型.中));
|
||||
let 文_idx = 缠K序列
|
||||
.iter()
|
||||
.position(|k| Rc::as_ptr(k) == Rc::as_ptr(&之前分型.中));
|
||||
let 武_idx = 缠K序列
|
||||
.iter()
|
||||
.position(|k| Rc::as_ptr(k) == Rc::as_ptr(&当前分型.中));
|
||||
|
||||
if let (Some(文_idx), Some(武_idx)) = (文_idx, 武_idx) {
|
||||
let 基础序列 = &缠K序列[文_idx..=武_idx];
|
||||
@@ -339,7 +425,9 @@ impl 笔 {
|
||||
|
||||
// Python line 2369-2372: 武将
|
||||
let 武将 = match 当前分型.结构 {
|
||||
分型结构::底 => Self::实际低点(基础序列, 配置.笔内相同终点取舍),
|
||||
分型结构::底 => {
|
||||
Self::实际低点(基础序列, 配置.笔内相同终点取舍)
|
||||
}
|
||||
_ => Self::实际高点(基础序列, 配置.笔内相同终点取舍),
|
||||
};
|
||||
|
||||
@@ -377,7 +465,9 @@ impl 笔 {
|
||||
} else {
|
||||
// Python line 2388-2390: 元素不足 → 右元素扩展
|
||||
if let Some(ref 右) = 当前分型.右 {
|
||||
if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 右) {
|
||||
if let Some(临时分型) =
|
||||
分型::从缠K序列中获取分型(缠K序列, 右)
|
||||
{
|
||||
栈.push(栈项::分型(Rc::new(临时分型), 递归层次 + 1));
|
||||
continue;
|
||||
}
|
||||
@@ -398,8 +488,7 @@ impl 笔 {
|
||||
let 被替换分型 = Rc::clone(&之前分型);
|
||||
Self::弹出旧笔(分型序列, 笔序列);
|
||||
|
||||
if let Some(k线序列) =
|
||||
缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中)
|
||||
if let Some(k线序列) = 缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中)
|
||||
{
|
||||
let 武将 = match 被替换分型.结构 {
|
||||
分型结构::顶 => {
|
||||
@@ -490,7 +579,8 @@ impl 笔 {
|
||||
|
||||
// Python line 2337-2341: 时序检查
|
||||
let 之前分型 = Rc::clone(分型序列.last().unwrap());
|
||||
if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1 {
|
||||
if 之前分型.时间戳 > 当前分型.时间戳 && 之前分型.中.序号 - 当前分型.中.序号 > 1
|
||||
{
|
||||
println!("时序错误-{}, {}, {}", 递归层次, 之前分型, 当前分型);
|
||||
return 递归层次;
|
||||
}
|
||||
@@ -509,7 +599,13 @@ impl 笔 {
|
||||
if 破位 {
|
||||
Self::弹出旧笔(分型序列, 笔序列);
|
||||
return Self::分析递归(
|
||||
当前分型, 分型序列, 笔序列, 缠K序列, _普K序列, 递归层次 + 1, 配置,
|
||||
当前分型,
|
||||
分型序列,
|
||||
笔序列,
|
||||
缠K序列,
|
||||
_普K序列,
|
||||
递归层次 + 1,
|
||||
配置,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -518,7 +614,8 @@ impl 笔 {
|
||||
// Python line 2350: 分型结构相反 → 可能成笔
|
||||
let 之前分型 = Rc::clone(分型序列.last().unwrap());
|
||||
if 之前分型.结构 != 当前分型.结构 {
|
||||
if let Some(基础序列) = 缠论K线::截取(缠K序列, &之前分型.中, &当前分型.中) {
|
||||
if let Some(基础序列) = 缠论K线::截取(缠K序列, &之前分型.中, &当前分型.中)
|
||||
{
|
||||
let 当前笔 = Rc::new(虚线::创建笔(
|
||||
Rc::clone(&之前分型),
|
||||
Rc::clone(&当前分型),
|
||||
@@ -549,7 +646,11 @@ impl 笔 {
|
||||
配置,
|
||||
);
|
||||
return Self::分析递归(
|
||||
当前分型, 分型序列, 笔序列, 缠K序列, _普K序列,
|
||||
当前分型,
|
||||
分型序列,
|
||||
笔序列,
|
||||
缠K序列,
|
||||
_普K序列,
|
||||
递归层次 + 1,
|
||||
配置,
|
||||
);
|
||||
@@ -559,9 +660,7 @@ impl 笔 {
|
||||
|
||||
// Python line 2369-2375: 武将 and笔形成
|
||||
let 武将 = match 当前分型.结构 {
|
||||
分型结构::底 => {
|
||||
Self::实际低点(&基础序列, 配置.笔内相同终点取舍)
|
||||
}
|
||||
分型结构::底 => Self::实际低点(&基础序列, 配置.笔内相同终点取舍),
|
||||
_ => Self::实际高点(&基础序列, 配置.笔内相同终点取舍),
|
||||
};
|
||||
|
||||
@@ -578,9 +677,7 @@ impl 笔 {
|
||||
// Python line 2378-2385: 笔次级成笔
|
||||
if 配置.笔次级成笔 {
|
||||
let 武将 = match 当前分型.结构 {
|
||||
分型结构::底 => {
|
||||
Self::次低(&基础序列, 配置.笔内相同终点取舍)
|
||||
}
|
||||
分型结构::底 => Self::次低(&基础序列, 配置.笔内相同终点取舍),
|
||||
_ => Self::次高(&基础序列, 配置.笔内相同终点取舍),
|
||||
};
|
||||
if let Some(ref 武将_k) = 武将 {
|
||||
@@ -595,8 +692,7 @@ impl 笔 {
|
||||
} else {
|
||||
// Python line 2388-2390: 元素不足 → 右元素扩展
|
||||
if let Some(ref 右) = 当前分型.右 {
|
||||
if let Some(临时分型) =
|
||||
分型::从缠K序列中获取分型(缠K序列, 右)
|
||||
if let Some(临时分型) = 分型::从缠K序列中获取分型(缠K序列, 右)
|
||||
{
|
||||
return Self::分析递归(
|
||||
Rc::new(临时分型),
|
||||
@@ -626,13 +722,10 @@ impl 笔 {
|
||||
let 被替换分型 = Rc::clone(&之前分型);
|
||||
Self::弹出旧笔(分型序列, 笔序列);
|
||||
|
||||
if let Some(k线序列) =
|
||||
缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中)
|
||||
if let Some(k线序列) = 缠论K线::截取(缠K序列, &被替换分型.中, &当前分型.中)
|
||||
{
|
||||
let 武将 = match 被替换分型.结构 {
|
||||
分型结构::顶 => {
|
||||
Self::实际低点(&k线序列, 配置.笔内相同终点取舍)
|
||||
}
|
||||
分型结构::顶 => Self::实际低点(&k线序列, 配置.笔内相同终点取舍),
|
||||
_ => Self::实际高点(&k线序列, 配置.笔内相同终点取舍),
|
||||
};
|
||||
|
||||
@@ -667,10 +760,11 @@ impl 笔 {
|
||||
|| ck.分型 == Some(分型结构::顶)
|
||||
{
|
||||
if let Some(错过分型) =
|
||||
分型::从缠K序列中获取分型(缠K序列, ck)
|
||||
分型::从缠K序列中获取分型(
|
||||
缠K序列, ck,
|
||||
)
|
||||
{
|
||||
let 错过分型_rc =
|
||||
Rc::new(错过分型);
|
||||
let 错过分型_rc = Rc::new(错过分型);
|
||||
递归层次 = Self::分析递归(
|
||||
Rc::clone(&错过分型_rc),
|
||||
分型序列,
|
||||
@@ -687,7 +781,11 @@ impl 笔 {
|
||||
}
|
||||
|
||||
return Self::分析递归(
|
||||
当前分型, 分型序列, 笔序列, 缠K序列, _普K序列,
|
||||
当前分型,
|
||||
分型序列,
|
||||
笔序列,
|
||||
缠K序列,
|
||||
_普K序列,
|
||||
递归层次 + 1,
|
||||
配置,
|
||||
);
|
||||
@@ -700,7 +798,13 @@ impl 笔 {
|
||||
分型::向序列中添加(分型序列, 当前分型);
|
||||
} else {
|
||||
return Self::分析递归(
|
||||
当前分型, 分型序列, 笔序列, 缠K序列, _普K序列, 递归层次 + 1, 配置,
|
||||
当前分型,
|
||||
分型序列,
|
||||
笔序列,
|
||||
缠K序列,
|
||||
_普K序列,
|
||||
递归层次 + 1,
|
||||
配置,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -714,20 +818,17 @@ impl 笔 {
|
||||
分型序列: &mut Vec<Rc<分型>>,
|
||||
笔序列: &mut Vec<Rc<虚线>>,
|
||||
新分型: Rc<分型>,
|
||||
新笔: Rc<虚线>,
|
||||
mut 新笔: Rc<虚线>,
|
||||
) {
|
||||
分型序列.push(新分型);
|
||||
let 序号 = if 笔序列.is_empty() {
|
||||
0
|
||||
} else {
|
||||
笔序列.last().unwrap().序号 + 1
|
||||
};
|
||||
let mut 虚线笔 = (*新笔).clone();
|
||||
虚线笔.序号 = 序号;
|
||||
if 虚线笔.武.左.is_none() && 虚线笔.武.右.is_none() {
|
||||
虚线笔.有效性 = false;
|
||||
if !笔序列.is_empty() {
|
||||
let seg = Rc::make_mut(&mut 新笔);
|
||||
seg.序号 = 笔序列.last().unwrap().序号 + 1;
|
||||
if seg.武.左.is_none() && seg.武.右.is_none() {
|
||||
seg.有效性 = false;
|
||||
}
|
||||
}
|
||||
笔序列.push(Rc::new(虚线笔));
|
||||
笔序列.push(新笔);
|
||||
}
|
||||
|
||||
/// 自检 — 验证笔的有效性(文为实际高/低点,武为实际低/高点)
|
||||
@@ -735,13 +836,15 @@ impl 笔 {
|
||||
let 笔序列 = &观察员.笔序列;
|
||||
let 配置 = &观察员.配置;
|
||||
let 基础序列 = 筆.获取缠K序列(&观察员.缠论K线序列);
|
||||
if Self::获取缠K数量(&基础序列, 笔序列, 配置) >= 配置.笔内元素数量 as usize {
|
||||
if Self::获取缠K数量(&基础序列, 笔序列, 配置) >= 配置.笔内元素数量 as usize
|
||||
{
|
||||
if 筆.方向() == 相对方向::向下 {
|
||||
if let (Some(实际高), Some(实际低)) = (
|
||||
Self::实际高点(&基础序列, false),
|
||||
Self::实际低点(&基础序列, 配置.笔内相同终点取舍),
|
||||
) {
|
||||
if Rc::ptr_eq(&筆.文.中, &实际高) && Rc::ptr_eq(&筆.武.中, &实际低) {
|
||||
if Rc::ptr_eq(&筆.文.中, &实际高) && Rc::ptr_eq(&筆.武.中, &实际低)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -751,7 +854,8 @@ impl 笔 {
|
||||
Self::实际低点(&基础序列, false),
|
||||
Self::实际高点(&基础序列, 配置.笔内相同终点取舍),
|
||||
) {
|
||||
if Rc::ptr_eq(&筆.文.中, &实际低) && Rc::ptr_eq(&筆.武.中, &实际高) {
|
||||
if Rc::ptr_eq(&筆.文.中, &实际低) && Rc::ptr_eq(&筆.武.中, &实际高)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +1,134 @@
|
||||
use crate::config::缠论配置;
|
||||
use crate::kline::bar::K线;
|
||||
use crate::structure::dash_line::虚线;
|
||||
use crate::types::相对方向;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// 背驰分析 — 判断进入段和离开段之间是否存在背驰
|
||||
pub struct 背驰分析;
|
||||
|
||||
impl 背驰分析 {
|
||||
/// MACD背驰 — 离开段MACD柱子面积小于进入段
|
||||
pub fn MACD背驰(进入段: &虚线, 离开段: &虚线, K线序列: &[Rc<K线>], 方式: &str) -> bool {
|
||||
// 获取进入段和离开段对应的K线
|
||||
let 进入段_始 = 进入段.文.中.原始起始序号 as usize;
|
||||
let 进入段_终 = 进入段.武.中.原始结束序号 as usize;
|
||||
let 离开段_始 = 离开段.文.中.原始起始序号 as usize;
|
||||
let 离开段_终 = 离开段.武.中.原始结束序号 as usize;
|
||||
/// MACD背驰 — MACD柱状线面积背驰
|
||||
/// 方式: "总"=阳+|阴|总面积, 其他=按进入段方向选阳或阴
|
||||
pub fn MACD背驰(
|
||||
进入段: &虚线, 离开段: &虚线, K线序列: &[Rc<K线>], 方式: &str
|
||||
) -> bool {
|
||||
let 进入MACD =
|
||||
Self::_获取MACD面积(K线序列, &进入段.文.中.标的K线, &进入段.武.中.标的K线);
|
||||
let 离开MACD =
|
||||
Self::_获取MACD面积(K线序列, &离开段.文.中.标的K线, &离开段.武.中.标的K线);
|
||||
|
||||
if 进入段_终 >= K线序列.len() || 离开段_终 >= K线序列.len() {
|
||||
return false;
|
||||
}
|
||||
// 计算面积(绝对值求和)
|
||||
let 进入面积 = if 方式 == "总" {
|
||||
进入MACD.总().abs()
|
||||
} else if 进入段.方向() == 相对方向::向上 {
|
||||
进入MACD.阳.abs()
|
||||
} else {
|
||||
进入MACD.阴.abs()
|
||||
};
|
||||
let 离开面积 = if 方式 == "总" {
|
||||
离开MACD.总().abs()
|
||||
} else if 进入段.方向() == 相对方向::向上 {
|
||||
离开MACD.阳.abs()
|
||||
} else {
|
||||
离开MACD.阴.abs()
|
||||
};
|
||||
|
||||
let 进入MACD = Self::柱子面积(&K线序列[进入段_始..=进入段_终], 方式);
|
||||
let 离开MACD = Self::柱子面积(&K线序列[离开段_始..=离开段_终], 方式);
|
||||
|
||||
// 背驰条件: 离开段面积绝对值小于进入段
|
||||
let 进入总面积 = 进入MACD.阳 + 进入MACD.阴.abs();
|
||||
let 离开总面积 = 离开MACD.阳 + 离开MACD.阴.abs();
|
||||
|
||||
if 进入总面积 < f64::EPSILON {
|
||||
return false;
|
||||
}
|
||||
离开总面积 < 进入总面积
|
||||
离开面积 < 进入面积
|
||||
}
|
||||
|
||||
/// 斜率背驰 — 离开段斜率小于进入段
|
||||
/// 斜率背驰 — 价格斜率背驰
|
||||
pub fn 斜率背驰(进入段: &虚线, 离开段: &虚线) -> bool {
|
||||
let 进入斜率 = (进入段.武.分型特征值 - 进入段.文.分型特征值).abs()
|
||||
/ (进入段.武.时间戳 - 进入段.文.时间戳).abs() as f64;
|
||||
let 离开斜率 = (离开段.武.分型特征值 - 离开段.文.分型特征值).abs()
|
||||
/ (离开段.武.时间戳 - 离开段.文.时间戳).abs() as f64;
|
||||
let dx = (进入段.武.时间戳 - 进入段.文.时间戳) as f64;
|
||||
let dy = 进入段.武.分型特征值 - 进入段.文.分型特征值;
|
||||
let 进入斜率 = dy / dx;
|
||||
|
||||
离开斜率 < 进入斜率
|
||||
let dx = (离开段.武.时间戳 - 离开段.文.时间戳) as f64;
|
||||
let dy = 离开段.武.分型特征值 - 离开段.文.分型特征值;
|
||||
let 离开斜率 = dy / dx;
|
||||
|
||||
if 进入段.方向() == 相对方向::向上 {
|
||||
离开段.高() > 进入段.高() && 离开斜率.abs() < 进入斜率.abs()
|
||||
} else {
|
||||
离开段.低() < 进入段.低() && 离开斜率.abs() < 进入斜率.abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// 测度背驰 — 价格测度的背驰判断
|
||||
/// 测度背驰 — 价格时间测度背驰
|
||||
pub fn 测度背驰(进入段: &虚线, 离开段: &虚线) -> bool {
|
||||
let 进入幅度 = (进入段.武.分型特征值 - 进入段.文.分型特征值).abs();
|
||||
let 离开幅度 = (离开段.武.分型特征值 - 离开段.文.分型特征值).abs();
|
||||
离开幅度 < 进入幅度
|
||||
let dx = (进入段.武.时间戳 - 进入段.文.时间戳) as f64;
|
||||
let dy = 进入段.武.分型特征值 - 进入段.文.分型特征值;
|
||||
let 进入测度 = (dx * dx + dy * dy).sqrt();
|
||||
|
||||
let dx = (离开段.武.时间戳 - 离开段.文.时间戳) as f64;
|
||||
let dy = 离开段.武.分型特征值 - 离开段.文.分型特征值;
|
||||
let 离开测度 = (dx * dx + dy * dy).sqrt();
|
||||
|
||||
if 进入段.方向() == 相对方向::向上 {
|
||||
离开段.高() > 进入段.高() && 离开测度.abs() < 进入测度.abs()
|
||||
} else {
|
||||
离开段.低() < 进入段.低() && 离开测度.abs() < 进入测度.abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// 全量背驰 — MACD + 斜率 + 测度 三者全满足
|
||||
pub fn 全量背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc<K线>]) -> bool {
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总")
|
||||
&& Self::斜率背驰(进入段, 离开段)
|
||||
&& Self::测度背驰(进入段, 离开段)
|
||||
&& Self::斜率背驰(进入段, 离开段)
|
||||
}
|
||||
|
||||
/// 任意背驰 — 任一条件满足即可
|
||||
pub fn 任意背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc<K线>]) -> bool {
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总")
|
||||
|| Self::斜率背驰(进入段, 离开段)
|
||||
|| Self::测度背驰(进入段, 离开段)
|
||||
|| Self::斜率背驰(进入段, 离开段)
|
||||
}
|
||||
|
||||
/// 配置背驰 — 根据配置选择判断方式
|
||||
pub fn 配置背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc<K线>], 配置: &缠论配置) -> bool {
|
||||
let mut result = true;
|
||||
if 配置.线段内部背驰_MACD {
|
||||
result = result && Self::MACD背驰(进入段, 离开段, 普K序列, "总");
|
||||
pub fn 配置背驰(
|
||||
进入段: &虚线,
|
||||
离开段: &虚线,
|
||||
普K序列: &[Rc<K线>],
|
||||
配置: &缠论配置,
|
||||
) -> bool {
|
||||
match (
|
||||
配置.线段内部背驰_MACD,
|
||||
配置.线段内部背驰_测度,
|
||||
配置.线段内部背驰_斜率,
|
||||
) {
|
||||
(true, true, true) => {
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总")
|
||||
&& Self::测度背驰(进入段, 离开段)
|
||||
&& Self::斜率背驰(进入段, 离开段)
|
||||
}
|
||||
(false, false, false) => false,
|
||||
|
||||
(true, false, true) => {
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总") && Self::斜率背驰(进入段, 离开段)
|
||||
}
|
||||
(false, true, false) => Self::测度背驰(进入段, 离开段),
|
||||
|
||||
(true, false, false) => Self::MACD背驰(进入段, 离开段, 普K序列, "总"),
|
||||
(false, true, true) => {
|
||||
Self::测度背驰(进入段, 离开段) && Self::斜率背驰(进入段, 离开段)
|
||||
}
|
||||
|
||||
(false, false, true) => Self::斜率背驰(进入段, 离开段),
|
||||
(true, true, false) => {
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总") && Self::测度背驰(进入段, 离开段)
|
||||
}
|
||||
}
|
||||
if 配置.线段内部背驰_斜率 {
|
||||
result = result && Self::斜率背驰(进入段, 离开段);
|
||||
}
|
||||
if 配置.线段内部背驰_测度 {
|
||||
result = result && Self::测度背驰(进入段, 离开段);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// 任选背驰
|
||||
/// 任选背驰 — 至少两个条件满足(多数投票)
|
||||
pub fn 任选背驰(进入段: &虚线, 离开段: &虚线, 普K序列: &[Rc<K线>]) -> bool {
|
||||
Self::任意背驰(进入段, 离开段, 普K序列)
|
||||
let 混沌槽 = [
|
||||
Self::MACD背驰(进入段, 离开段, 普K序列, "总"),
|
||||
Self::测度背驰(进入段, 离开段),
|
||||
Self::斜率背驰(进入段, 离开段),
|
||||
];
|
||||
混沌槽.iter().filter(|&&x| x).count() >= 2
|
||||
}
|
||||
|
||||
/// 背驰模式 — 根据模式字符串选择判断方式
|
||||
@@ -95,40 +143,34 @@ impl 背驰分析 {
|
||||
"全量" => Self::全量背驰(进入段, 离开段, 普K序列),
|
||||
"任意" => Self::任意背驰(进入段, 离开段, 普K序列),
|
||||
"配置" => Self::配置背驰(进入段, 离开段, 普K序列, 配置),
|
||||
"相对" => Self::测度背驰(进入段, 离开段),
|
||||
_ => Self::配置背驰(进入段, 离开段, 普K序列, 配置),
|
||||
"相对" => Self::任选背驰(进入段, 离开段, 普K序列),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 内部辅助 ----
|
||||
|
||||
fn 柱子面积(K线序列: &[Rc<K线>], 方式: &str) -> MACD面积 {
|
||||
fn _获取MACD面积(K线序列: &[Rc<K线>], 始: &Rc<K线>, 终: &Rc<K线>) -> MACD面积 {
|
||||
let 始_idx = K线序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(始));
|
||||
let 终_idx = K线序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(终));
|
||||
|
||||
let mut 阳 = 0.0f64;
|
||||
let mut 阴 = 0.0f64;
|
||||
for k in K线序列 {
|
||||
if let Some(ref macd) = k.macd {
|
||||
let hist = macd.MACD柱;
|
||||
match 方式 {
|
||||
"阳" => {
|
||||
if hist > 0.0 {
|
||||
阳 += hist
|
||||
}
|
||||
}
|
||||
"阴" => {
|
||||
if hist < 0.0 {
|
||||
阴 += hist
|
||||
}
|
||||
}
|
||||
"总" | _ => {
|
||||
if hist >= 0.0 {
|
||||
阳 += hist
|
||||
} else {
|
||||
阴 += hist
|
||||
}
|
||||
|
||||
if let (Some(始), Some(终)) = (始_idx, 终_idx) {
|
||||
let (始, 终) = if 始 <= 终 { (始, 终) } else { (终, 始) };
|
||||
for k in &K线序列[始..=终] {
|
||||
if let Some(ref macd) = k.macd {
|
||||
let hist = macd.MACD柱;
|
||||
if hist >= 0.0 {
|
||||
阳 += hist;
|
||||
} else {
|
||||
阴 += hist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MACD面积 { 阳, 阴 }
|
||||
}
|
||||
}
|
||||
@@ -137,3 +179,9 @@ struct MACD面积 {
|
||||
阳: f64,
|
||||
阴: f64,
|
||||
}
|
||||
|
||||
impl MACD面积 {
|
||||
fn 总(&self) -> f64 {
|
||||
self.阳 + self.阴
|
||||
}
|
||||
}
|
||||
|
||||
+240
-63
@@ -35,7 +35,10 @@ impl 中枢 {
|
||||
pub fn 图表标题(&self) -> String {
|
||||
format!(
|
||||
"{}:{}:{}:{}",
|
||||
self.文().中.标识, self.文().中.周期, self.标识, self.序号
|
||||
self.文().中.标识,
|
||||
self.文().中.周期,
|
||||
self.标识,
|
||||
self.序号
|
||||
)
|
||||
}
|
||||
|
||||
@@ -91,6 +94,15 @@ impl 中枢 {
|
||||
self.第三买卖线 = Some(线);
|
||||
}
|
||||
|
||||
/// 获取序列 — 基础序列 + 第三买卖线(若有)
|
||||
pub fn 获取序列(&self) -> Vec<Rc<虚线>> {
|
||||
let mut 序列: Vec<Rc<虚线>> = self.基础序列.clone();
|
||||
if let Some(ref 三买) = self.第三买卖线 {
|
||||
序列.push(Rc::clone(三买));
|
||||
}
|
||||
序列
|
||||
}
|
||||
|
||||
pub fn 获取数据文本(&self) -> String {
|
||||
let 第三买卖线_str = match &self.第三买卖线 {
|
||||
Some(x) => format!("{}", x),
|
||||
@@ -115,24 +127,158 @@ impl 中枢 {
|
||||
}
|
||||
|
||||
/// 校验中枢合法性
|
||||
pub fn 校验合法性(&self, 虚线序列: &[Rc<虚线>], _中枢序列: &[Rc<中枢>]) -> bool {
|
||||
// 1. 检查基础序列中的元素是否仍在虚线序列中
|
||||
pub fn 校验合法性(&mut self, 序列: &[Rc<虚线>]) -> bool {
|
||||
let mut 有效序列 = self.基础序列.clone();
|
||||
let mut 无效序列: Vec<Rc<虚线>> = Vec::new();
|
||||
for 元素 in &self.基础序列 {
|
||||
if !虚线序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(元素)) {
|
||||
if !序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(元素)) {
|
||||
无效序列.push(Rc::clone(元素));
|
||||
}
|
||||
}
|
||||
|
||||
if !无效序列.is_empty() {
|
||||
let 无效 = &无效序列[0];
|
||||
if let Some(pos) = self
|
||||
.基础序列
|
||||
.iter()
|
||||
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(无效))
|
||||
{
|
||||
有效序列 = self.基础序列[..pos].to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
if 有效序列.len() < 3 {
|
||||
self.第三买卖线 = None;
|
||||
self.本级_第三买卖线 = None;
|
||||
return false;
|
||||
}
|
||||
|
||||
self.基础序列 = 有效序列;
|
||||
|
||||
let 中枢高 = self.高();
|
||||
let 中枢低 = self.低();
|
||||
有效序列 = Vec::new();
|
||||
for 元素 in &self.基础序列 {
|
||||
if crate::types::相对方向::分析(中枢高, 中枢低, 元素.高(), 元素.低()).是否缺口()
|
||||
{
|
||||
break;
|
||||
}
|
||||
有效序列.push(Rc::clone(元素));
|
||||
}
|
||||
self.基础序列 = 有效序列;
|
||||
|
||||
if self.基础序列.len() < 3 {
|
||||
return false;
|
||||
}
|
||||
|
||||
for i in 1..self.基础序列.len() {
|
||||
let 前 = &self.基础序列[i - 1];
|
||||
let 后 = &self.基础序列[i];
|
||||
if !前.之后是(后) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 2. 检查前三根重叠是否有效
|
||||
if self.基础序列.len() >= 3 {
|
||||
let 高 = self.高();
|
||||
let 低 = self.低();
|
||||
if 高 <= 低 {
|
||||
|
||||
if !crate::types::相对方向::分析(
|
||||
self.基础序列[0].高(),
|
||||
self.基础序列[0].低(),
|
||||
self.基础序列[2].高(),
|
||||
self.基础序列[2].低(),
|
||||
)
|
||||
.是否缺口()
|
||||
{
|
||||
let 重叠高 = self.高();
|
||||
let 重叠低 = self.低();
|
||||
if 重叠低 > 重叠高 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref 三买线) = self.第三买卖线.clone() {
|
||||
if 序列.iter().any(|x| Rc::as_ptr(x) == Rc::as_ptr(三买线)) {
|
||||
if !self.基础序列.last().unwrap().之后是(三买线) {
|
||||
self.第三买卖线 = None;
|
||||
} else if !crate::types::相对方向::分析(
|
||||
self.高(),
|
||||
self.低(),
|
||||
三买线.高(),
|
||||
三买线.低(),
|
||||
)
|
||||
.是否缺口()
|
||||
{
|
||||
self.添加虚线(Rc::clone(三买线));
|
||||
self.第三买卖线 = None;
|
||||
}
|
||||
} else {
|
||||
self.第三买卖线 = None;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// 完整性 — 详见教你炒股票43:有关背驰的补习课
|
||||
/// 不完整时下一个中枢大概率会与当前中枢发生扩展
|
||||
pub fn 完整性(&self, 虚实: &str) -> bool {
|
||||
if self.基础序列[0].标识 == "笔" {
|
||||
return self.第三买卖线.is_some();
|
||||
}
|
||||
|
||||
let 线段内部中枢 = if 虚实 == "合" {
|
||||
&self.基础序列.last().unwrap().合_中枢序列
|
||||
} else {
|
||||
&self.基础序列.last().unwrap().实_中枢序列
|
||||
};
|
||||
for 内部中枢 in 线段内部中枢 {
|
||||
if crate::types::相对方向::分析(
|
||||
self.高(),
|
||||
self.低(),
|
||||
内部中枢.高(),
|
||||
内部中枢.低(),
|
||||
)
|
||||
.是否缺口()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 获取扩展中枢 — 当基础序列 >= 9 时生成扩展中枢
|
||||
pub fn 获取扩展中枢(
|
||||
&self, 扩展中枢: &mut Vec<Rc<中枢>>, 配置: &crate::config::缠论配置
|
||||
) {
|
||||
if self.基础序列.len() >= 9 {
|
||||
let mut 扩展线段: Vec<Rc<虚线>> = Vec::new();
|
||||
crate::algorithm::segment::线段::扩展分析(&self.基础序列, &mut 扩展线段, 配置);
|
||||
中枢::分析(
|
||||
&扩展线段,
|
||||
扩展中枢,
|
||||
false,
|
||||
&format!("{}_扩展中枢_", self.标识),
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 当前状态 — 详见教你炒股票49:利润率最大的操作模式
|
||||
/// 返回当前中枢最后一段所处的位置关系:中枢之中/中枢之上/中枢之下
|
||||
pub fn 当前状态(&self) -> &str {
|
||||
let 最后 = self.基础序列.last().unwrap();
|
||||
let 尾部_中 = if 最后.标识 == "笔" {
|
||||
&最后.武.中
|
||||
} else {
|
||||
&最后.基础序列.last().unwrap().武.中
|
||||
};
|
||||
let 关系 = crate::types::相对方向::分析(self.高(), self.低(), 尾部_中.高, 尾部_中.低);
|
||||
if 关系 == crate::types::相对方向::向上缺口 {
|
||||
"中枢之上"
|
||||
} else if 关系 == crate::types::相对方向::向下缺口 {
|
||||
"中枢之下"
|
||||
} else {
|
||||
"中枢之中"
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 关联函数 ----
|
||||
|
||||
/// 基础检查 — 三根虚线是否能形成中枢
|
||||
@@ -140,22 +286,27 @@ impl 中枢 {
|
||||
if !左.之后是(中) || !中.之后是(右) {
|
||||
return false;
|
||||
}
|
||||
let 高 = [左.高(), 中.高(), 右.高()]
|
||||
.iter()
|
||||
.copied()
|
||||
.min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.unwrap_or(0.0);
|
||||
let 低 = [左.低(), 中.低(), 右.低()]
|
||||
.iter()
|
||||
.copied()
|
||||
.max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.unwrap_or(0.0);
|
||||
高 > 低
|
||||
let 关系 = crate::types::相对方向::分析(左.高(), 左.低(), 右.高(), 右.低());
|
||||
matches!(
|
||||
关系,
|
||||
crate::types::相对方向::向下
|
||||
| crate::types::相对方向::向上
|
||||
| crate::types::相对方向::顺
|
||||
| crate::types::相对方向::逆
|
||||
| crate::types::相对方向::同
|
||||
)
|
||||
}
|
||||
|
||||
/// 创建中枢
|
||||
pub fn 创建(左: Rc<虚线>, 中: Rc<虚线>, 右: Rc<虚线>, 级别: i64, 标识: &str) -> Self {
|
||||
Self::new(0, format!("{}中枢<{}>", 标识, 中.标识), 级别, vec![左, 中, 右])
|
||||
pub fn 创建(
|
||||
左: Rc<虚线>, 中: Rc<虚线>, 右: Rc<虚线>, 级别: i64, 标识: &str
|
||||
) -> Self {
|
||||
Self::new(
|
||||
0,
|
||||
format!("{}中枢<{}>", 标识, 中.标识),
|
||||
级别,
|
||||
vec![左, 中, 右],
|
||||
)
|
||||
}
|
||||
|
||||
/// 从序列中获取中枢
|
||||
@@ -177,27 +328,32 @@ impl 中枢 {
|
||||
}
|
||||
|
||||
/// 向中枢序列尾部添加
|
||||
pub fn 向中枢序列尾部添加(中枢序列: &mut Vec<Rc<中枢>>, 待添加中枢: Rc<中枢>) {
|
||||
// Dedup
|
||||
pub fn 向中枢序列尾部添加(
|
||||
中枢序列: &mut Vec<Rc<中枢>>, mut 待添加中枢: Rc<中枢>
|
||||
) {
|
||||
if let Some(前一个) = 中枢序列.last() {
|
||||
if 前一个.高() == 待添加中枢.高() && 前一个.低() == 待添加中枢.低() {
|
||||
return;
|
||||
let 新 = Rc::make_mut(&mut 待添加中枢);
|
||||
新.序号 = 前一个.序号 + 1;
|
||||
// Python: assert seq[-1].获取序列()[-1].序号 <= new.获取序列()[-1].序号
|
||||
let 前_seq = 前一个.获取序列();
|
||||
let new_seq = 新.获取序列();
|
||||
if let (Some(前_last), Some(new_last)) = (前_seq.last(), new_seq.last()) {
|
||||
if 前_last.序号 > new_last.序号 {
|
||||
panic!(
|
||||
"向中枢序列尾部添加 序号错误 前last={} > new_last={}",
|
||||
前_last.序号, new_last.序号
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set序号: Python — if中枢序列: 待添加中枢.序号 = 中枢序列[-1].序号 + 1 else: stays 0
|
||||
if let Some(前一个) = 中枢序列.last() {
|
||||
let 新序号 = 前一个.序号 + 1;
|
||||
// Clone to mutate since Rc is immutable
|
||||
let mut cloned = (*待添加中枢).clone();
|
||||
cloned.序号 = 新序号;
|
||||
中枢序列.push(Rc::new(cloned));
|
||||
} else {
|
||||
中枢序列.push(待添加中枢);
|
||||
}
|
||||
中枢序列.push(待添加中枢);
|
||||
}
|
||||
|
||||
/// 从中枢序列尾部弹出
|
||||
pub fn 从中枢序列尾部弹出(中枢序列: &mut Vec<Rc<中枢>>, 待弹出: &Rc<中枢>) -> Option<Rc<中枢>> {
|
||||
pub fn 从中枢序列尾部弹出(
|
||||
中枢序列: &mut Vec<Rc<中枢>>,
|
||||
待弹出: &Rc<中枢>,
|
||||
) -> Option<Rc<中枢>> {
|
||||
if 中枢序列.last().map(|x| Rc::as_ptr(x)) == Some(Rc::as_ptr(待弹出)) {
|
||||
中枢序列.pop()
|
||||
} else {
|
||||
@@ -228,13 +384,17 @@ impl 中枢 {
|
||||
|
||||
if Self::基础检查(左, 中, 右) {
|
||||
// Python: 序号 = 虚线序列.index(左)
|
||||
let 序号 = 虚线序列.iter().position(|x| Rc::as_ptr(x) == Rc::as_ptr(左)).unwrap_or(i - 1);
|
||||
let 序号 = 虚线序列
|
||||
.iter()
|
||||
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(左))
|
||||
.unwrap_or(i - 1);
|
||||
if 跳过首部 && (左.序号 == 0 || 序号 == 0) {
|
||||
continue;
|
||||
}
|
||||
if 序号 >= 2 {
|
||||
let 前 = &虚线序列[序号 - 2];
|
||||
let 同向相对关系 = crate::types::相对方向::分析(前.高(), 前.低(), 左.高(), 左.低());
|
||||
let 同向相对关系 =
|
||||
crate::types::相对方向::分析(前.高(), 前.低(), 左.高(), 左.低());
|
||||
if 同向相对关系.是否向上() && 左.方向().是否向上() {
|
||||
continue;
|
||||
}
|
||||
@@ -259,46 +419,58 @@ impl 中枢 {
|
||||
}
|
||||
|
||||
// 增量更新
|
||||
let 当前中枢_idx = 中枢序列.len() - 1;
|
||||
let 当前中枢 = Rc::clone(&中枢序列[当前中枢_idx]);
|
||||
let mut 当前中枢_idx = 中枢序列.len() - 1;
|
||||
|
||||
if !当前中枢.校验合法性(虚线序列, 中枢序列) {
|
||||
// Validate in-place via Rc::make_mut — avoids full中枢 struct clone
|
||||
let needs_pop = {
|
||||
let cur = Rc::make_mut(&mut 中枢序列[当前中枢_idx]);
|
||||
!cur.校验合法性(虚线序列)
|
||||
};
|
||||
if needs_pop {
|
||||
let 当前中枢 = Rc::clone(&中枢序列[当前中枢_idx]);
|
||||
Self::从中枢序列尾部弹出(中枢序列, &当前中枢);
|
||||
Self::分析(虚线序列, 中枢序列, 跳过首部, 标识, 层级);
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到当前中枢最后一个元素在虚线序列中的位置
|
||||
let 最后元素 = &当前中枢.基础序列[当前中枢.基础序列.len() - 1];
|
||||
let 起始索引 = match 虚线序列
|
||||
.iter()
|
||||
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(最后元素))
|
||||
{
|
||||
Some(idx) => idx + 1,
|
||||
None => return,
|
||||
let 起始索引 = {
|
||||
let cur = &中枢序列[当前中枢_idx];
|
||||
let 最后元素 = &cur.基础序列[cur.基础序列.len() - 1];
|
||||
match 虚线序列
|
||||
.iter()
|
||||
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(最后元素))
|
||||
{
|
||||
Some(idx) => idx + 1,
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
|
||||
let 中枢高 = 当前中枢.高();
|
||||
let 中枢低 = 当前中枢.低();
|
||||
let mut 中枢高 = 中枢序列[当前中枢_idx].高();
|
||||
let mut 中枢低 = 中枢序列[当前中枢_idx].低();
|
||||
let mut 候选序列: Vec<Rc<虚线>> = Vec::new();
|
||||
|
||||
let mut 新当前中枢 = (*当前中枢).clone();
|
||||
|
||||
for i in 起始索引..虚线序列.len() {
|
||||
let 当前虚线 = Rc::clone(&虚线序列[i]);
|
||||
|
||||
// 检查是否超出中枢范围(缺口)
|
||||
if crate::types::相对方向::分析(中枢高, 中枢低, 当前虚线.高(), 当前虚线.低()).是否缺口() {
|
||||
if crate::types::相对方向::分析(中枢高, 中枢低, 当前虚线.高(), 当前虚线.低()).是否缺口()
|
||||
{
|
||||
候选序列.push(当前虚线.clone());
|
||||
|
||||
// Python: if 当前中枢.基础序列[-1].之后是(当前虚线):
|
||||
if 新当前中枢.基础序列.last().unwrap().之后是(&当前虚线) {
|
||||
新当前中枢.设置第三买卖线(当前虚线.clone());
|
||||
let needs_三买 = {
|
||||
let cur = &中枢序列[当前中枢_idx];
|
||||
cur.基础序列.last().unwrap().之后是(&当前虚线)
|
||||
};
|
||||
if needs_三买 {
|
||||
Rc::make_mut(&mut 中枢序列[当前中枢_idx])
|
||||
.设置第三买卖线(当前虚线.clone());
|
||||
}
|
||||
} else {
|
||||
if 候选序列.is_empty() {
|
||||
// 仍在范围内:延伸中枢
|
||||
新当前中枢.添加虚线(当前虚线);
|
||||
Rc::make_mut(&mut 中枢序列[当前中枢_idx]).添加虚线(当前虚线);
|
||||
} else {
|
||||
候选序列.push(当前虚线);
|
||||
}
|
||||
@@ -306,12 +478,20 @@ impl 中枢 {
|
||||
|
||||
// 候选序列积满3个:尝试创建新中枢
|
||||
while 候选序列.len() >= 3 {
|
||||
let 起始方向 = 新当前中枢.基础序列.last().unwrap().方向().翻转();
|
||||
let 起始方向 = 中枢序列[当前中枢_idx]
|
||||
.基础序列
|
||||
.last()
|
||||
.unwrap()
|
||||
.方向()
|
||||
.翻转();
|
||||
match Self::从序列中获取中枢(&候选序列, 起始方向, 标识) {
|
||||
Some(新中枢) => {
|
||||
中枢序列[当前中枢_idx] = Rc::new(新当前中枢.clone());
|
||||
Self::向中枢序列尾部添加(中枢序列, 新中枢);
|
||||
return;
|
||||
// Python: 当前中枢 = 新中枢
|
||||
当前中枢_idx = 中枢序列.len() - 1;
|
||||
中枢高 = 中枢序列[当前中枢_idx].高();
|
||||
中枢低 = 中枢序列[当前中枢_idx].低();
|
||||
候选序列.clear();
|
||||
}
|
||||
None => {
|
||||
候选序列.remove(0); // 滑动窗口
|
||||
@@ -319,9 +499,6 @@ impl 中枢 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新当前中枢
|
||||
中枢序列[当前中枢_idx] = Rc::new(新当前中枢);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+320
-352
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user