添加分型强弱计算,可以直接跑服务了

This commit is contained in:
Porter
2025-05-24 22:42:35 +08:00
parent a9d24233b0
commit cdc40f795c
13 changed files with 365 additions and 13 deletions
+347 -3
View File
@@ -49,6 +49,7 @@ class ChanKLC():
self.volume_ratio = self.volume_ratio / len(self.klus) self.volume_ratio = self.volume_ratio / len(self.klus)
self.volume = self.volume / len(self.klus) self.volume = self.volume / len(self.klus)
self.macdhist = self.macdhist / len(self.klus) self.macdhist = self.macdhist / len(self.klus)
def set_next(self, klc): def set_next(self, klc):
self.next = klc self.next = klc
def set_pre(self, klc): def set_pre(self, klc):
@@ -1132,7 +1133,7 @@ class ChanKLC():
# ===== 分型强度特征 ===== # ===== 分型强度特征 =====
# 添加分型强度相关特征 # 添加分型强度相关特征
features['klc_fx_strength'] = self.calculate_fx_strength() features['klc_fx_strength'] = self.cal_fx_strength()
features['klc_fx_strength_level'] = self.get_fx_strength_level() features['klc_fx_strength_level'] = self.get_fx_strength_level()
features['klc_is_strong_fx'] = 1 if self.is_strong_fx() else 0 features['klc_is_strong_fx'] = 1 if self.is_strong_fx() else 0
@@ -1146,6 +1147,269 @@ class ChanKLC():
return features return features
def cal_fx_strength(self):
"""
用self.pre和self.next实现分型强弱判断
核心缠论原理:
- 强分型:出现在笔的末端,能够终结当前笔,标志着趋势转折
- 弱分型:出现在笔的中间,是中继性质,笔还会继续延伸
返回值:
3: 极强分型(笔终结+强确认)
2: 强分型(笔终结)
1: 偏强分型(可能终结笔)
0: 中性分型
-1: 偏弱分型(中继特征明显)
-2: 弱分型(明显中继)
-3: 极弱分型(无效分型)
"""
# 检查是否为分型,且有前后K线数据
if self.fx == Chan_FX_TYPE.UNKNOWN:
return 0
if not self.pre or not self.next:
return 100
# === 核心判断:分型在笔中的位置 ===
# 1. 检查这个分型是否能够终结当前笔
is_bi_end = self._check_if_bi_ending_fx()
# 2. 检查分型的后续走势确认
post_fx_confirmation = self._check_post_fx_confirmation()
# 3. 检查分型的标准性和强度
fx_quality = self._check_fx_quality()
# === 综合评分 ===
base_score = 0
# 笔位置是最重要的判断标准
if is_bi_end == 2: # 强烈确认笔终结
base_score = 2
elif is_bi_end == 1: # 可能笔终结
base_score = 1
elif is_bi_end == -1: # 明显中继
base_score = -2
elif is_bi_end == -2: # 强烈中继特征
base_score = -3
else: # 不确定
base_score = 0
# 后续确认调整
base_score += post_fx_confirmation
# 分型质量调整
base_score += fx_quality
print(self.start_time, base_score, is_bi_end, post_fx_confirmation, fx_quality)
# 限制在-3到3范围内
return max(-3, min(3, base_score))
def _check_if_bi_ending_fx(self):
"""
检查分型是否为笔终结分型
返回值:
2: 强烈确认笔终结
1: 可能笔终结
0: 不确定
-1: 明显中继
-2: 强烈中继特征
"""
# 检查是否有足够的后续数据来判断
if not self.next or not hasattr(self.next, 'next'):
return 0
# 获取分型后的几根K线数据
subsequent_klcs = []
temp = self.next
for i in range(5): # 检查后续5根K线
if temp:
subsequent_klcs.append(temp)
temp = temp.next if hasattr(temp, 'next') else None
else:
break
if len(subsequent_klcs) < 2:
return 0
if self.fx == Chan_FX_TYPE.TOP:
return self._check_top_bi_ending(subsequent_klcs)
else: # BOTTOM
return self._check_bottom_bi_ending(subsequent_klcs)
def _check_top_bi_ending(self, subsequent_klcs):
"""检查顶分型是否为笔终结"""
# 强烈笔终结特征:
# 1. 后续K线持续下跌,且跌破关键位置
# 2. 没有新的更高的高点出现
broken_key_levels = 0
new_highs = 0
downward_trend = 0
# 检查关键价位突破
first_low = self.pre.low
middle_low = self.low
key_support = min(first_low, middle_low)
for i, klc in enumerate(subsequent_klcs):
# 检查是否跌破关键支撑
if klc.low < key_support:
broken_key_levels += 1
# 检查是否出现新高
if klc.high > self.high:
new_highs += 1
# 检查下跌趋势
if i > 0 and klc.close < subsequent_klcs[i-1].close:
downward_trend += 1
# 强烈笔终结:跌破关键位且无新高
if broken_key_levels >= 1 and new_highs == 0 and downward_trend >= 2:
return 2
# 可能笔终结:部分条件满足
if (broken_key_levels >= 1 and new_highs <= 1) or (new_highs == 0 and downward_trend >= 3):
return 1
# 明显中继:出现新高且未跌破关键位
if new_highs >= 2 and broken_key_levels == 0:
return -2
# 中继倾向:出现新高
if new_highs >= 1:
return -1
return 0
def _check_bottom_bi_ending(self, subsequent_klcs):
"""检查底分型是否为笔终结"""
# 强烈笔终结特征:
# 1. 后续K线持续上涨,且突破关键位置
# 2. 没有新的更低的低点出现
broken_key_levels = 0
new_lows = 0
upward_trend = 0
# 检查关键价位突破
first_high = self.pre.high
middle_high = self.high
key_resistance = max(first_high, middle_high)
for i, klc in enumerate(subsequent_klcs):
# 检查是否突破关键阻力
if klc.high > key_resistance:
broken_key_levels += 1
# 检查是否出现新低
if klc.low < self.low:
new_lows += 1
# 检查上涨趋势
if i > 0 and klc.close > subsequent_klcs[i-1].close:
upward_trend += 1
# 强烈笔终结:突破关键位且无新低
if broken_key_levels >= 1 and new_lows == 0 and upward_trend >= 2:
return 2
# 可能笔终结:部分条件满足
if (broken_key_levels >= 1 and new_lows <= 1) or (new_lows == 0 and upward_trend >= 3):
return 1
# 明显中继:出现新低且未突破关键位
if new_lows >= 2 and broken_key_levels == 0:
return -2
# 中继倾向:出现新低
if new_lows >= 1:
return -1
return 0
def _check_post_fx_confirmation(self):
"""
检查分型后的走势确认
返回值:-1到1的调整分数
"""
if not self.next:
return 0
score = 0
# 检查第三根K线的确认
third_klc = self.next
if self.fx == Chan_FX_TYPE.TOP:
# 顶分型:第三根K线应该走弱
middle_price = (self.high + self.low) / 2
if third_klc.close < middle_price:
score += 0.5
if third_klc.low < self.pre.low: # 跌破第一根K线低点
score += 0.5
if third_klc.close < third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5:
score += 0.3 # 明显阴线
else: # BOTTOM
# 底分型:第三根K线应该走强
middle_price = (self.high + self.low) / 2
if third_klc.close > middle_price:
score += 0.5
if third_klc.high > self.pre.high: # 突破第一根K线高点
score += 0.5
if third_klc.close > third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5:
score += 0.3 # 明显阳线
return min(1, max(-1, score))
def _check_fx_quality(self):
"""
检查分型本身的质量
返回值:-1到1的调整分数
"""
score = 0
# 检查分型的标准性
if self.fx == Chan_FX_TYPE.TOP:
# 高点突出程度
high_diff1 = (self.high - self.pre.high) / self.high if self.high > 0 else 0
high_diff2 = (self.high - self.next.high) / self.high if self.high > 0 else 0
min_diff = min(high_diff1, high_diff2)
if min_diff > 0.03: # 非常突出
score += 0.5
elif min_diff > 0.01: # 比较突出
score += 0.2
elif min_diff < 0.003: # 不够突出
score -= 0.5
else: # BOTTOM
# 低点突出程度
low_diff1 = (self.pre.low - self.low) / self.pre.low if self.pre.low > 0 else 0
low_diff2 = (self.next.low - self.low) / self.next.low if self.next.low > 0 else 0
min_diff = min(low_diff1, low_diff2)
if min_diff > 0.03: # 非常突出
score += 0.5
elif min_diff > 0.01: # 比较突出
score += 0.2
elif min_diff < 0.003: # 不够突出
score -= 0.5
# 检查量价配合
avg_volume = self._calculate_average_volume(lookback=5)
if avg_volume > 0:
volume_ratio = self.volume / avg_volume
if volume_ratio > 1.5:
score += 0.3
elif volume_ratio < 0.7:
score -= 0.2
return min(1, max(-1, score))
def calculate_fx_strength(self): def calculate_fx_strength(self):
""" """
基于专业缠论理论的分型强度评估体系 基于专业缠论理论的分型强度评估体系
@@ -1490,7 +1754,7 @@ class ChanKLC():
根据专业评分标准:≥80分为有效强势分型,≤40分建议忽略 根据专业评分标准:≥80分为有效强势分型,≤40分建议忽略
""" """
strength = self.calculate_fx_strength() strength = self.calculate_fx_strength()
return ""
if strength >= 80: if strength >= 80:
return "极强" return "极强"
elif strength >= 65: elif strength >= 65:
@@ -1507,4 +1771,84 @@ class ChanKLC():
判断是否为强分型 判断是否为强分型
根据专业标准调整阈值为65分 根据专业标准调整阈值为65分
""" """
return self.calculate_fx_strength() >= threshold return self.calculate_fx_strength() >= threshold
def _default_top_strength_judgment(self, first_info, middle_info, last_info, first_kline, middle_kline, last_kline):
"""
顶分型默认强弱判断
当不满足特定强弱条件时的保底判断
"""
# 严格的强分型判断条件
strong_signals = 0
# 判断条件1:成交量显著放大(提高标准)
avg_volume = self._calculate_average_volume(lookback=5)
volume_significantly_amplified = middle_kline.volume > avg_volume * 2.0 if avg_volume > 0 else False
if volume_significantly_amplified:
strong_signals += 1
# 判断条件2:中间K线有长上影线(提高标准)
has_long_upper_shadow = middle_info['upper_shadow_ratio'] > 0.6 # 从0.3提高到0.6
if has_long_upper_shadow:
strong_signals += 1
# 判断条件3:后续K线收盘明显偏低(更严格)
middle_range = middle_kline.high - middle_kline.low
last_close_position = (last_kline.close - middle_kline.low) / middle_range if middle_range > 0 else 0.5
close_significantly_low = last_close_position < 0.3 # 从0.6提高到0.3
if close_significantly_low:
strong_signals += 1
# 判断条件4:最后一根K线是明显的阴线且跌幅较大
is_significant_bearish = (last_info['is_bearish'] and
last_info['body_size'] > last_info['total_range'] * 0.5)
if is_significant_bearish:
strong_signals += 1
# 判断条件5:跌破前一根K线重要价位
breaks_important_level = last_kline.low < first_kline.low
if breaks_important_level:
strong_signals += 1
# 需要至少4个强信号才判断为强分型,否则为弱分型
return 1 if strong_signals >= 4 else -1
def _default_bottom_strength_judgment(self, first_info, middle_info, last_info, first_kline, middle_kline, last_kline):
"""
底分型默认强弱判断
当不满足特定强弱条件时的保底判断
"""
# 严格的强分型判断条件
strong_signals = 0
# 判断条件1:成交量显著放大(提高标准)
avg_volume = self._calculate_average_volume(lookback=5)
volume_significantly_amplified = middle_kline.volume > avg_volume * 2.0 if avg_volume > 0 else False
if volume_significantly_amplified:
strong_signals += 1
# 判断条件2:中间K线有长下影线(提高标准)
has_long_lower_shadow = middle_info['lower_shadow_ratio'] > 0.6 # 从0.3提高到0.6
if has_long_lower_shadow:
strong_signals += 1
# 判断条件3:后续K线收盘明显偏高(更严格)
middle_range = middle_kline.high - middle_kline.low
last_close_position = (last_kline.close - middle_kline.low) / middle_range if middle_range > 0 else 0.5
close_significantly_high = last_close_position > 0.7 # 从0.4降低到0.7
if close_significantly_high:
strong_signals += 1
# 判断条件4:最后一根K线是明显的阳线且涨幅较大
is_significant_bullish = (last_info['is_bullish'] and
last_info['body_size'] > last_info['total_range'] * 0.5)
if is_significant_bullish:
strong_signals += 1
# 判断条件5:突破前一根K线重要价位
breaks_important_level = last_kline.high > first_kline.high
if breaks_important_level:
strong_signals += 1
# 需要至少4个强信号才判断为强分型,否则为弱分型
return 1 if strong_signals >= 4 else -1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4 -2
View File
@@ -221,10 +221,12 @@ def analyze_chan(df):
for klc in klc_list: for klc in klc_list:
if hasattr(klc, 'klc_fx_type') and klc.klc_fx_type != Chan_KLC_FX.UNKNOWN: if hasattr(klc, 'klc_fx_type') and klc.klc_fx_type != Chan_KLC_FX.UNKNOWN:
# 计算分型强度 # 计算分型强度
fx_strength = klc.calculate_fx_strength() #fx_strength = klc.calculate_fx_strength()
fx_strength = klc.cal_fx_strength()
fx_strength_level = klc.get_fx_strength_level() fx_strength_level = klc.get_fx_strength_level()
is_strong_fx = klc.is_strong_fx() is_strong_fx = klc.is_strong_fx()
if fx_strength < 1:
fx_strength = 0
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,
+14 -8
View File
@@ -709,7 +709,7 @@
// 添加买卖点悬浮提示元素 // 添加买卖点悬浮提示元素
const tooltipElement = document.createElement('div'); const tooltipElement = document.createElement('div');
tooltipElement.className = 'point-tooltip'; tooltipElement.className = 'point-tooltip';
document.body.appendChild(tooltipElement); // document.body.appendChild(tooltipElement);
// 助手函数:转换UTC时间到所选时区 // 助手函数:转换UTC时间到所选时区
function convertToTimezone(utcDate, timezone) { function convertToTimezone(utcDate, timezone) {
@@ -2731,8 +2731,10 @@
fx_strength_level: fx.fx_strength_level, fx_strength_level: fx.fx_strength_level,
is_strong_fx: fx.is_strong_fx is_strong_fx: fx.is_strong_fx
}); });
const displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`; const displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`;
if (fx.fx_strength < 1) {
displayText = ''
}
console.log('显示文本:', displayText); console.log('显示文本:', displayText);
// 添加标记配置调试 // 添加标记配置调试
@@ -2821,6 +2823,9 @@
} }
// 构建小周期分型显示文本 // 构建小周期分型显示文本
if (fx.fx_strength < 1){
displayText = ''
}
const displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`; const displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`;
// 小周期分型标记配置 - 根据分型类型使用正确的箭头形状 // 小周期分型标记配置 - 根据分型类型使用正确的箭头形状
@@ -2828,7 +2833,6 @@
time: timestamp, time: timestamp,
position: fx.is_bottom ? 'belowBar' : 'aboveBar', position: fx.is_bottom ? 'belowBar' : 'aboveBar',
color: strengthColor, color: strengthColor,
shape: fx.is_bottom ? 'arrowUp' : 'arrowDown', // 底分型向上箭头,顶分型向下箭头
text: displayText, text: displayText,
size: fx.is_strong_fx ? 2 : 1 size: fx.is_strong_fx ? 2 : 1
}; };
@@ -2917,9 +2921,11 @@
// 绑定同步事件 // 绑定同步事件
bindSyncEvents(mainChartContainer, volumeChartContainer, macdChartContainer, mainChart, volumeChart, macdChart, showMacd); bindSyncEvents(mainChartContainer, volumeChartContainer, macdChartContainer, mainChart, volumeChart, macdChart, showMacd);
// 设置图表默认时间范围 // 只有在时间输入框都为空时才设置图表默认时间范围
setDefaultTimeRange(); if (!$('#start_time').val() && !$('#end_time').val()) {
setDefaultTimeRange();
}
// 添加买卖点提示 // 添加买卖点提示
setupTooltip(mainChart); setupTooltip(mainChart);
@@ -3193,7 +3199,7 @@
// 添加买卖点悬浮提示元素 // 添加买卖点悬浮提示元素
const tooltipElement = document.createElement('div'); const tooltipElement = document.createElement('div');
tooltipElement.className = 'point-tooltip'; tooltipElement.className = 'point-tooltip';
document.body.appendChild(tooltipElement); // document.body.appendChild(tooltipElement);
// 添加自定义十字线信息显示 // 添加自定义十字线信息显示
const crosshairTooltip = document.createElement('div'); const crosshairTooltip = document.createElement('div');
@@ -3207,7 +3213,7 @@
crosshairTooltip.style.zIndex = '1000'; crosshairTooltip.style.zIndex = '1000';
crosshairTooltip.style.pointerEvents = 'none'; crosshairTooltip.style.pointerEvents = 'none';
crosshairTooltip.style.display = 'none'; crosshairTooltip.style.display = 'none';
document.body.appendChild(crosshairTooltip); // document.body.appendChild(crosshairTooltip);
// 添加鼠标悬停事件显示提示 // 添加鼠标悬停事件显示提示
if (mainChart) { if (mainChart) {