第一版
This commit is contained in:
@@ -0,0 +1,771 @@
|
||||
use crate::algorithm::hub::中枢;
|
||||
use crate::config::缠论配置;
|
||||
use crate::kline::chan_kline::缠论K线;
|
||||
use crate::kline::bar::K线;
|
||||
use crate::structure::fractal_obj::分型;
|
||||
use crate::structure::segment_feat::线段特征;
|
||||
use crate::types::{分型结构, 相对方向, 缺口};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// 虚线 — 笔和线段的通用数据结构
|
||||
///
|
||||
/// 笔和线段共享此 struct,通过 `标识` 字段区分 ("笔"/"线段"/"扩展线段"等)
|
||||
#[derive(Debug, Clone)]
|
||||
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,
|
||||
}
|
||||
|
||||
impl 虚线 {
|
||||
pub fn new(序号: i64, 标识: String, 文: Rc<分型>, 武: Rc<分型>, 级别: i64, 有效性: bool) -> Self {
|
||||
Self {
|
||||
序号,
|
||||
标识,
|
||||
级别,
|
||||
文,
|
||||
武,
|
||||
有效性,
|
||||
基础序列: Vec::new(),
|
||||
特征序列: Vec::new(),
|
||||
实_中枢序列: Vec::new(),
|
||||
虚_中枢序列: Vec::new(),
|
||||
合_中枢序列: Vec::new(),
|
||||
确认K线: None,
|
||||
模式: "文武".into(),
|
||||
_特征序列_显示: false,
|
||||
前一缺口: None,
|
||||
前一结束位置: None,
|
||||
短路修正: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 笔序列(基础序列的别名)
|
||||
pub fn 笔序列(&self) -> &Vec<Rc<虚线>> {
|
||||
&self.基础序列
|
||||
}
|
||||
|
||||
pub fn 图表标题(&self) -> String {
|
||||
format!("{}:{}:{}:{}", self.文.中.标识, self.文.中.周期, self.标识, self.序号)
|
||||
}
|
||||
|
||||
/// 方向 — 文到武的方向
|
||||
pub fn 方向(&self) -> 相对方向 {
|
||||
match (self.文.结构, self.武.结构) {
|
||||
(分型结构::顶, 分型结构::底) => 相对方向::向下,
|
||||
(分型结构::顶, 分型结构::下) => 相对方向::向下,
|
||||
(分型结构::上, 分型结构::底) => 相对方向::向下,
|
||||
(分型结构::上, 分型结构::下) => 相对方向::向下,
|
||||
_ => 相对方向::向上,
|
||||
}
|
||||
}
|
||||
|
||||
/// 虚线高 — 文和武中高的那个
|
||||
pub fn 高(&self) -> f64 {
|
||||
self.武.分型特征值.max(self.文.分型特征值)
|
||||
}
|
||||
|
||||
/// 虚线低 — 文和武中低的那个
|
||||
pub fn 低(&self) -> f64 {
|
||||
self.武.分型特征值.min(self.文.分型特征值)
|
||||
}
|
||||
|
||||
/// 判断两个虚线是否首尾相连
|
||||
pub fn 之前是(&self, 之前: &虚线) -> bool {
|
||||
self.文.中.序号 == 之前.武.中.序号
|
||||
}
|
||||
|
||||
/// 判断两个虚线是否首尾相连
|
||||
pub fn 之后是(&self, 之后: &虚线) -> bool {
|
||||
self.武.中.序号 == 之后.文.中.序号
|
||||
}
|
||||
|
||||
/// 获取该虚线范围内的普K序列
|
||||
pub fn 获取普K序列(&self, 普K序列: &[Rc<K线>]) -> Vec<Rc<K线>> {
|
||||
let 始 = self.文.中.原始起始序号 as usize;
|
||||
let 终 = self.武.中.原始结束序号 as usize;
|
||||
if 始 < 普K序列.len() && 终 < 普K序列.len() && 始 <= 终 {
|
||||
普K序列[始..=终].to_vec()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取该虚线范围内的缠K序列
|
||||
pub fn 获取缠K序列(&self, 缠K序列: &[Rc<缠论K线>]) -> Vec<Rc<缠论K线>> {
|
||||
缠论K线::截取(缠K序列, &self.文.中, &self.武.中).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// 获取数据文本(用于保存/调试)
|
||||
pub fn 获取数据文本(&self) -> String {
|
||||
use crate::utils::format_f64_g;
|
||||
if self.标识 == "笔" {
|
||||
return format!(
|
||||
"{}, {}, {}, 文:({},{}), 武:({},{}), {}",
|
||||
self.标识,
|
||||
self.序号,
|
||||
self.级别,
|
||||
self.文.时间戳,
|
||||
format_f64_g(self.文.分型特征值),
|
||||
self.武.时间戳,
|
||||
format_f64_g(self.武.分型特征值),
|
||||
if self.有效性 { "True" } else { "False" },
|
||||
);
|
||||
}
|
||||
|
||||
// 非笔:线段/扩展线段等,完整输出
|
||||
let (前, 后, 三, 贯穿伤) =
|
||||
crate::algorithm::segment::线段::分割序列(self, None);
|
||||
let (特征_a, 特征_b, 特征_c) = crate::algorithm::segment::线段::特征序列状态(self);
|
||||
let 特征_bool = |b: bool| -> &str { if b { "True" } else { "False" } };
|
||||
|
||||
let 前一缺口_str = match &self.前一缺口 {
|
||||
Some(g) => format!("{}", g),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
let 前一结束位置_str = match &self.前一结束位置 {
|
||||
Some(d) => format!("{}", d),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
|
||||
// Format中枢序列 as Python-style list representations
|
||||
let 实_str = format!("[{}]", self.实_中枢序列.iter().map(|h| format!("{}", h)).collect::<Vec<_>>().join(", "));
|
||||
let 虚_str = format!("[{}]", self.虚_中枢序列.iter().map(|h| format!("{}", h)).collect::<Vec<_>>().join(", "));
|
||||
let 合_str = format!("[{}]", self.合_中枢序列.iter().map(|h| format!("{}", h)).collect::<Vec<_>>().join(", "));
|
||||
|
||||
let 前_str = format!("[{}]", 前.iter().map(|d| format!("{}", d)).collect::<Vec<_>>().join(", "));
|
||||
let 后_str = format!("[{}]", 后.iter().map(|d| format!("{}", d)).collect::<Vec<_>>().join(", "));
|
||||
let 三_str = format!("[{}]", 三.iter().map(|d| format!("{}", d)).collect::<Vec<_>>().join(", "));
|
||||
|
||||
format!(
|
||||
"{}, {}, {}, 文:({},{}), 武:({},{}), {}, {}, ({}, {}, {}), (前: {}, 后: {}, 三: {}, 伤: {}), 实: {}, 虚: {}, 合: {}, {}, {}, {}, {}",
|
||||
self.标识,
|
||||
self.序号,
|
||||
self.级别,
|
||||
self.文.时间戳,
|
||||
format_f64_g(self.文.分型特征值),
|
||||
self.武.时间戳,
|
||||
format_f64_g(self.武.分型特征值),
|
||||
if self.有效性 { "True" } else { "False" },
|
||||
self.基础序列.len(),
|
||||
特征_bool(特征_a),
|
||||
特征_bool(特征_b),
|
||||
特征_bool(特征_c),
|
||||
前_str,
|
||||
后_str,
|
||||
三_str,
|
||||
match &贯穿伤 { Some(d) => format!("{}", d), None => "None".to_string() },
|
||||
实_str,
|
||||
虚_str,
|
||||
合_str,
|
||||
self.模式,
|
||||
前一缺口_str,
|
||||
前一结束位置_str,
|
||||
if self.短路修正 { "True" } else { "False" },
|
||||
)
|
||||
}
|
||||
|
||||
// ---- 关联函数(静态工厂方法) ----
|
||||
|
||||
/// 创建笔
|
||||
pub fn 创建笔(文: Rc<分型>, 武: Rc<分型>, 有效性: bool) -> Self {
|
||||
Self::new(0, "笔".into(), 文, 武, 1, 有效性)
|
||||
}
|
||||
|
||||
/// 创建线段
|
||||
pub fn 创建线段(虚线序列: &[Rc<虚线>]) -> Self {
|
||||
let 文 = Rc::clone(&虚线序列[0].文);
|
||||
let 武 = Rc::clone(&虚线序列[虚线序列.len() - 1].武);
|
||||
let 标识 = if 虚线序列[0].标识 == "笔" {
|
||||
"线段".into()
|
||||
} else {
|
||||
format!("线段<{}>", 虚线序列[0].标识)
|
||||
};
|
||||
let 级别 = 虚线序列[0].级别 + 1;
|
||||
let mut 段 = Self::new(0, 标识, 文, 武, 级别, true);
|
||||
段.基础序列 = 虚线序列.to_vec();
|
||||
段.模式 = "文武".into();
|
||||
段
|
||||
}
|
||||
|
||||
// ---- 买卖点模式匹配 ----
|
||||
|
||||
/// 缠K买卖点模式 — 根据模式字符串选择匹配方法
|
||||
pub fn 缠K买卖点模式(模式: &str, 缠K: &缠论K线, 配置: &缠论配置) -> bool {
|
||||
match 模式 {
|
||||
"全量" => Self::买卖点全量匹配(缠K),
|
||||
"任意" => Self::买卖点任意匹配(缠K),
|
||||
"配置" => Self::买卖点配置匹配(缠K, 配置),
|
||||
"相对" => Self::买卖点相对匹配(缠K),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 买卖点配置匹配 — 根据配置中的指标开关组合判断
|
||||
pub fn 买卖点配置匹配(缠K: &缠论K线, 配置: &缠论配置) -> bool {
|
||||
match (配置.买卖点_指标匹配_MACD, 配置.买卖点_指标匹配_KDJ, 配置.买卖点_指标匹配_RSI) {
|
||||
(true, true, true) => 缠K.与MACD柱子匹配() && 缠K.与KDJ匹配() && 缠K.与RSI匹配(),
|
||||
(false, false, false) => false,
|
||||
(true, false, true) => 缠K.与MACD柱子匹配() && 缠K.与RSI匹配(),
|
||||
(false, true, false) => 缠K.与KDJ匹配(),
|
||||
(true, false, false) => 缠K.与MACD柱子匹配(),
|
||||
(false, true, true) => 缠K.与KDJ匹配() && 缠K.与RSI匹配(),
|
||||
(false, false, true) => 缠K.与RSI匹配(),
|
||||
(true, true, false) => 缠K.与MACD柱子匹配() && 缠K.与KDJ匹配(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 买卖点任意匹配 — 任一指标匹配
|
||||
pub fn 买卖点任意匹配(缠K: &缠论K线) -> bool {
|
||||
缠K.与MACD柱子匹配() || 缠K.与KDJ匹配() || 缠K.与RSI匹配()
|
||||
}
|
||||
|
||||
/// 买卖点全量匹配 — 全部指标匹配
|
||||
pub fn 买卖点全量匹配(缠K: &缠论K线) -> bool {
|
||||
缠K.与MACD柱子匹配() && 缠K.与KDJ匹配() && 缠K.与RSI匹配()
|
||||
}
|
||||
|
||||
/// 买卖点相对匹配 — 至少两个指标匹配
|
||||
pub fn 买卖点相对匹配(缠K: &缠论K线) -> bool {
|
||||
let 混沌槽 = [
|
||||
缠K.与MACD柱子匹配(),
|
||||
缠K.与KDJ匹配(),
|
||||
缠K.与RSI匹配(),
|
||||
];
|
||||
混沌槽.iter().filter(|&&x| x).count() >= 2
|
||||
}
|
||||
|
||||
// ---- MACD柱子均值计算 ----
|
||||
|
||||
/// 计算MACD柱子均值 — 虚线范围内所有MACD柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值(普K序列: &[Rc<K线>], 实线: &虚线) -> f64 {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
if K线序列.is_empty() {
|
||||
return 0.0;
|
||||
}
|
||||
let 总: f64 = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
.map(|m| m.MACD柱.abs())
|
||||
.sum();
|
||||
总 / K线序列.len() as f64
|
||||
}
|
||||
|
||||
/// 计算MACD柱子均值_阴 — 负柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值_阴(普K序列: &[Rc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
let 总: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
.filter(|m| m.MACD柱 < 0.0)
|
||||
.map(|m| m.MACD柱.abs())
|
||||
.collect();
|
||||
if 总.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(总.iter().sum::<f64>() / 总.len() as f64)
|
||||
}
|
||||
}
|
||||
|
||||
/// 计算MACD柱子均值_阳 — 正柱的绝对值均值
|
||||
pub fn 计算MACD柱子均值_阳(普K序列: &[Rc<K线>], 实线: &虚线) -> Option<f64> {
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
let 总: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
.filter(|m| m.MACD柱 > 0.0)
|
||||
.map(|m| m.MACD柱.abs())
|
||||
.collect();
|
||||
if 总.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(总.iter().sum::<f64>() / 总.len() as f64)
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 武之MACD比较 ----
|
||||
|
||||
/// 武之全量MACD均值 — 武端MACD柱是否小于均值(背驰)
|
||||
pub fn 武之全量MACD均值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
武_MACD < Self::计算MACD柱子均值(普K序列, 实线)
|
||||
}
|
||||
|
||||
/// 武之MACD均值 — 按方向选择阴/阳均值比对
|
||||
pub fn 武之MACD均值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
if 实线.方向() == 相对方向::向上 {
|
||||
Self::武之MACD均值_阳(普K序列, 实线)
|
||||
} else {
|
||||
Self::武之MACD均值_阴(普K序列, 实线)
|
||||
}
|
||||
}
|
||||
|
||||
/// 武之MACD均值_阴 — 武端负柱是否小于阴均值
|
||||
pub fn 武之MACD均值_阴(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
match Self::计算MACD柱子均值_阴(普K序列, 实线) {
|
||||
Some(均值) => 武_MACD < 均值.abs(),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 武之MACD均值_阳 — 武端正柱是否小于阳均值
|
||||
pub fn 武之MACD均值_阳(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
Some(m) => m.MACD柱.abs(),
|
||||
None => return false,
|
||||
};
|
||||
match Self::计算MACD柱子均值_阳(普K序列, 实线) {
|
||||
Some(均值) => 武_MACD < 均值,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 武之MACD极值 — 武端MACD柱是否为区间极值
|
||||
pub fn 武之MACD极值(普K序列: &[Rc<K线>], 实线: &虚线) -> bool {
|
||||
let 武_MACD = match &实线.武.中.标的K线.macd {
|
||||
Some(m) => m.MACD柱,
|
||||
None => return false,
|
||||
};
|
||||
let K线序列 = K线::截取rc(普K序列, &实线.文.中.标的K线, &实线.武.中.标的K线);
|
||||
let 所有柱子: Vec<f64> = K线序列
|
||||
.iter()
|
||||
.filter_map(|k| k.macd.as_ref())
|
||||
.map(|m| m.MACD柱)
|
||||
.collect();
|
||||
if 所有柱子.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if 武_MACD > 0.0 {
|
||||
let 极值 = 所有柱子.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
|
||||
极值 == 武_MACD
|
||||
} else {
|
||||
let 极值 = 所有柱子.iter().cloned().fold(f64::INFINITY, f64::min);
|
||||
极值 == 武_MACD
|
||||
}
|
||||
}
|
||||
|
||||
// ---- MACD趋向背驰 ----
|
||||
|
||||
/// 计算K线序列MACD趋向背驰 — 分析 MACD柱/DIF/DEA 三项背驰信号
|
||||
pub fn 计算K线序列MACD趋向背驰(普K序列: &[Rc<K线>], 方向: 相对方向) -> [bool; 3] {
|
||||
if 普K序列.is_empty() {
|
||||
return [false, false, false];
|
||||
}
|
||||
let 最后 = &普K序列[普K序列.len() - 1];
|
||||
|
||||
if 方向 == 相对方向::向上 {
|
||||
let 柱子序列: Vec<&Rc<K线>> = 普K序列
|
||||
.iter()
|
||||
.filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 > 0.0))
|
||||
.collect();
|
||||
if 柱子序列.is_empty() {
|
||||
return [false, false, false];
|
||||
}
|
||||
|
||||
let mut 结果 = [false; 3];
|
||||
|
||||
// MACD柱背驰
|
||||
let 最高柱子 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
a.macd.as_ref().unwrap().MACD柱
|
||||
.partial_cmp(&b.macd.as_ref().unwrap().MACD柱)
|
||||
.unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::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].高 {
|
||||
结果[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DIF背驰
|
||||
let 最高离差值 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
let da = a.macd.as_ref().and_then(|m| m.DIF).unwrap_or(0.0);
|
||||
let db = b.macd.as_ref().and_then(|m| m.DIF).unwrap_or(0.0);
|
||||
da.partial_cmp(&db).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对2 = vec![Rc::clone(*最高离差值), Rc::clone(最后)];
|
||||
柱对2.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对2[0].macd.as_ref(), 柱对2[1].macd.as_ref()) {
|
||||
let dif0 = m0.DIF.unwrap_or(0.0);
|
||||
let dif1 = m1.DIF.unwrap_or(0.0);
|
||||
if dif0 > dif1 && 柱对2[0].高 < 柱对2[1].高 {
|
||||
结果[1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DEA背驰
|
||||
let 最高信号线 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
let da = a.macd.as_ref().and_then(|m| m.DEA).unwrap_or(0.0);
|
||||
let db = b.macd.as_ref().and_then(|m| m.DEA).unwrap_or(0.0);
|
||||
da.partial_cmp(&db).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对3 = vec![Rc::clone(*最高信号线), Rc::clone(最后)];
|
||||
柱对3.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对3[0].macd.as_ref(), 柱对3[1].macd.as_ref()) {
|
||||
let dea0 = m0.DEA.unwrap_or(0.0);
|
||||
let dea1 = m1.DEA.unwrap_or(0.0);
|
||||
if dea0 > dea1 && 柱对3[0].高 < 柱对3[1].高 {
|
||||
结果[2] = true;
|
||||
}
|
||||
}
|
||||
|
||||
结果
|
||||
} else {
|
||||
let 柱子序列: Vec<&Rc<K线>> = 普K序列
|
||||
.iter()
|
||||
.filter(|k| k.macd.as_ref().map_or(false, |m| m.MACD柱 < 0.0))
|
||||
.collect();
|
||||
if 柱子序列.is_empty() {
|
||||
return [false, false, false];
|
||||
}
|
||||
|
||||
let mut 结果 = [false; 3];
|
||||
|
||||
// MACD柱背驰 (负向: absolute value comparison)
|
||||
let 最高柱子 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
a.macd.as_ref().unwrap().MACD柱.abs()
|
||||
.partial_cmp(&b.macd.as_ref().unwrap().MACD柱.abs())
|
||||
.unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对 = vec![Rc::clone(*最高柱子), Rc::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].低 {
|
||||
结果[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DIF背驰
|
||||
let 最高离差值 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
let da = a.macd.as_ref().and_then(|m| m.DIF).unwrap_or(0.0).abs();
|
||||
let db = b.macd.as_ref().and_then(|m| m.DIF).unwrap_or(0.0).abs();
|
||||
da.partial_cmp(&db).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对2 = vec![Rc::clone(*最高离差值), Rc::clone(最后)];
|
||||
柱对2.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对2[0].macd.as_ref(), 柱对2[1].macd.as_ref()) {
|
||||
let dif0 = m0.DIF.unwrap_or(0.0);
|
||||
let dif1 = m1.DIF.unwrap_or(0.0);
|
||||
if dif0 < dif1 && 柱对2[0].低 > 柱对2[1].低 {
|
||||
结果[1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DEA背驰
|
||||
let 最高信号线 = 柱子序列
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
let da = a.macd.as_ref().and_then(|m| m.DEA).unwrap_or(0.0).abs();
|
||||
let db = b.macd.as_ref().and_then(|m| m.DEA).unwrap_or(0.0).abs();
|
||||
da.partial_cmp(&db).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
let mut 柱对3 = vec![Rc::clone(*最高信号线), Rc::clone(最后)];
|
||||
柱对3.sort_by_key(|k| k.时间戳);
|
||||
if let (Some(m0), Some(m1)) = (柱对3[0].macd.as_ref(), 柱对3[1].macd.as_ref()) {
|
||||
let dea0 = m0.DEA.unwrap_or(0.0);
|
||||
let dea1 = m1.DEA.unwrap_or(0.0);
|
||||
if dea0 < dea1 && 柱对3[0].低 > 柱对3[1].低 {
|
||||
结果[2] = true;
|
||||
}
|
||||
}
|
||||
|
||||
结果
|
||||
}
|
||||
}
|
||||
|
||||
// ---- MACD柱子分段 ----
|
||||
|
||||
/// 计算MACD柱子分段 — 按正负号将MACD柱子分段
|
||||
pub fn 计算MACD柱子分段(k线序列: &[Rc<K线>]) -> Vec<Vec<f64>> {
|
||||
if k线序列.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let 符号 = |x: f64| -> &str {
|
||||
if x > 0.0 { "正" } else { "负" }
|
||||
};
|
||||
|
||||
let 首_MACD = match &k线序列[0].macd {
|
||||
Some(m) => m.MACD柱,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
let mut 当前符号 = 符号(首_MACD);
|
||||
let mut 当前段 = vec![首_MACD];
|
||||
let mut 结果 = Vec::new();
|
||||
|
||||
for k线 in &k线序列[1..] {
|
||||
let macd = match &k线.macd {
|
||||
Some(m) => m.MACD柱,
|
||||
None => continue,
|
||||
};
|
||||
let 新符号 = 符号(macd);
|
||||
if 新符号 == 当前符号 {
|
||||
当前段.push(macd);
|
||||
} else {
|
||||
结果.push(std::mem::take(&mut 当前段));
|
||||
当前段.push(macd);
|
||||
当前符号 = 新符号;
|
||||
}
|
||||
}
|
||||
if !当前段.is_empty() {
|
||||
结果.push(当前段);
|
||||
}
|
||||
结果
|
||||
}
|
||||
|
||||
// ---- 密集区域按间隔 ----
|
||||
|
||||
/// 密集区域按间隔 — 找出交叉标记中的密集区域
|
||||
pub fn 密集区域按间隔(
|
||||
交叉标记: &[i32],
|
||||
最大间隔: usize,
|
||||
最少交叉数: usize,
|
||||
) -> Vec<(usize, usize, usize)> {
|
||||
let 交叉索引: Vec<usize> = (0..交叉标记.len()).filter(|&i| 交叉标记[i] != 0).collect();
|
||||
if 交叉索引.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut 密集区 = Vec::new();
|
||||
let mut 当前块起始 = 交叉索引[0];
|
||||
let mut 当前块交叉数 = 1;
|
||||
|
||||
for i in 1..交叉索引.len() {
|
||||
let prev = 交叉索引[i - 1];
|
||||
let curr = 交叉索引[i];
|
||||
if curr - prev <= 最大间隔 {
|
||||
当前块交叉数 += 1;
|
||||
} else {
|
||||
if 当前块交叉数 >= 最少交叉数 {
|
||||
密集区.push((当前块起始, prev, 当前块交叉数));
|
||||
}
|
||||
当前块起始 = curr;
|
||||
当前块交叉数 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if 当前块交叉数 >= 最少交叉数 {
|
||||
密集区.push((当前块起始, 交叉索引[交叉索引.len() - 1], 当前块交叉数));
|
||||
}
|
||||
|
||||
密集区
|
||||
}
|
||||
|
||||
// ---- 统计MACD行为 ----
|
||||
|
||||
/// 统计MACD行为 — 分析DIF/DEA穿零轴和金叉死叉
|
||||
pub fn 统计MACD行为(普K序列: &[Rc<K线>], 最大间隔: usize, 最少交叉数: usize) -> std::collections::HashMap<String, String> {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut dif_up = 0;
|
||||
let mut dif_down = 0;
|
||||
let mut dea_up = 0;
|
||||
let mut dea_down = 0;
|
||||
|
||||
for i in 1..普K序列.len() {
|
||||
let pre = &普K序列[i - 1].macd;
|
||||
let cur = &普K序列[i].macd;
|
||||
if pre.is_none() || cur.is_none() {
|
||||
continue;
|
||||
}
|
||||
let (pre_dif, cur_dif) = (pre.as_ref().unwrap().DIF, cur.as_ref().unwrap().DIF);
|
||||
let (pre_dea, cur_dea) = (pre.as_ref().unwrap().DEA, cur.as_ref().unwrap().DEA);
|
||||
|
||||
if let (Some(pd), Some(cd)) = (pre_dif, cur_dif) {
|
||||
if pd < 0.0 && cd >= 0.0 { dif_up += 1; }
|
||||
if pd > 0.0 && cd <= 0.0 { dif_down += 1; }
|
||||
}
|
||||
if let (Some(pd), Some(cd)) = (pre_dea, cur_dea) {
|
||||
if pd < 0.0 && cd >= 0.0 { dea_up += 1; }
|
||||
if pd > 0.0 && cd <= 0.0 { dea_down += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
let mut golden = 0;
|
||||
let mut death = 0;
|
||||
let mut 交叉标记 = vec![0i32];
|
||||
|
||||
for i in 1..普K序列.len() {
|
||||
let pre = &普K序列[i - 1].macd;
|
||||
let cur = &普K序列[i].macd;
|
||||
if pre.is_none() || cur.is_none() {
|
||||
交叉标记.push(0);
|
||||
continue;
|
||||
}
|
||||
let pre_dif = pre.as_ref().unwrap().DIF;
|
||||
let pre_dea = pre.as_ref().unwrap().DEA;
|
||||
let cur_dif = cur.as_ref().unwrap().DIF;
|
||||
let cur_dea = cur.as_ref().unwrap().DEA;
|
||||
|
||||
if let (Some(pd), Some(cd), Some(pe), Some(ce)) = (pre_dif, cur_dif, pre_dea, cur_dea) {
|
||||
if pd <= pe && cd > ce {
|
||||
golden += 1;
|
||||
交叉标记.push(1);
|
||||
} else if pd >= pe && cd < ce {
|
||||
death += 1;
|
||||
交叉标记.push(-1);
|
||||
} else {
|
||||
交叉标记.push(0);
|
||||
}
|
||||
} else {
|
||||
交叉标记.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
let 密集区 = Self::密集区域按间隔(&交叉标记, 最大间隔, 最少交叉数);
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("DIF上穿0".into(), dif_up.to_string());
|
||||
map.insert("DIF下穿0".into(), dif_down.to_string());
|
||||
map.insert("DEA上穿0".into(), dea_up.to_string());
|
||||
map.insert("DEA下穿0".into(), dea_down.to_string());
|
||||
map.insert("金叉次数".into(), golden.to_string());
|
||||
map.insert("死叉次数".into(), death.to_string());
|
||||
map.insert("密集交叉区域".into(), format!("{:?}", 密集区));
|
||||
map
|
||||
}
|
||||
|
||||
// ---- 买卖意义 ----
|
||||
|
||||
/// 买卖意义 — 核心买卖点判断逻辑
|
||||
///
|
||||
/// 返回 (是否有意义, 原因字符串)
|
||||
pub fn 买卖意义(实线: &虚线, 观察员: &crate::business::observer::观察者) -> (bool, String) {
|
||||
let 普K序列 = &观察员.普通K线序列;
|
||||
let 配置 = &观察员.配置;
|
||||
|
||||
if 实线.标识 != "笔" && 实线.标识 != "线段" && !实线.标识.starts_with("线段<") {
|
||||
return (false, "标识不在范围内".into());
|
||||
}
|
||||
|
||||
// KDJ指标完整性检查
|
||||
match &实线.武.中.标的K线.kdj {
|
||||
Some(kdj) if kdj.K.is_some() && kdj.D.is_some() && kdj.J.is_some() => {}
|
||||
_ => return (false, "KDJ指标不完整".into()),
|
||||
}
|
||||
|
||||
let 意义 = Self::缠K买卖点模式(&配置.买卖点_指标模式, &实线.武.中, 配置);
|
||||
let 结果 = false;
|
||||
|
||||
let 背驰过: Vec<Rc<分型>> = if 实线.标识 == "笔" {
|
||||
crate::algorithm::bi::笔::是否背驰过(实线, 观察员)
|
||||
} else {
|
||||
crate::algorithm::segment::线段::是否背驰过(实线, 观察员)
|
||||
};
|
||||
|
||||
if 意义 {
|
||||
if 实线.标识 == "笔" {
|
||||
if Self::武之MACD均值(普K序列, 实线) {
|
||||
return (true, "武之MACD均值".into());
|
||||
}
|
||||
if Self::武之MACD极值(普K序列, 实线) && !背驰过.is_empty() {
|
||||
return (true, "背驰过且极值".into());
|
||||
} else if 实线.武.与MACD柱子分型匹配() {
|
||||
return (
|
||||
true,
|
||||
format!(
|
||||
"背驰过:{},极值:{},柱子分型匹配",
|
||||
背驰过.len(),
|
||||
Self::武之MACD极值(普K序列, 实线)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if 实线.标识 != "笔"
|
||||
&& crate::algorithm::segment::线段::判断线段内部是否背驰(实线, 观察员)
|
||||
{
|
||||
return (true, "线段内部背驰".into());
|
||||
}
|
||||
}
|
||||
|
||||
if !结果 && 意义 && 实线.武.中.与MACD柱子匹配() {
|
||||
if Self::武之MACD极值(普K序列, 实线) && 背驰过.len() > 2 {
|
||||
return (
|
||||
true,
|
||||
"没结果, 极值, 柱子分型匹配, 背驰过大于2次".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(结果, "".into())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 虚线 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.标识 == "笔" {
|
||||
write!(
|
||||
f,
|
||||
"笔({}, {}, {}, {}, 周期: {}, 数量: {})",
|
||||
self.序号,
|
||||
self.方向(),
|
||||
self.文,
|
||||
self.武,
|
||||
self.文.中.周期,
|
||||
self.武.中.序号 - self.文.中.序号 + 1
|
||||
)
|
||||
} else {
|
||||
let 四象 = crate::algorithm::segment::线段::四象(self);
|
||||
let 缺口 = crate::algorithm::segment::线段::获取缺口(self);
|
||||
let 缺口_str = match 缺口 {
|
||||
Some(g) => format!("{}", g),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
let 确认K线_str = match &self.确认K线 {
|
||||
Some(k) => format!("{}", k),
|
||||
None => "None".to_string(),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{}<{}, {}, {}, {}, {}, 数量: {}, 缺口: {}, {}>",
|
||||
self.标识,
|
||||
self.序号,
|
||||
四象,
|
||||
self.方向(),
|
||||
self.文,
|
||||
self.武,
|
||||
self.基础序列.len(),
|
||||
缺口_str,
|
||||
确认K线_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::structure::segment_feat::线段特征;
|
||||
use crate::types::分型结构;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// 特征分型 — 由三个线段特征元素构成的分型
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct 特征分型 {
|
||||
pub 左: Rc<线段特征>,
|
||||
pub 中: Rc<线段特征>,
|
||||
pub 右: Rc<线段特征>,
|
||||
pub 结构: 分型结构,
|
||||
}
|
||||
|
||||
impl 特征分型 {
|
||||
pub fn new(左: Rc<线段特征>, 中: Rc<线段特征>, 右: Rc<线段特征>, 结构: 分型结构) -> Self {
|
||||
Self { 左, 中, 右, 结构 }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 特征分型 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "特征分型<{}, {}>", self.结构, self.中)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
use crate::kline::chan_kline::缠论K线;
|
||||
use crate::types::分型结构;
|
||||
use crate::types::相对方向;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// 分型 — 由三根缠K构成(可能缺左或右)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct 分型 {
|
||||
pub 左: Option<Rc<缠论K线>>,
|
||||
pub 中: Rc<缠论K线>,
|
||||
pub 右: Option<Rc<缠论K线>>,
|
||||
pub 结构: 分型结构,
|
||||
pub 时间戳: i64,
|
||||
pub 分型特征值: f64,
|
||||
}
|
||||
|
||||
impl 分型 {
|
||||
pub fn new(左: Option<Rc<缠论K线>>, 中: Rc<缠论K线>, 右: Option<Rc<缠论K线>>) -> Self {
|
||||
let 结构 = 中.分型.unwrap_or(分型结构::散);
|
||||
let 时间戳 = 中.时间戳;
|
||||
let 分型特征值 = 中.分型特征值;
|
||||
Self {
|
||||
左,
|
||||
中,
|
||||
右,
|
||||
结构,
|
||||
时间戳,
|
||||
分型特征值,
|
||||
}
|
||||
}
|
||||
|
||||
/// 左中右三组关系
|
||||
pub fn 关系组(&self) -> Option<(相对方向, 相对方向, 相对方向)> {
|
||||
let 左 = self.左.as_ref()?;
|
||||
let 右 = self.右.as_ref()?;
|
||||
Some((
|
||||
相对方向::分析(左.高, 左.低, self.中.高, self.中.低),
|
||||
相对方向::分析(self.中.高, self.中.低, 右.高, 右.低),
|
||||
相对方向::分析(左.高, 左.低, 右.高, 右.低),
|
||||
))
|
||||
}
|
||||
|
||||
/// 分型强度
|
||||
pub fn 强度(&self) -> f64 {
|
||||
match self.结构 {
|
||||
分型结构::顶 | 分型结构::上 => {
|
||||
if let Some(ref 左) = self.左 {
|
||||
self.中.高 - 左.高
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
分型结构::底 | 分型结构::下 => {
|
||||
if let Some(ref 左) = self.左 {
|
||||
左.低 - self.中.低
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
分型结构::散 => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// MACD柱子分型匹配
|
||||
pub fn 与MACD柱子分型匹配(&self) -> bool {
|
||||
match self.结构 {
|
||||
分型结构::顶 | 分型结构::上 => {
|
||||
if let Some(ref 左) = self.左 {
|
||||
左.与MACD柱子匹配()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
分型结构::底 | 分型结构::下 => {
|
||||
if let Some(ref 右) = self.右 {
|
||||
右.与MACD柱子匹配()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
分型结构::散 => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断两个分型是否匹配
|
||||
pub fn 判断分型(左: &分型, 右: &分型, 模式: &str) -> bool {
|
||||
match 模式 {
|
||||
"中" => 左.中.序号 == 右.中.序号,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 从缠K序列中获取以指定缠K为中元素的分型
|
||||
pub fn 从缠K序列中获取分型(K线序列: &[Rc<缠论K线>], 中: &Rc<缠论K线>) -> Option<Self> {
|
||||
let idx = K线序列.iter().position(|k| Rc::as_ptr(k) == Rc::as_ptr(中))?;
|
||||
let 左 = if idx > 0 {
|
||||
Some(Rc::clone(&K线序列[idx - 1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let 右 = if idx + 1 < K线序列.len() {
|
||||
Some(Rc::clone(&K线序列[idx + 1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some(Self::new(左, Rc::clone(中), 右))
|
||||
}
|
||||
|
||||
/// 向分型序列中添加新分型
|
||||
pub fn 向序列中添加(分型序列: &mut Vec<Rc<分型>>, 当前分型: Rc<分型>) {
|
||||
if let Some(前一个) = 分型序列.last() {
|
||||
if 前一个.时间戳 == 当前分型.时间戳 {
|
||||
// 同一时间戳: 比较强度,保留更强的
|
||||
match 当前分型.结构 {
|
||||
分型结构::顶 | 分型结构::上 => {
|
||||
if 当前分型.分型特征值 >= 前一个.分型特征值 {
|
||||
分型序列.pop();
|
||||
分型序列.push(当前分型);
|
||||
}
|
||||
return;
|
||||
}
|
||||
分型结构::底 | 分型结构::下 => {
|
||||
if 当前分型.分型特征值 <= 前一个.分型特征值 {
|
||||
分型序列.pop();
|
||||
分型序列.push(当前分型);
|
||||
}
|
||||
return;
|
||||
}
|
||||
分型结构::散 => {}
|
||||
}
|
||||
}
|
||||
// 相同结构只保留更强的
|
||||
if 前一个.结构 == 当前分型.结构 {
|
||||
if (当前分型.结构 == 分型结构::顶 || 当前分型.结构 == 分型结构::上)
|
||||
&& 当前分型.分型特征值 >= 前一个.分型特征值
|
||||
{
|
||||
分型序列.pop();
|
||||
分型序列.push(当前分型);
|
||||
} else if (当前分型.结构 == 分型结构::底 || 当前分型.结构 == 分型结构::下)
|
||||
&& 当前分型.分型特征值 <= 前一个.分型特征值
|
||||
{
|
||||
分型序列.pop();
|
||||
分型序列.push(当前分型);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
分型序列.push(当前分型);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::types::fractal::有高低 for 分型 {
|
||||
fn 高(&self) -> f64 {
|
||||
self.中.高
|
||||
}
|
||||
fn 低(&self) -> f64 {
|
||||
self.中.低
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 分型 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}<{}, {}, None: {}, None: {}>",
|
||||
self.中.分型.unwrap_or(crate::types::分型结构::散),
|
||||
self.时间戳,
|
||||
crate::utils::format_f64_g(self.分型特征值),
|
||||
if self.左.is_none() { "True" } else { "False" },
|
||||
if self.右.is_none() { "True" } else { "False" },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod dash_line;
|
||||
pub mod feat_fractal;
|
||||
pub mod fractal_obj;
|
||||
pub mod segment_feat;
|
||||
@@ -0,0 +1,254 @@
|
||||
use crate::structure::dash_line::虚线;
|
||||
use crate::structure::feat_fractal::特征分型;
|
||||
use crate::structure::fractal_obj::分型;
|
||||
use crate::types::{分型结构, 相对方向};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// 线段特征 — 特征序列元素(内部是虚线的集合)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct 线段特征 {
|
||||
pub 序号: i64,
|
||||
pub 标识: String,
|
||||
pub 线段方向: 相对方向,
|
||||
pub 元素: Vec<Rc<虚线>>,
|
||||
}
|
||||
|
||||
impl 线段特征 {
|
||||
pub fn new(标识: String, 基础序列: Vec<Rc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
Self {
|
||||
序号: 0,
|
||||
标识,
|
||||
线段方向,
|
||||
元素: 基础序列,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn 图表标题(&self) -> String {
|
||||
self.标识.clone()
|
||||
}
|
||||
|
||||
/// 文 — 取特征序列元素中分型特征值最大/最小的文分型
|
||||
pub fn 文(&self) -> Rc<分型> {
|
||||
if self.线段方向.是否向上() {
|
||||
// 向上 → 取最大的文
|
||||
self.元素
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
a.文
|
||||
.分型特征值
|
||||
.partial_cmp(&b.文.分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.map(|x| Rc::clone(&x.文))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].文))
|
||||
} else {
|
||||
// 向下 → 取最小的文
|
||||
self.元素
|
||||
.iter()
|
||||
.min_by(|a, b| {
|
||||
a.文
|
||||
.分型特征值
|
||||
.partial_cmp(&b.文.分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.map(|x| Rc::clone(&x.文))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].文))
|
||||
}
|
||||
}
|
||||
|
||||
/// 武 — 取特征序列元素中分型特征值最大/最小的武分型
|
||||
pub fn 武(&self) -> Rc<分型> {
|
||||
if self.线段方向.是否向上() {
|
||||
self.元素
|
||||
.iter()
|
||||
.max_by(|a, b| {
|
||||
a.武
|
||||
.分型特征值
|
||||
.partial_cmp(&b.武.分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.map(|x| Rc::clone(&x.武))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].武))
|
||||
} else {
|
||||
self.元素
|
||||
.iter()
|
||||
.min_by(|a, b| {
|
||||
a.武
|
||||
.分型特征值
|
||||
.partial_cmp(&b.武.分型特征值)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.map(|x| Rc::clone(&x.武))
|
||||
.unwrap_or_else(|| Rc::clone(&self.元素[0].武))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn 高(&self) -> f64 {
|
||||
let 文 = self.文();
|
||||
let 武 = self.武();
|
||||
文.分型特征值.max(武.分型特征值)
|
||||
}
|
||||
|
||||
pub fn 低(&self) -> f64 {
|
||||
let 文 = self.文();
|
||||
let 武 = self.武();
|
||||
文.分型特征值.min(武.分型特征值)
|
||||
}
|
||||
|
||||
/// 方向 — 线段方向的翻转
|
||||
pub fn 方向(&self) -> 相对方向 {
|
||||
self.线段方向.翻转()
|
||||
}
|
||||
|
||||
/// 向特征序列元素中添加虚线
|
||||
pub fn 添加(&mut self, 待添加虚线: Rc<虚线>) -> Result<(), String> {
|
||||
if 待添加虚线.方向() == self.线段方向 {
|
||||
return Err("添加方向与线段方向相同".into());
|
||||
}
|
||||
self.元素.push(待添加虚线);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 新建特征序列元素
|
||||
pub fn 新建(虚线序列: Vec<Rc<虚线>>, 线段方向: 相对方向) -> Self {
|
||||
let 标识 = format!("特征<虚线>");
|
||||
Self::new(标识, 虚线序列, 线段方向)
|
||||
}
|
||||
|
||||
/// 静态分析 — 从虚线序列生成特征序列元素列表
|
||||
pub fn 静态分析(
|
||||
虚线序列: &[Rc<虚线>],
|
||||
线段方向: 相对方向,
|
||||
四象: &str,
|
||||
是否忽视: bool,
|
||||
) -> Vec<Rc<线段特征>> {
|
||||
let mut 结果: Vec<Rc<线段特征>> = Vec::new();
|
||||
|
||||
// 需要被合并的方向集合
|
||||
let 需要合并: Vec<相对方向> = match 四象 {
|
||||
"老阳" | "老阴" if !是否忽视 => vec![相对方向::顺, 相对方向::逆, 相对方向::同],
|
||||
_ => vec![相对方向::顺, 相对方向::同],
|
||||
};
|
||||
|
||||
for 虚线 in 虚线序列 {
|
||||
// 情况1:方向相同(可能触发分型替换)
|
||||
if 虚线.方向() == 线段方向 {
|
||||
if 结果.len() >= 3 {
|
||||
let 左 = Rc::clone(&结果[结果.len() - 3]);
|
||||
let 中 = Rc::clone(&结果[结果.len() - 2]);
|
||||
let 右 = Rc::clone(&结果[结果.len() - 1]);
|
||||
|
||||
if let Some(结构) = 分型结构::分析(&*左, &*中, &*右, true, true) {
|
||||
let 应替换 = (线段方向 == 相对方向::向上
|
||||
&& 结构 == 分型结构::顶
|
||||
&& 虚线.高() > 中.高())
|
||||
|| (线段方向 == 相对方向::向下
|
||||
&& 结构 == 分型结构::底
|
||||
&& 虚线.低() < 中.低());
|
||||
|
||||
if 应替换 {
|
||||
let 小号虚线 = if 中.元素[0].序号 < 右.元素[0].序号 {
|
||||
&中.元素[0]
|
||||
} else {
|
||||
&右.元素[0]
|
||||
};
|
||||
let 大号虚线 = if 中.元素.last().unwrap().序号
|
||||
> 右.元素.last().unwrap().序号
|
||||
{
|
||||
&中.元素[中.元素.len() - 1]
|
||||
} else {
|
||||
&右.元素[右.元素.len() - 1]
|
||||
};
|
||||
let fake = 虚线::创建笔(
|
||||
Rc::clone(&小号虚线.文),
|
||||
Rc::clone(&大号虚线.武),
|
||||
false,
|
||||
);
|
||||
结果.pop();
|
||||
let idx = 结果.len() - 1;
|
||||
结果[idx] =
|
||||
Rc::new(Self::新建(vec![Rc::new(fake)], 线段方向));
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 情况2:方向不同(执行特征序列的合并/添加)
|
||||
if 结果.is_empty() {
|
||||
结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查与最后一个特征序列的方向关系
|
||||
let 最后_idx = 结果.len() - 1;
|
||||
let 之前线段特征 = &*结果[最后_idx];
|
||||
if 需要合并.contains(&相对方向::分析(
|
||||
之前线段特征.高(),
|
||||
之前线段特征.低(),
|
||||
虚线.高(),
|
||||
虚线.低(),
|
||||
)) {
|
||||
// Clone-modify-replace
|
||||
let mut 新特征 = (*结果[最后_idx]).clone();
|
||||
let _ = 新特征.添加(Rc::clone(虚线));
|
||||
结果[最后_idx] = Rc::new(新特征);
|
||||
} else {
|
||||
结果.push(Rc::new(Self::新建(vec![Rc::clone(虚线)], 线段方向)));
|
||||
}
|
||||
}
|
||||
|
||||
结果
|
||||
}
|
||||
|
||||
/// 获取分型序列
|
||||
pub fn 获取分型序列(特征序列: &[Rc<线段特征>]) -> 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]);
|
||||
|
||||
if let Some(结构) = 分型结构::分析_对象(
|
||||
&*左 as &dyn crate::types::fractal::有高低,
|
||||
&*中 as &dyn crate::types::fractal::有高低,
|
||||
&*右 as &dyn crate::types::fractal::有高低,
|
||||
true,
|
||||
true,
|
||||
) {
|
||||
结果.push(特征分型::new(左, 中, 右, 结构));
|
||||
}
|
||||
}
|
||||
结果
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::types::fractal::有高低 for 线段特征 {
|
||||
fn 高(&self) -> f64 {
|
||||
self.高()
|
||||
}
|
||||
fn 低(&self) -> f64 {
|
||||
self.低()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 线段特征 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.元素.is_empty() {
|
||||
write!(f, "{}<{}, 空>", self.标识, self.线段方向)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{}<{}, {}, {}, {}>",
|
||||
self.标识,
|
||||
self.线段方向,
|
||||
self.文(),
|
||||
self.武(),
|
||||
self.元素.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user