Files
tradingview/ema_strategy_4lines.pine
2025-09-28 11:48:03 +08:00

190 lines
9.0 KiB
Plaintext

//@version=6
strategy("4均线开口策略", shorttitle="EMA4线", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10, calc_on_every_tick=true)
// 输入参数
ema1_length = input.int(5, "EMA1周期", minval=1)
ema2_length = input.int(10, "EMA2周期", minval=1)
ema3_length = input.int(26, "EMA3周期", minval=1)
ema4_length = input.int(52, "EMA4周期", minval=1)
// 开口阈值设置
opening_threshold = input.float(0.5, "开口阈值(%)", minval=0.1, maxval=5.0) / 100
// 交易频率控制
min_bars_between_trades = input.int(10, "最小交易间隔(K线数)", minval=1, maxval=100)
min_price_change = input.float(0.2, "最小价格变化(%)", minval=0.1, maxval=2.0) / 100
// 均线收束参数
max_ema_spread = input.float(0.8, "均线最大间距(%)", minval=0.1, maxval=2.0) / 100 // 均线间最大距离
convergence_periods = input.int(2, "收束确认周期", minval=1, maxval=10) // 收束状态持续周期
// 显示设置
show_signals = input.bool(true, "显示信号")
show_ema_lines = input.bool(true, "显示EMA线")
// 计算EMA
ema1 = ta.ema(close, ema1_length)
ema2 = ta.ema(close, ema2_length)
ema3 = ta.ema(close, ema3_length)
ema4 = ta.ema(close, ema4_length)
// 显示EMA线
plot(show_ema_lines ? ema1 : na, "EMA快线", color=color.red, linewidth=2)
plot(show_ema_lines ? ema2 : na, "EMA中线", color=color.orange, linewidth=2)
plot(show_ema_lines ? ema3 : na, "EMA慢线", color=color.blue, linewidth=2)
plot(show_ema_lines ? ema4 : na, "EMA超慢线", color=color.purple, linewidth=2)
// 计算均线间距
max_ema = math.max(math.max(ema1, ema2), math.max(ema3, ema4))
min_ema = math.min(math.min(ema1, ema2), math.min(ema3, ema4))
ema_range = (max_ema - min_ema) / close // 所有均线的最大间距
// 计算均线开口程度(使用相对距离)
ema_spread = math.abs(ema1 - ema4) / close
opening_magnitude = ema_spread
// 检测均线收束状态(所有均线距离很近)
emas_converged = ema_range <= max_ema_spread
emas_converged_prev = ema_range[1] <= max_ema_spread
// 简化的收束状态检测
was_converged = emas_converged[1] or emas_converged[2] // 前1-2根K线有收束状态即可
// 检测均线排列状态
// 多头排列:EMA1 > EMA2 > EMA3 > EMA4
bull_alignment_now = ema1 > ema2 and ema2 > ema3 and ema3 > ema4
bull_alignment = bull_alignment_now and bull_alignment_now[1] and bull_alignment_now[2] // 至少持续3个K线
// 空头排列:EMA1 < EMA2 < EMA3 < EMA4
bear_alignment_now = ema1 < ema2 and ema2 < ema3 and ema3 < ema4
bear_alignment = bear_alignment_now and bear_alignment_now[1] and bear_alignment_now[2] // 至少持续3个K线
// 检测均线同向趋势(通过斜率判断)
ema1_rising = ema1 > ema1[1]
ema2_rising = ema2 > ema2[1]
ema3_rising = ema3 > ema3[1]
ema4_rising = ema4 > ema4[1]
ema1_falling = ema1 < ema1[1]
ema2_falling = ema2 < ema2[1]
ema3_falling = ema3 < ema3[1]
ema4_falling = ema4 < ema4[1]
// 同向上升趋势
all_rising = ema1_rising and ema2_rising and ema3_rising and ema4_rising
// 同向下降趋势
all_falling = ema1_falling and ema2_falling and ema3_falling and ema4_falling
// 交易频率控制变量
var int last_trade_bar = 0
var float last_trade_price = 0.0
var int last_signal_bar = 0
// 价格过滤条件
price_above_ema60 = close > ema4 // 价格在EMA60上方
price_below_ema60 = close < ema4 // 价格在EMA60下方
// 交易间隔和价格变化检查
bars_since_last_trade = bar_index - last_trade_bar
sufficient_time_gap = bars_since_last_trade >= min_bars_between_trades
sufficient_price_change = last_trade_price == 0.0 or math.abs(close - last_trade_price) / last_trade_price >= min_price_change
// 检测均线开始发散(从收束状态开始向同一方向移动)
starting_divergence_up = was_converged and all_rising and not emas_converged // 从收束开始向上发散
starting_divergence_down = was_converged and all_falling and not emas_converged // 从收束开始向下发散
// 买入条件:均线从收束开始发散 + 价格过滤 + 频率控制
buy_long_condition = starting_divergence_up and price_above_ema60 and sufficient_time_gap and sufficient_price_change
buy_short_condition = starting_divergence_down and price_below_ema60 and sufficient_time_gap and sufficient_price_change
buy_condition = buy_long_condition or buy_short_condition
// 卖出条件:均线开口达到最大(这里用阈值判断)
// 使用历史最大开口的相对比较
var float max_opening = 0.0
if opening_magnitude > max_opening
max_opening := opening_magnitude
// 当开口超过阈值且达到近期高点时触发卖出
sell_condition = opening_magnitude >= opening_threshold and opening_magnitude >= max_opening * 0.9
// 重置最大开口(当开口显著收窄时)
if opening_magnitude < max_opening * 0.3
max_opening := opening_magnitude
// 执行交易
if buy_long_condition and strategy.position_size == 0
strategy.entry("多头买入", strategy.long)
last_trade_bar := bar_index
last_trade_price := close
if buy_short_condition and strategy.position_size == 0
strategy.entry("空头买入", strategy.short)
last_trade_bar := bar_index
last_trade_price := close
if sell_condition and strategy.position_size != 0
if strategy.position_size > 0
strategy.close("多头买入", comment="多头平仓")
else
strategy.close("空头买入", comment="空头平仓")
// 信号显示间隔控制
signal_gap_ok = bar_index - last_signal_bar >= min_bars_between_trades
// 显示信号 - 只在实际交易时显示
if show_signals
if buy_long_condition and strategy.position_size == 0 and sufficient_time_gap and sufficient_price_change and signal_gap_ok
label.new(bar_index, low, "买多", color=color.green, style=label.style_label_up, size=size.normal)
last_signal_bar := bar_index
if buy_short_condition and strategy.position_size == 0 and sufficient_time_gap and sufficient_price_change and signal_gap_ok
label.new(bar_index, high, "买空", color=color.red, style=label.style_label_down, size=size.normal)
last_signal_bar := bar_index
if sell_condition and strategy.position_size != 0
label.new(bar_index, close, "平仓", color=color.yellow, style=label.style_label_left, size=size.normal)
// 背景颜色指示
bgcolor(emas_converged ? color.new(color.yellow, 95) : na, title="均线收束背景")
bgcolor(starting_divergence_up ? color.new(color.green, 90) : na, title="向上发散背景")
bgcolor(starting_divergence_down ? color.new(color.red, 90) : na, title="向下发散背景")
// 信息表格
if barstate.islast
var table info_table = table.new(position.top_right, 2, 12, bgcolor=color.white, border_width=1)
table.cell(info_table, 0, 0, "4EMA收束发散策略", text_color=color.black, bgcolor=color.gray)
table.cell(info_table, 1, 0, "", text_color=color.black, bgcolor=color.gray)
table.cell(info_table, 0, 1, "均线间距", text_color=color.black)
table.cell(info_table, 1, 1, str.tostring(math.round(ema_range * 10000) / 100) + "%", text_color=color.black)
table.cell(info_table, 0, 2, "收束阈值", text_color=color.black)
table.cell(info_table, 1, 2, str.tostring(math.round(max_ema_spread * 10000) / 100) + "%", text_color=color.black)
table.cell(info_table, 0, 3, "当前收束", text_color=color.black)
table.cell(info_table, 1, 3, emas_converged ? "是" : "否", text_color=color.black)
table.cell(info_table, 0, 4, "之前收束", text_color=color.black)
table.cell(info_table, 1, 4, was_converged ? "是" : "否", text_color=color.black)
table.cell(info_table, 0, 5, "趋势方向", text_color=color.black)
table.cell(info_table, 1, 5, all_rising ? "同向上" : all_falling ? "同向下" : "分歧", text_color=color.black)
table.cell(info_table, 0, 6, "发散检测", text_color=color.black)
divergence_text = starting_divergence_up ? "向上发散" : starting_divergence_down ? "向下发散" : "无发散"
table.cell(info_table, 1, 6, divergence_text, text_color=color.black)
table.cell(info_table, 0, 7, "价格位置", text_color=color.black)
price_position = price_above_ema60 ? "EMA52上方" : price_below_ema60 ? "EMA52下方" : "EMA52附近"
table.cell(info_table, 1, 7, price_position, text_color=color.black)
table.cell(info_table, 0, 8, "时间间隔", text_color=color.black)
table.cell(info_table, 1, 8, sufficient_time_gap ? "满足" : "不足", text_color=color.black)
table.cell(info_table, 0, 9, "价格变化", text_color=color.black)
table.cell(info_table, 1, 9, sufficient_price_change ? "满足" : "不足", text_color=color.black)
table.cell(info_table, 0, 10, "买多条件", text_color=color.black)
table.cell(info_table, 1, 10, buy_long_condition ? "满足" : "不满足", text_color=color.black)
table.cell(info_table, 0, 11, "仓位状态", text_color=color.black)
position_text = strategy.position_size > 0 ? "多头" : strategy.position_size < 0 ? "空头" : "空仓"
table.cell(info_table, 1, 11, position_text, text_color=color.black)