diff --git a/ChanKLC.py b/ChanKLC.py
index dc4c62d..fd97864 100644
--- a/ChanKLC.py
+++ b/ChanKLC.py
@@ -4,7 +4,7 @@ from typing import Dict, Optional
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX, Chan_K_DIR, Chan_MACD_STATE, Chan_PRICE_TREND, Chan_EMA_POS, Chan_EMA_SEMANTIC, Chan_BSP_TYPE
import ChanKLU
import ChanCTime
-
+import Chan_FX_Box
# 根据结合律合并K线后的K线
class ChanKLC():
def __init__(self, klu: ChanKLU, index, ddir=Chan_KLINE_DIR.UP):
@@ -51,6 +51,8 @@ class ChanKLC():
self.ema104 = klu.ema104
self.ema156 = klu.ema156
self.ema208 = klu.ema208
+ self.ema13 = klu.ema13
+ self.ema7 = klu.ema7
self.trend = Chan_PRICE_TREND.UNKNOWN
self.exception = klu.exception
self.klc_dir = Chan_KLINE_DIR.UP if klu.close > klu.open else Chan_KLINE_DIR.DOWN
@@ -67,6 +69,9 @@ class ChanKLC():
self.bb2633middle = klu.bb2633middle
self.ema5 = klu.ema5
self.ma5 = klu.ma5
+ self.fx_box = None
+ self.in_fx = False
+ self.fx_confirmed = False
# ==================== EMA 通用计算方法 ====================
@staticmethod
@@ -320,6 +325,64 @@ class ChanKLC():
#print(self.end_time, ema_name, self.ema_status[ema_name]['semantic'], hist_div)
#self.cal_bb_out()
#print(self.pre.start_time, self.next.end_time, self.klc_fx_type)
+ if klc_fx_type == Chan_KLC_FX.TOP1 or klc_fx_type == Chan_KLC_FX.TOP2 or klc_fx_type == Chan_KLC_FX.BOTTOM1 or klc_fx_type == Chan_KLC_FX.BOTTOM2:
+ self.cal_fx_box()
+ def cal_fx_box(self):
+ # 每次重算前先清空,避免旧box残留
+ self.fx_box = None
+ start_time = None
+ end_time = None
+ high = 0
+ low = 0
+ display = False
+ if self.pre and self.next and self.next.end_time:
+ self.next.in_fx = True
+ if self.fx == Chan_FX_TYPE.TOP:
+ start_time = self.pre.end_time
+ end_time = self.next.end_time
+ high = self.high
+ low = self.pre.low if self.pre.low < self.next.low else self.next.low
+ if self.next.close < self.pre.low:
+ display = True
+ elif self.fx == Chan_FX_TYPE.BOTTOM:
+ start_time = self.pre.end_time
+ end_time = self.next.end_time
+ high = self.pre.high if self.pre.high > self.next.high else self.next.high
+ low = self.low
+ if self.next.close > self.pre.high:
+ display = True
+ if high > 0 and self.next.end_time and display:
+ #print(start_time, end_time, high, low)
+ # Chan_FX_BOX 这里导入的是模块,类名在模块内部为 Chan_FX_Box
+ self.fx_confirmed = True
+ self.fx_box = Chan_FX_Box.Chan_FX_Box(start_time, end_time, high, low)
+ def check_fx_confirmed(self, last_top, last_bottom):
+ if last_top and last_bottom:
+ if last_top.index > last_bottom.index:
+ if self.in_fx == False and last_top.fx_confirmed == False:
+ pre = last_top.pre
+ if pre.low > self.close:
+ last_top.fx_confirmed = True
+ if last_top.fx_box:
+ last_top.fx_box.end_time = self.end_time
+ print(self.end_time, "fx_confirmed top")
+ else:
+ high = last_top.high
+ low = self.low
+ last_top.fx_box = Chan_FX_Box.Chan_FX_Box(last_top.pre.end_time, self.end_time, high, low)
+ print(self.end_time, "fx_confirmed new box top")
+ elif self.in_fx == False and last_bottom.fx_confirmed == False:
+ pre = last_bottom.pre
+ if pre.high < self.close:
+ last_bottom.fx_confirmed = True
+ if last_bottom.fx_box:
+ last_bottom.fx_box.end_time = self.end_time
+ print(self.end_time, "fx_confirmed bottom")
+ else:
+ high = self.high
+ low = last_bottom.low
+ last_bottom.fx_box = Chan_FX_Box.Chan_FX_Box(last_bottom.pre.end_time, self.end_time, high, low)
+ print(self.end_time, "fx_confirmed new box bottom")
def add_klu(self, klu):
self.klu_list.append(klu)
def set_end_klu(self, klu):
@@ -347,8 +410,8 @@ class ChanKLC():
self.close = self.high
if self.close < self.low:
self.close = self.low
- if self.close > self.high:
- self.close = self.high
+ if self.open < self.low:
+ self.open = self.low
#print(self.end_time, self.open, self.close, self.high, self.low)
#print(klu.time, klu.open, klu.close, klu.high, klu.low)
def cal_fx(self):
@@ -397,6 +460,8 @@ class ChanKLC():
self.ema104 += self.klu_list[index].ema104
self.ema156 += self.klu_list[index].ema156
self.ema208 += self.klu_list[index].ema208
+ self.ema13 += self.klu_list[index].ema13
+ self.ema7 += self.klu_list[index].ema7
self.bb2633upper += self.klu_list[index].bb2633upper
self.bb2633lower += self.klu_list[index].bb2633lower
self.bb2633middle += self.klu_list[index].bb2633middle
@@ -415,6 +480,8 @@ class ChanKLC():
self.ema104 = self.ema104 / n
self.ema156 = self.ema156 / n
self.ema208 = self.ema208 / n
+ self.ema13 = self.ema13 / n
+ self.ema7 = self.ema7 / n
self.ma5 = self.ma5 / n
self.ema5 = self.ema5 / n
self.bb2633upper = self.bb2633upper / n
diff --git a/ChanKLU.py b/ChanKLU.py
index be7e1b6..4be0cda 100644
--- a/ChanKLU.py
+++ b/ChanKLU.py
@@ -182,6 +182,8 @@ class ChanKLU:
self.ema104 = float(item['ema104']) if 'ema104' in item and item['ema104'] else 0
self.ema156 = float(item['ema156']) if 'ema156' in item and item['ema156'] else 0
self.ema208 = float(item['ema208']) if 'ema208' in item and item['ema208'] else 0
+ self.ema13 = float(item['ema13']) if 'ema13' in item and item['ema13'] else 0
+ self.ema7 = float(item['ema7']) if 'ema7' in item and item['ema7'] else 0
self.rsi = float(item['rsi']) if 'rsi' in item and item['rsi'] else 0
self.volume_ratio = float(item['volume_ratio']) if 'volume_ratio' in item and item['volume_ratio'] else 0
self.bb52upper = float(item['bb52upper']) if 'bb52upper' in item and item['bb52upper'] else 0
diff --git a/ChanMACDHistSet.py b/ChanMACDHistSet.py
index fa990bc..484fc94 100644
--- a/ChanMACDHistSet.py
+++ b/ChanMACDHistSet.py
@@ -19,6 +19,7 @@ class ChanMACDHistSet():
self.start_klu = start_klu
self.peak_div_list = []
self.middle_area = 0
+ self.total_macdhist = 0
def set_next(self, next_histset):
self.next = next_histset
def set_pre(self, pre_histset):
@@ -102,6 +103,15 @@ class ChanMACDHistSet():
for peak_div in self.peak_div_list:
peak_str += f"{peak_div.time}, "
state_str += f"{peak_div.macd_state}, "
+ total_macdhist = 0
+ first_klu = self.klu_list[0]
+ last_klu = self.klu_list[-1]
+ if (first_klu.macd > 0 and last_klu.macd > 0 and first_klu.macdhist > 0) or (first_klu.macd < 0 and last_klu.macd < 0 and first_klu.macdhist < 0):
+ for klu in self.klu_list:
+ self.total_macdhist += klu.macdhist
+ if abs(self.total_macdhist) < 150:
+ #print(self.end_time, "Total MACDHist: ", self.total_macdhist)
+ last_klu.separate_div = 99999
#if self.peak_klu and len(self.peak_div_list) > 0:
#print("Continue Div: ",self.start_time, "Peak:", self.peak_klu.time, "Div: ", peak_str, state_str)
\ No newline at end of file
diff --git a/Chan_FX_Box.py b/Chan_FX_Box.py
new file mode 100644
index 0000000..8a9d9ec
--- /dev/null
+++ b/Chan_FX_Box.py
@@ -0,0 +1,7 @@
+class Chan_FX_Box():
+ def __init__(self, start_time, end_time, high, low):
+ self.start_time = start_time
+ self.end_time = end_time
+ self.high = high
+ self.low = low
+
\ No newline at end of file
diff --git a/TF_DF.py b/TF_DF.py
index d160503..e38f98b 100644
--- a/TF_DF.py
+++ b/TF_DF.py
@@ -122,6 +122,8 @@ class TF_DF():
df['ema156'] = ta.EMA(df, timeperiod=156)
df['ema208'] = ta.EMA(df, timeperiod=208)
df['ema26'] = ta.EMA(df, timeperiod=26)
+ df['ema13'] = ta.EMA(df, timeperiod=13)
+ df['ema7'] = ta.EMA(df, timeperiod=7)
df['rsi'] = ta.RSI(df, timeperiod=14)
df['volume_ratio'] = self.cal_volume_ratio(df)
return df
@@ -918,6 +920,7 @@ class TF_DF():
last_bottom = None
bi_klc_min = 4
for klc in klc_list:
+ klc.check_fx_confirmed(last_top, last_bottom)
fx = self.check_fx(klc)
if fx == Chan_FX_TYPE.TOP and False:
if last_bottom:
@@ -986,7 +989,7 @@ class TF_DF():
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)
+ #klc.set_klc_fx_type(Chan_KLC_FX.TOP3)
#print(klc.end_time, klc.fx, "二类卖点Sell 1")
else:
# A new top found
@@ -1001,11 +1004,11 @@ class TF_DF():
# 不满足结合律的分型
else:
#klc.set_klc_fx_type(Chan_KLC_FX.TOP0)
- print(klc.end_time, klc.klc_fx_type)
+ #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)
+ #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分型
@@ -1104,7 +1107,7 @@ class TF_DF():
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)
+ #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:
@@ -1125,7 +1128,7 @@ class TF_DF():
#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)
+ #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")
@@ -1213,331 +1216,29 @@ class TF_DF():
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)
return bi_list
- def cal_bi_list1(self, klc_list):
- bi_list = []
- last_top = None
- last_bottom = None
+ def get_above_zero_bsp(self, klc_list):
+ buy_bsp_list = []
+ sell_bsp_list = []
+ above_zero = False
+ buy_bsp = None
+ sell_bsp = None
for klc in klc_list:
- 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)
- 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:
- print("fx=unknown, 1")
- if last_bottom and klc.high > last_bi.high:
- 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:
- print("fx=unknown, 2")
- if last_bottom and last_bi.dir == Chan_BI_DIR.UP:
- if last_top and klc.low < last_bi.low:
- 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:
- if fx == Chan_FX_TYPE.TOP:
- 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:
- #klc.set_fx(Chan_FX_TYPE.TT)
- #klc.set_state("20")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- #klc.cal_invisible()
- #klc.set_klc_fx_type(Chan_KLC_FX.TOP3)
- #print(klc.start_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")
- #klc.set_fx(fx)
- #klc.set_state("10")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- else:
- # 不满足结合律的分型
- if last_bottom.index + 4 > klc.index:
- if last_top.high > klc.high:
- #print(klc.start_time, klc.fx, "二类卖点Sell 1")
- #klc.set_fx(Chan_FX_TYPE.PTOP)
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- # New TOP Found replace last top
- else:
- if last_top.index + 4 < 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])
- else:
- 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, "无效分型")
- # 满足结合律
- 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)
- #klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM7)
- #klc.bb_out = True
- 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)
- #klc.set_state('30')
- 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")
- #print(klc.start_time, klc.fx, "笔卖点Sell 2")
- # 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.set_fx(Chan_FX_TYPE.UNKNOWN)
- 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])
- #print(klc.start_time, klc.fx, "笔卖点Sell 3")
- else:
- klc.set_fx(Chan_FX_TYPE.TT)
- #klc.set_state('20')
- #print(klc.start_time, klc.fx, "二类卖点Sell 2")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- else:
- if last_bottom:
- # 不满足结合律的分型
- if last_bottom.index + 4 > 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])
- #print(klc.start_time, klc.fx, "一类卖点Sell 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)
- #klc.set_klc_fx_type(Chan_KLC_FX.TOP6)
- #klc.bb_out = True
- 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 Top Change 5")
- #print(klc.start_time, 'Create first top')
- #print(klc.start_time, klc.fx, "笔卖点Sell 1")
- #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:
- #klc.set_fx(Chan_FX_TYPE.BB)
- #klc.set_state("-20")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- #klc.cal_invisible()
- #klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM3)
- #print(last_bottom.start_time, last_bottom.end_time, "--------------------------------1")
- #print(klc.start_time, klc.fx, "二类买点Buy 1")
- else:
- # A new bottom found
- #last_bottom.set_fx(Chan_FX_TYPE.UNKNOWN)
- last_bottom = klc
- #print(klc.start_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.start_time, klc.fx, "一类买点Buy 1")
- #klc.set_state("-10")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- else:
- # 不满足结合律的分型
- if last_top.index + 4 > klc.index:
- if last_bottom.low < klc.low:
- #klc.set_fx(Chan_FX_TYPE.PBOTTOM)
- #klc.set_fx(Chan_FX_TYPE.BB)
- #klc.set_state("-100")
- #print(klc.start_time, klc.fx, "中枢买点Buy 1")
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- # Found new bottom
- else:
- if last_bottom.index + 4 < 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.set_fx(Chan_FX_TYPE.PBOTTOM)
- 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")
- #klc.set_state("-10")
- #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])
- else:
- #klc.set_fx(Chan_FX_TYPE.UNKNOWN)
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- #print(klc.start_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)
- #klc.set_klc_fx_type(Chan_KLC_FX.TOP6)
- #klc.bb_out = True
- 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)
- #klc.set_state('-30')
- bi_list[-1].add_klc(klc)
- klc.set_bi(bi_list[-1])
- #print(klc.start_time, klc.fx, "笔买点Buy 2")
- #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 + 4 > 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)
- #klc.bb_out = True
- 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")
- #if klc.fx != Chan_FX_TYPE.UNKNOWN:
- #print(klc.start_time, klc.fx, klc.index)
- """
- for klc in klc_list:
- if klc.fx == Chan_FX_TYPE.TOP:
- klc.state = "10"
- #print(klc.time, klc.state)
- if klc.fx == Chan_FX_TYPE.BOTTOM:
- klc.state = "-10"
- #print(klc.time, klc.state)
- """
- #for index in range(0, 10):
- #print(bi_list[index].start_time, bi_list[index].start_klc.start_time, bi_list[index].dir)
- return bi_list
+ if klc.pre and klc.pre.signal < 0 and klc.signal > 0:
+ above_zero = True
+ if klc.pre and klc.pre.signal > 0 and klc.signal < 0:
+ above_zero = False
+ if above_zero and klc.klc_fx_type == Chan_KLC_FX.BOTTOM2 and klc.macd > 0:
+ buy_bsp = klc
+ buy_bsp_list.append(klc)
+ #print(klc.end_time, "MACD 0轴上穿,回调笔底分型做多")
+ if buy_bsp and klc.pre and klc.pre.macdhist > 0 and klc.macdhist < 0:
+ sell_bsp = klc
+ sell_bsp_list.append(klc)
+ buy_bsp = None
+ #print(klc.end_time, "Sell BSP Found")
+ return buy_bsp_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 < 10):
return False
diff --git a/web/app.py b/web/app.py
index 3e0d086..887680d 100644
--- a/web/app.py
+++ b/web/app.py
@@ -439,6 +439,11 @@ def add_indicators(df):
df['ema24'] = (ta.EMA(df, timeperiod=24)).fillna(0)
df['ema52'] = (ta.EMA(df, timeperiod=52)).fillna(0)
df['ema26'] = (ta.EMA(df, timeperiod=26)).fillna(0)
+ df['ema13'] = (ta.EMA(df, timeperiod=13)).fillna(0)
+ df['ema7'] = (ta.EMA(df, timeperiod=7)).fillna(0)
+ df['ema104'] = (ta.EMA(df, timeperiod=104)).fillna(0)
+ df['ema156'] = (ta.EMA(df, timeperiod=156)).fillna(0)
+ df['ema208'] = (ta.EMA(df, timeperiod=208)).fillna(0)
# 常用SMA 24/52
try:
df['sma24'] = (ta.SMA(df, timeperiod=24)).fillna(0)
@@ -624,6 +629,16 @@ def analyze_chan(df, symbol=None, timeframe=None):
# 如果分型强度小于1,设为0
if fx_strength < 1:
fx_strength = 0
+
+ # KLC 分型框(起止时间+高低价):
+ # 仅使用 cal_fx_box 通过 display 条件后生成的 klc.fx_box。
+ # 若无 fx_box,则前端不应绘制分型框。
+ fx_box = getattr(klc, 'fx_box', None)
+ box_start_time = getattr(fx_box, 'start_time', None) if fx_box else None
+ box_end_time = getattr(fx_box, 'end_time', None) if fx_box else None
+ box_high = getattr(fx_box, 'high', None) if fx_box else None
+ box_low = getattr(fx_box, 'low', None) if fx_box else None
+
if klc.bb_out:
klc_fx_info.append({
'time': klc.end_time,
@@ -632,10 +647,22 @@ def analyze_chan(df, symbol=None, timeframe=None):
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
'fx_strength': fx_strength, # 分型强度分数 (0-100)
'fx_strength_level': fx_strength_level, # 分型强度等级 (极强/强/中等/弱/极弱)
- 'is_strong_fx': is_strong_fx # 是否为强分型
+ 'is_strong_fx': is_strong_fx, # 是否为强分型
+
+ # 虚线分型框信息(给前端画框用)
+ 'start_time': box_start_time,
+ 'end_time': box_end_time,
+ 'high': float(box_high) if box_high is not None else None,
+ 'low': float(box_low) if box_low is not None else None,
})
except Exception as e:
# 如果出错,仍然添加基本信息,但分型强度为0
+ fx_box = getattr(klc, 'fx_box', None)
+ box_start_time = getattr(fx_box, 'start_time', None) if fx_box else None
+ box_end_time = getattr(fx_box, 'end_time', None) if fx_box else None
+ box_high = getattr(fx_box, 'high', None) if fx_box else None
+ box_low = getattr(fx_box, 'low', None) if fx_box else None
+
klc_fx_info.append({
'time': klc.end_time,
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
@@ -643,7 +670,13 @@ def analyze_chan(df, symbol=None, timeframe=None):
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
'fx_strength': 0,
'fx_strength_level': "",
- 'is_strong_fx': False
+ 'is_strong_fx': False,
+
+ # 虚线分型框信息(给前端画框用)
+ 'start_time': box_start_time,
+ 'end_time': box_end_time,
+ 'high': float(box_high) if box_high is not None else None,
+ 'low': float(box_low) if box_low is not None else None,
})
@@ -1391,12 +1424,17 @@ def analyze():
# 添加K线分型信息
'klc_fx_info': [{
'time': format_time_safely(point['time'], client_tz),
+ 'start_time': format_time_safely(point['start_time'], client_tz),
+ 'end_time': format_time_safely(point['end_time'], client_tz),
'price': float(point['price']),
'fx_type': point['fx_type'],
'is_bottom': bool(point['is_bottom']),
'fx_strength': float(point['fx_strength']), # 分型强度分数
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
- 'is_strong_fx': bool(point['is_strong_fx']) # 是否为强分型
+ 'is_strong_fx': bool(point['is_strong_fx']), # 是否为强分型
+ # 分型框(虚线矩形)用到的高低价
+ 'high': float(point['high']) if point.get('high') is not None else None,
+ 'low': float(point['low']) if point.get('low') is not None else None
} for point in analysis_result['klc_fx_info']],
# 添加ChanMACD分析数据
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz),
@@ -1587,12 +1625,17 @@ def analyze():
# 添加小周期分型信息
result['element_klc_fx_info'] = [{
'time': format_time_safely(point['time'], client_tz),
+ 'start_time': format_time_safely(point['start_time'], client_tz),
+ 'end_time': format_time_safely(point['end_time'], client_tz),
'price': float(point['price']),
'fx_type': point['fx_type'],
'is_bottom': bool(point['is_bottom']),
'fx_strength': float(point['fx_strength']), # 分型强度分数
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
- 'is_strong_fx': bool(point['is_strong_fx']) # 是否为强分型
+ 'is_strong_fx': bool(point['is_strong_fx']), # 是否为强分型
+ # 分型框(虚线矩形)用到的高低价
+ 'high': float(point['high']) if point.get('high') is not None else None,
+ 'low': float(point['low']) if point.get('low') is not None else None
} for point in element_analysis['klc_fx_info']]
# 添加次周期ChanMACD分析数据
@@ -1619,6 +1662,9 @@ def analyze():
sub_sub_df = add_indicators(sub_sub_df)
sub_sub_analysis = analyze_chan(sub_sub_df, symbol, sub_sub_timeframe)
result['sub_sub_timeframe'] = sub_sub_timeframe
+ result['sub_sub_kline_data'] = clean_dataframe_for_json(sub_sub_df).to_dict('records')
+ result['sub_sub_atr'] = sub_sub_df['atr'].tolist()
+ result['sub_sub_macd'] = calculate_macd(sub_sub_df)
result['sub_sub_bi_list'] = [{
'start_time': bi.start_klc.end_time if isinstance(bi.start_klc.end_time, str) else bi.start_klc.end_time.astimezone(client_tz).isoformat(),
'end_time': (bi.end_klc.end_time if isinstance(bi.end_klc.end_time, str) else bi.end_klc.end_time.astimezone(client_tz).isoformat()) if bi.end_klc else None,
@@ -1637,6 +1683,20 @@ def analyze():
'direction': convert_direction(bi.dir),
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
} for bi in sub_sub_analysis['bi_list'] if not bi.end_klc]
+ # 次次周期 KLC 列表
+ result['sub_sub_klc_list'] = [{
+ 'date': klc.end_time if isinstance(klc.end_time, str) else klc.end_time.astimezone(client_tz).isoformat(),
+ 'open': float(klc.open),
+ 'high': float(klc.high),
+ 'low': float(klc.low),
+ 'close': float(klc.close),
+ 'volume': float(klc.volume) if hasattr(klc, 'volume') else 0,
+ 'direction': str(klc.dir).replace('Chan_KLINE_DIR.', ''),
+ 'fx_type': str(klc.fx).replace('Chan_FX_TYPE.', ''),
+ 'klc_fx_type': str(klc.klc_fx_type).replace('Chan_KLC_FX.', ''),
+ 'trend': str(klc.trend).replace('Chan_PRICE_TREND.', '')
+ } for klc in sub_sub_analysis.get('klc_list', []) if hasattr(klc, 'end_time') and klc.end_time]
+
result['sub_sub_seg_list'] = [{
'start_time': seg.start_bi.start_klc.end_time if isinstance(seg.start_bi.start_klc.end_time, str) else seg.start_bi.start_klc.end_time.astimezone(client_tz).isoformat(),
'end_time': (seg.end_bi.end_klc.end_time if isinstance(seg.end_bi.end_klc.end_time, str) else seg.end_bi.end_klc.end_time.astimezone(client_tz).isoformat()) if seg.end_bi else None,
@@ -1674,12 +1734,17 @@ def analyze():
} for zs in sub_sub_analysis.get('bi_zs_list', []) if not getattr(zs, 'is_sure', False)]
result['sub_sub_klc_fx_info'] = [{
'time': format_time_safely(point['time'], client_tz),
+ 'start_time': format_time_safely(point['start_time'], client_tz),
+ 'end_time': format_time_safely(point['end_time'], client_tz),
'price': float(point['price']),
'fx_type': point['fx_type'],
'is_bottom': bool(point['is_bottom']),
'fx_strength': float(point['fx_strength']),
'fx_strength_level': str(point['fx_strength_level']),
- 'is_strong_fx': bool(point['is_strong_fx'])
+ 'is_strong_fx': bool(point['is_strong_fx']),
+ # 分型框(虚线矩形)用到的高低价
+ 'high': float(point['high']) if point.get('high') is not None else None,
+ 'low': float(point['low']) if point.get('low') is not None else None
} for point in sub_sub_analysis['klc_fx_info']]
result['sub_sub_bsp_list'] = [{
'time': format_time_safely(bsp.end_time, client_tz),
diff --git a/web/templates/index.html b/web/templates/index.html
index 8207afe..9940e5c 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -851,6 +851,10 @@
+
+
+
+
-
+
-
+
-
+