To pull the live, dynamic spread directly from your broker's feed, we need to upgrade the script to Pine Script v6. This version introduced native ask and bid variables, allowing you to bypass static inputs and calculate the real-time spread instantly.
Because ask and bid are tick-level metrics, we have to request them specifically from the 1-tick ("1T") timeframe using request.security(). This ensures the live feed calculates accurately even if your primary structural analysis is on the M15 or H1 charts.
Code: Select all
//@version=6
indicator("Net Expectancy & Friction Model (Live Spread)", overlay=true)
// =========================================================================
// INPUTS: Statistical Averages
// =========================================================================
winRate = input.float(55.0, title="Historical Win Rate (%)", group="Strategy Metrics") / 100
meanGrossWin = input.float(4.0, title="Mean Gross Win (Pips)", group="Strategy Metrics")
meanGrossLoss = input.float(3.0, title="Mean Gross Loss (Pips)", group="Strategy Metrics")
// =========================================================================
// INPUTS: Execution Friction
// =========================================================================
commPerLot = input.float(7.0, title="Round Turn Comm ($/Lot)", group="Execution Costs")
pipValue = input.float(10.0, title="Pip Value ($/Lot)", group="Execution Costs")
estSlippage = input.float(0.2, title="Mean Slippage (Pips)", group="Execution Costs")
fallbackSp = input.float(0.8, title="Historical Fallback Spread", tooltip="Live spread is only available on real-time bars. This value is used for historical bars.", group="Execution Costs")
// =========================================================================
// LIVE SPREAD CALCULATION
// =========================================================================
// Fetch live Ask and Bid from the 1-tick timeframe
liveAsk = request.security(syminfo.tickerid, "1T", ask)
liveBid = request.security(syminfo.tickerid, "1T", bid)
// Determine pip size (Forex pairs usually have a pip size of mintick * 10, e.g., 0.0001. Indices/Metals use mintick * 1)
pipSize = syminfo.type == "forex" ? syminfo.mintick * 10 : syminfo.mintick
// Calculate live spread in pips. If na (historical bar), use fallback.
liveSpreadPips = (liveAsk - liveBid) / pipSize
activeSpread = not na(liveSpreadPips) ? liveSpreadPips : fallbackSp
// =========================================================================
// EXPECTANCY MATH
// =========================================================================
// Calculate total friction in pips
commInPips = commPerLot / pipValue
totalFriction = commInPips + activeSpread + estSlippage
// Calculate net distributions
netWinMean = meanGrossWin - totalFriction
netLossMean = meanGrossLoss + totalFriction
// Calculate Expectancy
grossExp = (meanGrossWin * winRate) - (meanGrossLoss * (1 - winRate))
netExp = (netWinMean * winRate) - (netLossMean * (1 - winRate))
// =========================================================================
// DASHBOARD UI
// =========================================================================
var table expTable = table.new(position.bottom_right, 2, 6, bgcolor=color.rgb(15, 15, 15, 10), border_width=1, border_color=color.rgb(60, 60, 60))
if barstate.islast
// Headers
table.cell(expTable, 0, 0, "METRIC", text_color=color.gray, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 0, "VALUE (PIPS)", text_color=color.gray, text_halign=text.align_right, text_size=size.small)
// Current Active Spread
spreadColor = not na(liveSpreadPips) ? color.aqua : color.gray
table.cell(expTable, 0, 1, "Live Spread Feed", text_color=color.white, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 1, str.tostring(activeSpread, "#.##"), text_color=spreadColor, text_halign=text.align_right, text_size=size.small)
// Execution Friction
table.cell(expTable, 0, 2, "Total Execution Friction", text_color=color.white, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 2, str.tostring(totalFriction, "#.##"), text_color=color.red, text_halign=text.align_right, text_size=size.small)
// Gross Expectancy
table.cell(expTable, 0, 3, "Gross Expectancy (Pre-Cost)", text_color=color.white, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 3, str.tostring(grossExp, "#.##"), text_color=color.gray, text_halign=text.align_right, text_size=size.small)
// Net Expectancy
color netColor = netExp > 0 ? color.lime : color.red
table.cell(expTable, 0, 4, "Net Expectancy (True Yield)", text_color=color.white, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 4, str.tostring(netExp, "#.##"), text_color=netColor, text_halign=text.align_right, text_size=size.small)
// N=100 Projection
table.cell(expTable, 0, 5, "Projected Yield (N=100)", text_color=color.white, text_halign=text.align_left, text_size=size.small)
table.cell(expTable, 1, 5, str.tostring(netExp * 100, "#.##"), text_color=netColor, text_halign=text.align_right, text_size=size.small)