This Pine v6 indicator calculates signed current values from fixed shares and synchronized daily closes. It plots dollar, market and one additional factor exposure divided by current gross value. The symbol defaults are feed placeholders; the quantities and coefficients come from the fictional example and are not estimates for those ETFs. Enter your own holdings and coefficients saved before the evaluation period.
Indicator only: fixed holdings, frozen coefficients and a close-based review condition. It does not estimate factors, submit orders or backtest a multi-asset account.pine
//@version=6
indicator("Four-asset neutrality monitor", overlay = false)
string a = input.symbol("AMEX:SPY", "Asset A")
string b = input.symbol("NASDAQ:QQQ", "Asset B")
string c = input.symbol("AMEX:IWM", "Asset C")
string d = input.symbol("AMEX:DIA", "Asset D")
float qa = input.float(400, "A signed shares")
float qb = input.float(300, "B signed shares")
float qc = input.float(-750, "C signed shares")
float qd = input.float(-250, "D signed shares")
float ba = input.float(1.6, "A frozen market loading")
float bb = input.float(0.8, "B frozen market loading")
float bc = input.float(1.2, "C frozen market loading")
float bd = input.float(1.0, "D frozen market loading")
float fa = input.float(1, "A frozen extra-factor loading")
float fb = input.float(0, "B frozen extra-factor loading")
float fc = input.float(0, "C frozen extra-factor loading")
float fd = input.float(1, "D frozen extra-factor loading")
int start = input.time(timestamp("01 Jan 2026 00:00 +0000"), "Holdings effective from")
float limit = input.float(1.0, "Review band (% of gross)", minval = 0.0)
if not timeframe.isdaily or timeframe.multiplier != 1
runtime.error("Use standard one-day candles with matching sessions.")
[pa, ta, ea] = request.security(a, "1D", [close, time, time_close], gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
[pb, tb, eb] = request.security(b, "1D", [close, time, time_close], gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
[pc, tc, ec] = request.security(c, "1D", [close, time, time_close], gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
[pd, td, ed] = request.security(d, "1D", [close, time, time_close], gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_off)
bool prices = not na(pa) and not na(pb) and not na(pc) and not na(pd) and pa > 0 and pb > 0 and pc > 0 and pd > 0
bool aligned = ta == time and tb == time and tc == time and td == time and ea == time_close and eb == time_close and ec == time_close and ed == time_close
float va = qa * pa
float vb = qb * pb
float vc = qc * pc
float vd = qd * pd
float gross = math.abs(va) + math.abs(vb) + math.abs(vc) + math.abs(vd)
bool ready = prices and aligned and barstate.isconfirmed and time >= start and gross > 0
float dollars = ready ? 100 * (va + vb + vc + vd) / gross : na
float market = ready ? 100 * (va * ba + vb * bb + vc * bc + vd * bd) / gross : na
float factor = ready ? 100 * (va * fa + vb * fb + vc * fc + vd * fd) / gross : na
plot(dollars, "Net dollars / gross (%)", color = color.blue, style = plot.style_linebr)
plot(market, "Market exposure / gross (%)", color = color.orange, style = plot.style_linebr)
plot(factor, "Extra-factor exposure / gross (%)", color = color.purple, style = plot.style_linebr)
hline(0, "Zero", color = color.gray)
hline(limit, "Upper review band", color = color.gray)
hline(-limit, "Lower review band", color = color.gray)
bool review = ready and (math.abs(dollars) > limit or math.abs(market) > limit or math.abs(factor) > limit)
alertcondition(review, "Exposure review", "A frozen-model exposure exceeds its review band.")