第一版
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 买卖点类型 —— 六类买卖点(一二三 + T1/T1P/T2/T2S/T3A/T3B)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum 买卖点类型 {
|
||||
#[serde(rename = "一买")]
|
||||
一买,
|
||||
#[serde(rename = "一卖")]
|
||||
一卖,
|
||||
#[serde(rename = "二买")]
|
||||
二买,
|
||||
#[serde(rename = "二卖")]
|
||||
二卖,
|
||||
#[serde(rename = "三买")]
|
||||
三买,
|
||||
#[serde(rename = "三卖")]
|
||||
三卖,
|
||||
#[serde(rename = "T1买")]
|
||||
T1买,
|
||||
#[serde(rename = "T1卖")]
|
||||
T1卖,
|
||||
#[serde(rename = "T1P买")]
|
||||
T1P买,
|
||||
#[serde(rename = "T1P卖")]
|
||||
T1P卖,
|
||||
#[serde(rename = "T2买")]
|
||||
T2买,
|
||||
#[serde(rename = "T2卖")]
|
||||
T2卖,
|
||||
#[serde(rename = "T2S买")]
|
||||
T2S买,
|
||||
#[serde(rename = "T2S卖")]
|
||||
T2S卖,
|
||||
#[serde(rename = "T3A买")]
|
||||
T3A买,
|
||||
#[serde(rename = "T3A卖")]
|
||||
T3A卖,
|
||||
#[serde(rename = "T3B买")]
|
||||
T3B买,
|
||||
#[serde(rename = "T3B卖")]
|
||||
T3B卖,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 买卖点类型 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::一买 => write!(f, "一买"),
|
||||
Self::一卖 => write!(f, "一卖"),
|
||||
Self::二买 => write!(f, "二买"),
|
||||
Self::二卖 => write!(f, "二卖"),
|
||||
Self::三买 => write!(f, "三买"),
|
||||
Self::三卖 => write!(f, "三卖"),
|
||||
Self::T1买 => write!(f, "T1买"),
|
||||
Self::T1卖 => write!(f, "T1卖"),
|
||||
Self::T1P买 => write!(f, "T1P买"),
|
||||
Self::T1P卖 => write!(f, "T1P卖"),
|
||||
Self::T2买 => write!(f, "T2买"),
|
||||
Self::T2卖 => write!(f, "T2卖"),
|
||||
Self::T2S买 => write!(f, "T2S买"),
|
||||
Self::T2S卖 => write!(f, "T2S卖"),
|
||||
Self::T3A买 => write!(f, "T3A买"),
|
||||
Self::T3A卖 => write!(f, "T3A卖"),
|
||||
Self::T3B买 => write!(f, "T3B买"),
|
||||
Self::T3B卖 => write!(f, "T3B卖"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl 买卖点类型 {
|
||||
pub fn 是买点(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::一买
|
||||
| Self::二买
|
||||
| Self::三买
|
||||
| Self::T1买
|
||||
| Self::T1P买
|
||||
| Self::T2买
|
||||
| Self::T2S买
|
||||
| Self::T3A买
|
||||
| Self::T3B买
|
||||
)
|
||||
}
|
||||
|
||||
pub fn 是卖点(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::一卖
|
||||
| Self::二卖
|
||||
| Self::三卖
|
||||
| Self::T1卖
|
||||
| Self::T1P卖
|
||||
| Self::T2卖
|
||||
| Self::T2S卖
|
||||
| Self::T3A卖
|
||||
| Self::T3B卖
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 相对方向 —— K线之间的相对位置关系
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum 相对方向 {
|
||||
#[serde(rename = "交叠向上")]
|
||||
向上,
|
||||
#[serde(rename = "交叠向下")]
|
||||
向下,
|
||||
#[serde(rename = "向上缺口")]
|
||||
向上缺口,
|
||||
#[serde(rename = "向下缺口")]
|
||||
向下缺口,
|
||||
#[serde(rename = "衔接向上")]
|
||||
衔接向上,
|
||||
#[serde(rename = "衔接向下")]
|
||||
衔接向下,
|
||||
#[serde(rename = "顺序包含")]
|
||||
顺,
|
||||
#[serde(rename = "逆序包含")]
|
||||
逆,
|
||||
#[serde(rename = "相同包含")]
|
||||
同,
|
||||
}
|
||||
|
||||
impl 相对方向 {
|
||||
pub fn 翻转(&self) -> Self {
|
||||
match self {
|
||||
Self::向上 => Self::向下,
|
||||
Self::向下 => Self::向上,
|
||||
Self::向上缺口 => Self::向下缺口,
|
||||
Self::向下缺口 => Self::向上缺口,
|
||||
Self::衔接向上 => Self::衔接向下,
|
||||
Self::衔接向下 => Self::衔接向上,
|
||||
Self::顺 => Self::逆,
|
||||
Self::逆 => Self::顺,
|
||||
other => *other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn 是否向上(&self) -> bool {
|
||||
matches!(self, Self::向上 | Self::向上缺口 | Self::衔接向上)
|
||||
}
|
||||
|
||||
pub fn 是否向下(&self) -> bool {
|
||||
matches!(self, Self::向下 | Self::向下缺口 | Self::衔接向下)
|
||||
}
|
||||
|
||||
pub fn 是否包含(&self) -> bool {
|
||||
matches!(self, Self::顺 | Self::逆 | Self::同)
|
||||
}
|
||||
|
||||
pub fn 是否缺口(&self) -> bool {
|
||||
matches!(self, Self::向下缺口 | Self::向上缺口)
|
||||
}
|
||||
|
||||
pub fn 是否衔接(&self) -> bool {
|
||||
matches!(self, Self::衔接向下 | Self::衔接向上)
|
||||
}
|
||||
|
||||
/// 分析两个K线之间的相对方向
|
||||
pub fn 分析(前高: f64, 前低: f64, 后高: f64, 后低: f64) -> Self {
|
||||
if (前高 - 后高).abs() < f64::EPSILON && (前低 - 后低).abs() < f64::EPSILON {
|
||||
return Self::同;
|
||||
}
|
||||
if 前高 > 后高 && 前低 > 后低 {
|
||||
if (前低 - 后高).abs() < f64::EPSILON {
|
||||
return Self::衔接向下;
|
||||
}
|
||||
if 前低 > 后高 {
|
||||
return Self::向下缺口;
|
||||
}
|
||||
return Self::向下;
|
||||
}
|
||||
if 前高 < 后高 && 前低 < 后低 {
|
||||
if (前高 - 后低).abs() < f64::EPSILON {
|
||||
return Self::衔接向上;
|
||||
}
|
||||
if 前高 < 后低 {
|
||||
return Self::向上缺口;
|
||||
}
|
||||
return Self::向上;
|
||||
}
|
||||
if 前高 >= 后高 && 前低 <= 后低 {
|
||||
return Self::顺;
|
||||
}
|
||||
if 前高 <= 后高 && 前低 >= 后低 {
|
||||
return Self::逆;
|
||||
}
|
||||
panic!("无法识别的方向: 前({},{}), 后({},{})", 前高, 前低, 后高, 后低);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 相对方向 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::向上 => write!(f, "相对方向.向上"),
|
||||
Self::向下 => write!(f, "相对方向.向下"),
|
||||
Self::向上缺口 => write!(f, "相对方向.向上缺口"),
|
||||
Self::向下缺口 => write!(f, "相对方向.向下缺口"),
|
||||
Self::衔接向上 => write!(f, "相对方向.衔接向上"),
|
||||
Self::衔接向下 => write!(f, "相对方向.衔接向下"),
|
||||
Self::顺 => write!(f, "相对方向.顺"),
|
||||
Self::逆 => write!(f, "相对方向.逆"),
|
||||
Self::同 => write!(f, "相对方向.同"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 分型结构 —— 三根K线构成的结构形态
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum 分型结构 {
|
||||
#[serde(rename = "三连向上")]
|
||||
上,
|
||||
#[serde(rename = "三连向下")]
|
||||
下,
|
||||
#[serde(rename = "顶分型")]
|
||||
顶,
|
||||
#[serde(rename = "底分型")]
|
||||
底,
|
||||
#[serde(rename = "向右扩散")]
|
||||
散,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 分型结构 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::上 => write!(f, "上"),
|
||||
Self::下 => write!(f, "下"),
|
||||
Self::顶 => write!(f, "顶"),
|
||||
Self::底 => write!(f, "底"),
|
||||
Self::散 => write!(f, "散"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl 分型结构 {
|
||||
/// 分析三根K线构成的分型结构(泛型版本)
|
||||
pub fn 分析(
|
||||
左: &impl 有高低,
|
||||
中: &impl 有高低,
|
||||
右: &impl 有高低,
|
||||
可以逆序包含: bool,
|
||||
忽视顺序包含: bool,
|
||||
) -> Option<Self> {
|
||||
Self::分析_内部(左.高(), 左.低(), 中.高(), 中.低(), 右.高(), 右.低(), 可以逆序包含, 忽视顺序包含)
|
||||
}
|
||||
|
||||
/// 分析三元素构成的分型结构(trait object 版本)
|
||||
pub fn 分析_对象(
|
||||
左: &dyn 有高低,
|
||||
中: &dyn 有高低,
|
||||
右: &dyn 有高低,
|
||||
可以逆序包含: bool,
|
||||
忽视顺序包含: bool,
|
||||
) -> Option<Self> {
|
||||
Self::分析_内部(左.高(), 左.低(), 中.高(), 中.低(), 右.高(), 右.低(), 可以逆序包含, 忽视顺序包含)
|
||||
}
|
||||
|
||||
fn 分析_内部(
|
||||
左高: f64, 左低: f64,
|
||||
中高: f64, 中低: f64,
|
||||
右高: f64, 右低: f64,
|
||||
可以逆序包含: bool,
|
||||
忽视顺序包含: bool,
|
||||
) -> Option<Self> {
|
||||
use crate::types::direction::相对方向;
|
||||
|
||||
let 左中关系 = 相对方向::分析(左高, 左低, 中高, 中低);
|
||||
let 中右关系 = 相对方向::分析(中高, 中低, 右高, 右低);
|
||||
|
||||
let 向上类 = |d: 相对方向| d.是否向上();
|
||||
let 向下类 = |d: 相对方向| d.是否向下();
|
||||
|
||||
match (左中关系, 中右关系) {
|
||||
// 顺序包含 — 忽视时可以绕过
|
||||
(相对方向::顺, _) if !忽视顺序包含 => {
|
||||
panic!("顺序包含: {:?} {:?}", 左中关系, 中右关系);
|
||||
}
|
||||
(_, 相对方向::顺) if !忽视顺序包含 => {
|
||||
panic!("顺序包含: {:?} {:?}", 左中关系, 中右关系);
|
||||
}
|
||||
// 向上 + 向上 = 三连上
|
||||
(a, b) if 向上类(a) && 向上类(b) => Some(Self::上),
|
||||
// 向上 + 向下 = 顶分型
|
||||
(a, b) if 向上类(a) && 向下类(b) => Some(Self::顶),
|
||||
// 向上 + 逆序包含 = 上
|
||||
(a, 相对方向::逆) if 向上类(a) && 可以逆序包含 => Some(Self::上),
|
||||
// 向下 + 向上 = 底分型
|
||||
(a, b) if 向下类(a) && 向上类(b) => Some(Self::底),
|
||||
// 向下 + 向下 = 三连下
|
||||
(a, b) if 向下类(a) && 向下类(b) => Some(Self::下),
|
||||
// 向下 + 逆序包含 = 下
|
||||
(a, 相对方向::逆) if 向下类(a) && 可以逆序包含 => Some(Self::下),
|
||||
// 逆序包含 + 向上 = 底
|
||||
(相对方向::逆, a) if 向上类(a) && 可以逆序包含 => Some(Self::底),
|
||||
// 逆序包含 + 向下 = 顶
|
||||
(相对方向::逆, a) if 向下类(a) && 可以逆序包含 => Some(Self::顶),
|
||||
// 逆序包含 + 逆序包含 = 散
|
||||
(相对方向::逆, 相对方向::逆) if 可以逆序包含 => Some(Self::散),
|
||||
_ => {
|
||||
eprintln!(
|
||||
"无法识别的分型结构: 左中={:?}, 中右={:?}",
|
||||
左中关系, 中右关系
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that have 高 and 低 (used by 分型结构::分析)
|
||||
pub trait 有高低 {
|
||||
fn 高(&self) -> f64;
|
||||
fn 低(&self) -> f64;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 缺口 —— 两个价格区间之间的空隙
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct 缺口 {
|
||||
pub 高: f64,
|
||||
pub 低: f64,
|
||||
}
|
||||
|
||||
impl 缺口 {
|
||||
pub fn new(高: f64, 低: f64) -> Self {
|
||||
assert!(高 > 低, "缺口高必须大于低: 高={高}, 低={低}");
|
||||
Self { 高, 低 }
|
||||
}
|
||||
|
||||
/// 在 [起点, 终点] 区间内居中截取一个子区间
|
||||
pub fn 居中截取区间(起点: f64, 终点: f64, 比例: f64) -> Option<Self> {
|
||||
let (起点, 终点) = if 起点 <= 终点 {
|
||||
(起点, 终点)
|
||||
} else {
|
||||
(终点, 起点)
|
||||
};
|
||||
|
||||
let 总长 = 终点 - 起点;
|
||||
let 偏移 = 总长 * 比例;
|
||||
let 中心 = (起点 + 终点) / 2.0;
|
||||
|
||||
let 下界 = 中心 - 偏移;
|
||||
let 上界 = 中心 + 偏移;
|
||||
|
||||
if 下界 > 终点 || 上界 < 起点 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let 下界 = 下界.max(起点);
|
||||
let 上界 = 上界.min(终点);
|
||||
|
||||
Some(Self::new(上界.max(下界), 上界.min(下界)))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for 缺口 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"缺口区间<{} <=> {}>",
|
||||
crate::utils::format_f64_g(self.低),
|
||||
crate::utils::format_f64_g(self.高)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
pub mod bsp_type;
|
||||
pub mod direction;
|
||||
pub mod fractal;
|
||||
pub mod gap;
|
||||
|
||||
pub use bsp_type::买卖点类型;
|
||||
pub use direction::相对方向;
|
||||
pub use fractal::分型结构;
|
||||
pub use gap::缺口;
|
||||
Reference in New Issue
Block a user