TradingView: Обход лимита 500 алертов Pine Script v5 через JSON мультиплексирование

TradingView: Обход лимита 500 алертов Pine Script v5 через JSON мультиплексирование Pine Script
Узнайте, как обойти ограничение в 500 алертов на аккаунт TradingView, используя технику мультиплексирования JSON-сообщений в одном скрипте Pine Script v5. Подробное руководство с кодом и инструкциями по настройке.
Суть: Обход лимита в 500 алертов на TradingView достигается путем консолидации множества потенциальных сигналов в одно JSON-сообщение, которое отправляется через единственный алерт. Это позволяет одному алерту передавать информацию о срабатывании десятков или сотен условий, эффективно мультиплексируя данные.

Исходный код

Ограничение в 500 активных алертов на аккаунт TradingView может стать серьезным препятствием для трейдеров и разработчиков, использующих сложные торговые стратегии, требующие мониторинга множества инструментов или условий. Однако, используя возможности Pine Script v5 по работе с JSON и вебхуками, можно элегантно обойти это ограничение.

Идея заключается в том, чтобы вместо создания отдельного алерта для каждого торгового условия (например, пересечение скользящих средних, RSI перекупленность/перепроданность, пробой уровня или обнаружение Order Blocks), мы собираем статусы всех интересующих нас условий в один JSON-объект. Этот JSON-объект затем отправляется через единственный алерт TradingView на ваш собственный вебхук-сервер. Ваш сервер, получив JSON, парсит его и уже на своей стороне принимает решение о том, какие уведомления отправлять и куда (Telegram, email, Discord и т.д.).

Представленный ниже скрипт демонстрирует, как мультиплексировать несколько типов алертов (пересечение скользящих средних, RSI перекупленность/перепроданность, всплеск объема) в одно JSON-сообщение. Вы можете легко расширить его, добавив свои собственные условия, например, для отслеживания дивергенций с осциллятором Стохастик или активации трейлинг-стопа по теням свечей.


//@version=5
indicator("Multiplexed Alerts JSON", overlay=true, max_alerts_per_calc=500)

// --- Inputs ---
var string GROUP_WEBHOOK = "Webhook Settings"
webhookUrl = input.string("https://your-webhook-receiver.com/alert", "Webhook URL", group=GROUP_WEBHOOK, tooltip="URL вашего сервера для приема JSON-сообщений. Пример: https://finfluct.com/webhook-processor")
alertMessagePrefix = input.string("TV_ALERT", "Alert Message Prefix", group=GROUP_WEBHOOK, tooltip="Префикс для идентификации сообщений от этого скрипта.")

var string GROUP_MA = "Moving Average Crossover Alert"
enableMAAlert = input.bool(true, "Enable MA Crossover Alert", group=GROUP_MA)
fastMALength = input.int(10, "Fast MA Length", minval=1, group=GROUP_MA)
slowMALength = input.int(30, "Slow MA Length", minval=1, group=GROUP_MA)

var string GROUP_RSI = "RSI Overbought/Oversold Alert"
enableRSIAlert = input.bool(true, "Enable RSI Alert", group=GROUP_RSI)
rsiLength = input.int(14, "RSI Length", minval=1, group=GROUP_RSI)
rsiOverbought = input.int(70, "RSI Overbought Level", minval=0, maxval=100, group=GROUP_RSI)
rsiOversold = input.int(30, "RSI Oversold Level", minval=0, maxval=100, group=GROUP_RSI)

var string GROUP_VOLUME = "Volume Spike Alert"
enableVolumeAlert = input.bool(true, "Enable Volume Spike Alert", group=GROUP_VOLUME)
volumeMultiplier = input.float(2.0, "Volume Avg Multiplier", minval=1.0, group=GROUP_VOLUME, tooltip="Объем должен быть в X раз выше среднего за последние N баров.")
volumeAvgLength = input.int(20, "Volume Avg Length", minval=1, group=GROUP_VOLUME)

// --- Calculations ---
fastMA = ta.sma(close, fastMALength)
slowMA = ta.sma(close, slowMALength)
rsiValue = ta.rsi(close, rsiLength)
avgVolume = ta.sma(volume, volumeAvgLength)

// --- Conditions ---
maCrossoverBullish = enableMAAlert and ta.crossover(fastMA, slowMA)
maCrossoverBearish = enableMAAlert and ta.crossunder(fastMA, slowMA)
rsiOverboughtTrigger = enableRSIAlert and ta.crossunder(rsiValue, rsiOverbought)
rsiOversoldTrigger = enableRSIAlert and ta.crossover(rsiValue, rsiOversold)
volumeSpikeTrigger = enableVolumeAlert and volume > avgVolume * volumeMultiplier

