添加识别中继分型
This commit is contained in:
+37
-1
@@ -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
|
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 ChanKLU
|
||||||
import ChanCTime
|
import ChanCTime
|
||||||
|
import Chan_FX_Box
|
||||||
# 根据结合律合并K线后的K线
|
# 根据结合律合并K线后的K线
|
||||||
class ChanKLC():
|
class ChanKLC():
|
||||||
def __init__(self, klu: ChanKLU, index, ddir=Chan_KLINE_DIR.UP):
|
def __init__(self, klu: ChanKLU, index, ddir=Chan_KLINE_DIR.UP):
|
||||||
@@ -51,6 +51,8 @@ class ChanKLC():
|
|||||||
self.ema104 = klu.ema104
|
self.ema104 = klu.ema104
|
||||||
self.ema156 = klu.ema156
|
self.ema156 = klu.ema156
|
||||||
self.ema208 = klu.ema208
|
self.ema208 = klu.ema208
|
||||||
|
self.ema13 = klu.ema13
|
||||||
|
self.ema7 = klu.ema7
|
||||||
self.trend = Chan_PRICE_TREND.UNKNOWN
|
self.trend = Chan_PRICE_TREND.UNKNOWN
|
||||||
self.exception = klu.exception
|
self.exception = klu.exception
|
||||||
self.klc_dir = Chan_KLINE_DIR.UP if klu.close > klu.open else Chan_KLINE_DIR.DOWN
|
self.klc_dir = Chan_KLINE_DIR.UP if klu.close > klu.open else Chan_KLINE_DIR.DOWN
|
||||||
@@ -67,6 +69,7 @@ class ChanKLC():
|
|||||||
self.bb2633middle = klu.bb2633middle
|
self.bb2633middle = klu.bb2633middle
|
||||||
self.ema5 = klu.ema5
|
self.ema5 = klu.ema5
|
||||||
self.ma5 = klu.ma5
|
self.ma5 = klu.ma5
|
||||||
|
self.fx_box = None
|
||||||
# ==================== EMA 通用计算方法 ====================
|
# ==================== EMA 通用计算方法 ====================
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -320,6 +323,35 @@ class ChanKLC():
|
|||||||
#print(self.end_time, ema_name, self.ema_status[ema_name]['semantic'], hist_div)
|
#print(self.end_time, ema_name, self.ema_status[ema_name]['semantic'], hist_div)
|
||||||
#self.cal_bb_out()
|
#self.cal_bb_out()
|
||||||
#print(self.pre.start_time, self.next.end_time, self.klc_fx_type)
|
#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:
|
||||||
|
if self.fx == Chan_FX_TYPE.TOP:
|
||||||
|
start_time = self.pre.start_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.open:
|
||||||
|
display = True
|
||||||
|
elif self.fx == Chan_FX_TYPE.BOTTOM:
|
||||||
|
start_time = self.pre.start_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.open:
|
||||||
|
display = True
|
||||||
|
if high > 0 and display:
|
||||||
|
print(start_time, end_time, high, low)
|
||||||
|
# Chan_FX_BOX 这里导入的是模块,类名在模块内部为 Chan_FX_Box
|
||||||
|
self.fx_box = Chan_FX_Box.Chan_FX_Box(start_time, end_time, high, low)
|
||||||
def add_klu(self, klu):
|
def add_klu(self, klu):
|
||||||
self.klu_list.append(klu)
|
self.klu_list.append(klu)
|
||||||
def set_end_klu(self, klu):
|
def set_end_klu(self, klu):
|
||||||
@@ -397,6 +429,8 @@ class ChanKLC():
|
|||||||
self.ema104 += self.klu_list[index].ema104
|
self.ema104 += self.klu_list[index].ema104
|
||||||
self.ema156 += self.klu_list[index].ema156
|
self.ema156 += self.klu_list[index].ema156
|
||||||
self.ema208 += self.klu_list[index].ema208
|
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.bb2633upper += self.klu_list[index].bb2633upper
|
||||||
self.bb2633lower += self.klu_list[index].bb2633lower
|
self.bb2633lower += self.klu_list[index].bb2633lower
|
||||||
self.bb2633middle += self.klu_list[index].bb2633middle
|
self.bb2633middle += self.klu_list[index].bb2633middle
|
||||||
@@ -415,6 +449,8 @@ class ChanKLC():
|
|||||||
self.ema104 = self.ema104 / n
|
self.ema104 = self.ema104 / n
|
||||||
self.ema156 = self.ema156 / n
|
self.ema156 = self.ema156 / n
|
||||||
self.ema208 = self.ema208 / n
|
self.ema208 = self.ema208 / n
|
||||||
|
self.ema13 = self.ema13 / n
|
||||||
|
self.ema7 = self.ema7 / n
|
||||||
self.ma5 = self.ma5 / n
|
self.ma5 = self.ma5 / n
|
||||||
self.ema5 = self.ema5 / n
|
self.ema5 = self.ema5 / n
|
||||||
self.bb2633upper = self.bb2633upper / n
|
self.bb2633upper = self.bb2633upper / n
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ class ChanKLU:
|
|||||||
self.ema104 = float(item['ema104']) if 'ema104' in item and item['ema104'] else 0
|
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.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.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.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.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
|
self.bb52upper = float(item['bb52upper']) if 'bb52upper' in item and item['bb52upper'] else 0
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class ChanMACDHistSet():
|
|||||||
self.start_klu = start_klu
|
self.start_klu = start_klu
|
||||||
self.peak_div_list = []
|
self.peak_div_list = []
|
||||||
self.middle_area = 0
|
self.middle_area = 0
|
||||||
|
self.total_macdhist = 0
|
||||||
def set_next(self, next_histset):
|
def set_next(self, next_histset):
|
||||||
self.next = next_histset
|
self.next = next_histset
|
||||||
def set_pre(self, pre_histset):
|
def set_pre(self, pre_histset):
|
||||||
@@ -102,6 +103,15 @@ class ChanMACDHistSet():
|
|||||||
for peak_div in self.peak_div_list:
|
for peak_div in self.peak_div_list:
|
||||||
peak_str += f"{peak_div.time}, "
|
peak_str += f"{peak_div.time}, "
|
||||||
state_str += f"{peak_div.macd_state}, "
|
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:
|
#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)
|
#print("Continue Div: ",self.start_time, "Peak:", self.peak_klu.time, "Div: ", peak_str, state_str)
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -122,6 +122,8 @@ class TF_DF():
|
|||||||
df['ema156'] = ta.EMA(df, timeperiod=156)
|
df['ema156'] = ta.EMA(df, timeperiod=156)
|
||||||
df['ema208'] = ta.EMA(df, timeperiod=208)
|
df['ema208'] = ta.EMA(df, timeperiod=208)
|
||||||
df['ema26'] = ta.EMA(df, timeperiod=26)
|
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['rsi'] = ta.RSI(df, timeperiod=14)
|
||||||
df['volume_ratio'] = self.cal_volume_ratio(df)
|
df['volume_ratio'] = self.cal_volume_ratio(df)
|
||||||
return df
|
return df
|
||||||
@@ -1001,7 +1003,7 @@ class TF_DF():
|
|||||||
# 不满足结合律的分型
|
# 不满足结合律的分型
|
||||||
else:
|
else:
|
||||||
#klc.set_klc_fx_type(Chan_KLC_FX.TOP0)
|
#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_bottom.index + bi_klc_min > klc.index:
|
||||||
if last_top.high > klc.high:
|
if last_top.high > klc.high:
|
||||||
#print(klc.start_time, klc.fx, "二类卖点Sell 1")
|
#print(klc.start_time, klc.fx, "二类卖点Sell 1")
|
||||||
@@ -1213,331 +1215,29 @@ class TF_DF():
|
|||||||
klc.set_bi(bi_list[-1])
|
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, bi_list[-1].dir, "Last Bottom Change 5")
|
||||||
#print(klc.start_time, klc.fx, "笔买点Buy 4")
|
#print(klc.start_time, klc.fx, "笔买点Buy 4")
|
||||||
|
self.get_above_zero_bsp(klc_list)
|
||||||
return bi_list
|
return bi_list
|
||||||
def cal_bi_list1(self, klc_list):
|
def get_above_zero_bsp(self, klc_list):
|
||||||
bi_list = []
|
buy_bsp_list = []
|
||||||
last_top = None
|
sell_bsp_list = []
|
||||||
last_bottom = None
|
above_zero = False
|
||||||
|
buy_bsp = None
|
||||||
|
sell_bsp = None
|
||||||
for klc in klc_list:
|
for klc in klc_list:
|
||||||
fx = self.check_fx(klc)
|
if klc.pre and klc.pre.signal < 0 and klc.signal > 0:
|
||||||
if fx == Chan_FX_TYPE.TOP:
|
above_zero = True
|
||||||
if last_bottom:
|
if klc.pre and klc.pre.signal > 0 and klc.signal < 0:
|
||||||
if self.check_top_fx(last_bottom, klc) == False:
|
above_zero = False
|
||||||
fx = Chan_FX_TYPE.UNKNOWN
|
if above_zero and klc.klc_fx_type == Chan_KLC_FX.BOTTOM2 and klc.macd > 0:
|
||||||
if fx == Chan_FX_TYPE.BOTTOM:
|
buy_bsp = klc
|
||||||
if last_top:
|
buy_bsp_list.append(klc)
|
||||||
if self.check_bottom_fx(last_top, klc) == False:
|
#print(klc.end_time, "MACD 0轴上穿,回调笔底分型做多")
|
||||||
#print(klc.end_time, last_top.end_time, "---")
|
if buy_bsp and klc.pre and klc.pre.macdhist > 0 and klc.macdhist < 0:
|
||||||
fx = Chan_FX_TYPE.UNKNOWN
|
sell_bsp = klc
|
||||||
# Do nothing
|
sell_bsp_list.append(klc)
|
||||||
if fx == Chan_FX_TYPE.UNKNOWN:
|
buy_bsp = None
|
||||||
if len(bi_list) > 0:
|
#print(klc.end_time, "Sell BSP Found")
|
||||||
bi_list[-1].add_klc(klc)
|
return buy_bsp_list
|
||||||
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
|
|
||||||
def check_top_fx(self, last_bottom, klc):
|
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):
|
if (last_bottom.high > klc.pre.low or last_bottom.high > klc.next.low) and (klc.index - last_bottom.index < 10):
|
||||||
return False
|
return False
|
||||||
|
|||||||
+67
-5
@@ -439,6 +439,11 @@ def add_indicators(df):
|
|||||||
df['ema24'] = (ta.EMA(df, timeperiod=24)).fillna(0)
|
df['ema24'] = (ta.EMA(df, timeperiod=24)).fillna(0)
|
||||||
df['ema52'] = (ta.EMA(df, timeperiod=52)).fillna(0)
|
df['ema52'] = (ta.EMA(df, timeperiod=52)).fillna(0)
|
||||||
df['ema26'] = (ta.EMA(df, timeperiod=26)).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
|
# 常用SMA 24/52
|
||||||
try:
|
try:
|
||||||
df['sma24'] = (ta.SMA(df, timeperiod=24)).fillna(0)
|
df['sma24'] = (ta.SMA(df, timeperiod=24)).fillna(0)
|
||||||
@@ -624,6 +629,16 @@ def analyze_chan(df, symbol=None, timeframe=None):
|
|||||||
# 如果分型强度小于1,设为0
|
# 如果分型强度小于1,设为0
|
||||||
if fx_strength < 1:
|
if fx_strength < 1:
|
||||||
fx_strength = 0
|
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:
|
if klc.bb_out:
|
||||||
klc_fx_info.append({
|
klc_fx_info.append({
|
||||||
'time': klc.end_time,
|
'time': klc.end_time,
|
||||||
@@ -632,10 +647,22 @@ def analyze_chan(df, symbol=None, timeframe=None):
|
|||||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||||
'fx_strength': fx_strength, # 分型强度分数 (0-100)
|
'fx_strength': fx_strength, # 分型强度分数 (0-100)
|
||||||
'fx_strength_level': fx_strength_level, # 分型强度等级 (极强/强/中等/弱/极弱)
|
'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:
|
except Exception as e:
|
||||||
# 如果出错,仍然添加基本信息,但分型强度为0
|
# 如果出错,仍然添加基本信息,但分型强度为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({
|
klc_fx_info.append({
|
||||||
'time': klc.end_time,
|
'time': klc.end_time,
|
||||||
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
|
'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,
|
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||||
'fx_strength': 0,
|
'fx_strength': 0,
|
||||||
'fx_strength_level': "",
|
'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线分型信息
|
# 添加K线分型信息
|
||||||
'klc_fx_info': [{
|
'klc_fx_info': [{
|
||||||
'time': format_time_safely(point['time'], client_tz),
|
'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']),
|
'price': float(point['price']),
|
||||||
'fx_type': point['fx_type'],
|
'fx_type': point['fx_type'],
|
||||||
'is_bottom': bool(point['is_bottom']),
|
'is_bottom': bool(point['is_bottom']),
|
||||||
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
||||||
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
|
'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']],
|
} for point in analysis_result['klc_fx_info']],
|
||||||
# 添加ChanMACD分析数据
|
# 添加ChanMACD分析数据
|
||||||
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz),
|
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz),
|
||||||
@@ -1587,12 +1625,17 @@ def analyze():
|
|||||||
# 添加小周期分型信息
|
# 添加小周期分型信息
|
||||||
result['element_klc_fx_info'] = [{
|
result['element_klc_fx_info'] = [{
|
||||||
'time': format_time_safely(point['time'], client_tz),
|
'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']),
|
'price': float(point['price']),
|
||||||
'fx_type': point['fx_type'],
|
'fx_type': point['fx_type'],
|
||||||
'is_bottom': bool(point['is_bottom']),
|
'is_bottom': bool(point['is_bottom']),
|
||||||
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
||||||
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
|
'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']]
|
} for point in element_analysis['klc_fx_info']]
|
||||||
|
|
||||||
# 添加次周期ChanMACD分析数据
|
# 添加次周期ChanMACD分析数据
|
||||||
@@ -1640,6 +1683,20 @@ def analyze():
|
|||||||
'direction': convert_direction(bi.dir),
|
'direction': convert_direction(bi.dir),
|
||||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
'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]
|
} 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'] = [{
|
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(),
|
'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,
|
'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,
|
||||||
@@ -1677,12 +1734,17 @@ def analyze():
|
|||||||
} for zs in sub_sub_analysis.get('bi_zs_list', []) if not getattr(zs, 'is_sure', False)]
|
} for zs in sub_sub_analysis.get('bi_zs_list', []) if not getattr(zs, 'is_sure', False)]
|
||||||
result['sub_sub_klc_fx_info'] = [{
|
result['sub_sub_klc_fx_info'] = [{
|
||||||
'time': format_time_safely(point['time'], client_tz),
|
'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']),
|
'price': float(point['price']),
|
||||||
'fx_type': point['fx_type'],
|
'fx_type': point['fx_type'],
|
||||||
'is_bottom': bool(point['is_bottom']),
|
'is_bottom': bool(point['is_bottom']),
|
||||||
'fx_strength': float(point['fx_strength']),
|
'fx_strength': float(point['fx_strength']),
|
||||||
'fx_strength_level': str(point['fx_strength_level']),
|
'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']]
|
} for point in sub_sub_analysis['klc_fx_info']]
|
||||||
result['sub_sub_bsp_list'] = [{
|
result['sub_sub_bsp_list'] = [{
|
||||||
'time': format_time_safely(bsp.end_time, client_tz),
|
'time': format_time_safely(bsp.end_time, client_tz),
|
||||||
|
|||||||
+251
-41
@@ -5817,6 +5817,64 @@
|
|||||||
|
|
||||||
allMainFxMarkers.push(markerConfig);
|
allMainFxMarkers.push(markerConfig);
|
||||||
|
|
||||||
|
// 画虚线分型框(根据 start/end + high/low)
|
||||||
|
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||||
|
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||||
|
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||||
|
const high = parseFloat(fx.high);
|
||||||
|
const low = parseFloat(fx.low);
|
||||||
|
|
||||||
|
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||||
|
const boxHigh = Math.max(high, low);
|
||||||
|
const boxLow = Math.min(high, low);
|
||||||
|
const boxColor = strengthColor;
|
||||||
|
|
||||||
|
const topSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2, // 虚线
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const bottomSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2, // 虚线
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||||
|
|
||||||
|
const leftSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2, // 虚线
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
// 左边竖线:同一 time 上下两个点(和你已有ZS绘制写法保持一致)
|
||||||
|
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const rightSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2, // 虚线
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
if (!tvWidget.series.mainKlcFxBoxSeries) tvWidget.series.mainKlcFxBoxSeries = [];
|
||||||
|
tvWidget.series.mainKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建分型标记对象,包含tooltip信息
|
// 创建分型标记对象,包含tooltip信息
|
||||||
const fxMarker = {
|
const fxMarker = {
|
||||||
time: timestamp,
|
time: timestamp,
|
||||||
@@ -5966,6 +6024,63 @@
|
|||||||
|
|
||||||
allElementFxMarkers.push(markerConfig);
|
allElementFxMarkers.push(markerConfig);
|
||||||
|
|
||||||
|
// 画虚线分型框(小周期)
|
||||||
|
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||||
|
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||||
|
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||||
|
const high = parseFloat(fx.high);
|
||||||
|
const low = parseFloat(fx.low);
|
||||||
|
|
||||||
|
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||||
|
const boxHigh = Math.max(high, low);
|
||||||
|
const boxLow = Math.min(high, low);
|
||||||
|
const boxColor = strengthColor;
|
||||||
|
|
||||||
|
const topSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const bottomSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||||
|
|
||||||
|
const leftSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const rightSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
if (!tvWidget.series.elementKlcFxBoxSeries) tvWidget.series.elementKlcFxBoxSeries = [];
|
||||||
|
tvWidget.series.elementKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建小周期分型标记对象,包含tooltip信息
|
// 创建小周期分型标记对象,包含tooltip信息
|
||||||
const elementFxMarker = {
|
const elementFxMarker = {
|
||||||
time: timestamp,
|
time: timestamp,
|
||||||
@@ -6061,6 +6176,63 @@
|
|||||||
size: (fx.is_strong_fx ? 0.6 : 0.5)
|
size: (fx.is_strong_fx ? 0.6 : 0.5)
|
||||||
};
|
};
|
||||||
allElementFxMarkers.push(markerConfig);
|
allElementFxMarkers.push(markerConfig);
|
||||||
|
|
||||||
|
// 画虚线分型框(次次周期)
|
||||||
|
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||||
|
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||||
|
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||||
|
const high = parseFloat(fx.high);
|
||||||
|
const low = parseFloat(fx.low);
|
||||||
|
|
||||||
|
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||||
|
const boxHigh = Math.max(high, low);
|
||||||
|
const boxLow = Math.min(high, low);
|
||||||
|
const boxColor = strengthColor;
|
||||||
|
|
||||||
|
const topSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const bottomSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||||
|
|
||||||
|
const leftSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
const rightSeries = mainChart.addLineSeries({
|
||||||
|
color: boxColor,
|
||||||
|
lineWidth: 1,
|
||||||
|
lineStyle: 2,
|
||||||
|
lastValueVisible: false,
|
||||||
|
priceLineVisible: false,
|
||||||
|
crosshairMarkerVisible: false,
|
||||||
|
});
|
||||||
|
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||||
|
|
||||||
|
if (!tvWidget.series.subSubKlcFxBoxSeries) tvWidget.series.subSubKlcFxBoxSeries = [];
|
||||||
|
tvWidget.series.subSubKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) { console.error('绘制次次周期KLC分型标记出错:', e); }
|
} catch (e) { console.error('绘制次次周期KLC分型标记出错:', e); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -6200,7 +6372,11 @@
|
|||||||
else if (klineType === 'baseline') targetSeries = tvWidget.series.baselineSeries;
|
else if (klineType === 'baseline') targetSeries = tvWidget.series.baselineSeries;
|
||||||
else if (klineType === 'klc') targetSeries = tvWidget.series.klcSeries;
|
else if (klineType === 'klc') targetSeries = tvWidget.series.klcSeries;
|
||||||
if (targetSeries) {
|
if (targetSeries) {
|
||||||
|
try {
|
||||||
targetSeries.setMarkers(combinedMarkers);
|
targetSeries.setMarkers(combinedMarkers);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('设置主系列标记失败(可能series已释放):', e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('未找到主数据系列,无法设置标记');
|
console.log('未找到主数据系列,无法设置标记');
|
||||||
}
|
}
|
||||||
@@ -6324,7 +6500,11 @@
|
|||||||
else if (klineType2 === 'baseline') targetSeries2 = tvWidget.series.baselineSeries;
|
else if (klineType2 === 'baseline') targetSeries2 = tvWidget.series.baselineSeries;
|
||||||
else if (klineType2 === 'klc') targetSeries2 = tvWidget.series.klcSeries;
|
else if (klineType2 === 'klc') targetSeries2 = tvWidget.series.klcSeries;
|
||||||
if (targetSeries2) {
|
if (targetSeries2) {
|
||||||
|
try {
|
||||||
targetSeries2.setMarkers(onlyMainAndU);
|
targetSeries2.setMarkers(onlyMainAndU);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('设置主系列标记失败(可能series已释放):', e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('未找到主数据系列,无法设置标记');
|
console.log('未找到主数据系列,无法设置标记');
|
||||||
}
|
}
|
||||||
@@ -6342,7 +6522,11 @@
|
|||||||
else if (klineType3 === 'baseline') targetSeries3 = tvWidget.series.baselineSeries;
|
else if (klineType3 === 'baseline') targetSeries3 = tvWidget.series.baselineSeries;
|
||||||
else if (klineType3 === 'klc') targetSeries3 = tvWidget.series.klcSeries;
|
else if (klineType3 === 'klc') targetSeries3 = tvWidget.series.klcSeries;
|
||||||
if (targetSeries3) {
|
if (targetSeries3) {
|
||||||
|
try {
|
||||||
targetSeries3.setMarkers([]);
|
targetSeries3.setMarkers([]);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('清空主系列标记失败(可能series已释放):', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6552,15 +6736,33 @@
|
|||||||
// 检查是否显示原始K线
|
// 检查是否显示原始K线
|
||||||
const showOriginalKline = $('#showOriginalKline').is(':checked');
|
const showOriginalKline = $('#showOriginalKline').is(':checked');
|
||||||
|
|
||||||
// 检查是否使用小周期数据
|
// 检查是否使用次次周期 / 小周期数据
|
||||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||||
|
currentData.sub_sub_timeframe &&
|
||||||
|
currentData.sub_sub_kline_data &&
|
||||||
|
Array.isArray(currentData.sub_sub_kline_data);
|
||||||
|
const useElementPeriod = !useSubSubPeriod &&
|
||||||
|
$('#elementPeriodKline').is(':checked') &&
|
||||||
currentData.element_timeframe &&
|
currentData.element_timeframe &&
|
||||||
currentData.element_kline_data &&
|
currentData.element_kline_data &&
|
||||||
Array.isArray(currentData.element_kline_data);
|
Array.isArray(currentData.element_kline_data);
|
||||||
|
|
||||||
// 转换K线数据
|
// 转换K线数据
|
||||||
let candles = [];
|
let candles = [];
|
||||||
if (useElementPeriod) {
|
if (useSubSubPeriod) {
|
||||||
|
console.log('使用次次周期K线数据');
|
||||||
|
candles = currentData.sub_sub_kline_data.map((kline) => {
|
||||||
|
const date = new Date(kline.date);
|
||||||
|
const timestamp = date.getTime() / 1000;
|
||||||
|
return {
|
||||||
|
time: timestamp,
|
||||||
|
open: parseFloat(kline.open),
|
||||||
|
high: parseFloat(kline.high),
|
||||||
|
low: parseFloat(kline.low),
|
||||||
|
close: parseFloat(kline.close),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else if (useElementPeriod) {
|
||||||
console.log('使用小周期K线数据');
|
console.log('使用小周期K线数据');
|
||||||
candles = currentData.element_kline_data.map((kline) => {
|
candles = currentData.element_kline_data.map((kline) => {
|
||||||
const date = new Date(kline.date);
|
const date = new Date(kline.date);
|
||||||
@@ -6622,7 +6824,16 @@
|
|||||||
|
|
||||||
// 更新成交量数据
|
// 更新成交量数据
|
||||||
let volumes = [];
|
let volumes = [];
|
||||||
if (useElementPeriod && currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) {
|
if (useSubSubPeriod && currentData.sub_sub_kline_data && Array.isArray(currentData.sub_sub_kline_data)) {
|
||||||
|
volumes = currentData.sub_sub_kline_data.map(kline => {
|
||||||
|
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||||
|
return {
|
||||||
|
time: timestamp,
|
||||||
|
value: parseFloat(kline.volume),
|
||||||
|
color: parseFloat(kline.close) >= parseFloat(kline.open) ? 'rgba(40, 167, 69, 0.5)' : 'rgba(220, 53, 69, 0.5)',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else if (useElementPeriod && currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) {
|
||||||
volumes = currentData.element_kline_data.map(kline => {
|
volumes = currentData.element_kline_data.map(kline => {
|
||||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||||
return {
|
return {
|
||||||
@@ -6649,9 +6860,9 @@
|
|||||||
// 更新ATR数据
|
// 更新ATR数据
|
||||||
if (tvWidget.series.atrLineSeries) {
|
if (tvWidget.series.atrLineSeries) {
|
||||||
const atrData = [];
|
const atrData = [];
|
||||||
const atrDataSource = useElementPeriod ?
|
const atrDataSource = useSubSubPeriod ?
|
||||||
(currentData.element_atr || currentData.atr) :
|
(currentData.sub_sub_atr || currentData.atr) :
|
||||||
currentData.atr;
|
(useElementPeriod ? (currentData.element_atr || currentData.atr) : currentData.atr);
|
||||||
|
|
||||||
if (atrDataSource && Array.isArray(atrDataSource)) {
|
if (atrDataSource && Array.isArray(atrDataSource)) {
|
||||||
const klineDataSource = useSubSubPeriod ? (currentData.sub_sub_kline_data || []) : (useElementPeriod ? currentData.element_kline_data : currentData.kline_data);
|
const klineDataSource = useSubSubPeriod ? (currentData.sub_sub_kline_data || []) : (useElementPeriod ? currentData.element_kline_data : currentData.kline_data);
|
||||||
@@ -9187,44 +9398,39 @@
|
|||||||
try { updateIndicatorPanel(); } catch(e) {}
|
try { updateIndicatorPanel(); } catch(e) {}
|
||||||
try { if ($('#maConfigModal').is(':visible')) { hideMAConfig(); } } catch(e) {}
|
try { if ($('#maConfigModal').is(':visible')) { hideMAConfig(); } } catch(e) {}
|
||||||
}
|
}
|
||||||
// 获取当前K线数据的辅助函数
|
// 获取当前K线数据的辅助函数(与基础显示的主/小/次次周期保持一致)
|
||||||
function getCurrentCandleData() {
|
function getCurrentCandleData() {
|
||||||
if (!currentData || !currentData.kline_data) {
|
if (!currentData || !currentData.kline_data) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否使用小周期数据
|
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
currentData.sub_sub_kline_data &&
|
||||||
|
Array.isArray(currentData.sub_sub_kline_data);
|
||||||
|
const useElementPeriod = !useSubSubPeriod &&
|
||||||
|
$('#elementPeriodKline').is(':checked') &&
|
||||||
currentData.element_kline_data &&
|
currentData.element_kline_data &&
|
||||||
Array.isArray(currentData.element_kline_data);
|
Array.isArray(currentData.element_kline_data);
|
||||||
|
|
||||||
let candles = [];
|
let source = currentData.kline_data;
|
||||||
if (useElementPeriod) {
|
if (useSubSubPeriod) {
|
||||||
candles = currentData.element_kline_data.map((kline) => {
|
source = currentData.sub_sub_kline_data;
|
||||||
const date = new Date(kline.date);
|
} else if (useElementPeriod) {
|
||||||
const timestamp = date.getTime() / 1000;
|
source = currentData.element_kline_data;
|
||||||
return {
|
|
||||||
time: timestamp,
|
|
||||||
open: parseFloat(kline.open),
|
|
||||||
high: parseFloat(kline.high),
|
|
||||||
low: parseFloat(kline.low),
|
|
||||||
close: parseFloat(kline.close),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
candles = currentData.kline_data.map((kline) => {
|
|
||||||
const date = new Date(kline.date);
|
|
||||||
const timestamp = date.getTime() / 1000;
|
|
||||||
return {
|
|
||||||
time: timestamp,
|
|
||||||
open: parseFloat(kline.open),
|
|
||||||
high: parseFloat(kline.high),
|
|
||||||
low: parseFloat(kline.low),
|
|
||||||
close: parseFloat(kline.close),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const candles = source.map((kline) => {
|
||||||
|
const date = new Date(kline.date);
|
||||||
|
const timestamp = date.getTime() / 1000;
|
||||||
|
return {
|
||||||
|
time: timestamp,
|
||||||
|
open: parseFloat(kline.open),
|
||||||
|
high: parseFloat(kline.high),
|
||||||
|
low: parseFloat(kline.low),
|
||||||
|
close: parseFloat(kline.close),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return candles;
|
return candles;
|
||||||
}
|
}
|
||||||
// 从蜡烛数据生成 Heikin-Ashi(平均K)
|
// 从蜡烛数据生成 Heikin-Ashi(平均K)
|
||||||
@@ -9253,14 +9459,20 @@
|
|||||||
function buildKLCFromAnalysis(data) {
|
function buildKLCFromAnalysis(data) {
|
||||||
if (!data) return [];
|
if (!data) return [];
|
||||||
|
|
||||||
// 检查是否使用小周期数据
|
// 根据基础显示的K线周期选择:次次周期 / 小周期 / 主周期
|
||||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||||
|
data.sub_sub_klc_list &&
|
||||||
|
Array.isArray(data.sub_sub_klc_list);
|
||||||
|
const useElementPeriod = !useSubSubPeriod &&
|
||||||
|
$('#elementPeriodKline').is(':checked') &&
|
||||||
data.element_klc_list &&
|
data.element_klc_list &&
|
||||||
Array.isArray(data.element_klc_list);
|
Array.isArray(data.element_klc_list);
|
||||||
|
|
||||||
const klcList = useElementPeriod ? data.element_klc_list : data.klc_list;
|
const klcList = useSubSubPeriod
|
||||||
|
? data.sub_sub_klc_list
|
||||||
|
: (useElementPeriod ? data.element_klc_list : data.klc_list);
|
||||||
|
|
||||||
if (!klcList) return [];
|
if (!klcList || !Array.isArray(klcList)) return [];
|
||||||
|
|
||||||
const klcCandles = [];
|
const klcCandles = [];
|
||||||
|
|
||||||
@@ -9268,11 +9480,9 @@
|
|||||||
klcList.forEach(klc => {
|
klcList.forEach(klc => {
|
||||||
if (!klc || !klc.date) return;
|
if (!klc || !klc.date) return;
|
||||||
|
|
||||||
// 使用KLC的date字段,转换为时间戳格式
|
|
||||||
const date = new Date(klc.date);
|
const date = new Date(klc.date);
|
||||||
const timestamp = date.getTime() / 1000;
|
const timestamp = date.getTime() / 1000;
|
||||||
|
|
||||||
// 创建KLC蜡烛数据
|
|
||||||
const candle = {
|
const candle = {
|
||||||
time: timestamp,
|
time: timestamp,
|
||||||
open: klc.open || 0,
|
open: klc.open || 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user