Structures P&L API
At-expiry profit-and-loss curve, breakevens, and max profit/loss for an arbitrary multi-leg option structure.
Endpoint
X-Api-Key)
Rate Limited: Yes
Basic+
Request Body Fields
| Name | In | Required | Default | Description |
|---|---|---|---|---|
legs | body | yes | - | One or more legs. Must be non-empty. |
legs[].action | body | yes | buy | buy (alias long) or sell (alias short). |
legs[].type | body | yes | call | call (alias c) or put (alias p). |
legs[].strike | body | yes | - | Strike price. Must be > 0. |
legs[].premium | body | yes | - | Per-contract premium paid/received. Must be >= 0. |
legs[].quantity | body | no | 1 | Number of contracts. Must be > 0. |
minUnderlying | body | no | derived | Lower bound of the underlying-price curve. If omitted (or not strictly below maxUnderlying), the range is derived from the leg strikes ±30%. |
maxUnderlying | body | no | derived | Upper bound of the curve. See minUnderlying. |
points | body | no | 81 | Number of equally-spaced curve sample points (endpoints inclusive). Clamped to a minimum of 2. |
Request Body
{
"legs": [
{ "action": "buy", "type": "call", "strike": 100, "premium": 3.20, "quantity": 1 },
{ "action": "sell", "type": "call", "strike": 110, "premium": 1.10, "quantity": 1 }
],
"minUnderlying": 80,
"maxUnderlying": 130,
"points": 81
}
curl -X POST "https://lab.flashalpha.com/v1/structures/pnl" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"legs": [
{ "action": "buy", "type": "call", "strike": 100, "premium": 3.20, "quantity": 1 },
{ "action": "sell", "type": "call", "strike": 110, "premium": 1.10, "quantity": 1 }
],
"minUnderlying": 80,
"maxUnderlying": 130,
"points": 81
}'
import requests
resp = requests.post(
"https://lab.flashalpha.com/v1/structures/pnl",
headers={"X-Api-Key": "YOUR_API_KEY"},
json={
"legs": [
{"action": "buy", "type": "call", "strike": 100, "premium": 3.20, "quantity": 1},
{"action": "sell", "type": "call", "strike": 110, "premium": 1.10, "quantity": 1},
],
"minUnderlying": 80,
"maxUnderlying": 130,
"points": 81,
},
)
data = resp.json()
print(f"Breakevens: {data['breakevens']}")
const resp = await fetch(
"https://lab.flashalpha.com/v1/structures/pnl",
{
method: "POST",
headers: {
"X-Api-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
legs: [
{ action: "buy", type: "call", strike: 100, premium: 3.20, quantity: 1 },
{ action: "sell", type: "call", strike: 110, premium: 1.10, quantity: 1 }
],
minUnderlying: 80,
maxUnderlying: 130,
points: 81
})
}
);
const data = await resp.json();
console.log("Breakevens:", data.breakevens);
This is a pure-math POST endpoint: the result is computed analytically from the legs you supply, with no market-data lookup, symbol resolution, or live IV. There is no live Try-It widget for it - run the cURL example above to try it.
Response
{
"legs": [
{ "action": "buy", "type": "call", "strike": 100, "premium": 3.2, "quantity": 1 },
{ "action": "sell", "type": "call", "strike": 110, "premium": 1.1, "quantity": 1 }
],
"pnl_curve": [
{ "underlying": 80, "pnl": -2.1 },
{ "underlying": 80.625, "pnl": -2.1 },
{ "underlying": 100, "pnl": -2.1 },
{ "underlying": 110, "pnl": 7.9 },
{ "underlying": 130, "pnl": 7.9 }
],
"breakevens": [102.1],
"max_profit": 7.9,
"max_loss": -2.1
}
Key Response Fields
| Field | Type | Description |
|---|---|---|
legs | array | Echoes the request body verbatim |
pnl_curve | array | Sampled payoff points, each { underlying, pnl } |
breakevens | array | Underlying prices where P&L crosses zero (may be empty) |
max_profit | number/null | Bounded maximum profit, or null when unbounded on that side |
max_loss | number/null | Bounded maximum loss, or null when unbounded on that side |
Errors
| Status | Error | When |
|---|---|---|
400 | empty_legs | legs is missing or empty. |
400 | invalid_action | leg[i].action is not buy/sell (or long/short). |
400 | invalid_type | leg[i].type is not call/put (or c/p). |
400 | invalid_strike | leg[i].strike <= 0. |
400 | invalid_premium | leg[i].premium < 0. |
400 | invalid_quantity | leg[i].quantity <= 0. |
403 | tier_restricted | Free plan. Requires Basic or higher. |
About
This endpoint is part of the Structures family of pure-math multi-leg utilities. Every result is a deterministic function of the legs you supply: there is no market-data lookup, no symbol resolution, and no live IV. You pass the legs and premiums, and the response is computed analytically.
The at-expiry payoff is piecewise-linear in the underlying, so breakevens and the bounded max/min are solved exactly from the kinks at the strikes. max_profit and max_loss are null on any side that is unbounded - for example, a naked long call has unbounded max_profit, and a naked short call has unbounded max_loss.
Common Use Cases
- Render an at-expiry payoff diagram by plotting the
pnl_curvepoints for any custom spread, condor, or butterfly - Surface exact
breakevensbefore placing a multi-leg order so you know where the trade turns profitable - Read
max_profitandmax_lossto confirm a structure is defined-risk and size the position to your risk budget - Detect unbounded exposure when
max_profitormax_losscomes backnull, flagging naked legs before you trade them - Compute reward-to-risk from
max_profitovermax_lossto rank candidate structures side by side without any market data - Set profit-target and stop levels off the
breakevensand curve kinks for an exit plan that matches the payoff - Validate a structure's shape across the supplied
minUnderlying/maxUnderlyingrange before committing capital
Related
Related reading
- Complete guide to spreads, iron condors & credit spreads - the structures whose payoff this endpoint draws
- VRP strategy scoring: pick the right structure - decide which structure to model here
Complementary endpoints
- Structure Greeks - add aggregate delta/gamma/theta/vega to the same legs
- Option Quote - pull real premiums and IV to feed the legs
- VRP - gauge whether the structure is rich or cheap to put on
Ready to build?
Get your free API key and start pulling live options data in 30 seconds.