196 lines
20 KiB
Plaintext
196 lines
20 KiB
Plaintext
//@version=6
|
||
indicator('ma200_p', shorttitle='ma200_p', overlay=true)
|
||
|
||
// ————————————— 输入参数 —————————————
|
||
exponential = input.bool(true, title='使用指数移动平均线 (EMA)')
|
||
default_dist = input.float(3.0, title='默认 MA200 距离阈值 (USD)', minval=0.1, step=0.1)
|
||
btc_dist = input.float(150.0, title='BTCUSD MA200 距离阈值 (USD)', minval=0.1, step=0.1)
|
||
xau_dist = input.float(3.0, title='XAUUSD MA200 距离阈值 (USD)', minval=0.1, step=0.1)
|
||
eth_dist = input.float(8.0, title='ETHUSD MA200 距离阈值 (USD)', minval=0.1, step=0.1)
|
||
gbp_dist = input.float(0.3, title='GBPJPY MA200 距离阈值 (USD)', minval=0.1, step=0.1)
|
||
|
||
flatness_period = input.int(20, title='MA200 波动回看周期', minval=1)
|
||
flatness_threshold = input.float(0.5, title='MA200 平坦度阈值 (USD)', minval=0.01, step=0.01)
|
||
oscillation_bars = input.int(10, title='价格波动回看周期', minval=1)
|
||
oscillation_threshold = input.float(5.0, title='价格波动范围阈值 (USD)', minval=0.1, step=0.1)
|
||
|
||
// ————————————— 自定义MA(xx)参数 —————————————
|
||
ma_custom_period = input.int(30, title='自定义MA周期', minval=1, maxval=500)
|
||
ma_custom_color = input.color(color.orange, title='自定义MA颜色')
|
||
ma_custom_linewidth = input.int(2, title='自定义MA线段粗细', minval=1, maxval=10)
|
||
|
||
// ————————————— 计算移动平均线 —————————————
|
||
src = close
|
||
ma50 = exponential ? ta.ema(src, 50) : ta.sma(src, 50)
|
||
ma100 = exponential ? ta.ema(src, 100) : ta.sma(src, 100)
|
||
ma200 = exponential ? ta.ema(src, 200) : ta.sma(src, 200)
|
||
ma_custom = exponential ? ta.ema(src, ma_custom_period) : ta.sma(src, ma_custom_period)
|
||
|
||
// ————————————— 移动平均线颜色函数 —————————————
|
||
maColor(ma, ref) => ma > ref ? color.lime : color.red
|
||
|
||
// ————————————— 绘制 MA50/MA100/MA200/自定义MA —————————————
|
||
plot(ma50, color=maColor(ma50, ma100), linewidth=2, title='MA50', display=display.all)
|
||
plot(ma100, color=maColor(ma100, ma200), linewidth=2, title='MA100', display=display.all)
|
||
plot(ma200, color=color.rgb(25, 58, 243), linewidth=4, title='MA200', display=display.all)
|
||
plot(ma_custom, color=ma_custom_color, linewidth=ma_custom_linewidth, title='MA自定义', display=display.all)
|
||
|
||
// ————————————— 价格标签(单行 label.new) —————————————
|
||
var label lbl50 = na
|
||
var label lbl100 = na
|
||
var label lbl200 = na
|
||
var label lbl_custom = na
|
||
|
||
if barstate.islast
|
||
if na(lbl50)
|
||
lbl50 := label.new(x=time, y=ma50, text='MA50: ' + str.tostring(ma50, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.lime, textcolor=color.white)
|
||
else
|
||
label.set_xy(lbl50, x=time, y=ma50), label.set_text(lbl50, 'MA50: ' + str.tostring(ma50, '#.####'))
|
||
|
||
if na(lbl100)
|
||
lbl100 := label.new(x=time, y=ma100, text='MA100: ' + str.tostring(ma100, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.white, textcolor=color.black)
|
||
else
|
||
label.set_xy(lbl100, x=time, y=ma100), label.set_text(lbl100, 'MA100: ' + str.tostring(ma100, '#.####'))
|
||
|
||
if na(lbl200)
|
||
lbl200 := label.new(x=time, y=ma200, text='MA200: ' + str.tostring(ma200, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=color.white, textcolor=color.black)
|
||
else
|
||
label.set_xy(lbl200, x=time, y=ma200), label.set_text(lbl200, 'MA200: ' + str.tostring(ma200, '#.####'))
|
||
|
||
if na(lbl_custom)
|
||
lbl_custom := label.new(x=time, y=ma_custom, text='MA自定义: ' + str.tostring(ma_custom, '#.####'), xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, color=ma_custom_color, textcolor=color.white)
|
||
else
|
||
label.set_xy(lbl_custom, x=time, y=ma_custom), label.set_text(lbl_custom, 'MA自定义: ' + str.tostring(ma_custom, '#.####'))
|
||
|
||
// ————————————— 阈值切换(异常交易对) —————————————
|
||
sym = ticker.standard(syminfo.tickerid)
|
||
distance_threshold =
|
||
sym == 'TICKMILL:BTCUSD' ? btc_dist :
|
||
sym == 'TICKMILL:XAUUSD' ? xau_dist :
|
||
sym == 'TICKMILL:ETHUSD' ? eth_dist :
|
||
sym == 'TICKMILL:GBPJPY' ? gbp_dist :
|
||
default_dist
|
||
|
||
// ————————————— 警报计算 —————————————
|
||
distance_usd = math.abs(close - ma200)
|
||
is_near_ma200 = distance_usd <= distance_threshold
|
||
ma200_max = ta.highest(ma200, flatness_period)
|
||
ma200_min = ta.lowest(ma200, flatness_period)
|
||
ma200_flatness = ma200_max - ma200_min
|
||
is_flat = ma200_flatness < flatness_threshold
|
||
cross_above = ta.crossover(close, ma200)
|
||
cross_below = ta.crossunder(close, ma200)
|
||
price_max = ta.highest(close, oscillation_bars)
|
||
price_min = ta.lowest(close, oscillation_bars)
|
||
is_oscillating = (price_max - price_min) < oscillation_threshold and (cross_above or cross_below)
|
||
is_above_ma200 = close > ma200
|
||
is_below_ma200 = close < ma200
|
||
|
||
// ————————————— 绘制供数据窗口使用 —————————————
|
||
plot(ma200, title='MA200', display=display.data_window)
|
||
plot(ma_custom, title='MA自定义', display=display.data_window)
|
||
plot(distance_usd, title='Distance USD', display=display.data_window)
|
||
plot(ma200_flatness, title='Flatness USD', display=display.data_window)
|
||
|
||
// ===== 统一警报系统 =====
|
||
// 统一警报系统 - 只需添加一次警报即可捕获所有信号
|
||
|
||
// 警报频率限制 - 每分钟只触发一次
|
||
var int last_alert_near_ma200 = 0
|
||
var int last_alert_ma200_flat = 0
|
||
var int last_alert_oscillating = 0
|
||
var int last_alert_cross_above = 0
|
||
var int last_alert_cross_below = 0
|
||
var int last_alert_above_ma200 = 0
|
||
var int last_alert_below_ma200 = 0
|
||
|
||
// 获取当前时间(分钟级别)
|
||
current_minute = math.floor(timenow / 60000)
|
||
|
||
// 检测所有警报条件并生成对应的JSON消息
|
||
alert_message = ""
|
||
|
||
// 价格靠近 MA200 - 每分钟限制
|
||
if is_near_ma200 and current_minute > last_alert_near_ma200
|
||
alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格靠近MA200","位置":"靠近MA200"}'
|
||
alert(alert_message, alert.freq_once_per_bar_close)
|
||
last_alert_near_ma200 := current_minute
|
||
|
||
// // MA200 波动较小 - 每分钟限制
|
||
// if is_flat and current_minute > last_alert_ma200_flat
|
||
// alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","波动范围":"' + str.tostring(ma200_flatness, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"MA200波动较小","位置":"MA200波动很小"}'
|
||
// alert(alert_message, alert.freq_once_per_bar_close)
|
||
// last_alert_ma200_flat := current_minute
|
||
|
||
// // 价格在 MA200 附近上下波动 - 每分钟限制
|
||
// if is_oscillating and current_minute > last_alert_oscillating
|
||
// alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","波动范围":"' + str.tostring(ma200_flatness, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格在MA200上下波动","位置":"MA200附近波动"}'
|
||
// alert(alert_message, alert.freq_once_per_bar_close)
|
||
// last_alert_oscillating := current_minute
|
||
|
||
// 价格穿越 MA200 信号 - 每分钟限制
|
||
// if cross_above and current_minute > last_alert_cross_above
|
||
// alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格上穿MA200","信号":"buy","位置":"突破MA200"}'
|
||
// alert(alert_message, alert.freq_once_per_bar_close)
|
||
// last_alert_cross_above := current_minute
|
||
|
||
// if cross_below and current_minute > last_alert_cross_below
|
||
// alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格下穿MA200","信号":"sell","位置":"跌破MA200"}'
|
||
// alert(alert_message, alert.freq_once_per_bar_close)
|
||
// last_alert_cross_below := current_minute
|
||
|
||
// 价格位置状态警报 - 每分钟限制
|
||
if is_above_ma200 and current_minute > last_alert_above_ma200
|
||
alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格在MA200以上","位置":"MA200以上"}'
|
||
alert(alert_message, alert.freq_once_per_bar)
|
||
last_alert_above_ma200 := current_minute
|
||
|
||
if is_below_ma200 and current_minute > last_alert_below_ma200
|
||
alert_message := '{"指标名称":"MA200","交易对":"' + syminfo.ticker + '","周期":"' + timeframe.period + '","MA50":"' + str.tostring(ma50, '#.####') + '","MA100":"' + str.tostring(ma100, '#.####') + '","MA200":"' + str.tostring(ma200, '#.####') + '","距离(美元)":"' + str.tostring(distance_usd, '#.##') + '","开盘价":"' + str.tostring(open, '#.####') + '","收盘价":"' + str.tostring(close, '#.####') + '","最高价":"' + str.tostring(high, '#.####') + '","最低价":"' + str.tostring(low, '#.####') + '","触发时间":"' + str.tostring(timenow) + '","时间":"' + str.tostring(time) + '","事件":"价格在MA200以下","位置":"MA200以下"}'
|
||
alert(alert_message, alert.freq_once_per_bar)
|
||
last_alert_below_ma200 := current_minute
|
||
|
||
// ===== 传统警报条件(保留兼容性)=====
|
||
// 注意:使用统一警报系统时,建议只使用上面的alert()函数
|
||
// 以下alertcondition保留用于需要单独设置警报的情况
|
||
|
||
// 创建用于警报的plot变量
|
||
plot(ma50, title = 'MA50值', display = display.none)
|
||
plot(ma100, title = 'MA100值', display = display.none)
|
||
plot(ma200, title = 'MA200值', display = display.none)
|
||
plot(ma_custom, title = 'MA自定义值', display = display.none)
|
||
plot(distance_usd, title = '距离美元', display = display.none)
|
||
plot(ma200_flatness, title = 'MA200波动范围', display = display.none)
|
||
|
||
// 价格靠近MA200警报
|
||
alertcondition(is_near_ma200, title = '价格靠近MA200', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格靠近MA200","位置":"靠近MA200","信号":"near_ma200"}')
|
||
|
||
// MA200波动较小警报
|
||
// alertcondition(is_flat, title = 'MA200波动较小', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","波动范围":"{{plot("MA200波动范围")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MA200波动较小","位置":"MA200波动很小","信号":"ma200_flat"}')
|
||
|
||
// // 价格在MA200上下波动警报
|
||
// alertcondition(is_oscillating, title = '价格在MA200上下波动', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","波动范围":"{{plot("MA200波动范围")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格在MA200上下波动","位置":"MA200附近波动","信号":"oscillating_ma200"}')
|
||
|
||
// // 价格穿越MA200警报
|
||
// alertcondition(cross_above, title = '价格上穿MA200', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格上穿MA200","信号":"buy","位置":"突破MA200"}')
|
||
|
||
// alertcondition(cross_below, title = '价格下穿MA200', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格下穿MA200","信号":"sell","位置":"跌破MA200"}')
|
||
|
||
// 价格位置状态警报
|
||
alertcondition(is_above_ma200, title = '价格在MA200以上', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格在MA200以上","位置":"MA200以上","信号":"above_ma200"}')
|
||
|
||
alertcondition(is_below_ma200, title = '价格在MA200以下', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"价格在MA200以下","位置":"MA200以下","信号":"below_ma200"}')
|
||
|
||
// MA50和MA100穿越警报
|
||
// alertcondition(ta.crossover(ma50, ma100), title = 'MA50上穿MA100', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MA50上穿MA100","信号":"ma50_cross_above_ma100","位置":"MA50突破MA100"}')
|
||
|
||
// alertcondition(ta.crossunder(ma50, ma100), title = 'MA50下穿MA100', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MA50下穿MA100","信号":"ma50_cross_below_ma100","位置":"MA50跌破MA100"}')
|
||
|
||
// alertcondition(ta.crossover(ma100, ma200), title = 'MA100上穿MA200', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MA100上穿MA200","信号":"ma100_cross_above_ma200","位置":"MA100突破MA200"}')
|
||
|
||
// alertcondition(ta.crossunder(ma100, ma200), title = 'MA100下穿MA200', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"MA100下穿MA200","信号":"ma100_cross_below_ma200","位置":"MA100跌破MA200"}')
|
||
|
||
// 综合移动平均线排列警报
|
||
alertcondition(ma50 > ma100 and ma100 > ma200, title = '多头排列', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"多头排列","信号":"bullish_alignment","位置":"MA50>MA100>MA200"}')
|
||
|
||
alertcondition(ma50 < ma100 and ma100 < ma200, title = '空头排列', message = '{"指标名称":"MA200","交易对":"{{ticker}}","周期":"{{interval}}","MA50":"{{plot("MA50值")}}","MA100":"{{plot("MA100值")}}","MA200":"{{plot("MA200值")}}","距离(美元)":"{{plot("距离美元")}}","开盘价":"{{open}}","收盘价":"{{close}}","最高价":"{{high}}","最低价":"{{low}}","触发时间":"{{timenow}}","时间":"{{time}}","事件":"空头排列","信号":"bearish_alignment","位置":"MA50<MA100<MA200"}') |