//@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)