添加识别笔破坏

This commit is contained in:
jackyu66git
2026-02-28 19:27:36 +08:00
parent a7ab32133b
commit d8f2269a49
3 changed files with 302 additions and 12 deletions
+1
View File
@@ -316,6 +316,7 @@ class ChanKLC():
#if ema_name: #if ema_name:
#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)
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):
+289
View File
@@ -891,6 +891,293 @@ class TF_DF():
return seg_list return seg_list
def cal_bi_list(self, klc_list): def cal_bi_list(self, klc_list):
bi_list = []
last_top = None
last_bottom = None
bi_klc_min = 4
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:
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
"""
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
"""
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:
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
#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:
# 不满足结合律的分型
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_fx(Chan_FX_TYPE.PTOP)
bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1])
# New TOP Found没有意义,前面的UKNOWN已经出现TOP7
else:
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])
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)
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])
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])
#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:
# 不满足结合律的分型
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])
# 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])
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)
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")
return bi_list
def cal_bi_list1(self, klc_list):
bi_list = [] bi_list = []
last_top = None last_top = None
last_bottom = None last_bottom = None
@@ -914,6 +1201,7 @@ class TF_DF():
last_bi = bi_list[-1] 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") #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_top and last_bi.dir == Chan_BI_DIR.DOWN:
print("fx=unknown, 1")
if last_bottom and klc.high > last_bi.high: if last_bottom and klc.high > last_bi.high:
last_bi.set_end_klc(last_bottom, klc) last_bi.set_end_klc(last_bottom, klc)
bi = ChanBI(last_bottom, len(bi_list), Chan_BI_DIR.UP) bi = ChanBI(last_bottom, len(bi_list), Chan_BI_DIR.UP)
@@ -928,6 +1216,7 @@ class TF_DF():
klc.set_bi(bi) klc.set_bi(bi)
#print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low, bi.is_sure) #print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low, bi.is_sure)
else: else:
print("fx=unknown, 2")
if last_bottom and last_bi.dir == Chan_BI_DIR.UP: if last_bottom and last_bi.dir == Chan_BI_DIR.UP:
if last_top and klc.low < last_bi.low: if last_top and klc.low < last_bi.low:
last_bi.set_end_klc(last_top, klc) last_bi.set_end_klc(last_top, klc)
+12 -12
View File
@@ -1243,7 +1243,7 @@
r.close, r.close,
r.ema5, r.ema5,
r.ema10, r.ema10,
r.ema24, r.ema26,
r.ema52, r.ema52,
`<button class="btn btn-sm btn-outline-primary" data-symbol="${r.symbol}" data-timeframe="${timeframe}">查看</button>` `<button class="btn btn-sm btn-outline-primary" data-symbol="${r.symbol}" data-timeframe="${timeframe}">查看</button>`
]); ]);
@@ -1284,7 +1284,7 @@
trendDetailTable.row.add([ trendDetailTable.row.add([
new Date(row.timestamp).toLocaleString('zh-CN', { timeZone: data.timezone }), new Date(row.timestamp).toLocaleString('zh-CN', { timeZone: data.timezone }),
row.open, row.high, row.low, row.close, row.volume, row.open, row.high, row.low, row.close, row.volume,
row.ema5, row.ema10, row.ema24, row.ema52 row.ema5, row.ema10, row.ema26, row.ema52
]); ]);
}); });
trendDetailTable.draw(); trendDetailTable.draw();
@@ -1317,7 +1317,7 @@
// 关闭均线的价格线与最后值标签,仅保留K线的当前价格虚线 // 关闭均线的价格线与最后值标签,仅保留K线的当前价格虚线
const ema5 = chart.addLineSeries({ color: '#ff0000', lineWidth: 2, lastValueVisible: false, priceLineVisible: false }); const ema5 = chart.addLineSeries({ color: '#ff0000', lineWidth: 2, lastValueVisible: false, priceLineVisible: false });
const ema10 = chart.addLineSeries({ color: '#2962FF', lineWidth: 2, lastValueVisible: false, priceLineVisible: false }); const ema10 = chart.addLineSeries({ color: '#2962FF', lineWidth: 2, lastValueVisible: false, priceLineVisible: false });
const ema24 = chart.addLineSeries({ color: '#008000', lineWidth: 2, lastValueVisible: false, priceLineVisible: false }); const ema26 = chart.addLineSeries({ color: '#008000', lineWidth: 2, lastValueVisible: false, priceLineVisible: false });
const ema52 = chart.addLineSeries({ color: '#800080', lineWidth: 2, lastValueVisible: false, priceLineVisible: false }); const ema52 = chart.addLineSeries({ color: '#800080', lineWidth: 2, lastValueVisible: false, priceLineVisible: false });
const k = (data.kline_data || []).map(r => ({ const k = (data.kline_data || []).map(r => ({
@@ -1347,7 +1347,7 @@
}; };
ema5.setData(sanitizeMA('ema5')); ema5.setData(sanitizeMA('ema5'));
ema10.setData(sanitizeMA('ema10')); ema10.setData(sanitizeMA('ema10'));
ema24.setData(sanitizeMA('ema24')); ema26.setData(sanitizeMA('ema26'));
ema52.setData(sanitizeMA('ema52')); ema52.setData(sanitizeMA('ema52'));
// 趋势线(使用返回的拟合参数) // 趋势线(使用返回的拟合参数)
@@ -1400,12 +1400,12 @@
function classifyStageFrontend(kline, directionHint) { function classifyStageFrontend(kline, directionHint) {
const close = kline.map(r => Number(r.close)); const close = kline.map(r => Number(r.close));
const ema24 = computeEMA(close, 24); const ema26 = computeEMA(close, 26);
const ema52 = computeEMA(close, 52); const ema52 = computeEMA(close, 52);
const last = close[close.length-1]; const last = close[close.length-1];
const e24 = ema24[ema24.length-1]; const e26 = ema26[ema26.length-1];
const e52 = ema52[ema52.length-1]; const e52 = ema52[ema52.length-1];
const s24 = slope(ema24, 20); const s26 = slope(ema26, 20);
const s52 = slope(ema52, 30); const s52 = slope(ema52, 30);
const dist52 = (e52 && isFinite(e52)) ? (last - e52)/e52 : 0; const dist52 = (e52 && isFinite(e52)) ? (last - e52)/e52 : 0;
const { hist } = computeMACDSeries(close); const { hist } = computeMACDSeries(close);
@@ -1417,8 +1417,8 @@
let direction = directionHint; let direction = directionHint;
if (!direction) { if (!direction) {
if (e24 > e52 && s24 > 0 && s52 > 0) direction = 'bull'; if (e26 > e52 && s26 > 0 && s52 > 0) direction = 'bull';
else if (e24 < e52 && s24 < 0 && s52 < 0) direction = 'bear'; else if (e26 < e52 && s26 < 0 && s52 < 0) direction = 'bear';
else direction = 'sideways'; else direction = 'sideways';
} }
@@ -1426,11 +1426,11 @@
const ad = Math.abs(dist52); const ad = Math.abs(dist52);
if (direction === 'bull') { if (direction === 'bull') {
if (ad < 0.03 && growth > 0) stage = 'early'; if (ad < 0.03 && growth > 0) stage = 'early';
else if (ad < 0.10 && (growth >= 0 || s24 > 0)) stage = 'mid'; else if (ad < 0.10 && (growth >= 0 || s26 > 0)) stage = 'mid';
else stage = 'late'; else stage = 'late';
} else if (direction === 'bear') { } else if (direction === 'bear') {
if (ad < 0.03 && growth > 0) stage = 'early'; if (ad < 0.03 && growth > 0) stage = 'early';
else if (ad < 0.10 && (growth >= 0 || s24 < 0)) stage = 'mid'; else if (ad < 0.10 && (growth >= 0 || s26 < 0)) stage = 'mid';
else stage = 'late'; else stage = 'late';
} else { } else {
stage = 'early'; stage = 'early';
@@ -6035,7 +6035,7 @@
const defaultMAs = [ const defaultMAs = [
{ type: 'EMA', length: 52, color: '#800080', name: 'EMA52' }, // 紫色 { type: 'EMA', length: 52, color: '#800080', name: 'EMA52' }, // 紫色
{ type: 'EMA', length: 24, color: '#008000', name: 'EMA24' }, // 深绿色 { type: 'EMA', length: 26, color: '#008000', name: 'EMA26' }, // 深绿色
{ type: 'EMA', length: 104, color: '#FF8C00', name: 'EMA104' }, // 橙色 { type: 'EMA', length: 104, color: '#FF8C00', name: 'EMA104' }, // 橙色
{ type: 'EMA', length: 156, color: '#1E90FF', name: 'EMA156' }, // 蓝色 { type: 'EMA', length: 156, color: '#1E90FF', name: 'EMA156' }, // 蓝色
{ type: 'EMA', length: 208, color: '#1F004F', name: 'EMA312' } // 蓝色 { type: 'EMA', length: 208, color: '#1F004F', name: 'EMA312' } // 蓝色