use crate::kline::chan_kline::缠论K线;
use crate::types::分型结构;
use crate::types::相对方向;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use tracing::warn;
pub static 分型模式: AtomicBool = AtomicBool::new(true);
#[derive(Debug, Clone)]
pub struct 分型 {
pub 左: Option<Arc<缠论K线>>,
pub 中: Arc<缠论K线>,
pub 右: Option<Arc<缠论K线>>,
pub 结构: 分型结构,
pub 时间戳: i64,
pub 分型特征值: f64,
}
impl 分型 {
pub fn new(
左: Option<Arc<缠论K线>>, 中: Arc<缠论K线>, 右: Option<Arc<缠论K线>>
) -> Self {
if let (Some(左), Some(右)) = (&左, &右) {
assert!(
左.时间戳.load(Ordering::Relaxed) < 中.时间戳.load(Ordering::Relaxed)
&& 中.时间戳.load(Ordering::Relaxed) < 右.时间戳.load(Ordering::Relaxed),
"分型时间戳断言失败: 左={}, 中={}, 右={}",
左.时间戳.load(Ordering::Relaxed),
中.时间戳.load(Ordering::Relaxed),
右.时间戳.load(Ordering::Relaxed),
);
}
let 结构 = 中.分型.read().unwrap().unwrap_or(分型结构::散);
let 时间戳 = 中.时间戳.load(Ordering::Relaxed);
let 分型特征值 = 中.分型特征值.get();
Self {
左,
中,
右,
结构,
时间戳,
分型特征值,
}
}
pub fn 时间戳(&self) -> i64 {
if 分型模式.load(Ordering::Relaxed) {
self.时间戳
} else {
self.中.时间戳.load(Ordering::Relaxed)
}
}
pub fn 结构(&self) -> 分型结构 {
if 分型模式.load(Ordering::Relaxed) {
self.结构
} else {
self.中.分型.read().unwrap().unwrap_or(分型结构::散) }
}
pub fn 分型特征值(&self) -> f64 {
if 分型模式.load(Ordering::Relaxed) {
self.分型特征值
} else {
self.中.分型特征值.get()
}
}
pub fn 关系组(&self) -> Option<(相对方向, 相对方向, 相对方向)> {
let 左 = self.左.as_ref()?;
let 右 = self.右.as_ref()?;
Some((
相对方向::分析(左.高.get(), 左.低.get(), self.中.高.get(), self.中.低.get()),
相对方向::分析(self.中.高.get(), self.中.低.get(), 右.高.get(), 右.低.get()),
相对方向::分析(左.高.get(), 左.低.get(), 右.高.get(), 右.低.get()),
))
}
pub fn 强度(&self) -> &str {
if self.结构() != 分型结构::底 && self.结构() != 分型结构::顶 {
return "未知";
}
if self.右.is_none() || self.左.is_none() {
return "未知";
}
if let Some(ref 关系组) = self.关系组() {
if self.结构() == 分型结构::底 {
if 关系组.2.是否向下() {
return "弱";
} else if 关系组.2.是否向上() {
return "强";
} else {
return "中";
}
} else if self.结构() == 分型结构::顶 {
if 关系组.2.是否向上() {
return "弱";
} else if 关系组.2.是否向下() {
return "强";
} else {
return "中";
}
}
}
if let (Some(左), Some(右)) = (&self.左, &self.右) {
if self.结构() == 分型结构::底 {
if 右.标的K线.read().unwrap().收盘价 > 左.标的K线.read().unwrap().高 {
return "强";
} else if 右.标的K线.read().unwrap().收盘价 > self.中.标的K线.read().unwrap().高
{
return "中";
} else {
return "弱";
}
} else if self.结构() == 分型结构::顶 {
if 右.标的K线.read().unwrap().收盘价 < 左.标的K线.read().unwrap().低 {
return "强";
} else if 右.标的K线.read().unwrap().收盘价 < self.中.标的K线.read().unwrap().低
{
return "中";
} else {
return "弱";
}
}
}
"未知"
}
pub fn 与MACD柱子分型匹配(&self) -> bool {
if let (Some(左), Some(右)) = (&self.左, &self.右) {
if self.结构() == 分型结构::底 {
let 左_k = 左.标的K线.read().unwrap();
let 中_k = self.中.标的K线.read().unwrap();
let 右_k = 右.标的K线.read().unwrap();
let 左_m = 左_k.指标.read().unwrap();
let 中_m = 中_k.指标.read().unwrap();
let 右_m = 右_k.指标.read().unwrap();
if let (Some(左macd), Some(中macd), Some(右macd)) =
(左_m.macd(), 中_m.macd(), 右_m.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();
let 左_m = 左_k.指标.read().unwrap();
let 中_m = 中_k.指标.read().unwrap();
let 右_m = 右_k.指标.read().unwrap();
if let (Some(左macd), Some(中macd), Some(右macd)) =
(左_m.macd(), 中_m.macd(), 右_m.macd())
{
return 左macd.MACD柱 < 中macd.MACD柱 && 中macd.MACD柱 > 右macd.MACD柱;
}
}
}
false
}
pub fn 判断分型(左: &Arc<分型>, 右: &Arc<分型>, _模式: &str) -> bool {
Arc::as_ptr(左) == Arc::as_ptr(右)
}
pub fn 从缠K序列中获取分型(
K线序列: &[Arc<缠论K线>],
中: &Arc<缠论K线>,
) -> Option<Self> {
let idx = K线序列
.iter()
.position(|k| Arc::as_ptr(k) == Arc::as_ptr(中))?;
let 左 = if idx > 0 {
Some(Arc::clone(&K线序列[idx - 1]))
} else {
None
};
let 右 = if idx + 1 < K线序列.len() {
Some(Arc::clone(&K线序列[idx + 1]))
} else {
None
};
Some(Self::new(左, Arc::clone(中), 右))
}
pub fn 向序列中添加(分型序列: &mut Vec<Arc<分型>>, 当前分型: Arc<分型>) {
if 分型序列.is_empty() {
if 当前分型.结构() != 分型结构::顶 && 当前分型.结构() != 分型结构::底
{
panic!("首次添加分型不为 顶底 {:?}", 当前分型);
}
} else {
let 前一个 = &分型序列[分型序列.len() - 1];
if 前一个.结构() == 当前分型.结构() {
panic!("分型相同无法添加 {:?} {:?}", 前一个, 当前分型);
}
if 前一个.右.is_none() {
warn!("分型.向序列中添加, 分型异常 {:?}", 前一个);
}
}
分型序列.push(当前分型);
}
pub fn 相等(&self, other: &Self, 浮点容差: f64) -> (bool, String) {
match (&self.左, &other.左) {
(None, None) => {}
(Some(a), Some(b)) => {
let (eq, msg) = a.相等(b, 浮点容差);
if !eq {
return (false, format!("分型: [左]缠论K线异常 >> {msg}"));
}
}
(a, b) => {
return (
false,
format!("分型: [左]空值不一致 A={},B={}", a.is_some(), b.is_some()),
);
}
}
{
let (eq, msg) = self.中.相等(&other.中, 浮点容差);
if !eq {
return (false, format!("分型: [中]缠论K线异常 >> {msg}"));
}
}
match (&self.右, &other.右) {
(None, None) => {}
(Some(a), Some(b)) => {
let (eq, msg) = a.相等(b, 浮点容差);
if !eq {
return (false, format!("分型: [右]缠论K线异常 >> {msg}"));
}
}
(a, b) => {
return (
false,
format!("分型: [右]空值不一致 A={},B={}", a.is_some(), b.is_some()),
);
}
}
if self.结构 != other.结构 {
return (
false,
format!("分型: [结构] 不等 A={},B={}", self.结构, other.结构),
);
}
if self.时间戳 != other.时间戳 {
return (
false,
format!("分型: [时间戳] 不等 A={},B={}", self.时间戳, other.时间戳),
);
}
if (self.分型特征值 - other.分型特征值).abs() > 浮点容差 {
return (
false,
format!(
"分型: [分型特征值] 浮点超限 A={:.10},B={:.10}",
self.分型特征值, other.分型特征值
),
);
}
(true, "分型: 全部字段一致".into())
}
}
impl crate::types::fractal::有高低 for 分型 {
fn 高(&self) -> f64 {
self.中.高.get()
}
fn 低(&self) -> f64 {
self.中.低.get()
}
}
impl std::fmt::Display for 分型 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}<{}, {}, None: {}, None: {}>",
self.结构(),
self.时间戳(),
crate::utils::format_f64_g(self.分型特征值()),
if self.左.is_none() { "True" } else { "False" },
if self.右.is_none() { "True" } else { "False" },
)
}
}