Files
tradingview/ema_macd_trend_indicator.pine
T

317 lines
15 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//@version=6
indicator(title="EMA+MACD 三态趋势判断", shorttitle="EMA+MACD趋势", overlay=true, max_labels_count=500)
// ========================= 输入参数 =========================
// EMA 参数
ema1_len = input.int(9, "EMA1 快线周期", minval=1, inline="ema1")
ema2_len = input.int(21, "EMA2 中线周期", minval=1, inline="ema2")
ema3_len = input.int(55, "EMA3 慢线周期", minval=1, inline="ema3")
ema4_len = input.int(200, "EMA4 超慢线周期", minval=1, inline="ema4")
use_ema4 = input.bool(true, "启用第4条均线(EMA200)", inline="ema4")
// MACD 参数
macd_fast = input.int(12, "MACD快线周期", minval=1, group="MACD设置")
macd_slow = input.int(26, "MACD慢线周期", minval=1, group="MACD设置")
macd_signal = input.int(9, "MACD信号线周期", minval=1, group="MACD设置")
// 趋势判断参数
ema_spread_thresh = input.float(0.3, "EMA收束阈值(%)", minval=0.1, maxval=2.0, step=0.1, group="趋势判断") / 100
macd_zero_zone = input.float(0.1, "MACD零轴区域(%)", minval=0.01, maxval=0.5, step=0.01, group="趋势判断") / 100
confirm_bars = input.int(2, "趋势确认周期", minval=1, maxval=5, group="趋势判断")
// 显示设置
show_ema = input.bool(true, "显示EMA线", group="显示设置")
show_signals = input.bool(true, "显示状态切换信号", group="显示设置")
show_background = input.bool(true, "背景着色", group="显示设置")
show_info_panel = input.bool(true, "显示信息面板", group="显示设置")
// 颜色设置
col_uptrend = input.color(color.new(color.teal, 80), "上涨趋势颜色", group="颜色设置")
col_downtrend = input.color(color.new(color.red, 80), "下跌趋势颜色", group="颜色设置")
col_consolidation = input.color(color.new(color.gray, 85), "盘整趋势颜色", group="颜色设置")
// ========================= 指标计算 =========================
// EMA计算
ema1 = ta.ema(close, ema1_len)
ema2 = ta.ema(close, ema2_len)
ema3 = ta.ema(close, ema3_len)
ema4 = use_ema4 ? ta.ema(close, ema4_len) : na
// MACD计算
[macdLine, signalLine, histLine] = ta.macd(close, macd_fast, macd_slow, macd_signal)
macd_normalized = macdLine / close // 归一化MACD便于比较
// ========================= EMA排列判断 =========================
// 多头排列: EMA1 > EMA2 > EMA3 (> EMA4 if enabled)
bull_alignment_3 = ema1 > ema2 and ema2 > ema3
bull_alignment = use_ema4 ? (bull_alignment_3 and ema3 > ema4) : bull_alignment_3
// 空头排列: EMA1 < EMA2 < EMA3 (< EMA4 if enabled)
bear_alignment_3 = ema1 < ema2 and ema2 < ema3
bear_alignment = use_ema4 ? (bear_alignment_3 and ema3 < ema4) : bear_alignment_3
// EMA方向一致性(斜率判断)
ema1_rising = ema1 > ema1[1]
ema2_rising = ema2 > ema2[1]
ema3_rising = ema3 > ema3[1]
ema4_rising = use_ema4 ? ema4 > ema4[1] : true
ema1_falling = ema1 < ema1[1]
ema2_falling = ema2 < ema2[1]
ema3_falling = ema3 < ema3[1]
ema4_falling = use_ema4 ? ema4 < ema4[1] : true
all_rising = ema1_rising and ema2_rising and ema3_rising and (not use_ema4 or ema4_rising)
all_falling = ema1_falling and ema2_falling and ema3_falling and (not use_ema4 or ema4_falling)
// EMA收束程度(判断盘整)
max_ema = math.max(math.max(ema1, ema2), ema3)
min_ema = math.min(math.min(ema1, ema2), ema3)
ema_spread = (max_ema - min_ema) / close
emas_converged = ema_spread < ema_spread_thresh
// ========================= MACD状态判断 =========================
// MACD方向
macd_bullish = macdLine > signalLine
macd_bearish = macdLine < signalLine
// MACD位置
macd_above_zero = macdLine > 0
macd_below_zero = macdLine < 0
macd_near_zero = math.abs(macd_normalized) < macd_zero_zone
// MACD柱状图趋势
hist_expanding_up = histLine > histLine[1] and histLine > 0
hist_expanding_down = histLine < histLine[1] and histLine < 0
hist_shrinking = math.abs(histLine) < math.abs(histLine[1])
// MACD综合强度评分 (-2 到 +2)
macd_score = 0
macd_score := macd_bullish ? macd_score + 1 : macd_score - 1
macd_score := macd_above_zero ? macd_score + 1 : macd_below_zero ? macd_score - 1 : macd_score
// ========================= 综合趋势判断 =========================
// 上涨趋势条件:
// 1. EMA多头排列 OR (EMA方向一致向上 AND 价格在EMA上方)
// 2. MACD评分 >= 1 (至少看涨)
price_above_emas = close > ema1 and close > ema2 and close > ema3
uptrend_ema = bull_alignment or (all_rising and price_above_emas)
uptrend_macd = macd_score >= 1 or (macd_bullish and not macd_near_zero)
uptrend_raw = uptrend_ema and uptrend_macd
// 下跌趋势条件:
// 1. EMA空头排列 OR (EMA方向一致向下 AND 价格在EMA下方)
// 2. MACD评分 <= -1 (至少看跌)
price_below_emas = close < ema1 and close < ema2 and close < ema3
downtrend_ema = bear_alignment or (all_falling and price_below_emas)
downtrend_macd = macd_score <= -1 or (macd_bearish and not macd_near_zero)
downtrend_raw = downtrend_ema and downtrend_macd
// 盘整趋势条件:
// 1. EMA收束 OR 无明确排列
// 2. MACD在零轴附近 OR 柱状图收缩
consolidation_ema = emas_converged or (not bull_alignment and not bear_alignment)
consolidation_macd = macd_near_zero or hist_shrinking
consolidation_raw = (consolidation_ema and consolidation_macd) or (not uptrend_raw and not downtrend_raw)
// ========================= 连续确认计数 =========================
var int uptrend_count = 0
var int downtrend_count = 0
var int consolidation_count = 0
uptrend_count := uptrend_raw ? uptrend_count + 1 : 0
downtrend_count := downtrend_raw ? downtrend_count + 1 : 0
consolidation_count := consolidation_raw ? consolidation_count + 1 : 0
// 确认后的趋势信号
uptrend_confirmed = uptrend_count >= confirm_bars
downtrend_confirmed = downtrend_count >= confirm_bars
consolidation_confirmed = consolidation_count >= confirm_bars
// ========================= 状态机 =========================
// 状态: 0=盘整, 1=上涨, -1=下跌
var int trend_state = 0
prev_state = nz(trend_state[1], 0)
// 状态转换逻辑
int new_state = prev_state
if prev_state == 0 // 当前盘整
if uptrend_confirmed
new_state := 1
else if downtrend_confirmed
new_state := -1
else if prev_state == 1 // 当前上涨
if downtrend_confirmed
new_state := -1
else if consolidation_confirmed and not uptrend_raw
new_state := 0
else if prev_state == -1 // 当前下跌
if uptrend_confirmed
new_state := 1
else if consolidation_confirmed and not downtrend_raw
new_state := 0
// 仅在K线收盘时更新状态
trend_state := barstate.isconfirmed ? new_state : prev_state
// ========================= 可视化 =========================
// 绘制EMA线
plot(show_ema ? ema1 : na, "EMA1 快线", color=color.new(color.red, 30), linewidth=1)
plot(show_ema ? ema2 : na, "EMA2 中线", color=color.new(color.orange, 30), linewidth=1)
plot(show_ema ? ema3 : na, "EMA3 慢线", color=color.new(color.blue, 30), linewidth=2)
plot(show_ema and use_ema4 ? ema4 : na, "EMA4 超慢线", color=color.new(color.purple, 30), linewidth=2)
// 背景着色
bg_color = trend_state == 1 ? col_uptrend : trend_state == -1 ? col_downtrend : col_consolidation
bgcolor(show_background ? bg_color : na, title="趋势背景")
// 状态切换信号
entered_up = barstate.isconfirmed and trend_state == 1 and prev_state != 1
entered_down = barstate.isconfirmed and trend_state == -1 and prev_state != -1
entered_consolidation = barstate.isconfirmed and trend_state == 0 and prev_state != 0
exit_up = barstate.isconfirmed and prev_state == 1 and trend_state != 1
exit_down = barstate.isconfirmed and prev_state == -1 and trend_state != -1
// ========================= 类缠论笔的绘制 =========================
// 趋势线宽度
trend_line_width = input.int(2, "趋势笔宽度", minval=1, maxval=5, group="显示设置")
// 上涨笔:记录起点
var int up_start_bar = na
var float up_start_price = na
// 下跌笔:记录起点
var int down_start_bar = na
var float down_start_price = na
// 上涨趋势开始 - 记录起点
if entered_up
up_start_bar := bar_index
up_start_price := low
// 上涨趋势结束 - 画笔(终点 = 结束时的K线)
if exit_up and show_signals and not na(up_start_bar)
line.new(up_start_bar, up_start_price, bar_index, close, color=color.teal, width=trend_line_width, style=line.style_solid)
// 下跌趋势开始 - 记录起点
if entered_down
down_start_bar := bar_index
down_start_price := high
// 下跌趋势结束 - 画笔(终点 = 结束时的K线)
if exit_down and show_signals and not na(down_start_bar)
line.new(down_start_bar, down_start_price, bar_index, close, color=color.red, width=trend_line_width, style=line.style_solid)
// 当前进行中的笔(实时显示)
var line current_up_line = na
var line current_down_line = na
if show_signals
if not na(current_up_line)
line.delete(current_up_line)
if not na(current_down_line)
line.delete(current_down_line)
// 上涨中 - 画到当前K线
if trend_state == 1 and not na(up_start_bar)
current_up_line := line.new(up_start_bar, up_start_price, bar_index, close, color=color.new(color.teal, 40), width=trend_line_width, style=line.style_dotted)
// 下跌中 - 画到当前K线
if trend_state == -1 and not na(down_start_bar)
current_down_line := line.new(down_start_bar, down_start_price, bar_index, close, color=color.new(color.red, 40), width=trend_line_width, style=line.style_dotted)
// ========================= 信息面板 =========================
if show_info_panel and barstate.islast
var table info_table = table.new(position.top_right, 2, 10, bgcolor=color.new(color.black, 80), border_width=1)
// 标题
table.cell(info_table, 0, 0, "EMA+MACD趋势", text_color=color.white, bgcolor=color.new(color.gray, 60), text_size=size.small)
table.cell(info_table, 1, 0, "", bgcolor=color.new(color.gray, 60))
// 当前状态
state_text = trend_state == 1 ? "📈 上涨趋势" : trend_state == -1 ? "📉 下跌趋势" : "📊 盘整趋势"
state_color = trend_state == 1 ? color.teal : trend_state == -1 ? color.red : color.gray
table.cell(info_table, 0, 1, "当前状态", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 1, state_text, text_color=state_color, text_size=size.small)
// EMA排列
ema_text = bull_alignment ? "多头排列" : bear_alignment ? "空头排列" : "无序排列"
ema_color = bull_alignment ? color.teal : bear_alignment ? color.red : color.gray
table.cell(info_table, 0, 2, "EMA排列", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 2, ema_text, text_color=ema_color, text_size=size.small)
// EMA收束度
spread_text = str.tostring(math.round(ema_spread * 10000) / 100, "#.##") + "%"
spread_color = emas_converged ? color.orange : color.white
table.cell(info_table, 0, 3, "EMA间距", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 3, spread_text + (emas_converged ? " 收束" : ""), text_color=spread_color, text_size=size.small)
// EMA方向
dir_text = all_rising ? "全部上升" : all_falling ? "全部下降" : "方向分歧"
dir_color = all_rising ? color.teal : all_falling ? color.red : color.gray
table.cell(info_table, 0, 4, "EMA方向", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 4, dir_text, text_color=dir_color, text_size=size.small)
// MACD状态
macd_status = macd_bullish ? "看涨" : "看跌"
macd_pos = macd_above_zero ? " (零上)" : macd_below_zero ? " (零下)" : " (零轴)"
macd_color = macd_bullish and macd_above_zero ? color.teal : macd_bearish and macd_below_zero ? color.red : color.orange
table.cell(info_table, 0, 5, "MACD状态", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 5, macd_status + macd_pos, text_color=macd_color, text_size=size.small)
// MACD数值
table.cell(info_table, 0, 6, "MACD值", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 6, str.tostring(macdLine, "#.####"), text_color=macdLine > 0 ? color.teal : color.red, text_size=size.small)
// 柱状图状态
hist_text = hist_expanding_up ? "放大(多)" : hist_expanding_down ? "放大(空)" : hist_shrinking ? "收缩" : "平稳"
hist_color = hist_expanding_up ? color.teal : hist_expanding_down ? color.red : color.gray
table.cell(info_table, 0, 7, "柱状图", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 7, hist_text, text_color=hist_color, text_size=size.small)
// MACD综合评分
score_text = macd_score > 0 ? "+" + str.tostring(macd_score) : str.tostring(macd_score)
score_color = macd_score > 0 ? color.teal : macd_score < 0 ? color.red : color.gray
table.cell(info_table, 0, 8, "MACD评分", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 8, score_text + " / 2", text_color=score_color, text_size=size.small)
// 价格位置
price_pos = price_above_emas ? "均线上方" : price_below_emas ? "均线下方" : "均线之间"
price_color = price_above_emas ? color.teal : price_below_emas ? color.red : color.gray
table.cell(info_table, 0, 9, "价格位置", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 9, price_pos, text_color=price_color, text_size=size.small)
// ========================= 告警 =========================
alertcondition(entered_up, title="上涨趋势开始", message="{{ticker}} {{interval}} 进入上涨趋势 价格:{{close}}")
alertcondition(entered_down, title="下跌趋势开始", message="{{ticker}} {{interval}} 进入下跌趋势 价格:{{close}}")
alertcondition(entered_consolidation, title="盘整趋势开始", message="{{ticker}} {{interval}} 进入盘整趋势 价格:{{close}}")
// ========================= 指标说明 =========================
// 【EMA+MACD三态趋势判断指标】
//
// 核心逻辑:
// 1. 使用4条EMA9/21/55/200)判断均线排列和方向
// 2. 结合MACD的位置、方向和柱状图状态
// 3. 综合判断市场处于三种状态之一
//
// 📈 上涨趋势判定:
// - EMA多头排列(快>中>慢>超慢)或均线同向上升+价格在上方
// - MACD看涨(MACD线>信号线 或 MACD在零轴上方)
//
// 📉 下跌趋势判定:
// - EMA空头排列(快<中<慢<超慢)或均线同向下降+价格在下方
// - MACD看跌(MACD线<信号线 或 MACD在零轴下方)
//
// 📊 盘整趋势判定:
// - EMA线收束(间距小于阈值)或无明确排列
// - MACD在零轴附近 或 柱状图收缩
// - 不满足上涨/下跌条件时自动判定为盘整
//
// 参数建议:
// - 短线交易:EMA 5/10/20/50, 确认周期1-2
// - 中线交易:EMA 9/21/55/200, 确认周期2-3(默认)
// - 长线交易:EMA 20/50/100/200, 确认周期3-5