Skip to main content

Pine Script Bid Ask: Access Real-Time Spread Data

· 12 min read
Pineify Team
Pine Script and AI trading workflow research team

Pine Script bid ask variables let you read real-time bid and ask prices from your connected broker directly inside TradingView. These were added in platform version 6, and most traders don't realize they exist.

I've been using them for about six months now, and they've saved me from entering at least a dozen bad trades on EUR/USD alone. The spread cost on a standard lot during news events can hit $50 or more if you're not watching.

What Pine Script Bid Ask Actually Gives You

Think of a flea market. The seller wants $20, you're willing to pay $15. That $5 gap is the spread.

  • Bid = the highest price someone will pay to buy from you
  • Ask = the lowest price someone will sell to you
  • Spread = the difference (the broker's cut)

Pine Script can grab these prices through built-in variables. The catch is they only update when a trade executes, not continuously.

Why Bother Checking Spread Data

  • Entry timing: spreads tighten and widen throughout the day. Enter when they're narrow.
  • Cost clarity: a 3-pip spread on a 20-pip target eats 15% of your profit.
  • Liquidity reads: wide spreads usually mean thin liquidity or a news spike.
  • Filter bad trades: skip setups when the spread is wider than your stop distance.

Getting the Data: The One-Liner That Works

Here's the trick: bid and ask variables only work on the 1-tick (1T) timeframe. But you can pull them onto any chart with request.security.

//@version=6
indicator("Bid Ask Spread", overlay=true)

// This is the magic trick - pull data from 1T timeframe
float askPrice = request.security(syminfo.tickerid, "1T", ask)
float bidPrice = request.security(syminfo.tickerid, "1T", bid)

// Calculate the actual spread
float spread = askPrice - bidPrice

// Plot it so you can see what's happening
plot(askPrice, color=color.red, title="Ask Price")
plot(bidPrice, color=color.lime, title="Bid Price")
plot(spread, display=display.status_line, title="Spread")

The request.security call says "give me the ask price from the 1-tick chart, even though I'm looking at a 15-minute chart." Simple, but easy to forget the timeframe requirement.

The Variables You'll Use

  • ask: current asking price
  • bid: current bidding price
  • syminfo.tickerid: the symbol identifier request.security needs

Important: these only return live data from a 1T context. Without request.security, they're useless on any other timeframe.

Check out more Pine Script indicators on Pineify for ready-to-use trading tools.

Filters, Monitors, and Practical Code

Knowing the spread is one thing. Acting on it is another. Here's what I actually run on my charts.

The "I'm Not Touching This" Filter:

//@version=6
indicator("Spread Filter", overlay=true)

// Set your max acceptable spread
float maxSpread = input.float(2.0, "Max Spread (in pips)")

// Get the data
float askPrice = request.security(syminfo.tickerid, "1T", ask)
float bidPrice = request.security(syminfo.tickerid, "1T", bid)
float spread = askPrice - bidPrice

// Simple logic: if spread is too high, don't trade
bool isSpreadHigh = spread > maxSpread

// Paint the background red when spreads are nasty
bgcolor(isSpreadHigh ? color.new(color.red, 50) : na)

I run this on every forex pair I trade. On December 8, 2025, GBP/JPY hit a 7-pip spread during the NFP release. My screen turned solid red for 12 minutes. I sat on my hands and watched other traders get stopped out.

Advanced Spread Monitor

//@version=6
indicator("Advanced Spread Monitor", overlay=false)

// Input parameters
maxSpreadPips = input.float(2.0, "Max Acceptable Spread (pips)", minval=0.1)
showSpreadHistory = input.bool(true, "Show Spread History")
alertOnWideSpread = input.bool(true, "Alert on Wide Spreads")

// Get bid ask data
askPrice = request.security(syminfo.tickerid, "1T", ask)
bidPrice = request.security(syminfo.tickerid, "1T", bid)
spreadPoints = askPrice - bidPrice

// Convert to pips (for forex pairs)
pipValue = syminfo.mintick * 10
spreadPips = spreadPoints / pipValue

// Spread analysis
avgSpread = ta.sma(spreadPips, 20)
maxSpread = ta.highest(spreadPips, 50)
minSpread = ta.lowest(spreadPips, 50)

// Conditions
isWideSpread = spreadPips > maxSpreadPips
isNormalSpread = spreadPips <= maxSpreadPips

// Plots
plot(spreadPips, "Current Spread", color=isWideSpread ? color.red : color.green, linewidth=2)
plot(avgSpread, "Average Spread", color=color.blue, linewidth=1)
plot(maxSpreadPips, "Max Acceptable", color=color.orange, style=plot.style_line)

// Background coloring
bgcolor(isWideSpread ? color.new(color.red, 90) : na, title="Wide Spread Warning")

// Alerts
if alertOnWideSpread and isWideSpread
alert("Wide spread detected: " + str.tostring(spreadPips, "#.#") + " pips", alert.freq_once_per_bar)

Trading Strategies That Use Spread Data

Skip the chop. Don't enter when spreads are wide. Wait for them to normalize. I'd rather miss a trade than enter one where the spread is half my target.

Session timing. EUR/USD spreads tighten during London-New York overlap (roughly 1-4 PM GMT). I've checked this consistently — the difference is usually 0.3 to 0.6 pips tighter than Asian session.

Position sizing adjustments. If the spread eats 10% or more of my target, I cut position size by half. On USD/JPY with a 2-pip spread and a 15-pip target, that's 13.3% friction. Not worth full size.

Spread Impact Calculator

//@version=6
indicator("Spread Impact Calculator", overlay=true)

// Trading parameters
targetPips = input.float(20.0, "Target Profit (pips)")
stopLossPips = input.float(10.0, "Stop Loss (pips)")
positionSize = input.float(1.0, "Position Size (lots)")

// Get spread data
askPrice = request.security(syminfo.tickerid, "1T", ask)
bidPrice = request.security(syminfo.tickerid, "1T", bid)
spreadPoints = askPrice - bidPrice
pipValue = syminfo.mintick * 10
spreadPips = spreadPoints / pipValue

// Calculate spread impact
spreadCostUSD = spreadPips * positionSize * 10 // Assuming $10 per pip per lot
targetProfitUSD = targetPips * positionSize * 10
spreadImpactPercent = (spreadPips / targetPips) * 100

// Display results
var table infoTable = table.new(position.top_right, 2, 5, bgcolor=color.white, border_width=1)
if barstate.islast
table.cell(infoTable, 0, 0, "Metric", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 0, "Value", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 0, 1, "Current Spread", text_color=color.black)
table.cell(infoTable, 1, 1, str.tostring(spreadPips, "#.#") + " pips", text_color=color.black)
table.cell(infoTable, 0, 2, "Spread Cost", text_color=color.black)
table.cell(infoTable, 1, 2, "$" + str.tostring(spreadCostUSD, "#.##"), text_color=color.black)
table.cell(infoTable, 0, 3, "Target Profit", text_color=color.black)
table.cell(infoTable, 1, 3, "$" + str.tostring(targetProfitUSD, "#.##"), text_color=color.black)
table.cell(infoTable, 0, 4, "Spread Impact", text_color=color.black)
table.cell(infoTable, 1, 4, str.tostring(spreadImpactPercent, "#.#") + "%",
text_color=spreadImpactPercent > 15 ? color.red : color.green)

What This Can't Do (And I Wish It Could)

Let me be blunt about the limitations:

It's not actually streaming. The bid/ask values update per trade, not per millisecond. If the market goes quiet for 30 seconds, your spread reading is 30 seconds stale. During fast moves, that's a real problem.

You need a live broker feed. Paper trading accounts and free TradingView accounts won't return bid/ask data. You need an active connection through OANDA, Interactive Brokers, FXCM, Pepperstone, IG, Binance, or similar. See Pineify pricing for broker-connected plan options.

No historical data. You can't go back and see what the spread was an hour ago. Backtesting a spread-dependent strategy requires approximation, which I haven't found to be reliable enough for serious use.

Supported Brokers and Markets

TradingView-connected brokers that pass bid/ask data:

  • Forex: OANDA, FXCM, Interactive Brokers, Pepperstone
  • CFDs: IG, CMC Markets, City Index
  • Crypto: Binance, Coinbase Pro, Kraken (limited pairs)
  • Stocks: Interactive Brokers, TradeStation

Markets covered:

  • Forex pairs (major, minor, exotic)
  • CFDs on indices, commodities, stocks
  • Crypto pairs (select exchanges)
  • Futures (limited)

Things I've Learned Running This Code

Start minimal. A simple spread filter tells you more in a week than a complex monitor does. I started with just the background color change and only added the alert system after two months.

Session matters more than I expected. London open spreads on EUR/GBP are about 0.8 pips tighter than during Tokyo hours. I haven't tested this across every pair, but for the majors, the pattern holds.

Broker quality varies. One of my broker feeds shows spreads that jump from 0.5 to 4 pips randomly for no apparent reason. Another broker on the same pair stays under 1.5 pips. If you see weird gaps, check your broker first, not your code.

Always validate the data before using it:

// Always check if data exists before using it
bool dataAvailable = not na(askPrice) and not na(bidPrice)
float validSpread = dataAvailable ? spread : na

Safe Data Handling

//@version=6
indicator("Robust Bid Ask Handler", overlay=true)

// Function to safely get bid ask data
getSafeBidAsk() =>
askPrice = request.security(syminfo.tickerid, "1T", ask)
bidPrice = request.security(syminfo.tickerid, "1T", bid)

// Validate data
isValidData = not na(askPrice) and not na(bidPrice) and askPrice > bidPrice

// Return validated data or na
[isValidData ? askPrice : na, isValidData ? bidPrice : na, isValidData]

[safeAsk, safeBid, isDataValid] = getSafeBidAsk()
safeSpread = isDataValid ? safeAsk - safeBid : na

// Visual indicators
plotshape(not isDataValid, "Data Invalid", shape.xcross, location.top, color.red, size=size.small)
plot(safeSpread, "Safe Spread", color=isDataValid ? color.green : na)

When Bid/Ask Isn't Available

If your broker or instrument doesn't support these variables, you can approximate:

// Not perfect, but better than nothing
bidApprox = request.security(syminfo.tickerid, timeframe.period, low)
askApprox = request.security(syminfo.tickerid, timeframe.period, high)
spreadApprox = askApprox - bidApprox

It's a rough estimate. It won't replace real bid/ask data, but it gives you a volatility signal.

High-Low Approximation Script

//@version=6
indicator("Spread Approximation", overlay=false)

// Get OHLC data from 1-tick timeframe
tickHigh = request.security(syminfo.tickerid, "1T", high)
tickLow = request.security(syminfo.tickerid, "1T", low)
tickClose = request.security(syminfo.tickerid, "1T", close)

// Calculate approximate spread
approxSpread = tickHigh - tickLow

// Convert to pips for forex
pipValue = syminfo.mintick * 10
approxSpreadPips = approxSpread / pipValue

// Smooth the data
smoothedSpread = ta.ema(approxSpreadPips, 5)

// Plot results
plot(approxSpreadPips, "Approx Spread (Raw)", color=color.gray, linewidth=1)
plot(smoothedSpread, "Approx Spread (Smoothed)", color=color.blue, linewidth=2)

// Add reference lines
hline(1.0, "1 Pip", color=color.green, linestyle=hline.style_dashed)
hline(2.0, "2 Pips", color=color.orange, linestyle=hline.style_dashed)
hline(3.0, "3 Pips", color=color.red, linestyle=hline.style_dashed)

Frequently Asked Questions

Do Pine Script bid ask variables work on all TradingView accounts?

No. You need a broker-connected account through TradingView. Free and paper trading accounts don't get real bid/ask data.

Can I use Pine Script bid ask data for backtesting?

Only in a limited way. The variables give current data, not historical spreads. You can approximate with high/low bars, but I haven't found those results trustworthy enough to act on.

Which timeframes support Pine Script bid ask functionality?

Just the 1-tick (1T) timeframe. But you can pull it onto any chart using request.security(), which is what everyone actually does.

How accurate is Pine Script bid ask data compared to broker feeds?

It comes directly from your broker, so accuracy depends on them. Most major brokers provide reliable feeds, but I've seen odd gaps with smaller ones.

Can I get historical bid ask spreads in Pine Script?

No. Current data only. For historical analysis, you'll need approximation or external sources.

Does Pine Script bid ask work with cryptocurrency trading?

Yes, for select pairs on major exchanges like Binance and Coinbase Pro. Not every pair is supported though.

How often does Pine Script bid ask data update?

Each tick — so every time the price changes. During active sessions, that's multiple times per second.

Can I use Pine Script bid ask for automated trading?

You can build bid/ask logic into strategies, but the actual execution depends on your broker's API. Pine Script handles the logic, the broker handles the fills.

The bid/ask variables aren't flashy, but they've changed how I evaluate a setup before pulling the trigger. If you're trading forex or CFDs through a connected broker, there's no reason not to add a spread check to your indicator stack.

Browse more TradingView guides on the Pineify resources hub for additional strategies and tools.