Files
tradingview/ema_macd_trend_strategy.pine

320 lines
14 KiB
Plaintext

//@version=6
strategy(title="EMA+MACD 趋势跟踪策略", shorttitle="EMA+MACD策略", overlay=true,
default_qty_type=strategy.percent_of_equity, default_qty_value=10,
initial_capital=100000, commission_type=strategy.commission.percent, commission_value=0.1,
pyramiding=0, calc_on_every_tick=false)
// ========================= 策略参数 =========================
// 交易方向
trade_direction = input.string("双向交易", "交易方向", options=["只做多", "只做空", "双向交易"], group="策略设置")
// 止损止盈
use_sl = input.bool(true, "启用止损", group="风控设置")
sl_pct = input.float(3.0, "止损比例(%)", minval=0.5, maxval=20, step=0.5, group="风控设置")
use_tp = input.bool(true, "启用止盈", group="风控设置")
tp_pct = input.float(6.0, "止盈比例(%)", minval=1, maxval=50, step=0.5, group="风控设置")
// 平仓逻辑:趋势结束即平仓
// 移动止损
use_trailing = input.bool(false, "启用移动止损", group="风控设置")
trail_pct = input.float(2.0, "移动止损比例(%)", minval=0.5, maxval=10, step=0.5, group="风控设置")
// ========================= EMA 参数 =========================
ema1_len = input.int(9, "EMA1 快线周期", minval=1, group="EMA设置")
ema2_len = input.int(21, "EMA2 中线周期", minval=1, group="EMA设置")
ema3_len = input.int(55, "EMA3 慢线周期", minval=1, group="EMA设置")
ema4_len = input.int(200, "EMA4 超慢线周期", minval=1, group="EMA设置")
use_ema4 = input.bool(true, "启用第4条均线(EMA200)", group="EMA设置")
// ========================= 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_background = input.bool(true, "背景着色", group="显示设置")
show_signals = input.bool(true, "显示趋势笔", group="显示设置")
// ========================= 颜色设置 =========================
col_uptrend = color.new(color.teal, 80)
col_downtrend = color.new(color.red, 80)
col_consolidation = color.new(color.gray, 85)
// ========================= 指标计算 =========================
// 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
// ========================= EMA排列判断 =========================
bull_alignment_3 = ema1 > ema2 and ema2 > ema3
bull_alignment = use_ema4 ? (bull_alignment_3 and ema3 > ema4) : bull_alignment_3
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_bullish = macdLine > signalLine
macd_bearish = macdLine < signalLine
macd_above_zero = macdLine > 0
macd_below_zero = macdLine < 0
macd_near_zero = math.abs(macd_normalized) < macd_zero_zone
hist_shrinking = math.abs(histLine) < math.abs(histLine[1])
// MACD评分
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
// ========================= 综合趋势判断 =========================
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
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
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
// ========================= 状态机 =========================
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
trend_state := barstate.isconfirmed ? new_state : prev_state
// 状态切换信号
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
// ========================= 交易逻辑 =========================
// 做多条件
can_long = trade_direction == "只做多" or trade_direction == "双向交易"
can_short = trade_direction == "只做空" or trade_direction == "双向交易"
// 开仓信号
long_signal = entered_up and can_long
short_signal = entered_down and can_short
// 平仓信号:趋势结束即平仓
close_long_signal = exit_up // 上涨趋势结束 → 平多仓
close_short_signal = exit_down // 下跌趋势结束 → 平空仓
// 止损止盈价格
long_sl = use_sl ? strategy.position_avg_price * (1 - sl_pct / 100) : na
long_tp = use_tp ? strategy.position_avg_price * (1 + tp_pct / 100) : na
short_sl = use_sl ? strategy.position_avg_price * (1 + sl_pct / 100) : na
short_tp = use_tp ? strategy.position_avg_price * (1 - tp_pct / 100) : na
// 执行交易
if long_signal
strategy.entry("做多", strategy.long)
if short_signal
strategy.entry("做空", strategy.short)
// 平仓
if close_long_signal and strategy.position_size > 0
strategy.close("做多", comment="趋势结束")
if close_short_signal and strategy.position_size < 0
strategy.close("做空", comment="趋势结束")
// 止损止盈
if strategy.position_size > 0
if use_trailing
strategy.exit("多头止损止盈", "做多", stop=long_sl, limit=long_tp, trail_points=close * trail_pct / 100 / syminfo.mintick, trail_offset=close * trail_pct / 100 / syminfo.mintick)
else
strategy.exit("多头止损止盈", "做多", stop=long_sl, limit=long_tp)
if strategy.position_size < 0
if use_trailing
strategy.exit("空头止损止盈", "做空", stop=short_sl, limit=short_tp, trail_points=close * trail_pct / 100 / syminfo.mintick, trail_offset=close * trail_pct / 100 / syminfo.mintick)
else
strategy.exit("空头止损止盈", "做空", stop=short_sl, limit=short_tp)
// ========================= 可视化 =========================
// 绘制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="趋势背景")
// ========================= 类缠论笔的绘制 =========================
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)
// ========================= 信息面板 =========================
var table info_table = table.new(position.top_right, 2, 8, bgcolor=color.new(color.black, 80), border_width=1)
if barstate.islast
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)
pos_text = strategy.position_size > 0 ? "多头持仓" : strategy.position_size < 0 ? "空头持仓" : "空仓"
pos_color = strategy.position_size > 0 ? color.teal : strategy.position_size < 0 ? color.red : color.gray
table.cell(info_table, 0, 2, "持仓状态", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 2, pos_text, text_color=pos_color, text_size=size.small)
if strategy.position_size != 0
table.cell(info_table, 0, 3, "入场价", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 3, str.tostring(strategy.position_avg_price, "#.##"), text_color=color.white, text_size=size.small)
pnl_pct = (close - strategy.position_avg_price) / strategy.position_avg_price * 100 * (strategy.position_size > 0 ? 1 : -1)
pnl_color = pnl_pct > 0 ? color.teal : color.red
table.cell(info_table, 0, 4, "浮动盈亏", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 4, str.tostring(pnl_pct, "#.##") + "%", text_color=pnl_color, text_size=size.small)
if use_sl
sl_price = strategy.position_size > 0 ? long_sl : short_sl
table.cell(info_table, 0, 5, "止损价", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 5, str.tostring(sl_price, "#.##"), text_color=color.red, text_size=size.small)
if use_tp
tp_price = strategy.position_size > 0 ? long_tp : short_tp
table.cell(info_table, 0, 6, "止盈价", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 6, str.tostring(tp_price, "#.##"), text_color=color.teal, text_size=size.small)
table.cell(info_table, 0, 7, "总交易次数", text_color=color.white, text_size=size.small)
table.cell(info_table, 1, 7, str.tostring(strategy.closedtrades), text_color=color.white, text_size=size.small)
// ========================= 策略说明 =========================
// 【EMA+MACD 趋势跟踪策略】
//
// 交易逻辑:
// 1. 上涨趋势确认时 → 开多仓
// 2. 下跌趋势确认时 → 开空仓(或平多仓)
// 3. 进入盘整时 → 根据设置决定是否平仓
//
// 风控设置:
// - 止损:默认3%,可自定义
// - 止盈:默认6%,可自定义
// - 移动止损:可选开启
//
// 交易方向:
// - 只做多:仅在上涨趋势开仓
// - 只做空:仅在下跌趋势开仓
// - 双向交易:趋势转换时反向开仓