// --- JSON Payload Construction ---
// Создаем map для хранения статусов всех алертов
var map> alertsData = na

// Инициализируем или обновляем map на каждом баре
if barstate.islast
    alertsData := map.new()

    // MA Crossover
    if enableMAAlert
        alertsData.put("ma_crossover_bullish", map.new(
             "name", "MA Crossover Bullish",
             "triggered", maCrossoverBullish,
             "fast_ma", fastMA,
             "slow_ma", slowMA
        ))
        alertsData.put("ma_crossover_bearish", map.new(
             "name", "MA Crossover Bearish",
             "triggered", maCrossoverBearish,
             "fast_ma", fastMA,
             "slow_ma", slowMA
        ))

    // RSI
    if enableRSIAlert
        alertsData.put("rsi_overbought", map.new(
             "name", "RSI Overbought",
             "triggered", rsiOverboughtTrigger,
             "rsi_value", rsiValue,
             "level", float(rsiOverbought)
        ))
        alertsData.put("rsi_oversold", map.new(
             "name", "RSI Oversold",
             "triggered", rsiOversoldTrigger,
             "rsi_value", rsiValue,
             "level", float(rsiOversold)
        ))

    // Volume Spike
    if enableVolumeAlert
        alertsData.put("volume_spike", map.new(
             "name", "Volume Spike",
             "triggered", volumeSpikeTrigger,
             "current_volume", volume,
             "avg_volume", avgVolume
        ))

// --- Main Alert Logic ---
// Проверяем, сработало ли какое-либо из включенных условий
anyAlertTriggered = maCrossoverBullish or maCrossoverBearish or rsiOverboughtTrigger or rsiOversoldTrigger or volumeSpikeTrigger

if anyAlertTriggered
    // Собираем полный JSON-payload
    payload = map.new()
    payload.put("symbol", syminfo.tickerid)
    payload.put("interval", timeframe.period)
    payload.put("time", str.format("{0,date,yyyy-MM-dd HH:mm:ss}", time))
    payload.put("alerts", alertsData) // Встраиваем map с алертами

    // Конвертируем map в JSON-строку
    jsonString = json.tostring(payload)

    // Отправляем алерт с JSON-payload
    alert(alertMessagePrefix + " " + jsonString, alert.webhook_url)

// --- Plotting (Optional, for visualization) ---
plot(fastMA, "Fast MA", color.blue)
plot(slowMA, "Slow MA", color.orange)
plot(rsiValue, "RSI", color.purple, display=display.none) // Скрываем график RSI
hline(rsiOverbought, "RSI Overbought Level", color.red, display=display.none)
hline(rsiOversold, "RSI Oversold Level", color.green, display=display.none)

// Отображение срабатываний алертов для визуального подтверждения
plotshape(maCrossoverBullish, title="MA Bullish", location=location.belowbar, color=color.new(color.green, 0), style=shape.triangleup, size=size.small)
plotshape(maCrossoverBearish, title="MA Bearish", location=location.abovebar, color=color.new(color.red, 0), style=shape.triangledown, size=size.small)
plotshape(rsiOversoldTrigger, title="RSI Oversold", location=location.belowbar, color=color.new(color.lime, 0), style=shape.circle, size=size.small)
plotshape(rsiOverboughtTrigger, title="RSI Overbought", location=location.abovebar, color=color.new(color.fuchsia, 0), style=shape.circle, size=size.small)
plotshape(volumeSpikeTrigger, title="Volume Spike", location=location.abovebar, color=color.new(color.yellow, 0), style=shape.arrowdown, size=size.small)

Разбор параметров

  • webhookUrl: URL вашего сервера, который будет принимать JSON-сообщения от TradingView. Это критически важный параметр, так как именно на этот адрес будут отправляться все мультиплексированные алерты.
  • alertMessagePrefix: Произвольный префикс, который будет добавлен к началу JSON-сообщения. Помогает идентифицировать алерты от данного скрипта на вашем вебхук-сервере.
  • enableMAAlert: Включение/отключение алерта по пересечению скользящих средних.
  • fastMALength: Длина быстрой скользящей средней.
  • slowMALength: Длина медленной скользящей средней.
  • enableRSIAlert: Включение/отключение алерта по RSI (перекупленность/перепроданность).
  • rsiLength: Период расчета RSI.
  • rsiOverbought: Уровень RSI, выше которого считается перекупленность.
  • rsiOversold: Уровень RSI, ниже которого считается перепроданность.
  • enableVolumeAlert: Включение/отключение алерта по всплеску объема.
  • volumeMultiplier: Множитель, определяющий, во сколько раз текущий объем должен превышать средний объем за последние volumeAvgLength баров, чтобы сработал алерт.
  • volumeAvgLength: Период для расчета среднего объема.

