添加新的指标和厕率

This commit is contained in:
jackyu66git
2026-02-09 18:02:10 +08:00
parent cde6ddb134
commit c4b066ebc3
6 changed files with 2549 additions and 0 deletions
+5
View File
@@ -1,2 +1,7 @@
# tradingview # tradingview
TradingView scripts TradingView scripts
1. 使用MA160判断大的趋势,MA40判断小趋势。走势价格在MA160上方,大级别为多头趋势,下方则为空头趋势。走势价格在MA40上方,小级别走势为多头趋势,下方则为空头趋势
2. 使用顺大逆小的趋势策略,捕捉大级别趋势行情中的小级别调整走势,即大级别为多头趋势时,小级别为空头趋势,小级别空头趋势后会继续沿着大级别运行。大级别为空头趋势时反向操作。具体方法如下:
3. 如果大级别趋势是上涨趋势,小级别下跌趋势在完成,找到macd金叉,金叉后面三根k线仍然按照金叉涨的趋势运行,并且价格在后面10根k线站稳和突破MA40,此时时出现买入信号,止损设在回调的低点,止盈参考1:2的盈亏比设置
4. 大趋势是下跌趋势时反向操作。
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
//@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
+319
View File
@@ -0,0 +1,319 @@
//@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%,可自定义
// - 移动止损:可选开启
//
// 交易方向:
// - 只做多:仅在上涨趋势开仓
// - 只做空:仅在下跌趋势开仓
// - 双向交易:趋势转换时反向开仓
+259
View File
@@ -0,0 +1,259 @@
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © 三重滤网均线交易策略
//@version=6
strategy("三重滤网均线交易策略", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10, initial_capital=100000)
// ==================== 参数设置 ====================
// 均线参数
ema156_length = input.int(156, "大趋势均线周期 (EMA156)", minval=1, group="均线设置")
ema52_length = input.int(52, "小趋势均线周期 (EMA52)", minval=1, group="均线设置")
// 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设置")
// 策略参数
confirm_bars = input.int(3, "金叉/死叉后确认K线数", minval=1, maxval=10, group="策略设置")
breakout_bars = input.int(10, "突破EMA52确认K线数", minval=1, maxval=20, group="策略设置")
risk_reward_ratio = input.float(2.0, "盈亏比", minval=1.0, maxval=5.0, step=0.5, group="策略设置")
// 显示设置
show_ema156 = input.bool(true, "显示EMA156", group="显示设置")
show_ema52 = input.bool(true, "显示EMA52", group="显示设置")
show_signals = input.bool(true, "显示信号标记", group="显示设置")
// ==================== 计算均线 ====================
ema156 = ta.ema(close, ema156_length)
ema52 = ta.ema(close, ema52_length)
// ==================== 计算MACD ====================
[macd_line, signal_line, hist] = ta.macd(close, macd_fast, macd_slow, macd_signal)
// MACD金叉和死叉
macd_golden_cross = ta.crossover(macd_line, signal_line)
macd_death_cross = ta.crossunder(macd_line, signal_line)
// ==================== 趋势判断 ====================
// 大趋势:价格相对于EMA156的位置
big_trend_bullish = close > ema156 // 大级别多头趋势
big_trend_bearish = close < ema156 // 大级别空头趋势
// 小趋势:价格相对于EMA52的位置
small_trend_bullish = close > ema52 // 小级别多头趋势
small_trend_bearish = close < ema52 // 小级别空头趋势
// ==================== 金叉/死叉后趋势确认 ====================
// 记录最近的金叉/死叉位置
var int bars_since_golden = na
var int bars_since_death = na
var float golden_cross_price = na
var float death_cross_price = na
if macd_golden_cross
bars_since_golden := 0
golden_cross_price := close
else if not na(bars_since_golden)
bars_since_golden := bars_since_golden + 1
if macd_death_cross
bars_since_death := 0
death_cross_price := close
else if not na(bars_since_death)
bars_since_death := bars_since_death + 1
// 检查金叉后confirm_bars根K线是否持续上涨(收盘价逐步走高或维持)
golden_cross_confirmed = false
if not na(bars_since_golden) and bars_since_golden >= confirm_bars and bars_since_golden <= confirm_bars + 5
// 检查金叉后的K线是否按上涨趋势运行
trend_up_after_golden = true
for i = 1 to confirm_bars
if close[bars_since_golden - i] < golden_cross_price
trend_up_after_golden := false
break
golden_cross_confirmed := trend_up_after_golden
// 检查死叉后confirm_bars根K线是否持续下跌
death_cross_confirmed = false
if not na(bars_since_death) and bars_since_death >= confirm_bars and bars_since_death <= confirm_bars + 5
trend_down_after_death = true
for i = 1 to confirm_bars
if close[bars_since_death - i] > death_cross_price
trend_down_after_death := false
break
death_cross_confirmed := trend_down_after_death
// ==================== 价格站稳EMA52确认 ====================
// 检查价格是否在近期突破并站稳EMA52
price_above_ema52_stable = true
for i = 0 to math.min(breakout_bars - 1, bar_index)
if close[i] < ema52[i]
price_above_ema52_stable := false
break
price_below_ema52_stable = true
for i = 0 to math.min(breakout_bars - 1, bar_index)
if close[i] > ema52[i]
price_below_ema52_stable := false
break
// 检测EMA52突破
ema52_breakout_up = ta.crossover(close, ema52)
ema52_breakout_down = ta.crossunder(close, ema52)
// 近期是否有EMA52突破
recent_ema52_breakout_up = false
recent_ema52_breakout_down = false
for i = 0 to breakout_bars - 1
if ema52_breakout_up[i]
recent_ema52_breakout_up := true
if ema52_breakout_down[i]
recent_ema52_breakout_down := true
// ==================== 计算回调低点/高点作为止损 ====================
// 寻找最近的回调低点(用于多头止损)
var float swing_low = na
lookback_period = 20
swing_low := ta.lowest(low, lookback_period)
// 寻找最近的回调高点(用于空头止损)
var float swing_high = na
swing_high := ta.highest(high, lookback_period)
// ==================== 入场条件 ====================
// 多头入场条件:
// 1. 大级别为多头趋势(价格在EMA156上方)
// 2. 小级别刚从空头转多头(价格突破EMA52)
// 3. MACD金叉已确认(金叉后K线继续上涨)
// 4. 价格站稳EMA52
long_condition = big_trend_bullish and
small_trend_bullish and
(golden_cross_confirmed or (not na(bars_since_golden) and bars_since_golden <= breakout_bars)) and
(recent_ema52_breakout_up or price_above_ema52_stable) and
macd_line > signal_line
// 空头入场条件(反向操作):
// 1. 大级别为空头趋势(价格在EMA156下方)
// 2. 小级别刚从多头转空头(价格跌破EMA52)
// 3. MACD死叉已确认
// 4. 价格站稳EMA52下方
short_condition = big_trend_bearish and
small_trend_bearish and
(death_cross_confirmed or (not na(bars_since_death) and bars_since_death <= breakout_bars)) and
(recent_ema52_breakout_down or price_below_ema52_stable) and
macd_line < signal_line
// ==================== 计算止损止盈 ====================
// 多头止损止盈
long_stop_loss = swing_low
long_risk = close - long_stop_loss
long_take_profit = close + long_risk * risk_reward_ratio
// 空头止损止盈
short_stop_loss = swing_high
short_risk = short_stop_loss - close
short_take_profit = close - short_risk * risk_reward_ratio
// ==================== 执行交易 ====================
// 避免重复开仓
var bool in_long_position = false
var bool in_short_position = false
// 更新持仓状态
if strategy.position_size > 0
in_long_position := true
in_short_position := false
else if strategy.position_size < 0
in_long_position := false
in_short_position := true
else
in_long_position := false
in_short_position := false
// 多头入场
if long_condition and not in_long_position and long_risk > 0
strategy.entry("多头", strategy.long)
strategy.exit("多头止盈止损", "多头", stop=long_stop_loss, limit=long_take_profit)
// 空头入场
if short_condition and not in_short_position and short_risk > 0
strategy.entry("空头", strategy.short)
strategy.exit("空头止盈止损", "空头", stop=short_stop_loss, limit=short_take_profit)
// ==================== 绘制均线 ====================
plot(show_ema156 ? ema156 : na, "EMA156 大趋势", color=color.new(color.orange, 0), linewidth=2)
plot(show_ema52 ? ema52 : na, "EMA52 小趋势", color=color.new(color.blue, 0), linewidth=1)
// ==================== 绘制趋势背景 ====================
// 大趋势背景色
bg_color = big_trend_bullish ? color.new(color.green, 93) : big_trend_bearish ? color.new(color.red, 93) : na
bgcolor(bg_color, title="大趋势背景")
// ==================== 绘制信号标记 ====================
// 多头信号
plotshape(show_signals and long_condition and not in_long_position[1] ? low : na,
title="多头信号", style=shape.triangleup, location=location.belowbar,
color=color.new(color.green, 0), size=size.small, text="买入")
// 空头信号
plotshape(show_signals and short_condition and not in_short_position[1] ? high : na,
title="空头信号", style=shape.triangledown, location=location.abovebar,
color=color.new(color.red, 0), size=size.small, text="卖出")
// MACD金叉标记
plotshape(show_signals and macd_golden_cross ? low : na,
title="MACD金叉", style=shape.circle, location=location.belowbar,
color=color.new(color.lime, 0), size=size.tiny)
// MACD死叉标记
plotshape(show_signals and macd_death_cross ? high : na,
title="MACD死叉", style=shape.circle, location=location.abovebar,
color=color.new(color.fuchsia, 0), size=size.tiny)
// ==================== 绘制止损止盈线 ====================
plot(strategy.position_size > 0 ? long_stop_loss : na, "多头止损", color=color.red, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size > 0 ? long_take_profit : na, "多头止盈", color=color.green, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size < 0 ? short_stop_loss : na, "空头止损", color=color.red, style=plot.style_linebr, linewidth=1)
plot(strategy.position_size < 0 ? short_take_profit : na, "空头止盈", color=color.green, style=plot.style_linebr, linewidth=1)
// ==================== 信息面板 ====================
var table info_panel = table.new(position.top_right, 2, 8, bgcolor=color.new(color.black, 80), border_width=1)
if barstate.islast
table.cell(info_panel, 0, 0, "指标", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 0, "状态", text_color=color.white, text_size=size.small)
table.cell(info_panel, 0, 1, "大趋势(EMA156)", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 1, big_trend_bullish ? "📈 多头" : "📉 空头",
text_color=big_trend_bullish ? color.lime : color.red, text_size=size.small)
table.cell(info_panel, 0, 2, "小趋势(EMA52)", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 2, small_trend_bullish ? "📈 多头" : "📉 空头",
text_color=small_trend_bullish ? color.lime : color.red, text_size=size.small)
table.cell(info_panel, 0, 3, "MACD状态", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 3, macd_line > signal_line ? "金叉状态" : "死叉状态",
text_color=macd_line > signal_line ? color.lime : color.red, text_size=size.small)
table.cell(info_panel, 0, 4, "持仓状态", text_color=color.white, text_size=size.small)
position_text = strategy.position_size > 0 ? "多头持仓" : strategy.position_size < 0 ? "空头持仓" : "空仓"
position_color = strategy.position_size > 0 ? color.lime : strategy.position_size < 0 ? color.red : color.gray
table.cell(info_panel, 1, 4, position_text, text_color=position_color, text_size=size.small)
table.cell(info_panel, 0, 5, "EMA156", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 5, str.tostring(ema156, "#.##"), text_color=color.orange, text_size=size.small)
table.cell(info_panel, 0, 6, "EMA52", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 6, str.tostring(ema52, "#.##"), text_color=color.blue, text_size=size.small)
table.cell(info_panel, 0, 7, "盈亏比", text_color=color.white, text_size=size.small)
table.cell(info_panel, 1, 7, "1:" + str.tostring(risk_reward_ratio, "#.#"), text_color=color.yellow, text_size=size.small)
// ==================== 警报条件 ====================
alertcondition(long_condition and not in_long_position[1], title="多头入场信号", message="三重滤网策略:多头入场信号触发!大趋势多头,小趋势回调完成,MACD金叉确认")
alertcondition(short_condition and not in_short_position[1], title="空头入场信号", message="三重滤网策略:空头入场信号触发!大趋势空头,小趋势反弹完成,MACD死叉确认")
alertcondition(macd_golden_cross, title="MACD金叉", message="MACD金叉出现")
alertcondition(macd_death_cross, title="MACD死叉", message="MACD死叉出现")
+388
View File
@@ -0,0 +1,388 @@
//@version=6
indicator("多周期WMA52 (HTF/LTF)", overlay=true, max_labels_count=500, max_lines_count=500)
// ======================== 配置输入 ========================
// 主控
enableCTF = input.bool(true, "启用本级别", group="显示")
enableHTF = input.bool(true, "启用长级别", group="显示")
enableLTF = input.bool(true, "启用次级别", group="显示")
maxHTFInput = input.int(10, "最多显示长级别数量", minval=1, maxval=12, group="显示")
maxLTFInput = input.int(3, "最多显示次级别数量", minval=1, maxval=4, group="显示")
includeSeconds = input.bool(false, "包含秒级别(需高级套餐)", group="显示")
protectAutoscale = input.bool(true, "防拉伸: 仅绘制可视区间内", group="显示")
lookbackBars = input.int(300, "可视区间近多少根K线", minval=50, maxval=5000, group="显示")
padPercent = input.float(2.0, "可视边界留白(%)", minval=0.0, maxval=20.0, step=0.1, group="显示")
// 视觉(虚线效果)
dashLenHTF = input.int(6, "长级别虚线段长度", minval=1, maxval=50, group="线型")
dashGapHTF = input.int(4, "长级别虚线间隔", minval=1, maxval=50, group="线型")
dashLenLTF = input.int(2, "次级别虚线段长度", minval=1, maxval=50, group="线型")
dashGapLTF = input.int(3, "次级别虚线间隔", minval=1, maxval=50, group="线型")
lineWidthHTF = input.int(1, "长级别线宽", minval=1, maxval=4, group="线型")
lineWidthLTF = input.int(1, "次级别线宽", minval=1, maxval=4, group="线型")
lineWidthCTF = input.int(1, "本级别线宽", minval=1, maxval=4, group="线型")
enableSmooth = input.bool(true, "平滑显示(EMA)", group="线型")
smoothLenHTF = input.int(3, "长级别平滑长度", minval=1, maxval=50, group="线型")
smoothLenLTF = input.int(3, "次级别平滑长度", minval=1, maxval=50, group="线型")
smoothLenCTF = input.int(3, "本级别平滑长度", minval=1, maxval=50, group="线型")
smoothMethod = input.string("ALMA", "平滑方法", options=["EMA","DEMA","TEMA","WMA","HMA","ALMA","LinReg"], group="线型")
almaOffset = input.float(0.85, "ALMA偏移(0-1)", minval=0.0, maxval=1.0, step=0.05, group="线型")
almaSigma = input.float(6.0, "ALMA Sigma", minval=0.5, maxval=10.0, step=0.5, group="线型")
labelBgAlpha = input.int(85, "标签背景透明(0-100)", minval=0, maxval=100, group="标注")
labelSize = input.string("normal", "标签字号", options=["tiny","small","normal","large","huge"], group="标注")
labelOffsetBars = input.int(2, "标签右移K线的距离(根数)", minval=0, maxval=50, group="标注")
// 常量上限(编译期固定,用于生成固定数量的 plot 位)
const int MAX_HTF = 12
const int MAX_LTF = 4
// ======================== 工具函数 ========================
f_dash(series float v, int phase, int dashLen, int dashGap) =>
// 通过丢弃部分柱来营造虚线效果
isShow = (bar_index + phase) % (dashLen + dashGap) < dashLen
isShow ? v : na
// 自定义 DEMA / TEMAPine 无内置 dema/tema
f_dema(series float v, int len) =>
ema1 = ta.ema(v, len)
ema2 = ta.ema(ema1, len)
2.0 * ema1 - ema2
f_tema(series float v, int len) =>
ema1 = ta.ema(v, len)
ema2 = ta.ema(ema1, len)
ema3 = ta.ema(ema2, len)
3.0 * (ema1 - ema2) + ema3
// 通用平滑(仅用于显示)
f_smooth(series float v, int len) =>
not enableSmooth or len <= 1 ? v :
smoothMethod == "EMA" ? ta.ema(v, len) :
smoothMethod == "DEMA" ? f_dema(v, len) :
smoothMethod == "TEMA" ? f_tema(v, len) :
smoothMethod == "WMA" ? ta.wma(v, len) :
smoothMethod == "HMA" ? ta.hma(v, len) :
smoothMethod == "ALMA" ? ta.alma(v, len, almaOffset, almaSigma) :
ta.linreg(v, len, 0)
f_strToSize(string s) => switch s
"tiny" => size.tiny
"small" => size.small
"normal" => size.normal
"large" => size.large
=> size.huge
// 颜色调色板(循环使用)
var color[] PALETTE = array.new_color()
if barstate.isfirst and array.size(PALETTE) == 0
array.push(PALETTE, color.new(color.teal, 0))
array.push(PALETTE, color.new(color.orange, 0))
array.push(PALETTE, color.new(color.fuchsia,0))
array.push(PALETTE, color.new(color.aqua, 0))
array.push(PALETTE, color.new(color.yellow, 0))
array.push(PALETTE, color.new(color.purple, 0))
array.push(PALETTE, color.new(color.lime, 0))
array.push(PALETTE, color.new(color.red, 0))
array.push(PALETTE, color.new(color.blue, 0))
array.push(PALETTE, color.new(color.navy, 0))
array.push(PALETTE, color.new(color.maroon, 0))
array.push(PALETTE, color.new(color.silver, 0))
f_paletteColor(int idx) =>
sz = math.max(1, array.size(PALETTE))
array.get(PALETTE, idx % sz)
// 是否为秒级分辨率,如 "1S","5S"
f_isSecondsTf(string tf) =>
ln = str.length(tf)
ln > 0 and str.substring(tf, ln - 1, ln) == 'S'
// 计算可视范围边界(近 N 根 K 线 + 百分比留白)
rangeHi = ta.highest(high, lookbackBars)
rangeLo = ta.lowest(low, lookbackBars)
rangeSpan = rangeHi - rangeLo
pad = rangeSpan * padPercent * 0.01
minY = rangeLo - pad
maxY = rangeHi + pad
// 仅在可视区间内绘制(超出返回 na,以避免影响自动缩放)。
f_gate(series float v) => protectAutoscale ? (v >= minY and v <= maxY ? v : na) : v
// 检查是否在可视区间内
f_inRange(series float v) => protectAutoscale ? (v >= minY and v <= maxY) : true
// 周期字符串美化(如 1 -> 1m, 60 -> 1h, D -> 1D, W -> 1W, 3M -> 3M
f_prettyTf(string tf) =>
s = timeframe.in_seconds(tf)
string out = tf
if not na(s)
if s < 3600
mins = math.max(1, math.round(s / 60))
out := str.tostring(mins) + 'm'
else if s % 3600 == 0 and s < 86400
hrs = math.round(s / 3600)
out := str.tostring(hrs) + 'h'
else if s % 86400 == 0 and s < 7 * 86400
days = math.round(s / 86400)
out := str.tostring(days) + 'D'
else if s % (7 * 86400) == 0 and s < 30 * 86400
weeks = math.round(s / (7 * 86400))
out := str.tostring(weeks) + 'W'
else
out := tf
else
// 月等返回 na 的分辨率保持原样(M/3M)
out := tf
out
// ======================== 标准时间周期表 ========================
// 备注:TradingView 分辨率字符串 —— 分钟: "1","3","5"...;小时: "60","120"...
// 天: "D","2D";周: "W","2W";月: "M","3M";秒级可能为 "1S","5S" 等。
var string[] ALL_RES = array.new_string()
if barstate.isfirst and array.size(ALL_RES) == 0
// 由低到高,便于筛选
// 秒级(若品种/权限不支持,请忽略,筛选时会自动排除)
array.push(ALL_RES, "1S")
array.push(ALL_RES, "5S")
array.push(ALL_RES, "15S")
array.push(ALL_RES, "30S")
// 分钟
array.push(ALL_RES, "1")
array.push(ALL_RES, "3")
array.push(ALL_RES, "5")
array.push(ALL_RES, "15")
array.push(ALL_RES, "30")
array.push(ALL_RES, "45")
// 小时(以分钟表示)
array.push(ALL_RES, "60")
array.push(ALL_RES, "120")
array.push(ALL_RES, "240")
array.push(ALL_RES, "360")
array.push(ALL_RES, "480")
array.push(ALL_RES, "720")
// 日/周/月
array.push(ALL_RES, "D")
array.push(ALL_RES, "2D")
array.push(ALL_RES, "3D")
array.push(ALL_RES, "W")
array.push(ALL_RES, "2W")
array.push(ALL_RES, "M")
array.push(ALL_RES, "3M")
// ======================== 周期间关系与选择 ========================
curResStr = timeframe.period
curResSec = timeframe.in_seconds(curResStr)
// 构建长/次级别列表
var string[] htfRes = array.new_string()
var string[] ltfRes = array.new_string()
array.clear(htfRes)
array.clear(ltfRes)
for i = 0 to array.size(ALL_RES) - 1
res = array.get(ALL_RES, i)
// 非高级用户默认不包含秒级周期
if not includeSeconds and f_isSecondsTf(res)
continue
rsec = timeframe.in_seconds(res)
// timeframe.in_seconds 不支持时返回 na,需跳过
if na(rsec)
continue
if rsec > curResSec
array.push(htfRes, res)
else if rsec < curResSec
array.push(ltfRes, res)
// 选取靠近当前周期的若干次级别(更有参考意义):取 ltfRes 的末尾(更接近当前)
var string[] ltfSel = array.new_string()
array.clear(ltfSel)
ltfsz = array.size(ltfRes)
if ltfsz > 0
take = math.min(maxLTFInput, MAX_LTF, ltfsz)
for k = 0 to take - 1
array.push(ltfSel, array.get(ltfRes, ltfsz - 1 - k))
// 限制长级别数量
htfCountSelected = math.min(array.size(htfRes), maxHTFInput, MAX_HTF)
ltfCountSelected = math.min(array.size(ltfSel), MAX_LTF)
// ======================== 计算各周期 WMA52 ========================
// 预分配数值数组(保持固定最大长度)
var float[] htfVals = array.new_float()
var float[] ltfVals = array.new_float()
float ctfVal = na
if barstate.isfirst
for _i = 0 to MAX_HTF - 1
array.push(htfVals, na)
for _j = 0 to MAX_LTF - 1
array.push(ltfVals, na)
// 填充长级别数值
for i = 0 to MAX_HTF - 1
float val = na
if enableHTF and i < htfCountSelected
tfStr = array.get(htfRes, i)
// 计算该长级别的 WMA52
val := request.security(syminfo.tickerid, tfStr, ta.wma(close, 52), barmerge.gaps_off, barmerge.lookahead_off)
array.set(htfVals, i, val)
// 填充次级别数值
for i = 0 to MAX_LTF - 1
float val = na
if enableLTF and i < ltfCountSelected
tfStr = array.get(ltfSel, i)
// 计算该次级别的 WMA52(低级别向上合成,注意其更频繁更新)
val := request.security(syminfo.tickerid, tfStr, ta.wma(close, 52), barmerge.gaps_off, barmerge.lookahead_off)
array.set(ltfVals, i, val)
// 本级别 WMA52
if enableCTF
ctfVal := ta.wma(close, 52)
// ======================== 绘制(虚线 + 标签) ========================
// 顶层固定 plot(避免在局部/循环中调用 plot)
plot(enableCTF ? f_gate(f_smooth(ctfVal, smoothLenCTF)) : na, title='CTF WMA52', color=color.new(color.white, 0), linewidth=lineWidthCTF, style=plot.style_line)
plot((enableHTF and 0 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 0), smoothLenHTF), 0 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 1', color=f_paletteColor(0), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 1 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 1), smoothLenHTF), 1 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 2', color=f_paletteColor(1), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 2 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 2), smoothLenHTF), 2 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 3', color=f_paletteColor(2), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 3 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 3), smoothLenHTF), 3 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 4', color=f_paletteColor(3), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 4 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 4), smoothLenHTF), 4 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 5', color=f_paletteColor(4), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 5 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 5), smoothLenHTF), 5 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 6', color=f_paletteColor(5), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 6 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 6), smoothLenHTF), 6 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 7', color=f_paletteColor(6), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 7 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 7), smoothLenHTF), 7 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 8', color=f_paletteColor(7), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 8 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 8), smoothLenHTF), 8 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 9', color=f_paletteColor(8), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 9 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 9), smoothLenHTF), 9 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 10', color=f_paletteColor(9), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 10 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 10), smoothLenHTF), 10 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 11', color=f_paletteColor(10), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableHTF and 11 < htfCountSelected) ? f_gate(f_dash(f_smooth(array.get(htfVals, 11), smoothLenHTF), 11 * 2, dashLenHTF, dashGapHTF)) : na, title='HTF WMA52 12', color=f_paletteColor(11), linewidth=lineWidthHTF, style=plot.style_line)
plot((enableLTF and 0 < ltfCountSelected) ? f_gate(f_dash(f_smooth(array.get(ltfVals, 0), smoothLenLTF), 0 * 3 + 1, dashLenLTF, dashGapLTF)) : na, title='LTF WMA52 1', color=color.new(f_paletteColor(0), 30), linewidth=lineWidthLTF, style=plot.style_line)
plot((enableLTF and 1 < ltfCountSelected) ? f_gate(f_dash(f_smooth(array.get(ltfVals, 1), smoothLenLTF), 1 * 3 + 1, dashLenLTF, dashGapLTF)) : na, title='LTF WMA52 2', color=color.new(f_paletteColor(1), 30), linewidth=lineWidthLTF, style=plot.style_line)
plot((enableLTF and 2 < ltfCountSelected) ? f_gate(f_dash(f_smooth(array.get(ltfVals, 2), smoothLenLTF), 2 * 3 + 1, dashLenLTF, dashGapLTF)) : na, title='LTF WMA52 3', color=color.new(f_paletteColor(2), 30), linewidth=lineWidthLTF, style=plot.style_line)
plot((enableLTF and 3 < ltfCountSelected) ? f_gate(f_dash(f_smooth(array.get(ltfVals, 3), smoothLenLTF), 3 * 3 + 1, dashLenLTF, dashGapLTF)) : na, title='LTF WMA52 4', color=color.new(f_paletteColor(3), 30), linewidth=lineWidthLTF, style=plot.style_line)
// 右侧标签(仅在最后一根柱更新,避免重复创建)
var label[] htfLabels = array.new_label()
var label[] ltfLabels = array.new_label()
var label ctfLabel = na
var string lastTicker = na
var string lastTf = na
if barstate.isfirst
for _i = 0 to MAX_HTF - 1
array.push(htfLabels, na)
for _j = 0 to MAX_LTF - 1
array.push(ltfLabels, na)
lastTicker := syminfo.tickerid
lastTf := timeframe.period
// 更新/清理标签
// 如果品种或周期变化,清理旧标签
symbolChanged = lastTicker != syminfo.tickerid
tfChanged = lastTf != timeframe.period
if symbolChanged or tfChanged
for i = 0 to MAX_HTF - 1
lab = array.get(htfLabels, i)
if not na(lab)
label.delete(lab)
array.set(htfLabels, i, na)
for i = 0 to MAX_LTF - 1
lab = array.get(ltfLabels, i)
if not na(lab)
label.delete(lab)
array.set(ltfLabels, i, na)
if not na(ctfLabel)
label.delete(ctfLabel)
ctfLabel := na
lastTicker := syminfo.tickerid
lastTf := timeframe.period
if barstate.islast
// 长级别
for i = 0 to MAX_HTF - 1
lab = array.get(htfLabels, i)
if enableHTF and i < htfCountSelected
tfStr = array.get(htfRes, i)
v = array.get(htfVals, i)
col = f_paletteColor(i)
txt = f_prettyTf(tfStr) + ' ' + str.tostring(v, format.mintick)
// 可视区间外则隐藏标签;区间内按真实价格绘制,确保与标尺一致
if protectAutoscale and not f_inRange(v)
if not na(lab)
label.delete(lab)
array.set(htfLabels, i, na)
else
if na(lab)
lab := label.new(bar_index + labelOffsetBars, v, txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, textcolor=col, color=color.new(col, labelBgAlpha), size=f_strToSize(labelSize))
array.set(htfLabels, i, lab)
else
label.set_xy(lab, bar_index + labelOffsetBars, v)
label.set_text(lab, txt)
label.set_textcolor(lab, col)
label.set_color(lab, color.new(col, labelBgAlpha))
label.set_style(lab, label.style_label_left)
label.set_size(lab, f_strToSize(labelSize))
else
if not na(lab)
label.delete(lab)
array.set(htfLabels, i, na)
// 次级别
for i = 0 to MAX_LTF - 1
lab = array.get(ltfLabels, i)
if enableLTF and i < ltfCountSelected
tfStr = array.get(ltfSel, i)
v = array.get(ltfVals, i)
base = f_paletteColor(i)
col = color.new(base, 0)
txt = f_prettyTf(tfStr) + ' ' + str.tostring(v, format.mintick)
if protectAutoscale and not f_inRange(v)
if not na(lab)
label.delete(lab)
array.set(ltfLabels, i, na)
else
if na(lab)
lab := label.new(bar_index + labelOffsetBars, v, txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, textcolor=col, color=color.new(col, labelBgAlpha + 10 > 100 ? 100 : labelBgAlpha + 10), size=f_strToSize(labelSize))
array.set(ltfLabels, i, lab)
else
label.set_xy(lab, bar_index + labelOffsetBars, v)
label.set_text(lab, txt)
label.set_textcolor(lab, col)
label.set_color(lab, color.new(col, labelBgAlpha + 10 > 100 ? 100 : labelBgAlpha + 10))
label.set_style(lab, label.style_label_left)
label.set_size(lab, f_strToSize(labelSize))
else
if not na(lab)
label.delete(lab)
array.set(ltfLabels, i, na)
// 本级别
if enableCTF
v = ctfVal
col = color.new(color.white, 0)
txt = f_prettyTf(curResStr) + ' ' + str.tostring(v, format.mintick)
if protectAutoscale and not f_inRange(v)
if not na(ctfLabel)
label.delete(ctfLabel)
ctfLabel := na
else
if na(ctfLabel)
ctfLabel := label.new(bar_index + labelOffsetBars, v, txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, textcolor=col, color=color.new(col, labelBgAlpha), size=f_strToSize(labelSize))
else
label.set_xy(ctfLabel, bar_index + labelOffsetBars, v)
label.set_text(ctfLabel, txt)
label.set_textcolor(ctfLabel, col)
label.set_color(ctfLabel, color.new(col, labelBgAlpha))
label.set_style(ctfLabel, label.style_label_left)
label.set_size(ctfLabel, f_strToSize(labelSize))
else
if not na(ctfLabel)
label.delete(ctfLabel)
ctfLabel := na
// ======================== 备注 ========================
// 1) 当前周期通过 timeframe.period 自动识别,并用 timeframe.in_seconds(
// ) 转换成秒以进行相对大小比较。
// 2) 长级别/次级别集合从标准分辨率表中过滤得出,绘图数量受 MAX_* 与输入上限控制。
// 3) 虚线效果通过在 plot 中周期性输出 na 实现,性能优于逐柱绘制 line 对象。
// 4) 标签在最后一根柱更新,避免过量对象;颜色与曲线一致。
// 5) 次级别(低于当前)WMA52 也计算并显示,更新频率更高,默认更淡。