Исходный код
Представленный ниже код реализует простую стратегию парного трейдинга. Она основана на предположении, что спред между двумя высококоррелированными активами является стационарным и будет возвращаться к своему среднему значению после отклонений. Мы используем Z-score для определения моментов входа и выхода из позиций.
Для получения данных по второму активу используется функция request.security, что позволяет работать с двумя разными тикерами на одном графике. Это ключевой элемент для мультисимвольных стратегий в Pine Script v5, как мы уже рассматривали в статье Скрипт Pine Script v5: Поиск скрытой медвежьей дивергенции по RSI с request.security.
//@version=5
strategy("Pairs Trading Strategy (Spread Z-Score)", overlay=false, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.05)
// --- Input Parameters ---
symbol1 = input.string(syminfo.tickerid, "Symbol 1 (Current Chart)", group="Symbols")
symbol2 = input.string("QQQ", "Symbol 2", group="Symbols")
lookbackPeriod = input.int(60, "Lookback Period for Spread Stats", minval=10, group="Strategy Settings")
stdDevEntry = input.float(2.0, "Std Dev Entry Threshold", minval=0.5, step=0.1, group="Strategy Settings")
stdDevExit = input.float(0.5, "Std Dev Exit Threshold", minval=0.1, step=0.1, group="Strategy Settings")
hedgeRatio = input.float(1.0, "Fixed Hedge Ratio (Symbol1 / Symbol2)", minval=0.01, step=0.01, group="Strategy Settings")
useDynamicHedgeRatio = input.bool(false, "Use Dynamic Hedge Ratio (Linear Regression)", group="Strategy Settings")
// --- Get Prices ---
price1 = request.security(symbol1, timeframe.period, close)
price2 = request.security(symbol2, timeframe.period, close)
// --- Calculate Dynamic Hedge Ratio (Optional) ---
var float currentHedgeRatio = hedgeRatio
if useDynamicHedgeRatio
// Calculate linear regression slope (beta) between price1 and price2
// This is a simplified approach. A more robust method would involve cointegration tests.
[slope, intercept, rsq] = ta.linreg(price1, price2, lookbackPeriod)
currentHedgeRatio := slope
// Ensure hedge ratio is not zero or negative
if currentHedgeRatio <= 0
currentHedgeRatio := 1.0 // Fallback to fixed ratio
// --- Calculate Spread ---
spread = price1 - currentHedgeRatio * price2
// --- Calculate Z-Score of the Spread ---
meanSpread = ta.sma(spread, lookbackPeriod)
stdDevSpread = ta.stdev(spread, lookbackPeriod)
zScore = (spread - meanSpread) / stdDevSpread
// --- Plotting ---
plot(spread, "Spread", color.blue)
plot(meanSpread, "Mean Spread", color.orange, style=plot.style_linebr)
plot(zScore, "Z-Score", color.purple, display=display.pane)
hline(stdDevEntry, "Upper Entry Threshold", color.red, linestyle=hline.style_solid, display=display.pane)
hline(-stdDevEntry, "Lower Entry Threshold", color.green, linestyle=hline.style_solid, display=display.pane)
hline(stdDevExit, "Upper Exit Threshold", color.gray, linestyle=hline.style_dotted, display=display.pane)
hline(-stdDevExit, "Lower Exit Threshold", color.gray, linestyle=hline.style_dotted, display=display.pane)
hline(0, "Zero Line", color.black, linestyle=hline.style_dotted, display=display.pane)
// --- Strategy Logic ---
float tradeSizePercent = 0.5 // Percentage of equity to allocate to the *first leg* of the pair
float qty1 = (strategy.equity * tradeSizePercent) / price1
float qty2 = qty1 * currentHedgeRatio // Calculate qty for Symbol2 based on qty1 and hedge ratio
// Long the spread (Buy Symbol1, Sell Symbol2)
if ta.crossunder(zScore, -stdDevEntry) and strategy.opentrades == 0
strategy.entry("LongS1", strategy.long, qty=qty1, comment="Long S1")
strategy.entry("ShortS2", strategy.short, qty=qty2, comment="Short S2")
// Short the spread (Sell Symbol1, Buy Symbol2)
if ta.crossover(zScore, stdDevEntry) and strategy.opentrades == 0
strategy.entry("ShortS1", strategy.short, qty=qty1, comment="Short S1")
strategy.entry("LongS2", strategy.long, qty=qty2, comment="Long S2")
// Exit Long Spread (Close Buy Symbol1, Close Sell Symbol2)
if strategy.position_size("LongS1") > 0 and ta.crossover(zScore, -stdDevExit)
strategy.close("LongS1", comment="Exit Long S1")
strategy.close("ShortS2", comment="Exit Short S2")
// Exit Short Spread (Close Sell Symbol1, Close Buy Symbol2)
if strategy.position_size("ShortS1") > 0 and ta.crossunder(zScore, stdDevExit)
strategy.close("ShortS1", comment="Exit Short S1")
strategy.close("LongS2", comment="Exit Long S2")
// Optional: Close all positions if Z-score returns to zero (mean reversion)
if strategy.opentrades > 0 and ta.cross(zScore, 0)
strategy.close_all("Mean Reversion Exit")
// Example of sending alerts (can be integrated with Discord webhook)
// For more advanced alerts, see: https://finfluct.com/pine-script/pine-script-v5-i-discord-otpravka-grafikov-cherez-webhook-pri-alertah/
alertcondition(ta.crossunder(zScore, -stdDevEntry), "Long Spread Entry Alert", "Z-Score below lower entry threshold for {{ticker}} and {{tickerid}}")
alertcondition(ta.crossover(zScore, stdDevEntry), "Short Spread Entry Alert", "Z-Score above upper entry threshold for {{ticker}} and {{tickerid}}")
Разбор параметров
symbol1: Текущий символ графика, на котором запущена стратегия.symbol2: Символ второго актива для парного трейдинга (например, «QQQ» или «MSFT»).lookbackPeriod: Период (в барах) для расчета скользящего среднего и стандартного отклонения спреда. Влияет на чувствительность Z-score и адаптивность стратегии к изменениям рынка.stdDevEntry: Количество стандартных отклонений, при достижении которых Z-score спреда открывается позиция. Чем выше значение, тем реже входы, но потенциально выше качество сигнала (меньше ложных срабатываний).stdDevExit: Количество стандартных отклонений, при достижении которых Z-score спреда закрывается позиция. Обычно это значение ближе к нулю, чемstdDevEntry, чтобы зафиксировать прибыль при возврате спреда к среднему.hedgeRatio: Фиксированный коэффициент хеджирования. Определяет, сколько единицsymbol2нужно купить/продать на одну единицуsymbol1для нейтрализации рыночного риска. ЕслиuseDynamicHedgeRatioустановлено вfalse, используется это значение.useDynamicHedgeRatio: Еслиtrue, коэффициент хеджирования будет рассчитываться динамически с использованием линейной регрессии (наклона) за периодlookbackPeriod. Это позволяет стратегии адаптироваться к изменяющимся отношениям между активами.
Для более глубокого понимания работы с различными временными рамками и предотвращения перерисовки, что критически важно для надежных расчетов, рекомендуем ознакомиться с нашей статьей Chaikin Money Flow (CMF) MTF без перерисовки в Pine Script v5.
Как запустить
1. Откройте TradingView и перейдите на график любого актива (например, SPY).
2. Нажмите кнопку «Indicators» (Индикаторы) или «Strategy Tester» (Тестер стратегий).
3. Выберите «Pine Script Editor» (Редактор Pine Script).
4. Вставьте предоставленный выше код в редактор.
5. Нажмите «Add to Chart» (Добавить на график).
6. В настройках стратегии (шестеренка рядом с названием стратегии на графике) вы можете настроить параметры:
- Укажите
Symbol 2(например, «QQQ», еслиSymbol 1— «SPY»). - Настройте
Lookback Period,Std Dev Entry ThresholdиStd Dev Exit Thresholdв соответствии с вашими предпочтениями и результатами бэктестинга. - Определите
Hedge Ratioили включитеUse Dynamic Hedge Ratio.
7. Перейдите во вкладку «Strategy Tester» (Тестер стратегий) для анализа результатов бэктестинга. Обратите внимание, что для корректного бэктестинга необходимо, чтобы оба символа имели достаточно исторической информации на выбранном таймфрейме.
8. Для получения уведомлений о сигналах, вы можете настроить алерты на основе alertcondition, которые затем можно интегрировать с внешними системами, например, через вебхуки Discord, как описано в статье Pine Script v5 и Discord: Отправка графиков через Webhook при алертах.