Как запустить

Для успешной реализации этой стратегии вам потребуется не только Pine Script, но и внешний сервер для обработки вебхуков.

  1. Добавьте скрипт на график TradingView: Скопируйте предоставленный Pine Script код и добавьте его на любой график в TradingView.

  2. Настройте параметры скрипта: В настройках скрипта укажите webhookUrl вашего сервера. Убедитесь, что этот URL доступен извне и готов принимать POST-запросы.

  3. Создайте единственный алерт TradingView:

    • Нажмите на кнопку ‘Алерт’ на панели инструментов TradingView.
    • В качестве условия выберите ваш индикатор (Multiplexed Alerts JSON).
    • Для условия срабатывания выберите Any alert() call.
    • В разделе ‘Уведомления’ обязательно активируйте опцию ‘Webhook URL’ и вставьте туда тот же webhookUrl, который вы указали в параметрах скрипта.
    • В поле ‘Сообщение’ введите {{strategy.order.alert_message}}. Это гарантирует, что TradingView отправит именно то JSON-сообщение, которое было сформировано в вашем Pine Script.
    • Нажмите ‘Создать’.
  4. Настройте ваш вебхук-сервер: Вам понадобится небольшой серверный скрипт (например, на Python с Flask, Node.js с Express или PHP), который будет:

    • Принимать POST-запросы на указанный webhookUrl.
    • Парсить входящее JSON-сообщение.
    • Анализировать поле alerts в JSON, чтобы определить, какие из виртуальных алертов сработали (где "triggered": true).
    • На основе этой информации отправлять индивидуальные уведомления в нужные каналы (Telegram, email, Discord, Slack и т.д.).

    Пример простейшего обработчика на Python (Flask):

    
    from flask import Flask, request, jsonify
    import json
    
    app = Flask(__name__)
    
    @app.route('/alert', methods=['POST'])
    def handle_alert():
        if request.is_json:
            data = request.get_json()
            print(f"Received JSON: {json.dumps(data, indent=2)}")
    
            # Extract relevant info
            symbol = data.get('symbol')
            interval = data.get('interval')
            timestamp = data.get('time')
            alerts = data.get('alerts', {})
    
            triggered_alerts = []
            for alert_id, alert_info in alerts.items():
                if alert_info.get('triggered'):
                    triggered_alerts.append(alert_info.get('name', alert_id))
    
            if triggered_alerts:
                message = f"TradingView Alert on {symbol} ({interval}) at {timestamp}:\n"
                for ta_name in triggered_alerts:
                    message += f"- {ta_name} triggered!\n"
                
                # Здесь вы можете отправить уведомление в Telegram, Email и т.д.
                print(f"Sending notification: {message}")
                # Пример: send_telegram_message(message)
            else:
                print("No specific alerts triggered in this payload.")
    
            return jsonify({"status": "success", "message": "Alert processed"}), 200
        else:
            # Handle non-JSON payloads, e.g., if alertMessagePrefix is used without JSON
            raw_message = request.data.decode('utf-8')
            if raw_message.startswith("TV_ALERT "):
                try:
                    json_part = raw_message[len("TV_ALERT "):]
                    data = json.loads(json_part)
                    # Process as above
                    print(f"Received prefixed JSON: {json.dumps(data, indent=2)}")
                    return jsonify({"status": "success", "message": "Prefixed JSON alert processed"}), 200
                except json.JSONDecodeError:
                    print(f"Received raw message: {raw_message}")
                    return jsonify({"status": "error", "message": "Could not parse JSON from prefixed message"}), 400
            else:
                print(f"Received raw message: {raw_message}")
                return jsonify({"status": "error", "message": "Invalid content type or format"}), 400
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=5000)
    

Таким образом, вы эффективно обходите лимит в 500 алертов, используя всего один активный алерт на TradingView, который служит шлюзом для передачи неограниченного количества сигналов на ваш собственный, полностью контролируемый сервер.

Оцените статью
FinFluct