第二版

This commit is contained in:
YuWuKunCheng
2026-05-25 04:26:15 +08:00
parent f92eef11fb
commit bf96517c9d
21 changed files with 1599 additions and 1002 deletions
+167 -63
View File
@@ -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;
}
}
+117 -69
View File
@@ -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
View File
@@ -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();
}
}
File diff suppressed because it is too large Load Diff
+50 -65
View File
@@ -11,10 +11,8 @@ use std::collections::HashMap;
pub struct {
pub : Vec<i64>,
: i64,
: i64,
K线合成器: K线合成器,
: HashMap<i64, >,
K线计数: HashMap<i64, usize>,
}
impl {
@@ -27,11 +25,6 @@ impl 立体分析器 {
let mut = ;
.sort();
let = [0];
let = if .len() > 1 {
[1]
} else {
[0]
};
let = .unwrap_or_default();
let = .unwrap_or_default();
@@ -40,50 +33,28 @@ impl 立体分析器 {
let mut = HashMap::new();
for & in & {
let mut = .get(&).cloned().unwrap_or_else(|| .clone());
let mut =
.get(&)
.cloned()
.unwrap_or_else(|| .clone());
.K线 = false;
.线 = false;
// Set 标识 to match 符号
. = .clone();
let = ::new(.clone(), , );
.insert(, );
}
// Configure display period
if let Some() = .get_mut(&) {
..K线 = true;
.. = true;
..线 = true;
.. = true;
.();
}
// Align other periods to display period's 缠K序列
// (in practice, this is done during data loading)
for & in & {
if != {
// Other periods will reference display period's 缠论K线序列
// This is done during the K-line callback flow
}
}
let mut K线计数 = HashMap::new();
for & in & {
K线计数.insert(, 0);
}
Self {
,
,
,
K线合成器,
,
K线计数,
}
}
/// 投喂K线 — 统一入口,接收最小周期K线
/// 匹配 Python __K线回调:合成器完成K线时喂给观察者
pub fn K线(&mut self, K: K线) {
if K. != self. {
eprintln!(
@@ -93,36 +64,13 @@ impl 立体分析器 {
return;
}
// Record current K-line counts before feeding
let mut = HashMap::new();
for & in &self. {
.insert(, self.K线合成器.K线列表.get(&).map(|v| v.len()).unwrap_or(0));
}
// Feed to synthesizer, get completion events
let = self.K线合成器.K线(K);
// Feed to synthesizer
self.K线合成器.K线(K);
// Dispatch new K-lines to observers
for & in &self. {
let K线列表 = self.K线合成器.K线列表.get(&);
let = [&];
if let Some() = K线列表 {
for k线 in .iter().skip() {
// Clone the K-line for feeding to observer
let K线 = k线.clone();
if let Some() = self..get_mut(&) {
.K线(K线);
}
}
}
// Also feed the current in-progress K-line (if any)
if let Some(Some(K线)) = self.K线合成器.K线.get(&).cloned() {
if let Some() = self..get_mut(&) {
// Feed a clone of current in-progress K-line for real-time updates
// Note: this may cause duplicate data, matching Python behavior
.K线(K线);
}
// Dispatch on completion events (matching Python's __K线回调)
for (, K线) in {
if let Some() = self..get_mut(&) {
.K线(K线);
}
}
}
@@ -137,12 +85,49 @@ impl 立体分析器 {
self..get_mut(&)
}
/// 测试_保存数据
/// 测试_保存数据 — 多级别数据拆分保存
/// 创建父目录 PyM_{标识}_{起始时间}_{结束时间},各周期观察者保存到子目录
pub fn _保存数据(&self) {
let = std::env::current_dir().unwrap_or_default();
let = self
.
.get(&self.)
.and_then(|o| o.K线序列.first())
.map(|k| k.)
.unwrap_or(0);
let = self
.
.get(&self.)
.and_then(|o| o.K线序列.last())
.map(|k| k.)
.unwrap_or(0);
let = self
.
.get(&self.)
.map(|o| o..clone())
.unwrap_or_default();
let = self
.
.get(&self.)
.map(|o| o.)
.unwrap_or_default();
let = format!("RustM_{}:{}_{}_{}", , , , );
let = .join(&);
if let Err(e) = std::fs::create_dir_all(&) {
eprintln!("创建目录失败: {} -> {}", .display(), e);
return;
}
for in &self. {
if let Some() = self..get() {
._保存数据(None);
._保存数据(Some(.to_str().unwrap()));
}
}
println!("多级别数据拆分保存完成,目录:{}", .display());
}
}
+84 -96
View File
@@ -51,8 +51,7 @@ pub struct 观察者 {
impl {
pub fn new(: String, : i64, : ) -> Self {
let = if . != "1970-01-01 00:00:00"
&& !..is_empty()
let = if . != "1970-01-01 00:00:00" && !..is_empty()
{
datetime::(&.)
} else {
@@ -129,10 +128,10 @@ impl 观察者 {
}
/// 核心数据处理管道
fn __处理数据(&mut self, mut K: K线) {
fn __处理数据(&mut self, K: K线) {
// Step 1: 缠论K线分析 (普K is consumed by 分析 as &mut)
let (_, ) = K线::(
&mut K,
K,
&mut self.K线序列,
&mut self.K线序列,
&self.,
@@ -175,31 +174,25 @@ impl 观察者 {
&[::, ::],
);
}
// Clone to avoid borrow issues
let 线_克隆 = self.线.clone();
if self..线 {
::(&线_克隆, &mut self., true, "", 0);
::(&self.线, &mut self., true, "", 0);
}
// Step 5: 扩展线段(笔级)
let _克隆 = self..clone();
if self..线 {
线::(&_克隆, &mut self.线, &self.);
线::(&self., &mut self.线, &self.);
}
let 线_克隆 = self.线.clone();
if self..线 {
::(&线_克隆, &mut self., true, "", 0);
::(&self.线, &mut self., true, "", 0);
}
// Step 6: 扩展线段(线段级)
let 线_克隆2 = self.线.clone();
if self..线 {
线::(&线_克隆2, &mut self.线_线段, &self.);
线::(&self.线, &mut self.线_线段, &self.);
}
let 线_线段_克隆 = self.线_线段.clone();
if self..线 {
::(
&线_线段_克隆,
&self.线_线段,
&mut self._线段,
true,
"",
@@ -208,10 +201,9 @@ impl 观察者 {
}
// Step 7: 线段之线段
let 线_克隆3 = self.线.clone();
if self..线 {
线::(
&线_克隆3,
&self.线,
&mut self.线_线段序列,
&self.,
0,
@@ -224,30 +216,21 @@ impl 观察者 {
],
);
}
let 线_线段_克隆 = self.线_线段序列.clone();
if self..线 {
::(
&线_线段_克隆,
&mut self.线_中枢序列,
true,
"",
0,
);
::(&self.线_线段序列, &mut self.线_中枢序列, true, "", 0);
}
// Step 8: 扩展线段之扩展线段
let 线_克隆2 = self.线.clone();
if self..线 {
线::(
&线_克隆2,
&self.线,
&mut self.线_扩展线段,
&self.,
);
}
let 线_扩展线段_克隆 = self.线_扩展线段.clone();
if self..线 {
::(
&线_扩展线段_克隆,
&self.线_扩展线段,
&mut self._扩展线段,
true,
"",
@@ -272,21 +255,18 @@ impl 观察者 {
self.线_扩展线段.clear();
self._扩展线段.clear();
let K克隆 = self.K线序列.clone();
let K克隆 = self.K线序列.clone();
for i in 1..K克隆.len() - 1 {
for i in 1..self.K线序列.len() - 1 {
let = ::new(
Some(Rc::clone(&K克隆[i - 1])),
Rc::clone(&K克隆[i]),
Some(Rc::clone(&K克隆[i + 1])),
Some(Rc::clone(&self.K线序列[i - 1])),
Rc::clone(&self.K线序列[i]),
Some(Rc::clone(&self.K线序列[i + 1])),
);
::(
Rc::new(),
&mut self.,
&mut self.,
&K克隆,
&K克隆,
&self.K线序列,
&self.K线序列,
&self.,
);
}
@@ -295,38 +275,32 @@ impl 观察者 {
::(&self., &mut self._中枢序列, true, "", 0);
}
let = self..clone();
if self..线 {
线::(
&,
&self.,
&mut self.线,
&self.,
0,
&[::, ::],
);
}
let 线 = self.线.clone();
if self..线 {
::(&线, &mut self., true, "", 0);
::(&self.线, &mut self., true, "", 0);
}
let 2 = self..clone();
if self..线 {
线::(&2, &mut self.线, &self.);
线::(&self., &mut self.线, &self.);
}
let 线 = self.线.clone();
if self..线 {
::(&线, &mut self., true, "", 0);
::(&self.线, &mut self., true, "", 0);
}
let 线2 = self.线.clone();
if self..线 {
线::(&线2, &mut self.线_线段, &self.);
线::(&self.线, &mut self.线_线段, &self.);
}
let 线_线段_克隆 = self.线_线段.clone();
if self..线 {
::(
&线_线段_克隆,
&self.线_线段,
&mut self._线段,
true,
"",
@@ -334,10 +308,9 @@ impl 观察者 {
);
}
let 线3 = self.线.clone();
if self..线 {
线::(
&线3,
&self.线,
&mut self.线_线段序列,
&self.,
0,
@@ -350,36 +323,18 @@ impl 观察者 {
],
);
}
let 线_线段_克隆 = self.线_线段序列.clone();
if self..线 {
::(
&线_线段_克隆,
&mut self.线_中枢序列,
true,
"",
0,
);
::(&self.线_线段序列, &mut self.线_中枢序列, true, "", 0);
}
}
/// 测试_保存数据 — 输出各序列数据文本到文件
pub fn _保存数据(&self, root: Option<&str>) {
let _文本数据: Vec<String> = self
.
.iter()
.map(|b| b.())
.collect();
let 线_文本数据: Vec<String> = self
.线
.iter()
.map(|s| s.())
.collect();
let 线_数据文本: Vec<String> = self
.线
.iter()
.map(|s| s.())
.collect();
let _文本数据: Vec<String> = self..iter().map(|b| b.()).collect();
let 线_文本数据: Vec<String> =
self.线.iter().map(|s| s.()).collect();
let 线_数据文本: Vec<String> =
self.线.iter().map(|s| s.()).collect();
let 线_线段_数据文本: Vec<String> = self
.线_线段
.iter()
@@ -396,21 +351,12 @@ impl 观察者 {
.map(|s| s.())
.collect();
let _中枢序列_数据文本: Vec<String> = self
._中枢序列
.iter()
.map(|h| h.())
.collect();
let _数据文本: Vec<String> = self
.
.iter()
.map(|h| h.())
.collect();
let _数据文本: Vec<String> = self
.
.iter()
.map(|h| h.())
.collect();
let _中枢序列_数据文本: Vec<String> =
self._中枢序列.iter().map(|h| h.()).collect();
let _数据文本: Vec<String> =
self..iter().map(|h| h.()).collect();
let _数据文本: Vec<String> =
self..iter().map(|h| h.()).collect();
let _线段_数据文本: Vec<String> = self
._线段
.iter()
@@ -436,7 +382,7 @@ impl 观察者 {
// 生成子目录名称
let = self.K线序列.first().map(|k| k.).unwrap_or(0);
let = self.K线序列.last().map(|k| k.).unwrap_or(0);
let = format!("Rust_{}_{}_{}", self., , );
let = format!("Rust_{}:{}_{}_{}", self., self., , );
let = .join(&);
if let Err(e) = std::fs::create_dir_all(&) {
@@ -444,19 +390,57 @@ impl 观察者 {
return;
}
// 缠K data for debugging
let K序列_数据文本: Vec<String> = self
.K线序列
.iter()
.map(|ck| {
format!(
"缠K, {}, {}, {:?}, {}, {}, {}, {}, {}",
ck.,
ck.,
ck.,
ck.,
ck.,
ck.,
ck.,
ck.
)
})
.collect();
let _数据文本: Vec<String> = self
.
.iter()
.enumerate()
.map(|(i, fx)| {
format!(
"分型, {}, {}, {:?}, {}, {}, {}",
i, fx., fx., fx., fx.., fx..,
)
})
.collect();
let : Vec<(&str, &[String])> = vec![
("笔序列_文本数据", &_文本数据),
("线段序列_文本数据", &线_文本数据),
("扩展线段序列_数据文本", &线_数据文本),
("扩展线段序列_线段_数据文本", &线_线段_数据文本),
("线段_线段序列_数据文本", &线_线段序列_数据文本),
("扩展线段序列_扩展线段_数据文本", &线_扩展线段_数据文本),
(
"扩展线段序列_扩展线段_数据文本",
&线_扩展线段_数据文本,
),
("笔_中枢序列_数据文本", &_中枢序列_数据文本),
("中枢序列_数据文本", &_数据文本),
("扩展中枢序列_数据文本", &_数据文本),
("扩展中枢序列_线段_数据文本", &_线段_数据文本),
("线段_中枢序列_数据文本", &线_中枢序列_数据文本),
("扩展中枢序列_扩展线段_数据文本", &_扩展线段_数据文本),
(
"扩展中枢序列_扩展线段_数据文本",
&_扩展线段_数据文本,
),
("缠K序列_数据文本", &K序列_数据文本),
("分型序列_数据文本", &_数据文本),
];
for (, ) in & {
@@ -471,7 +455,9 @@ impl 观察者 {
}
/// 读取数据文件 — 从 .nb 文件加载数据
pub fn (: &str, : Option<>) -> Result<Self, String> {
pub fn (
: &str, : Option<>
) -> Result<Self, String> {
let = .unwrap_or_default();
// Parse filename: btcusd-300-1631772074-1632222374.nb
@@ -485,7 +471,9 @@ impl 观察者 {
return Err(format!("invalid filename format: {}", name));
}
let = parts[0].to_string();
let : i64 = parts[1].parse().map_err(|e| format!("parse period: {}", e))?;
let : i64 = parts[1]
.parse()
.map_err(|e| format!("parse period: {}", e))?;
let mut = Self::new(, , );
+35 -28
View File
@@ -30,31 +30,38 @@ impl K线合成器 {
}
/// 投喂K线 — 输入最小周期K线,合成为所有目标周期
pub fn K线(&mut self, K: K线) {
/// 返回本次投喂完成了哪些周期的K线(周期 → 完成K线)
pub fn K线(&mut self, K: K线) -> Vec<(i64, K线)> {
let mut = Vec::new();
let = self..clone();
for in {
self._处理单个周期(, &K);
if let Some(K线) = self._处理单个周期(, &K) {
.push((, K线));
}
}
}
fn _处理单个周期(&mut self, : i64, K: &K线) {
fn _处理单个周期(&mut self, : i64, K: &K线) -> Option<K线> {
let = self._对齐时间戳(K., );
let K线 = self.K线.get(&).unwrap().clone();
let = self.K线[&]
.as_ref()
.map(|k| k. == )
.unwrap_or(false);
if K线.is_none() {
// 创建新K线
if self.K线[&].is_none() {
let K线 = self._创建新K线(, , K);
*self.K线.get_mut(&).unwrap() = Some(K线);
} else if K线.as_ref().unwrap(). == {
// 更新当前K线
let mut k线 = K线.unwrap();
self._更新K线(&mut k线, K);
*self.K线.get_mut(&).unwrap() = Some(k线);
self.K线.insert(, Some(K线));
None
} else if {
let ent = self.K线.get_mut(&).unwrap();
Self::_更新K线(ent.as_mut().unwrap(), K);
None
} else {
// 完成当前K线,创建新K线
self._完成K线();
let K线 = self._完成K线();
let K线 = self._创建新K线(, , K);
*self.K线.get_mut(&).unwrap() = Some(K线);
self.K线.insert(, Some(K线));
K线
}
}
@@ -86,26 +93,26 @@ impl K线合成器 {
)
}
fn _更新K线(&self, K线: &mut K线, : &K线) {
fn _更新K线(K线: &mut K线, : &K线) {
K线. = K线..max(.);
K线. = K线..min(.);
K线. = .;
K线. += .;
}
fn _完成K线(&mut self, : i64) {
let K线 = self.K线.get(&).and_then(|k| k.clone());
if let Some(mut k线) = K线 {
k线. = self
.K线列表
.get(&)
.and_then(|list| list.last())
.map(|k| k. + 1)
.unwrap_or(0);
fn _完成K线(&mut self, : i64) -> Option<K线> {
let ent = self.K线.get_mut(&).unwrap();
let mut k线 = ent.take()?;
k线. = self
.K线列表
.get(&)
.and_then(|list| list.last())
.map(|k| k. + 1)
.unwrap_or(0);
self.K线列表.get_mut(&).unwrap().push(k线);
*self.K线.get_mut(&).unwrap() = None;
}
let K线 = k线.clone();
self.K线列表.get_mut(&).unwrap().push(k线);
Some(K线)
}
/// 获取指定周期当前正在合成的K线
+12 -8
View File
@@ -244,26 +244,30 @@ impl 缠论配置 {
}
/// 按序号重组字典 — 兼容旧版配置的复合key格式
pub fn (: &Self, : &serde_json::Value) -> Vec<(i64, Self)> {
pub fn (
: &Self,
: &serde_json::Value,
) -> Vec<(i64, Self)> {
let mut result = Vec::new();
if let serde_json::Value::Object(map) = {
// 按数字前缀分组: "1_open" → group 1 key "open"
let mut groups: std::collections::BTreeMap<i64, serde_json::Map<String, serde_json::Value>> =
std::collections::BTreeMap::new();
let mut groups: std::collections::BTreeMap<
i64,
serde_json::Map<String, serde_json::Value>,
> = std::collections::BTreeMap::new();
for (key, value) in map {
if let Some(pos) = key.find('_') {
if let Ok(num) = key[..pos].parse::<i64>() {
let field = key[pos + 1..].to_string();
groups
.entry(num)
.or_default()
.insert(field, value.clone());
groups.entry(num).or_default().insert(field, value.clone());
}
}
}
for (num, fields) in groups {
let mut config = .clone();
if let Ok(partial) = serde_json::from_value::<>(serde_json::Value::Object(fields)) {
if let Ok(partial) =
serde_json::from_value::<>(serde_json::Value::Object(fields))
{
// merge partial into config (override matching fields)
config = partial;
}
+7 -1
View File
@@ -87,7 +87,13 @@ impl 随机指标 {
}
/// 基于前一个 KDJ 增量计算当前 KDJ
pub fn (KDJ: &Self, : f64, : f64, : f64, : i64) -> Self {
pub fn (
KDJ: &Self,
: f64,
: f64,
: f64,
: i64,
) -> Self {
let N = KDJ.N;
let M1 = KDJ.M1;
let M2 = KDJ.M2;
+7 -1
View File
@@ -45,7 +45,13 @@ fn 平滑系数(周期: i64) -> f64 {
impl 线 {
/// 首次计算 MACD 指标(无历史数据时使用)
pub fn (: f64, : i64, 线: i64, 线: i64, : i64) -> Self {
pub fn (
: f64,
: i64,
线: i64,
线: i64,
: i64,
) -> Self {
let 线EMA = ;
let 线EMA = ;
let DIF = 线EMA - 线EMA;
+2 -2
View File
@@ -1,9 +1,9 @@
pub mod macd;
pub mod kdj;
pub mod macd;
pub mod rsi;
pub use macd::线;
pub use kdj::;
pub use macd::线;
pub use rsi::;
/// K线取值 —— 根据计算方式从K线提取对应的价格
+12 -4
View File
@@ -1,4 +1,4 @@
use crate::indicators::{线, , };
use crate::indicators::{线, , };
use crate::types::;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize};
@@ -140,8 +140,14 @@ impl K线 {
/// 获取两K线之间的 MACD 柱面积
pub fn MACD(K线序列: &[&Self], : &Self, : &Self) -> HashMap<String, f64> {
let _idx = K线序列.iter().position(|k| std::ptr::eq(*k, )).unwrap_or(0);
let _idx = K线序列.iter().position(|k| std::ptr::eq(*k, )).unwrap_or(0);
let _idx = K线序列
.iter()
.position(|k| std::ptr::eq(*k, ))
.expect("获取MACD: 始K线不在序列中");
let _idx = K线序列
.iter()
.position(|k| std::ptr::eq(*k, ))
.expect("获取MACD: 终K线不在序列中");
let = &K线序列[_idx..=_idx];
let mut = 0.0f64;
@@ -219,7 +225,9 @@ mod tests {
#[test]
fn test_serialization_roundtrip() {
let k = K线::K("test", 1600000000, 100.5, 110.2, 95.3, 105.7, 5000.0, 42, 60);
let k = K线::K(
"test", 1600000000, 100.5, 110.2, 95.3, 105.7, 5000.0, 42, 60,
);
let bytes = k.to_bytes();
let restored = K线::from_bytes(&bytes, 60, "test").unwrap();
+121 -84
View File
@@ -1,5 +1,7 @@
use crate::config::;
use crate::indicators::{K线取值, 线, , };
use crate::indicators::{
线, , , K线取值
};
use crate::kline::bar::K线;
use crate::structure::fractal_obj::;
use crate::types::;
@@ -142,12 +144,14 @@ impl 缠论K线 {
if let Some() = 线.first() {
for k in 线.iter().rev() {
if . < k线. {
if k线. <= k. && k. <= k线. + k线. {
if k线. <= k. && k. <= k线. + k线.
{
if (k线. - k.).abs() < f64::EPSILON {
return k.;
}
}
} else if k. <= k线. && k线. <= k. + k. {
} else if k. <= k线. && k线. <= k. + k.
{
if (k线. - k.).abs() < f64::EPSILON {
return k.;
}
@@ -207,7 +211,7 @@ impl 缠论K线 {
/// 返回 (新缠K, 模式) — 模式: "添加"/"替换"/None
pub fn (
K: Option<&K线>,
K: &K线,
K: &mut K线,
K: &K线,
: &,
) -> (Option<Rc<K线>>, Option<String>) {
@@ -234,40 +238,50 @@ impl 缠论K线 {
return (Some(Rc::new(K)), Some("添加".into()));
}
// 包含关系 — 合并到当前缠K
// 取值方向:向下 → 取低低、高高(即全部取最低);向上 → 取高高、低低(即全部取最高)
// 方向由之前缠K与当前缠K的关系决定
// 重复提交检测 — 当序号相同时认为是重复提交K线
if K. == K. {
return (None, None);
}
// 序号连续性检查
if K. - 1 != K. && K. != K.
{
panic!(
"兼并: 不可追加不连续元素 缠K.原始结束序号: {}, 当前普K.序号: {}",
K., K.
);
}
// 包含关系 — 原地合并到当前缠K
let : fn(f64, f64) -> f64 = if let Some() = K {
if ::(., ., K., K.).() {
if ::(., ., K., K.).()
{
f64::min
} else {
f64::max
}
} else {
f64::max // 默认向上取max
f64::max
};
let mut = K.();
// 逆序包含时更新时间和标的K线
if != :: {
. = K.;
.K线 = Rc::new(K.clone());
K. = K.;
K.K线 = Rc::new(K.clone());
}
. = (., K.);
. = (., K.);
. = K.;
. = K.();
K. = (K., K.);
K. = (K., K.);
K. = K.;
K. = K.();
if let Some() = K {
. = . + 1;
K. = . + 1;
}
if .K合并替换 {
(Some(Rc::new()), Some("替换".into()))
(Some(Rc::new(K.())), Some("替换".into()))
} else {
// 兼并:返回新值让调用方决定是原地修改还是替换
(Some(Rc::new()), Some("兼并".into()))
(None, None)
}
}
@@ -275,7 +289,7 @@ impl 缠论K线 {
///
/// 返回 (状态, 形态)
pub fn (
K线: &mut K线,
mut K线: K线,
K序列: &mut Vec<Rc<K线>>,
K序列: &mut Vec<Rc<K线>>,
: &,
@@ -286,14 +300,26 @@ impl 缠论K线 {
if K序列.is_empty() {
if . {
K线.macd = Some(线::(
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
.线_快线周期,
.线_慢线周期,
.线_信号周期,
));
K线.rsi = Some(::(
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
._周期,
._超买阈值,
@@ -312,7 +338,7 @@ impl 缠论K线 {
._超卖阈值,
));
}
let K线_rc = Rc::new(K线.clone());
let K线_rc = Rc::new(K线);
K序列.push(K线_rc);
} else {
let K = K序列.last().unwrap();
@@ -324,14 +350,26 @@ impl 缠论K线 {
if let Some(ref prev_macd) = K序列[K序列.len() - 2].macd {
K线.macd = Some(线::(
prev_macd,
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
));
}
if let Some(ref prev_rsi) = K序列[K序列.len() - 2].rsi {
K线.rsi = Some(::(
prev_rsi,
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
));
}
@@ -347,7 +385,7 @@ impl 缠论K线 {
}
}
K序列.pop();
K序列.push(Rc::new(K线.clone()));
K序列.push(Rc::new(K线));
} else {
if K. > K线. {
panic!("时序错误: 之前={}, 当前={}", K., K线.);
@@ -357,14 +395,26 @@ impl 缠论K线 {
if let Some(ref prev_macd) = K.macd {
K线.macd = Some(线::(
prev_macd,
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
));
}
if let Some(ref prev_rsi) = K.rsi {
K线.rsi = Some(::(
prev_rsi,
K线取值(K线., K线., K线., K线., &.),
K线取值(
K线.,
K线.,
K线.,
K线.,
&.,
),
K线.,
));
}
@@ -378,67 +428,48 @@ impl 缠论K线 {
));
}
}
K序列.push(Rc::new(K线.clone()));
K序列.push(Rc::new(K线));
}
}
// ---- 阶段2: 缠K合并 ----
let K: Option<&K线> = if K序列.len() >= 2 {
Some(&K序列[K序列.len() - 2])
} else {
None
};
let : String;
let K线_ref: &K线 = &*K序列.last().unwrap();
if !K序列.is_empty() {
let K = &K序列[K序列.len() - 1];
// 需要从 Rc 中取出引用
let K_ref = Rc::as_ref(K);
let (K, ) = Self::(K, K_ref, K线, );
let len = K序列.len();
let (, ) = K序列.split_at_mut(len - 1);
let K: Option<&K线> = .last().map(|rc| Rc::as_ref(rc));
let K_mut = Rc::make_mut(&mut [0]);
let (K, ) = Self::(K, K_mut, K线_ref, );
if let Some(k) = K {
if let Some(ref m) = {
if m == "添加" {
match .as_deref() {
Some("添加") => {
K序列.push(k);
= "创建".into();
} else if m == "替换" {
}
Some("替换") => {
K序列.pop();
K序列.push(k);
= "替换".into();
} else {
// 兼并:尝试原地修改以保持Rc指针不变
let _idx = K序列.len() - 1;
if let Some() = Rc::get_mut(&mut K序列[_idx]) {
. = k.;
. = k.;
. = k.;
. = k.;
. = k.;
.K线 = k.K线.clone();
. = k.;
= "兼并".into();
} else {
// 有其他引用时回退到替换
K序列.pop();
K序列.push(k);
= "兼并".into();
}
}
} else {
= "兼并".into();
_ => {
= "兼并".into();
}
}
} else {
= "兼并".into();
}
} else {
let K = Self::K(
K线.,
K线.,
K线.,
K线.(),
K线_ref.,
K线_ref.,
K线_ref.,
K线_ref.(),
None,
K线.,
Rc::new(K线.clone()),
K线_ref.,
Rc::clone(K序列.last().unwrap()),
None,
);
K序列.push(Rc::new(K));
@@ -511,10 +542,10 @@ impl 缠论K线 {
}
let = if matches!(, :: | ::) {
// 三连方向不算完整分型 — 只有中+右
// Python: 形态 = 分型(中, 右, None) — 左=中K线, 中=右K线, 右=None
Rc::new(::new(
None,
Rc::clone(&K序列[idx - 2]),
Some(Rc::clone(&K序列[idx - 2])),
Rc::clone(&K序列[idx - 1]),
None,
))
} else {
@@ -532,9 +563,15 @@ impl 缠论K线 {
}
/// 截取缠K序列从始到终
pub fn (: &[Rc<K线>], : &K线, : &K线) -> Option<Vec<Rc<K线>>> {
let _idx = .iter().position(|k| Rc::as_ptr(k) == ( as *const _))?;
let _idx = .iter().position(|k| Rc::as_ptr(k) == ( as *const _))?;
pub fn (
: &[Rc<K线>], : &K线, : &K线
) -> Option<Vec<Rc<K线>>> {
let _idx =
.iter()
.position(|k| Rc::as_ptr(k) == ( as *const _))?;
let _idx =
.iter()
.position(|k| Rc::as_ptr(k) == ( as *const _))?;
Some([_idx..=_idx].to_vec())
}
}
@@ -569,11 +606,11 @@ mod tests {
#[test]
fn test_分析_empty_sequence() {
let config = ::default();
let mut pk = make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0);
let pk = make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0);
let mut K序列 = Vec::new();
let mut K序列 = Vec::new();
let (, ) = K线::(&mut pk, &mut K序列, &mut K序列, &config);
let (, ) = K线::(pk, &mut K序列, &mut K序列, &config);
assert_eq!(, "新建");
assert_eq!(K序列.len(), 1);
assert!(.is_none()); // 不够3根
@@ -586,16 +623,16 @@ mod tests {
let mut K序列 = Vec::new();
// 三根形成顶分型: 低高 → 更高高 → 低高
let mut pk1 = make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0);
let 1 = K线::(&mut pk1, &mut K序列, &mut K序列, &config);
let pk1 = make_普K(1000, 100.0, 110.0, 95.0, 105.0, 0);
let 1 = K线::(pk1, &mut K序列, &mut K序列, &config);
assert_eq!(1.0, "新建");
let mut pk2 = make_普K(1001, 105.0, 115.0, 102.0, 112.0, 1);
let 2 = K线::(&mut pk2, &mut K序列, &mut K序列, &config);
let pk2 = make_普K(1001, 105.0, 115.0, 102.0, 112.0, 1);
let 2 = K线::(pk2, &mut K序列, &mut K序列, &config);
assert!(2.1.is_none()); // 仍不够
let mut pk3 = make_普K(1002, 112.0, 113.0, 100.0, 103.0, 2);
let (_状态3, ) = K线::(&mut pk3, &mut K序列, &mut K序列, &config);
let pk3 = make_普K(1002, 112.0, 113.0, 100.0, 103.0, 2);
let (_状态3, ) = K线::(pk3, &mut K序列, &mut K序列, &config);
assert!(.is_some()); // 分型产生了
}
}
+126 -6
View File
@@ -1,29 +1,82 @@
use chanlun::business::multi_frame::;
use chanlun::business::observer::;
use chanlun::config::;
use chanlun::kline::bar::K线;
use std::env;
use std::time::Instant;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("用法: {} <.nb文件路径>", args[0]);
eprintln!("用法:");
eprintln!(
" {} read <.nb文件路径> 测试_读取数据(单周期分析)",
args[0]
);
eprintln!(
" {} synth <.nb文件路径> 测试_周期合成(多周期合成)",
args[0]
);
std::process::exit(1);
}
let = &args[1];
println!("读取文件: {}", );
let = &args[1];
match ::(, None) {
match .as_str() {
"read" | "r" => {
if args.len() < 3 {
eprintln!("用法: {} read <.nb文件路径>", args[0]);
std::process::exit(1);
}
_读取数据(&args[2]);
}
"synth" | "s" => {
if args.len() < 3 {
eprintln!("用法: {} synth <.nb文件路径>", args[0]);
std::process::exit(1);
}
_周期合成(&args[2]);
}
// Backward compatibility: if first arg is a file path, treat as "read"
other if other.ends_with(".nb") => {
_读取数据(other);
}
_ => {
eprintln!("未知命令: {},请使用 read 或 synth", );
std::process::exit(1);
}
}
}
/// 测试_读取数据 — 单周期分析
fn _读取数据(: &str) {
let = Instant::now();
let = ::default().();
match ::(, Some()) {
Ok() => {
let = .elapsed();
println!(
"测试_读取数据 耗时 {:.2?} 普K数量 {}",
,
.K线序列.len()
);
println!("符号: {}", .);
println!("周期: {}", .);
println!("普K数量: {}", .K线序列.len());
println!("缠K数量: {}", .K线序列.len());
println!("分型数量: {}", ..len());
println!("笔数量: {}", ..len());
println!("笔中枢数量: {}", ._中枢序列.len());
println!("线段数量: {}", .线.len());
println!("中枢数量: {}", ..len());
println!("扩展线段数量: {}", .线.len());
println!("线段_线段序列数量: {}", .线_线段序列.len());
println!(
"扩展线段_扩展线段数量: {}",
.线_扩展线段.len()
);
println!("\n===== 数据分析 =====\n");
println!("\n===== 保存分析数据 =====\n");
._保存数据(None);
}
Err(e) => {
@@ -32,3 +85,70 @@ fn main() {
}
}
}
/// 测试_周期合成 — 多周期合成分析
fn _周期合成(: &str) {
let = Instant::now();
// Parse filename to extract metadata
let path = std::path::Path::new();
let name = path
.file_stem()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
let parts: Vec<&str> = name.split('-').collect();
if parts.len() < 4 {
eprintln!(
"invalid filename format: {}, expected 符号-周期-起始-结束",
name
);
std::process::exit(1);
}
let = parts[0].to_string();
let : i64 = parts[1].parse().unwrap_or(300);
let = vec![, * 5, * 5 * 6];
let = ::default().();
let mut = ::new(.clone(), , Some(), None);
// Read binary file and feed K-lines
let data = match std::fs::read() {
Ok(d) => d,
Err(e) => {
eprintln!("读取文件失败: {}", e);
std::process::exit(1);
}
};
let size: usize = 48; // 6 × f64 big-endian
let k线数量 = data.len() / size;
for i in 0..k线数量 {
let offset = i * size;
if let Some(k线) = K线::from_bytes(&data[offset..offset + size], , &) {
.K线(k线);
}
}
let = .elapsed();
println!("测试_周期合成 耗时 {:.2?} 普K数量 {}", , k线数量);
println!("符号: {}", );
println!("周期组: {:?}", vec![, * 5, * 5 * 6]);
// Display stats per period
for &p in &[, * 5, * 5 * 6] {
if let Some() = .(p) {
println!(
"周期<{}>: 缠K={}, 分型={}, 笔={}, 线段={}, 中枢={}",
p,
.K线序列.len(),
..len(),
..len(),
.线.len(),
..len(),
);
}
}
println!("\n===== 保存分析数据 =====\n");
._保存数据();
}
+144 -59
View File
@@ -1,7 +1,7 @@
use crate::algorithm::hub::;
use crate::config::;
use crate::kline::chan_kline::K线;
use crate::kline::bar::K线;
use crate::kline::chan_kline::K线;
use crate::structure::fractal_obj::;
use crate::structure::segment_feat::线;
use crate::types::{, , };
@@ -32,7 +32,14 @@ pub struct 虚线 {
}
impl 线 {
pub fn new(: i64, : String, : Rc<>, : Rc<>, : i64, : bool) -> Self {
pub fn new(
: i64,
: String,
: Rc<>,
: Rc<>,
: i64,
: bool,
) -> Self {
Self {
,
,
@@ -60,7 +67,10 @@ impl 虚线 {
}
pub fn (&self) -> String {
format!("{}:{}:{}:{}", self..., self..., self., self.)
format!(
"{}:{}:{}:{}",
self..., self..., self., self.
)
}
/// 方向 — 文到武的方向
@@ -74,24 +84,38 @@ impl 虚线 {
}
}
/// 虚线高 — 文和武中高的那个
/// 虚线高
pub fn (&self) -> f64 {
self...max(self..)
if self.() == :: {
self...
} else {
self...
}
}
/// 虚线低 — 文和武中低的那个
/// 虚线低
pub fn (&self) -> f64 {
self...min(self..)
if self.() == :: {
self...
} else {
self...
}
}
/// 判断两个虚线是否首尾相连
pub fn (&self, : &线) -> bool {
self... == ...
if self. != . {
return false;
}
Rc::as_ptr(&.) == Rc::as_ptr(&self.)
}
/// 判断两个虚线是否首尾相连
pub fn (&self, : &线) -> bool {
self... == ...
if self. != . {
return false;
}
Rc::as_ptr(&self.) == Rc::as_ptr(&.)
}
/// 获取该虚线范围内的普K序列
@@ -128,10 +152,15 @@ impl 虚线 {
}
// 非笔:线段/扩展线段等,完整输出
let (, , , 穿) =
crate::algorithm::segment::线::(self, None);
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 _bool = |b: bool| -> &str {
if b {
"True"
} else {
"False"
}
};
let _str = match &self. {
Some(g) => format!("{}", g),
@@ -143,13 +172,52 @@ impl 虚线 {
};
// 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!(
"[{}]",
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(", "));
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!(
"{}, {}, {}, 文:({},{}), 武:({},{}), {}, {}, ({}, {}, {}), (前: {}, 后: {}, 三: {}, 伤: {}), 实: {}, 虚: {}, 合: {}, {}, {}, {}, {}",
@@ -217,7 +285,11 @@ impl 虚线 {
/// 买卖点配置匹配 — 根据配置中的指标开关组合判断
pub fn (K: &K线, : &) -> bool {
match (._指标匹配_MACD, ._指标匹配_KDJ, ._指标匹配_RSI) {
match (
._指标匹配_MACD,
._指标匹配_KDJ,
._指标匹配_RSI,
) {
(true, true, true) => K.MACD柱子匹配() && K.KDJ匹配() && K.RSI匹配(),
(false, false, false) => false,
(true, false, true) => K.MACD柱子匹配() && K.RSI匹配(),
@@ -241,11 +313,7 @@ impl 虚线 {
/// 买卖点相对匹配 — 至少两个指标匹配
pub fn (K: &K线) -> bool {
let = [
K.MACD柱子匹配(),
K.KDJ匹配(),
K.RSI匹配(),
];
let = [K.MACD柱子匹配(), K.KDJ匹配(), K.RSI匹配()];
.iter().filter(|&&x| x).count() >= 2
}
@@ -368,7 +436,9 @@ impl 虚线 {
// ---- MACD趋向背驰 ----
/// 计算K线序列MACD趋向背驰 — 分析 MACD柱/DIF/DEA 三项背驰信号
pub fn K线序列MACD趋向背驰(K序列: &[Rc<K线>], : ) -> [bool; 3] {
pub fn K线序列MACD趋向背驰(
K序列: &[Rc<K线>], :
) -> [bool; 3] {
if K序列.is_empty() {
return [false, false, false];
}
@@ -389,7 +459,10 @@ impl 虚线 {
let =
.iter()
.max_by(|a, b| {
a.macd.as_ref().unwrap().MACD柱
a.macd
.as_ref()
.unwrap()
.MACD柱
.partial_cmp(&b.macd.as_ref().unwrap().MACD柱)
.unwrap()
})
@@ -402,7 +475,7 @@ impl 虚线 {
}
}
// DIF背驰
// DIF背驰 (no sort — Python compares peak vs last directly)
let =
.iter()
.max_by(|a, b| {
@@ -411,17 +484,15 @@ impl 虚线 {
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()) {
if let (Some(m0), Some(m1)) = (.macd.as_ref(), .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]. {
if dif0 > dif1 && . < . {
[1] = true;
}
}
// DEA背驰
// DEA背驰 (no sort — Python compares peak vs last directly)
let 线 =
.iter()
.max_by(|a, b| {
@@ -430,12 +501,10 @@ impl 虚线 {
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()) {
if let (Some(m0), Some(m1)) = (线.macd.as_ref(), .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]. {
if dea0 > dea1 && 线. < . {
[2] = true;
}
}
@@ -456,7 +525,11 @@ impl 虚线 {
let =
.iter()
.max_by(|a, b| {
a.macd.as_ref().unwrap().MACD柱.abs()
a.macd
.as_ref()
.unwrap()
.MACD柱
.abs()
.partial_cmp(&b.macd.as_ref().unwrap().MACD柱.abs())
.unwrap()
})
@@ -469,7 +542,7 @@ impl 虚线 {
}
}
// DIF背驰
// DIF背驰 (no sort — Python compares peak vs last directly)
let =
.iter()
.max_by(|a, b| {
@@ -478,17 +551,15 @@ impl 虚线 {
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()) {
if let (Some(m0), Some(m1)) = (.macd.as_ref(), .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]. {
if dif0 < dif1 && . > . {
[1] = true;
}
}
// DEA背驰
// DEA背驰 (no sort — Python compares peak vs last directly)
let 线 =
.iter()
.max_by(|a, b| {
@@ -497,12 +568,10 @@ impl 虚线 {
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()) {
if let (Some(m0), Some(m1)) = (线.macd.as_ref(), .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]. {
if dea0 < dea1 && 线. > . {
[2] = true;
}
}
@@ -520,7 +589,11 @@ impl 虚线 {
}
let = |x: f64| -> &str {
if x > 0.0 { "" } else { "" }
if x > 0.0 {
""
} else {
""
}
};
let _MACD = match &k线序列[0].macd {
@@ -592,7 +665,11 @@ impl 虚线 {
// ---- 统计MACD行为 ----
/// 统计MACD行为 — 分析DIF/DEA穿零轴和金叉死叉
pub fn MACD行为(K序列: &[Rc<K线>], : usize, : usize) -> std::collections::HashMap<String, String> {
pub fn MACD行为(
K序列: &[Rc<K线>],
: usize,
: usize,
) -> std::collections::HashMap<String, String> {
use std::collections::HashMap;
let mut dif_up = 0;
@@ -610,12 +687,20 @@ impl 虚线 {
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 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; }
if pd < 0.0 && cd >= 0.0 {
dea_up += 1;
}
if pd > 0.0 && cd <= 0.0 {
dea_down += 1;
}
}
}
@@ -668,11 +753,14 @@ impl 虚线 {
/// 买卖意义 — 核心买卖点判断逻辑
///
/// 返回 (是否有意义, 原因字符串)
pub fn (线: &线, : &crate::business::observer::) -> (bool, String) {
pub fn (
线: &线, : &crate::business::observer::
) -> (bool, String) {
let K序列 = &.K线序列;
let = &.;
if 线. != "" && 线. != "线段" && !线..starts_with("线段<") {
if 线. != "" && 线. != "线段" && !线..starts_with("线段<")
{
return (false, "标识不在范围内".into());
}
@@ -718,10 +806,7 @@ impl 虚线 {
if ! && && 线...MACD柱子匹配() {
if Self::MACD极值(K序列, 线) && .len() > 2 {
return (
true,
"没结果, 极值, 柱子分型匹配, 背驰过大于2次".into(),
);
return (true, "没结果, 极值, 柱子分型匹配, 背驰过大于2次".into());
}
}
+6 -2
View File
@@ -12,8 +12,12 @@ pub struct 特征分型 {
}
impl {
pub fn new(: Rc<线>, : Rc<线>, : Rc<线>, : ) -> Self {
Self { , , , }
pub fn new(
: Rc<线>, : Rc<线>, : Rc<线>, :
) -> Self {
Self {
, , ,
}
}
}
+82 -69
View File
@@ -15,7 +15,9 @@ pub struct 分型 {
}
impl {
pub fn new(: Option<Rc<K线>>, : Rc<K线>, : Option<Rc<K线>>) -> Self {
pub fn new(
: Option<Rc<K线>>, : Rc<K线>, : Option<Rc<K线>>
) -> Self {
let = ..unwrap_or(::);
let = .;
let = .;
@@ -40,59 +42,93 @@ impl 分型 {
))
}
/// 分型强度
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,
/// 分型强度 — 返回 "强"/"中"/"弱"/"未知"
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(ref ), Some(ref )) = (&self., &self.) {
if self. == :: {
if .K线. > .K线. {
return "";
} else if .K线. > self..K线. {
return "";
} else {
return "";
}
} else if self. == :: {
if .K线. < .K线. {
return "";
} else if .K线. < self..K线. {
return "";
} else {
return "";
}
}
}
"未知"
}
/// MACD柱子分型匹配
/// MACD柱子分型匹配 — 检查左中右MACD柱形成顶/底形态
pub fn MACD柱子分型匹配(&self) -> bool {
match self. {
:: | :: => {
if let Some(ref ) = self. {
.MACD柱子匹配()
} else {
false
if let (Some(ref ), Some(ref )) = (&self., &self.) {
if self. == :: {
if let (Some(ref macd), Some(ref macd), Some(ref macd)) =
(&.K线.macd, &self..K线.macd, &.K线.macd)
{
return macd.MACD柱 > macd.MACD柱 && macd.MACD柱 < macd.MACD柱;
}
}
:: | :: => {
if let Some(ref ) = self. {
.MACD柱子匹配()
} else {
false
if self. == :: {
if let (Some(ref macd), Some(ref macd), Some(ref macd)) =
(&.K线.macd, &self..K线.macd, &.K线.macd)
{
return macd.MACD柱 < macd.MACD柱 && macd.MACD柱 > macd.MACD柱;
}
}
:: => false,
}
false
}
/// 判断两个分型是否匹配
pub fn (: &, : &, : &str) -> bool {
pub fn (: &Rc<>, : &Rc<>, : &str) -> bool {
match {
"" => .. == ..,
"" => Rc::as_ptr() == Rc::as_ptr(),
_ => 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())?;
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 {
@@ -108,41 +144,18 @@ impl 分型 {
/// 向分型序列中添加新分型
pub fn (: &mut Vec<Rc<>>, : Rc<>) {
if let Some() = .last() {
if . == . {
// 同一时间戳: 比较强度,保留更强的
match . {
:: | :: => {
if . >= . {
.pop();
.push();
}
return;
}
:: | :: => {
if . <= . {
.pop();
.push();
}
return;
}
:: => {}
}
if .is_empty() {
if . != :: && . != ::
{
panic!("首次添加分型不为 顶底 {:?}", );
}
// 相同结构只保留更强的
} else {
let = &[.len() - 1];
if . == . {
if (. == :: || . == ::)
&& . >= .
{
.pop();
.push();
} else if (. == :: || . == ::)
&& . <= .
{
.pop();
.push();
}
return;
panic!("分型相同无法添加 {:?} {:?}", , );
}
if ..is_none() {
eprintln!("分型.向序列中添加, 分型异常 {:?}", );
}
}
.push();
+29 -20
View File
@@ -28,9 +28,9 @@ impl 线段特征 {
}
/// 文 — 取特征序列元素中分型特征值最大/最小的文分型
/// tiebreaker: later时间戳 wins when特征值 equal (matches Python)
pub fn (&self) -> Rc<> {
if self.线.() {
// 向上 → 取最大的文
self.
.iter()
.max_by(|a, b| {
@@ -38,11 +38,11 @@ impl 线段特征 {
.
.partial_cmp(&b..)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a...cmp(&b..))
})
.map(|x| Rc::clone(&x.))
.unwrap_or_else(|| Rc::clone(&self.[0].))
} else {
// 向下 → 取最小的文
self.
.iter()
.min_by(|a, b| {
@@ -50,6 +50,7 @@ impl 线段特征 {
.
.partial_cmp(&b..)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| b...cmp(&a..))
})
.map(|x| Rc::clone(&x.))
.unwrap_or_else(|| Rc::clone(&self.[0].))
@@ -57,6 +58,7 @@ impl 线段特征 {
}
/// 武 — 取特征序列元素中分型特征值最大/最小的武分型
/// tiebreaker: later时间戳 wins when特征值 equal (matches Python)
pub fn (&self) -> Rc<> {
if self.线.() {
self.
@@ -66,6 +68,7 @@ impl 线段特征 {
.
.partial_cmp(&b..)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a...cmp(&b..))
})
.map(|x| Rc::clone(&x.))
.unwrap_or_else(|| Rc::clone(&self.[0].))
@@ -77,6 +80,7 @@ impl 线段特征 {
.
.partial_cmp(&b..)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| b...cmp(&a..))
})
.map(|x| Rc::clone(&x.))
.unwrap_or_else(|| Rc::clone(&self.[0].))
@@ -109,6 +113,23 @@ impl 线段特征 {
Ok(())
}
/// 从特征序列元素中删除虚线
pub fn (&mut self, 线: &Rc<线>) -> Result<(), String> {
if 线.() == self.() {
return Err("删除方向与特征序列方向相同".into());
}
if let Some(pos) = self
.
.iter()
.position(|x| Rc::as_ptr(x) == Rc::as_ptr(线))
{
self..remove(pos);
Ok(())
} else {
Err("待删除虚线不在特征序列中".into())
}
}
/// 新建特征序列元素
pub fn (线: Vec<Rc<线>>, 线: ) -> Self {
let = format!("特征<虚线>");
@@ -147,18 +168,8 @@ impl 线段特征 {
&& 线.() < .());
if {
let 线 = if .[0]. < .[0]. {
&.[0]
} else {
&.[0]
};
let 线 = if ..last().unwrap().
> ..last().unwrap().
{
&.[..len() - 1]
} else {
&.[..len() - 1]
};
let 线 = ..iter().min_by_key(|o| o.).unwrap();
let 线 = ..iter().max_by_key(|o| o.).unwrap();
let fake = 线::(
Rc::clone(&线.),
Rc::clone(&线.),
@@ -166,8 +177,7 @@ impl 线段特征 {
);
.pop();
let idx = .len() - 1;
[idx] =
Rc::new(Self::(vec![Rc::new(fake)], 线));
[idx] = Rc::new(Self::(vec![Rc::new(fake)], 线));
}
}
}
@@ -212,15 +222,14 @@ impl 线段特征 {
let = Rc::clone(&[i - 1]);
let = Rc::clone(&[i]);
if let Some() = ::_对象(
let = ::_对象(
&* as &dyn crate::types::fractal::,
&* as &dyn crate::types::fractal::,
&* as &dyn crate::types::fractal::,
true,
true,
) {
.push(::new(, , , ));
}
);
.push(::new(, , , .unwrap_or(::)));
}
}
+7 -4
View File
@@ -60,11 +60,11 @@ impl 相对方向 {
/// 分析两个K线之间的相对方向
pub fn (: f64, : f64, : f64, : f64) -> Self {
if ( - ).abs() < f64::EPSILON && ( - ).abs() < f64::EPSILON {
if == && == {
return Self::;
}
if > && > {
if ( - ).abs() < f64::EPSILON {
if == {
return Self::;
}
if > {
@@ -73,7 +73,7 @@ impl 相对方向 {
return Self::;
}
if < && < {
if ( - ).abs() < f64::EPSILON {
if == {
return Self::;
}
if < {
@@ -87,7 +87,10 @@ impl 相对方向 {
if <= && >= {
return Self::;
}
panic!("无法识别的方向: 前({},{}), 后({},{})", , , , );
panic!(
"无法识别的方向: 前({},{}), 后({},{})",
, , ,
);
}
}
+26 -5
View File
@@ -36,7 +36,16 @@ impl 分型结构 {
: bool,
: bool,
) -> Option<Self> {
Self::_内部(.(), .(), .(), .(), .(), .(), , )
Self::_内部(
.(),
.(),
.(),
.(),
.(),
.(),
,
,
)
}
/// 分析三元素构成的分型结构(trait object 版本)
@@ -47,13 +56,25 @@ impl 分型结构 {
: bool,
: bool,
) -> Option<Self> {
Self::_内部(.(), .(), .(), .(), .(), .(), , )
Self::_内部(
.(),
.(),
.(),
.(),
.(),
.(),
,
,
)
}
fn _内部(
: f64, : f64,
: f64, : f64,
: f64, : f64,
: f64,
: f64,
: f64,
: f64,
: f64,
: f64,
: bool,
: bool,
) -> Option<Self> {
+5 -1
View File
@@ -4,7 +4,11 @@ pub fn format_f64_g(value: f64) -> String {
return "nan".to_string();
}
if value.is_infinite() {
return if value > 0.0 { "inf".to_string() } else { "-inf".to_string() };
return if value > 0.0 {
"inf".to_string()
} else {
"-inf".to_string()
};
}
// Use high precision then trim trailing zeros