Companion film
Portfolio risk engine
Trim one position and see totals, carry, duration, stress, and concentration move as one connected portfolio.
21 secGrid 0.61.0
Open film page →Canonical Grid model
Large portable example for portfolio translation, weighting, carry, and duration stress.
What this model gives you
30 min to study · Source reviewed 2026-08-26
Continue with guided practiceExpected checkpoint
After both FX requests reach terminal failure without a satisfactory cached value, so the authored 1.08 EUR/USD and 1.25 GBP/USD fallbacks apply. These source-derived values are not yet backed by a runtime receipt; the current contract certifies provider terminal status only.
N1 and N2 remain raw FX_RATE bindings. Position rows apply DEFAULT at the point of use, so an operator can inspect whether EUR and GBP values are live, stale, failed, or using the authored continuity rate.
Each row retains notional, price, currency, and effective FX before computing market value and carry. A changed provider result therefore invalidates only the positions that consume that currency.
H9 establishes total market value; each J-row then contributes its market-value weight times duration. The apparent forward reference is a dependency edge, not an evaluation-order instruction.
The two 200-basis-point shocks expose portfolio P&L while M2:M4 turn concentration, carry, and duration thresholds into readable decisions. Keep both layers so a classification always has an auditable numeric basis.
MODEL "Portfolio Risk Engine"
DESCRIPTION "Large portable example for portfolio translation, weighting, carry, and duration stress."
VERSION "1.0.0"
AUTHOR "Grid Team"
TAGS "canonical", "portable", "large", "risk"
# FX inputs
N1 = FX_RATE("EUR", "USD")
N2 = FX_RATE("GBP", "USD")
# Positions: name, notional, price, duration, coupon, currency, fx, mv_usd, carry, dur_contrib, up_200bp, down_200bp
A1 = "UST2Y"
B1 = 150000
C1 = 1.00
D1 = 1.8
E1 = 0.031
F1 = "USD"
G1 = 1
H1 = ROUND(B1 * C1 * G1, 2)
I1 = ROUND(H1 * E1, 2)
J1 = ROUND(H1 / H9 * D1, 6)
K1 = ROUND(H1 * (1 - D1 * 0.02), 2)
L1 = ROUND(H1 * (1 + D1 * 0.02), 2)
A2 = "UST10Y"
B2 = 210000
C2 = 0.99
D2 = 7.2
E2 = 0.042
F2 = "USD"
G2 = 1
H2 = ROUND(B2 * C2 * G2, 2)
I2 = ROUND(H2 * E2, 2)
J2 = ROUND(H2 / H9 * D2, 6)
K2 = ROUND(H2 * (1 - D2 * 0.02), 2)
L2 = ROUND(H2 * (1 + D2 * 0.02), 2)
A3 = "CorpA"
B3 = 90000
C3 = 1.02
D3 = 4.1
E3 = 0.057
F3 = "EUR"
G3 = N1 DEFAULT 1.08
H3 = ROUND(B3 * C3 * G3, 2)
I3 = ROUND(H3 * E3, 2)
J3 = ROUND(H3 / H9 * D3, 6)
K3 = ROUND(H3 * (1 - D3 * 0.02), 2)
L3 = ROUND(H3 * (1 + D3 * 0.02), 2)
A4 = "CorpB"
B4 = 125000
C4 = 0.96
D4 = 5.3
E4 = 0.064
F4 = "EUR"
G4 = N1 DEFAULT 1.08
H4 = ROUND(B4 * C4 * G4, 2)
I4 = ROUND(H4 * E4, 2)
J4 = ROUND(H4 / H9 * D4, 6)
K4 = ROUND(H4 * (1 - D4 * 0.02), 2)
L4 = ROUND(H4 * (1 + D4 * 0.02), 2)
A5 = "MBS"
B5 = 80000
C5 = 1.01
D5 = 3.7
E5 = 0.049
F5 = "USD"
G5 = 1
H5 = ROUND(B5 * C5 * G5, 2)
I5 = ROUND(H5 * E5, 2)
J5 = ROUND(H5 / H9 * D5, 6)
K5 = ROUND(H5 * (1 - D5 * 0.02), 2)
L5 = ROUND(H5 * (1 + D5 * 0.02), 2)
A6 = "LoanA"
B6 = 60000
C6 = 0.98
D6 = 2.5
E6 = 0.071
F6 = "GBP"
G6 = N2 DEFAULT 1.25
H6 = ROUND(B6 * C6 * G6, 2)
I6 = ROUND(H6 * E6, 2)
J6 = ROUND(H6 / H9 * D6, 6)
K6 = ROUND(H6 * (1 - D6 * 0.02), 2)
L6 = ROUND(H6 * (1 + D6 * 0.02), 2)
A7 = "LoanB"
B7 = 72000
C7 = 0.94
D7 = 3.1
E7 = 0.083
F7 = "GBP"
G7 = N2 DEFAULT 1.25
H7 = ROUND(B7 * C7 * G7, 2)
I7 = ROUND(H7 * E7, 2)
J7 = ROUND(H7 / H9 * D7, 6)
K7 = ROUND(H7 * (1 - D7 * 0.02), 2)
L7 = ROUND(H7 * (1 + D7 * 0.02), 2)
A8 = "HY_ETF"
B8 = 50000
C8 = 1.03
D8 = 4.8
E8 = 0.058
F8 = "USD"
G8 = 1
H8 = ROUND(B8 * C8 * G8, 2)
I8 = ROUND(H8 * E8, 2)
J8 = ROUND(H8 / H9 * D8, 6)
K8 = ROUND(H8 * (1 - D8 * 0.02), 2)
L8 = ROUND(H8 * (1 + D8 * 0.02), 2)
# Portfolio summaries
H9 = ROUND(SUM(H1:H8), 2)
I9 = ROUND(SUM(I1:I8), 2)
J9 = ROUND(SUM(J1:J8), 6)
K9 = ROUND(SUM(K1:K8) - H9, 2)
L9 = ROUND(SUM(L1:L8) - H9, 2)
M1 = MAX(H1:H8) / H9
M2 = M1 > 0.22 THEN "concentrated" ELSE "balanced"
M3 = I9 / H9 > 0.06 THEN "high-carry" ELSE I9 / H9 > 0.04 THEN "core-carry" ELSE "low-carry"
M4 = J9 > 4 THEN "duration-heavy" ELSE "duration-light"
M5 = `mv_usd={H9} carry={I9} duration={J9}`
M6 = `up={K9} down={L9} mix={M2}`
END MODEL