
Pairs trading is one of the most fundamental quantitative trading strategies, offering a market-neutral approach to profiting from the mean-reverting relationship between two correlated assets. In this deep-dive tutorial, we'll show you how to build an automated pairs trading bot using PineScript, AI assistance, and TradersPost for execution.
Pairs trading operates on a simple premise: two highly correlated assets will occasionally diverge in price, creating a temporary imbalance. When this happens, you can profit by simultaneously buying the underperforming asset and shorting the outperforming one, betting they'll converge back to their normal relationship.
Unlike directional strategies that bet on price going up or down, pairs trading is market-neutral. You're not trading the absolute price of either asset—you're trading the spread between them. This makes the strategy less sensitive to overall market direction and more focused on relative value.
Traditional pairs trading relies on concepts like cointegration and stationarity to identify asset pairs that truly move together over the long term. The gold standard test is the Augmented Dickey-Fuller (ADF) test, which determines whether the spread between two assets is stationary (mean-reverting).
However, PineScript lacks access to these advanced statistical functions that are common in Python or R. You can't easily implement ADF or cointegration tests directly in TradingView. This limitation forces us to take a more practical approach: identifying pairs through correlation analysis and visual inspection.
For a pairs trading strategy to work in PineScript, focus on assets with:
One of the most interesting developments in 2025 is using AI to accelerate strategy development. Rather than coding everything from scratch, you can leverage tools like ChatGPT, Claude, or Grok to generate PineScript code based on educational content.
Here's the process:
Start with a well-explained video or article about pairs trading. Look for content that clearly outlines the strategy mechanics, entry conditions, and exit signals. YouTube is excellent for this—search for "pairs trading algorithm" or "mean reversion strategy."
Use a transcript downloading tool (like tactic.io) to capture the video content with timestamps. These timestamps are crucial—when you need to reference where specific concepts were explained, you can jump directly to that moment in the video.
Take the transcript and provide it to your AI coding assistant with clear instructions:
` Based on this conversation about pairs trading, create a pairs trading bot indicator in PineScript version 6. Include the following:
`
The first output rarely works perfectly. You'll need to:
The key advantage of AI assistance isn't that it produces perfect code immediately—it's that it dramatically accelerates the iteration cycle. You can test ideas in minutes rather than hours.
Your pairs trading bot needs to measure the relationship between two assets. There are two common approaches:
Ratio Method: Divide the price of Asset 1 by Asset 2 `pinescript ratio = close / security(syminfo.tickerid_2, timeframe.period, close) `
Spread Method: Subtract Asset 2 price from Asset 1 `pinescript spread = close - security(syminfo.tickerid_2, timeframe.period, close) `
Both methods work, but ratio is generally preferred for assets with different price magnitudes (like SPY at $580 and QQQ at $500). The spread method works better for similar-priced assets like futures contracts.
The z-score tells you how many standard deviations the current spread is from its historical mean. This standardized metric makes it easy to identify extreme divergences.
`pinescript // Calculate mean and standard deviation over a lookback period lookback = input.int(20, "Lookback Period") mean = ta.sma(ratio, lookback) std_dev = ta.stdev(ratio, lookback)
// Calculate z-score z_score = (ratio - mean) / std_dev `
When the z-score reaches +2 or -2, the spread has moved two standard deviations from normal—a potential entry signal. When it returns to zero, the spread has reverted to the mean—your exit signal.
Your strategy should track whether you're currently in a position and only enter new trades when flat:
`pinescript // Entry conditions long_entry = ta.crossunder(z_score, -2) and not in_position short_entry = ta.crossover(z_score, 2) and not in_position
// Exit condition exit_signal = ta.cross(z_score, 0) `
The logic is simple: when the z-score drops below -2, Asset 1 is undervalued relative to Asset 2, so you buy Asset 1 and sell Asset 2. When it rises above +2, the opposite is true. When it returns to zero, you close both positions.
Here's where pairs trading gets tricky in TradingView: You need to send two separate orders to your broker at the same time. TradingView's standard alert system only references one symbol—the chart you're viewing.
The solution involves clever alert message construction:
`pinescript // Define alert messages in indicator settings buy_message = input.text('{"ticker":"{{ticker}}", "action":"buy", "price":"{{close}}"}') sell_message = input.text('{"ticker":"SYMBOL2", "action":"sell", "price":"PRICE2"}')
// On entry signal, replace placeholders and send both alerts if long_entry // Replace {{ticker}} with syminfo.ticker for chart symbol alert_msg_1 = str.replace(buy_message, "{{ticker}}", syminfo.ticker) alert_msg_1 := str.replace(alert_msg_1, "{{close}}", str.tostring(close)) alert(alert_msg_1, alert.freq_once_per_bar)
// Replace placeholders for second symbol alert_msg_2 = str.replace(sell_message, "SYMBOL2", symbol_2_input) alert_msg_2 := str.replace(alert_msg_2, "PRICE2", str.tostring(price_2)) alert(alert_msg_2, alert.freq_once_per_bar) `
This approach fires two webhook alerts to TradersPost, each containing the correct symbol and action. TradersPost receives both messages and executes the orders simultaneously against your connected broker account.
Because you're using an indicator (not a strategy), you don't get automatic performance metrics from TradingView. However, you can build your own tracking system using arrays:
`pinescript // Define trade type type Trade int bar_index int time float entry_price float exit_price bool ended = false int pair // 1 or 2 to track which symbol
// Array to store all trades var array
// On entry, add new trade if long_entry array.push(trades, Trade.new(bar_index, time, close, na, false, 1))
// On exit, update last trade if exit_signal last_trade = array.get(trades, array.size(trades) - 1) last_trade.exit_price := close last_trade.ended := true `
You can then calculate win rate, profit factor, and other metrics by iterating through the trades array and displaying results in a table on your chart.
When configuring your TradersPost strategy subscription for pairs trading:
Position Sizing: Use fixed contract quantities rather than percentage-based sizing. Pairs trading requires equal notional value on both sides, so calculate this beforehand.
Side Swapping: Enable this feature so your strategy can automatically reverse from long to short (or vice versa) when signals flip.
Subtract Signal Quantity: For futures, enable this to ensure proper position offsetting when reversing positions.
Auto Submit: During testing, disable auto-submit to manually approve each trade and verify both legs executed correctly.
Problem: The two symbols don't stay correlated over time.
Solution: Regularly monitor correlation coefficients. If correlation drops below 0.7, consider finding a new pair or pausing the strategy until conditions improve.
Problem: One leg of the trade executes but the other fails.
Solution: Implement error handling and position reconciliation. TradersPost tracks both positions, so you can manually close the orphaned leg if needed.
Problem: Spread stops mean-reverting after you enter.
Solution: Add a stop-loss based on z-score extremes. If the z-score reaches -3 or +3, exit even without mean reversion—you've encountered a regime change.
Problem: Slippage eats into profits on simultaneous execution.
Solution: Use limit orders with a small buffer from market price, or only trade highly liquid pairs where bid-ask spreads are tight.
For proper risk management, both legs of your pairs trade should have equal dollar value:
` If Asset 1 trades at $100 and you want $10,000 exposure:
If Asset 2 trades at $80:
`
This dollar neutrality ensures you're truly market-neutral—gains on one leg offset losses on the other, leaving only the spread movement as your profit source.
Once you have a basic pairs trading bot working, consider these enhancements:
Dynamic Pair Selection: Scan multiple potential pairs and automatically trade the ones with the highest z-scores.
Multiple Timeframe Analysis: Confirm divergences across multiple timeframes before entering (e.g., signal on 1-hour, confirm on 4-hour).
Volume-Weighted Entries: Only enter when both symbols show above-average volume, ensuring liquidity for execution.
Correlation Decay Monitoring: Plot a 30-day rolling correlation and pause trading if it drops below your threshold.
Calendar Awareness: Avoid entering new pairs trades before major economic reports or earnings announcements that could disrupt correlations.
Equity Pairs:
Futures Pairs:
Crypto Pairs:
As AI tools continue to improve, expect pairs trading development to become even more accessible. Future enhancements might include:
The barrier to entry for quantitative trading strategies like pairs trading has never been lower. With TradingView's visual tools, AI coding assistants, and execution platforms like TradersPost, retail traders can implement institutional-grade strategies that were once exclusive to hedge funds and proprietary trading firms.
Whether you're a quantitative trading novice or an experienced systematic trader, pairs trading offers a compelling risk-adjusted return profile. By automating the strategy with PineScript and TradersPost, you can capture mean reversion opportunities 24/7 without manual monitoring. Start with well-correlated pairs, test thoroughly across different market regimes, and scale slowly as you gain confidence in your system's reliability.