Files
Chan/chanlun/pipeline/builders/bi.py
T
jackyu66gitandCursor 7f393b93ed refactor: 精简仓库为 chanlun 核心与 web 分析,移除威科夫与遗留模块
删除根目录旧 Chan 模块、策略、配置、文档及 wyckoff 相关代码;更新缠论 pipeline 与笔中枢计算;补充 research 研究与 web 测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 01:05:12 +08:00

683 lines
29 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""TF_DF builder mixin — 由 split_tfdf_builders 自动生成,逻辑与原 TF_DF 一致。"""
from __future__ import annotations
from datetime import timedelta
from decimal import Decimal
import numpy as np
import pandas as pd
import talib.abstract as ta
from pandas import DataFrame
from technical.util import resample_to_interval
from chanlun.core.ChanBI import ChanBI
from chanlun.core.ChanBIZS import ChanBIZS
from chanlun.core.ChanBSP import ChanBSP
from chanlun.core.ChanEnum import (
Chan_BI_DIR,
Chan_BSP_DIR,
Chan_BSP_TYPE,
Chan_FX_TYPE,
Chan_K_DIR,
Chan_KLC_FX,
Chan_KLC_STATE,
Chan_KLINE_DIR,
Chan_KLU_PATTERN,
Chan_PRICE_TREND,
Chan_SEG_DIR,
Chan_ZS_DIR,
)
from chanlun.core.ChanKLC import ChanKLC
from chanlun.core.ChanKLU import ChanKLU
from chanlun.core.ChanSBI import ChanSBI
from chanlun.core.ChanSEG import ChanSEG
from chanlun.core.ChanZS import ChanZS, ChanZS_Big
from chanlun.indicators.ChanMACD import ChanMACD
class BiBuilderMixin:
def cal_trend(self, klc_list):
"""
基于价格与EMA24/EMA52的位置关系、以及MACD/Signal/Hist的方向,
为每个KLC打上趋势标签:'UP' / 'DOWN' / 'FLAT'。
仅设置 klc.trend,不影响其它字段。
"""
if not klc_list:
return klc_list
last_trend = Chan_PRICE_TREND.UNKNOWN
# 趋势延续性:参考近 N 根已完成的KLC
lookback_n = 5
prev_klcs = []
for klc in klc_list:
price = getattr(klc, 'close', None)
ema24 = getattr(klc, 'ema24', None)
ema52 = getattr(klc, 'ema52', None)
macd_raw = getattr(klc, 'macd', None)
signal_raw = getattr(klc, 'signal', None)
hist_raw = getattr(klc, 'macdhist', None)
macd = macd_raw if macd_raw is not None else 0
signal = signal_raw if signal_raw is not None else 0
hist = hist_raw if hist_raw is not None else 0
rsi = getattr(klc, 'rsi', None)
macd_ready = macd_raw is not None and signal_raw is not None
hist_ready = hist_raw is not None
trend = Chan_PRICE_TREND.UNKNOWN
score = 0
try:
# 有效性
price_valid = price is not None and price != 0
ema24_valid = ema24 is not None and ema24 != 0
ema52_valid = ema52 is not None and ema52 != 0
# 多因子投票
# 1) 均线结构 + 价位
if ema24_valid or ema52_valid:
ma_votes = 0
if ema24_valid and ema52_valid:
ma_votes += 1 if ema24 > ema52 else -1
if price_valid and ema24_valid:
ma_votes += 1 if price > ema24 else 0
if price_valid and ema52_valid:
ma_votes += 1 if price > ema52 else -1
# 限幅,避免相关因子重复计分
score += max(-2, min(2, ma_votes))
# 2) MACD结构
if macd_ready:
score += 1 if macd >= signal else -1
if hist_ready and hist != 0:
score += 1 if hist > 0 else -1
# 3) 动量与均线差分斜率
pre = getattr(klc, 'pre', None)
pre_hist = getattr(pre, 'macdhist', None) if pre else None
if pre:
pre_close = getattr(pre, 'close', None)
if price_valid and pre_close is not None:
score += 1 if price >= pre_close else -1
pre_ema24 = getattr(pre, 'ema24', None)
pre_ema52 = getattr(pre, 'ema52', None)
if ema24_valid and ema52_valid and pre_ema24 not in (None, 0) and pre_ema52 not in (None, 0):
spread_now = ema24 - ema52
spread_pre = pre_ema24 - pre_ema52
score += 1 if spread_now >= spread_pre else -1
# 3.1) MACD柱体动量趋势:考虑 macdhist 的斜率与过零
if hist_ready and pre_hist is not None:
# 柱体斜率:上升加分,下降减分
if hist > pre_hist:
score += 1
elif hist < pre_hist:
score -= 1
# 过零加权:负转正更偏多,正转负更偏空
if pre_hist < 0 and hist > 0:
score += 1
elif pre_hist > 0 and hist < 0:
score -= 1
# 3.2) EMA52 突破/跌破加权
if ema52_valid and price_valid and pre_close is not None and pre_ema52 not in (None, 0):
# 看多突破:从均线下方上破且动量配合
if pre_close <= pre_ema52 and price > ema52 and (hist is None or pre_hist is None or hist >= pre_hist):
score += 1
# 看空跌破:从均线上方下破且动量配合
if pre_close >= pre_ema52 and price < ema52 and (hist is None or pre_hist is None or hist <= pre_hist):
score -= 1
# 3.3) EMA52 支撑/阻力触碰(非强穿越)
if ema52_valid and price_valid:
low_v = getattr(klc, 'low', None)
high_v = getattr(klc, 'high', None)
if low_v is not None and high_v is not None and ema52 not in (None, 0):
# 触碰容差(相对EMA52的0.15%
touch_tol = 0.0015
# 作为支撑:收盘在上,最低靠近EMA52
near_support_touch = (price > ema52) and (abs(low_v - ema52) / abs(ema52) <= touch_tol)
# 作为阻力:收盘在下,最高靠近EMA52
near_resistance_touch = (price < ema52) and (abs(high_v - ema52) / abs(ema52) <= touch_tol)
if near_support_touch:
# 若动量不弱,则更偏多
score += 1 if (hist is None or pre_hist is None or hist >= pre_hist) else 0
if near_resistance_touch:
# 若动量不强,则更偏空
score -= 1 if (hist is None or pre_hist is None or hist <= pre_hist) else 0
# 3.4) 多次对 EMA52 的"拒绝"配合 MACD 逆向:易形成压/支并反向
# 统计近窗口内的上/下拒绝次数:
# - 上拒绝:价格位于 EMA52 下方,最高触及/越过 EMA52 但收盘仍在下方
# - 下拒绝:价格位于 EMA52 上方,最低触及/跌破 EMA52 但收盘仍在上方
recent_up_rejects = 0
recent_down_rejects = 0
if ema52_valid:
window_rej = prev_klcs[-lookback_n:] if len(prev_klcs) > 0 else []
rej_tol = 0.0015
for wk in window_rej:
wk_close = getattr(wk, 'close', None)
wk_ema52 = getattr(wk, 'ema52', None)
wk_high = getattr(wk, 'high', None)
wk_low = getattr(wk, 'low', None)
if wk_close is None or wk_ema52 in (None, 0):
continue
# 上拒绝(阻力):下方多次试图上破但未站上
if wk_close < wk_ema52 and wk_high is not None:
if wk_high >= wk_ema52 or abs(wk_high - wk_ema52) / abs(wk_ema52) <= rej_tol:
recent_up_rejects += 1
# 下拒绝(支撑):上方多次试图下破但未跌破
if wk_close > wk_ema52 and wk_low is not None:
if wk_low <= wk_ema52 or abs(wk_low - wk_ema52) / abs(wk_ema52) <= rej_tol:
recent_down_rejects += 1
# 定义 MACD 的方向偏好
macd_bias_up = macd_ready and (macd >= signal) and (not hist_ready or pre_hist is None or hist >= pre_hist)
macd_bias_down = macd_ready and (macd <= signal) and (not hist_ready or pre_hist is None or hist <= pre_hist)
# 若多次上拒绝且 MACD 偏空,则更偏向下行;若多次下拒绝且 MACD 偏多,则更偏向上行
if recent_up_rejects >= 2 and macd_bias_down:
score -= 2
if recent_down_rejects >= 2 and macd_bias_up:
score += 2
# 4) RSI 辅助
if rsi is not None:
if rsi >= 55:
score += 1
elif rsi <= 45:
score -= 1
# 5) 指标未就绪回退(EMA/MACD缺失时,用动量与RSI辅助,延续趋势)
has_full_ind = ema24_valid and ema52_valid and not (macd == 0 and signal == 0 and hist == 0)
if not has_full_ind:
# 仅根据价动量/RSI做轻量判断,默认延续 last_trend,除非出现强反向
strong_up = False
strong_down = False
pre = getattr(klc, 'pre', None)
if pre:
pre_close = getattr(pre, 'close', None)
if price_valid and pre_close is not None:
strong_up = (price >= pre_close)
strong_down = (price < pre_close)
if rsi is not None:
if rsi >= 60:
strong_up = True
elif rsi <= 40:
strong_down = True
if last_trend == Chan_PRICE_TREND.UP and not strong_down:
trend = Chan_PRICE_TREND.UP
elif last_trend == Chan_PRICE_TREND.DOWN and not strong_up:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.UP if strong_up and not strong_down else (Chan_PRICE_TREND.DOWN if strong_down and not strong_up else Chan_PRICE_TREND.FLAT)
else:
# 6) 震荡过滤(仅当极近EMA52且MACD贴合时判作震荡)
near_flat = False
if price_valid and ema52_valid:
near_ema52 = abs(price - ema52) / abs(ema52) <= 0.0005 # 0.05%
if macd_ready:
macd_scale = max(abs(macd), abs(signal), 1e-6)
near_macd = abs(macd - signal) / macd_scale <= 0.05
else:
near_macd = False
near_flat = near_ema52 and near_macd
# 7) 动态阈值 + 趋势记忆(更强粘滞:趋势中容忍小幅反分)
# 引入过去 N 根KLC 的趋势延续性来动态调整翻转阈值,并结合 EMA52 支撑/阻力触碰强化门槛
force_flip_down = False
force_flip_up = False
if near_flat:
trend = Chan_PRICE_TREND.FLAT
else:
# 计算过去窗口的趋势一致性
window = prev_klcs[-lookback_n:] if len(prev_klcs) > 0 else []
persist_up = 0
persist_down = 0
for wk in window:
if getattr(wk, 'trend', None) == Chan_PRICE_TREND.UP:
persist_up += 1
elif getattr(wk, 'trend', None) == Chan_PRICE_TREND.DOWN:
persist_down += 1
persist_ratio_up = (persist_up / len(window)) if len(window) > 0 else 0
persist_ratio_down = (persist_down / len(window)) if len(window) > 0 else 0
# 基准阈值
down_flip_threshold = -2
up_flip_threshold = 2
# 若最近多为UP,则从UP翻转需更强反向信号;同理对DOWN
if last_trend == Chan_PRICE_TREND.UP and persist_ratio_up >= 0.6:
down_flip_threshold = -3
elif last_trend == Chan_PRICE_TREND.DOWN and persist_ratio_down >= 0.6:
up_flip_threshold = 3
# EMA52 触碰强化门槛:UP时若出现支撑触碰,下翻更难;DOWN时若出现阻力触碰,上翻更难
if ema52_valid and price_valid:
low_v = getattr(klc, 'low', None)
high_v = getattr(klc, 'high', None)
if low_v is not None and high_v is not None and ema52 not in (None, 0):
touch_tol = 0.0015
near_support_touch = (price > ema52) and (abs(low_v - ema52) / abs(ema52) <= touch_tol)
near_resistance_touch = (price < ema52) and (abs(high_v - ema52) / abs(ema52) <= touch_tol)
if last_trend == Chan_PRICE_TREND.UP and near_support_touch:
# 强化维持UP:进一步降低向下翻转阈值
down_flip_threshold = min(down_flip_threshold - 1, -3)
if last_trend == Chan_PRICE_TREND.DOWN and near_resistance_touch:
# 强化维持DOWN:进一步提高向上翻转阈值
up_flip_threshold = max(up_flip_threshold + 1, 3)
# 7.1) 复合拐头信号:MACD/Signal 同向拐头 + hist 连续减弱 + 多次未能越过 EMA52
pre_macd = getattr(pre, 'macd', None) if pre else None
pre_signal = getattr(pre, 'signal', None) if pre else None
macd_slope = (macd - pre_macd) if (macd_ready and pre_macd is not None) else 0
signal_slope = (signal - pre_signal) if (macd_ready and pre_signal is not None) else 0
# hist 连续减弱(绝对值缩小)
hist_seq = []
for wk in prev_klcs[-2:]:
val = getattr(wk, 'macdhist', None)
if val is not None:
hist_seq.append(val)
if hist is not None:
hist_seq.append(hist)
weaken_steps = 0
for i in range(1, len(hist_seq)):
if abs(hist_seq[i]) < abs(hist_seq[i-1]):
weaken_steps += 1
# 近窗口对 EMA52 的"未能站上/跌破"统计(放宽窗口与条件)
window_ema = prev_klcs[-4:] if len(prev_klcs) > 0 else []
no_up_break = False
no_down_break = False
if ema52_valid:
# 未能有效上破:最近若干根收盘大多数不在 EMA52 上方,且高点多次触及/接近
cnt_touch_up = 0
cnt_close_above = 0
for wk in window_ema:
wk_close = getattr(wk, 'close', None)
wk_high = getattr(wk, 'high', None)
wk_ema = getattr(wk, 'ema52', None)
if wk_close is not None and wk_ema not in (None, 0):
if wk_close > wk_ema:
cnt_close_above += 1
if wk_high is not None and (wk_high >= wk_ema or abs(wk_high - wk_ema) / abs(wk_ema) <= 0.0015):
cnt_touch_up += 1
no_up_break = (cnt_close_above <= 1 and cnt_touch_up >= 1 and price <= ema52)
# 未能有效下破:最近若干根收盘大多数不在 EMA52 下方,且低点多次触及/接近
cnt_touch_down = 0
cnt_close_below = 0
for wk in window_ema:
wk_close = getattr(wk, 'close', None)
wk_low = getattr(wk, 'low', None)
wk_ema = getattr(wk, 'ema52', None)
if wk_close is not None and wk_ema not in (None, 0):
if wk_close < wk_ema:
cnt_close_below += 1
if wk_low is not None and (wk_low <= wk_ema or abs(wk_low - wk_ema) / abs(wk_ema) <= 0.0015):
cnt_touch_down += 1
no_down_break = (cnt_close_below <= 1 and cnt_touch_down >= 1 and price >= ema52)
# 若当前为UP趋势,出现明显拐头+hist减弱+未能上破EMA52,则加速看空
if last_trend == Chan_PRICE_TREND.UP and macd_slope < 0 and signal_slope < 0 and weaken_steps >= 1 and no_up_break and macd_bias_down:
score -= 3
down_flip_threshold = max(down_flip_threshold, 0)
force_flip_down = True
# 若当前为DOWN趋势,出现明显拐头+hist减弱+未能下破EMA52,则加速看多
if last_trend == Chan_PRICE_TREND.DOWN and macd_slope > 0 and signal_slope > 0 and weaken_steps >= 1 and no_down_break and macd_bias_up:
score += 3
up_flip_threshold = min(up_flip_threshold, 0)
force_flip_up = True
# 多次对 EMA52 的拒绝配合 MACD 逆向:加速反向翻转(降低相反方向阈值)
if recent_up_rejects >= 2 and macd_bias_down:
# 从 UP 向 DOWN 的翻转更容易
down_flip_threshold = max(down_flip_threshold, -1)
if recent_down_rejects >= 2 and macd_bias_up:
# 从 DOWN 向 UP 的翻转更容易
up_flip_threshold = min(up_flip_threshold, 1)
if force_flip_down:
trend = Chan_PRICE_TREND.DOWN
elif force_flip_up:
trend = Chan_PRICE_TREND.UP
elif last_trend == Chan_PRICE_TREND.UP:
if score <= down_flip_threshold:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.UP
elif last_trend == Chan_PRICE_TREND.DOWN:
if score >= up_flip_threshold:
trend = Chan_PRICE_TREND.UP
else:
trend = Chan_PRICE_TREND.DOWN
else:
# 初始无记忆时,降低进入门槛
if score >= 1:
trend = Chan_PRICE_TREND.UP
elif score <= -1:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.FLAT
except Exception:
trend = Chan_PRICE_TREND.UNKNOWN
# 写回趋势
if klc.end_time is None:
trend = Chan_PRICE_TREND.FLAT
if hasattr(klc, 'set_trend'):
klc.set_trend(trend)
else:
setattr(klc, 'trend', trend)
last_trend = trend
# 更新滑窗:仅向后看
prev_klcs.append(klc)
price_diff = klc.close - klc.pre.close if klc.pre else 0
#if klc.index > len(klc_list) - 10:
#print(klc.start_time, klc.end_time, klc.close, klc.ema24, klc.ema52, klc.macd, klc.signal, klc.macdhist, klc.trend, price_diff, score)
#print(klc.start_time, klc.end_time, klc.trend, price_diff, score)
return klc_list
def get_bi_list(self, dataframe):
bi_list = self.cal_bi_list(self.get_klc_list(dataframe))
#bi_list = self.cal_bi_list_chanlun(self.get_klc_list(dataframe))
return bi_list
def cal_bi_list(self, klc_list):
bi_list = []
last_top = None
last_bottom = None
bi_klc_min = 4
last_fx_klc = None
for klc in klc_list:
if last_fx_klc:
klc.check_klc_state(last_fx_klc)
klc.check_fx_confirmed(last_top, last_bottom)
fx = self.check_fx(klc)
if fx == Chan_FX_TYPE.TOP:
if last_bottom:
if self.check_top_fx(last_bottom, klc) == False:
fx = Chan_FX_TYPE.UNKNOWN
if fx == Chan_FX_TYPE.BOTTOM:
if last_top:
if self.check_bottom_fx(last_top, klc) == False:
#print(klc.end_time, last_top.end_time, "---")
fx = Chan_FX_TYPE.UNKNOWN
# Do nothing
if fx == Chan_FX_TYPE.UNKNOWN:
if len(bi_list) > 0:
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#continue
if len(bi_list) > 0 and klc.end_klu:
last_bi = bi_list[-1]
#print(klc.start_time, last_bi.start_time, last_bi.end_time, last_bi.dir, last_bi.high, last_bi.low, last_bottom.end_time, "last bi")
if last_top and last_bi.dir == Chan_BI_DIR.DOWN:
if last_bottom and klc.high > last_bi.high:
#print(klc.end_time, "Top 7, 1", last_bi.start_time, klc.high, last_bi.high)
#klc.klc_fx_type = Chan_KLC_FX.TOP7
#klc.fx = Chan_FX_TYPE.TOP
"""
last_bi.set_end_klc(last_bottom, klc)
bi = ChanBI(last_bottom, len(bi_list), Chan_BI_DIR.UP)
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM7)
#klc.bb_out = True
last_bi.set_next(bi)
bi.set_pre(last_bi)
for klc_index in range(last_bi.end_klc.index, len(klc_list)):
bi.add_klc(klc_list[klc_index])
bi_list.append(bi)
last_top = klc
klc.set_bi(bi)
#print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low, bi.is_sure)
"""
else:
if last_bottom and last_bi.dir == Chan_BI_DIR.UP:
if last_top and klc.low < last_bi.low:
#print(klc.end_time, "Bottom 8, 2", last_bi.start_time)
#klc.klc_fx_type = Chan_KLC_FX.BOTTOM8
#klc.fx = Chan_FX_TYPE.BOTTOM
"""
last_bi.set_end_klc(last_top, klc)
bi = ChanBI(last_top, len(bi_list), Chan_BI_DIR.DOWN)
#klc.set_klc_fx_type(Chan_KLC_FX.TOP6)
#klc.bb_out = True
last_bi.set_next(bi)
bi.set_pre(last_bi)
for klc_index in range(last_bi.end_klc.index, len(klc_list)):
bi.add_klc(klc_list[klc_index])
bi_list.append(bi)
last_bottom = klc
klc.set_bi(bi)
#print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low, bi.is_sure)
"""
else:
last_fx_klc = klc
if fx == Chan_FX_TYPE.TOP:
#print(klc.end_time, fx, klc.pre.high, klc.high, klc.pre.start_time, klc.pre.end_time)
if last_top:
if last_bottom:
#print(klc.start_time, last_bottom.start_time, last_top.start_time)
if last_bottom.index < last_top.index:
# Second top lower to be second sell point
if last_top.high > klc.high:
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#klc.set_klc_fx_type(Chan_KLC_FX.TOP3)
#print(klc.end_time, klc.fx, "二类卖点Sell 1")
else:
# A new top found
#last_top.set_fx(Chan_FX_TYPE.UNKNOWN)
last_top = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 1")
klc.set_klc_fx_type(Chan_KLC_FX.TOP1)
self.check_fx_pattern(klc)
#print(klc.end_time, klc.fx, "一类卖点Sell 1")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# 不满足结合律的分型
else:
#klc.set_klc_fx_type(Chan_KLC_FX.TOP0)
#print(klc.end_time, klc.klc_fx_type)
if last_bottom.index + bi_klc_min > klc.index:
if last_top.high > klc.high:
#print(klc.start_time, klc.fx, "二类卖点Sell 1")
#klc.set_klc_fx_type(Chan_KLC_FX.TOP8)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# New TOP Found前面的UKNOWN可能出现TOP7,但是这里的也可能出现TOP8分型
else:
# 顶分型在出现2之前超过前一个笔的顶 TOP8
if last_top.index + bi_klc_min < klc.index and len(bi_list) > 1:
pre_last_bi = bi_list[-2]
last_bi = bi_list[-1]
if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.UP and False:
#pre_last_bi.update_bi(klc)
bi_list.remove(last_bi)
pre_last_bi.set_next(None)
#last_top.set_fx(Chan_FX_TYPE.PTOP)
last_top = klc
last_bottom = pre_last_bi.start_klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Bottom Change 1")
klc.set_klc_fx_type(Chan_KLC_FX.TOP2)
#print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi")
#klc.set_state("10")
#print(klc.start_time, klc.fx, "笔卖点Sell 1")
###klc.set_klc_fx_type(Chan_KLC_FX.TOP2) # when bi is down but the fx is top
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#klc.set_klc_fx_type(Chan_KLC_FX.TOP8)
#print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi")
else:
#klc.set_fx(Chan_FX_TYPE.PTOP)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.end_time, klc.fx, "无效顶分型")
# 满足结合律
else:
# New Temp TOP and last bottom confirmed ***** confirm last down bi(last bottom and last top)
last_bi = bi_list[-1]
if not last_bi.is_sure:
last_bi.set_end_klc(last_bottom, klc)
bi = ChanBI(last_bottom, len(bi_list), Chan_BI_DIR.UP)
last_bi.set_next(bi)
bi.set_pre(last_bi)
bi.add_klc(klc)
bi_list.append(bi)
last_top = klc
#print(klc.end_time, klc.fx, bi_list[-1].dir, "Last Top Change 2")
klc.set_klc_fx_type(Chan_KLC_FX.TOP2)
self.check_fx_pattern(klc)
#bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, last_bottom.start_time, "Normal TOP Found, Confirm down bi 4")
# last bottom = None 初始化的时候用,其他时间不用
else:
# 初始化的时候用,其他时间不用
if last_top.high < klc.high:
last_bi = bi_list[-1]
last_bi.set_start_klc(klc, Chan_BI_DIR.DOWN)
last_top = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 3")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# 初始化的时候用,其他时间不用
else:
#klc.set_fx(Chan_FX_TYPE.TT)
#print(klc.start_time, klc.fx, "二类卖点Sell 2")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# last_top == None 初始化的时候用,其他时间不用
else:
if last_bottom:
# 不满足结合律的分型
if last_bottom.index + bi_klc_min > klc.index:
#klc.set_fx(Chan_FX_TYPE.PTOP)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, "中枢卖点Sell 1")
else:
# First temp top and last bottom confirmed
last_top = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 4")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# Last top = None, last bottom = None, create first down bi 初始化的时候用,其他时间不用
else:
# First temp top
last_top = klc
bi = ChanBI(klc, len(bi_list), Chan_BI_DIR.DOWN)
bi_list.append(bi)
bi.add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 5")
#klc.fx = Bottom ========================
else:
if last_bottom:
if last_top:
# Bottom after top and find a new bottom
if last_top.index < last_bottom.index:
# Second bottom uppper to be second buy point and confirm last bi
if last_bottom.low < klc.low:
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM3)
#print(last_bottom.start_time, last_bottom.end_time, "--------------------------------1")
#print(klc.end_time, klc.fx, "二类买点Buy 1")
else:
# A new bottom found
last_bottom = klc
#print(klc.end_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 1")
klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM1)
self.check_fx_pattern(klc)
#print(klc.end_time, klc.fx, "一类买点Buy 1")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# 不满足结合律的分型
else:
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM0)
#print(klc.end_time, klc.klc_fx_type)
if last_top.index + bi_klc_min > klc.index:
if last_bottom.low < klc.low:
#print(klc.end_time, klc.fx, "中枢买点Buy 1")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM8)
# Found new bottom没有意义,上面UNKNOWN的时候已经是笔破坏了
else:
#print(klc.end_time, last_bottom.end_time, "Found a new bottom")
if last_bottom.index + bi_klc_min < klc.index and len(bi_list) > 1:
pre_last_bi = bi_list[-2]
last_bi = bi_list[-1]
if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.DOWN and False:
#pre_last_bi.update_bi(klc)
bi_list.remove(last_bi)
pre_last_bi.set_next(None)
last_bottom = klc
last_top = pre_last_bi.start_klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Bottom Change 2")
klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2)
#print(klc.start_time, last_bi.start_klc.start_time, "New BOTTOM Found reset last bi")
#print(klc.start_time, klc.fx, "笔买点Buy 1")
###klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2) # when bi is up but the fx is bottom
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM8)
else:
#klc.set_fx(Chan_FX_TYPE.UNKNOWN)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
print(klc.end_time, klc.fx, "无效底分型")
# 满足结合律的分型
else:
# New Temp Bottom and last top confirmed ***** confirm last up bi(last bottom and last top)
last_bi = bi_list[-1]
if not last_bi.is_sure:
last_bi.set_end_klc(last_top, klc)
bi = ChanBI(last_top, len(bi_list), Chan_BI_DIR.DOWN)
last_bi.set_next(bi)
bi.set_pre(last_bi)
bi.add_klc(klc)
bi_list.append(bi)
last_bottom = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 2")
klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2)
self.check_fx_pattern(klc)
#bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, last_top.start_time, "Normal Bottom Found, Confirm up bi 6")
# last_top = None 初始化的时候用,其他时间不用
else:
if last_bottom.low > klc.low:
last_bi = bi_list[-1]
last_bi.set_start_klc(klc, Chan_BI_DIR.UP)
#last_bottom.set_fx(Chan_FX_TYPE.UNKNOWN)
last_bottom = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 3")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, "笔买点Buy 3")
else:
#klc.set_fx(Chan_FX_TYPE.BB)
#klc.set_state('-20')
#print(klc.start_time, klc.fx, "二类买点Buy 2")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# last_bottom = None 初始化的时候用,其他时间不用
else:
if last_top:
# 不满足结合律的分型
if last_top.index + bi_klc_min > klc.index:
#klc.set_fx(Chan_FX_TYPE.PBOTTOM)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, "中枢买点Buy 1")
else:
# First temp bottom and last top confirmed
last_bottom = klc
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 4")
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, "一类买点Buy 1")
# Last top = None, last bottom = None, create first up bi
else:
# First temp bottom and no top yet
last_bottom = klc
bi = ChanBI(klc, len(bi_list), Chan_BI_DIR.UP)
#klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM7)
bi_list.append(bi)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 5")
#print(klc.start_time, klc.fx, "笔买点Buy 4")
self.get_above_zero_bsp(klc_list)
#print(bi_list[-1].start_time, bi_list[-1].end_time, len(bi_list[-1].klc_list))
return bi_list
def check_top_fx(self, last_bottom, klc):
if (last_bottom.high > klc.pre.low or last_bottom.high > klc.next.low) and (klc.index - last_bottom.index < 100):
return False
return True
def check_bottom_fx(self, last_top, klc):
if (last_top.low < klc.pre.high or last_top.low < klc.next.high) and (klc.index - last_top.index < 100):
return False
return True
# 线段内的中枢