Three tasks from Citi's Markets Quant job simulation, completed in July 2026. I priced a six-month coffee option three different ways, used the same engine to design a coffee-linked structured note for a client, and set out how a desk should manage the market, credit and operational risks around it. Everything below was built in Python and checked by re-running the code.
An option is like insurance. A coffee call option gives you the right, but not the obligation, to buy coffee at a fixed price later. If coffee gets expensive, the insurance pays out; if it doesn't, you've only lost the premium. The hard part is deciding what that insurance is worth today, and how much risk you carry once you've sold it to someone.
1
Price the option
Fair futures price from cost of carry, option value from Black-76, then a Monte Carlo simulation to check the answer and measure tail risk.
2
Build a structured note
A product paying a coupon plus coffee upside. Solved for the participation rate that makes it worth exactly what the client pays, and showed the client's 26.6% chance of losing money.
3
Manage the risks
Hedging a weather view, onboarding a risky supplier, and fixing manual trade errors — each sized before it is mitigated.
4
Know the model's limits
A single flat volatility misprices out-of-the-money options. In production I'd price off the implied volatility surface.
Task 16-month call · strike $1.25/lb
Three Models, One Answer
The desk needed a fair value for a six-month call on coffee struck at $1.25 per pound. Rather than trust one model, I chained three together so each one checks the next.
01
Cost of carry
What should coffee for delivery in 6 months cost? F = $1.2181
→
02
Black-76
What is the insurance on that future worth? $0.0712/lb
→
03
Monte Carlo
Simulate 500,000 futures and check: $0.0712 ± 0.0004
Step 1 — the fair futures price
Why isn't coffee for later delivery the same price as coffee today?
Because holding coffee costs money. If you bought beans today to sell in six months, you'd pay interest on the money you borrowed and pay to store them. So the price for later delivery must include those costs, or someone could lock in a free profit.
Cost of carry — spot plus the cost of holding it
F = S0 × e(r + u − y)T = 1.20 × e0.015 = $1.2181
S₀
Spot price today — $1.20/lb
r
Interest rate — 2% a year
u
Storage cost — 1% a year
y
Convenience yield — the benefit of physically having beans (not given, set to 0 and stress-tested)
Step 2 — Black-76 and the Greeks
Black-76 is the version of Black-Scholes used for options on futures. Drag the sliders to see how the option's value responds. The gap between the curve and the dashed line is time value — what you pay for the chance that coffee rises before expiry.
Call Value vs Futures Price — Strike $1.25
Futures price$1.2181
Volatility25%
Months left6
Call value
–
Delta
–
Vega / vol pt
–
Theta / day
–
P(exercise)
–
What the Greeks mean for a trader
Delta (0.47): hedge each option with about half a futures contract. Gamma (1.83): that hedge ratio moves quickly, so it needs frequent rebalancing. Vega: one extra point of volatility adds about $128 per contract. Theta: every day that passes, the option loses a little value.
Step 3 — Monte Carlo as a cross-check
Monte Carlo prices an option by brute force: simulate thousands of possible futures prices at expiry, work out the payoff in each, and average them. On a simple option it should match the formula. If it does, you can trust the same engine on complicated products where no formula exists. That's exactly what Task 2 needed.
Simulated Coffee Futures Price at Expiry
–
This in-browser version runs 20,000 paths for speed. The Python model uses 500,000 antithetic paths and lands within 0.02% of Black-76, with 40.7% of paths finishing above the strike.
How real-world shocks reprice the option
A model is only as good as its inputs. I mapped real events — frost, drought, shipping disruption — onto the inputs and re-priced the option each time.
Call Value Under Each Scenario ($/lb) — base case $0.0712
The key finding
The shocks are lopsided. A Brazilian frost lifts the call by +366%, because it pushes up the price and the volatility at the same time — delta and vega add together. A bumper crop takes it down 90%, but an option can't fall below zero. Long options are the natural way to express weather risk.
Task 22-year note · moderate-risk client
Designing a Coffee-Linked Note
The client wanted two things that pull against each other: steady income, like a bond, and a share of any rise in coffee prices, like an option. A structured note combines both — but every feature has to be paid for by another.
A note is just three simpler pieces
Note = Zero-coupon bond + α × Call − Down-and-in Put
Bond
Returns the client's money at maturity — the safe part
Call
The client's share (α) of any coffee upside
Put
The client sells protection below an 80% barrier; that premium funds the coupon and upside
Nothing is free — the funding constraint
At a 2% interest rate, guaranteeing $1,000 back in two years costs:
Bond = 1,000 × e^(−0.02 × 2) = $960.79
Left to buy upside = 1,000 − 960.79 = $39.21 → only 23% participation
To give the client a coupon and real upside, they have to give something up. The 80% barrier is that trade-off: it's a put the client sells, and its premium lifts participation to 40.9%.
Structure
Coupon
Downside
Participation α
P(loss)
A. Full protection
none
Protected
23.0%
0.0%
B. Full protection, capped +40%
none
Protected
32.8%
0.0%
C. Recommended
3% p.a.
80% barrier
40.9%
26.6%
D. Aggressive coupon
5% p.a.
70% barrier, cap +50%
4.1%
15.8%
Payoff at Maturity on a $1,000 Note (Structure C)
Above $1.20 the client keeps 40.9% of the upside plus the $60 coupon. Between the barrier and $1.20 they get $1,060 back. Below $0.96 they lose one-for-one with coffee.
The disclosure that matters
Sold as "80% protected", the note still has a 26.6% chance of losing the client money in my 400,000-path simulation, with a 5th-percentile payoff of $618. A single price can't show that; the full distribution can. That's why the Monte Carlo output belongs in the client documents.
The risk Citi keeps after selling it
Selling the note leaves the bank short the payoff. The hardest part is gamma near the barrier: as coffee falls towards $0.96, the hedge changes sharply, forcing the desk to trade heavily in a falling, nervous market. That cost doesn't appear in the note's theoretical value, so it has to be priced in.
Task 3Market · credit · operational
You Can't Hedge What You Haven't Measured
Three risk scenarios, one framework: identify the exposure, size it, mitigate it, then monitor it.
Holding One Contract of Coffee (37,500 lb) — Worst-Case Losses
From the Task 1 simulation: buying a $1.25 put costs $3,853 (8.6% of the position's value) and cuts the average loss in the worst 1% of outcomes from $17,544 to $2,658. I reported Expected Shortfall alongside VaR because coffee has fat tails — VaR tells you where the bad zone starts, ES tells you how bad it gets.
M
Market risk — a weather view
First establish which side you're on. For a buyer, I recommended a collar or a 60–80% futures hedge, sized with the minimum-variance hedge ratio, because the weather view may already be in the price.
C
Credit risk — a new supplier
The danger is wrong-way risk: a drought makes the supplier likely to default exactly when replacing their coffee is most expensive. Collateral is the one fix that still works then.
O
Operational risk — manual errors
Diagnose the root cause, then automate execution to settlement. Checks and approvals are back-ups for a manual step that shouldn't exist.
Σ
The common thread
Hedging doesn't remove basis risk; collateral doesn't remove wrong-way risk; automation moves risk into the system. Risk management is choosing which risks to keep, and at what price.
Reflection
Where the Model Breaks
The maths was the easy part. The real risk sits in the assumptions, and these are the ones I'd change first on a real desk.
1. One volatility number isn't enough
I used a flat 25% volatility for every strike. Real markets don't: coffee traders pay extra for out-of-the-money calls because frost risk only pushes prices one way. A flat-vol model therefore under-prices the call in Task 1 and the barrier put in Task 2 — meaning the note would be sold too cheaply. The fix is to price off the implied volatility surface.
2. Prices don't move smoothly
The simulation assumes prices drift and wobble smoothly. Coffee jumps: a frost can move it 30% in a week. A mean-reverting jump-diffusion model would show barrier breaches and tail losses more honestly.
3. The hedge has costs the price ignores
Gamma near the barrier, margin calls on a working futures hedge, and basis risk between physical beans and the exchange contract all cost money. None of them show up in a theoretical value, so they need explicit reserves.
The core code
def black76(F, K, r, T, sigma):
"""Call, put and Greeks for an option on a futures contract."""
sqrtT = np.sqrt(T)
d1 = (np.log(F / K) + 0.5 * sigma**2 * T) / (sigma * sqrtT)
d2 = d1 - sigma * sqrtT
disc = np.exp(-r * T)
call = disc * (F * norm.cdf(d1) - K * norm.cdf(d2))
put = disc * (K * norm.cdf(-d2) - F * norm.cdf(-d1))
delta = disc * norm.cdf(d1)
gamma = disc * norm.pdf(d1) / (F * sigma * sqrtT)
vega = disc * F * norm.pdf(d1) * sqrtT / 100 # per vol point
return call, put, delta, gamma, vega
Skills used
Pricing an option is half the job; knowing how far to trust the price is the other half.