Structures P&L API - At-Expiry Payoff & Breakevens - FlashAlpha Lab API
Lab API Structures P&L

Structures P&L API

At-expiry profit-and-loss curve, breakevens, and max profit/loss for an arbitrary multi-leg option structure.

Endpoint

POST /v1/structures/pnl
Auth required (X-Api-Key) Rate Limited: Yes Basic+

Request Body Fields

Name In Required Default Description
legsbodyyes - One or more legs. Must be non-empty.
legs[].actionbodyyesbuybuy (alias long) or sell (alias short).
legs[].typebodyyescallcall (alias c) or put (alias p).
legs[].strikebodyyes - Strike price. Must be > 0.
legs[].premiumbodyyes - Per-contract premium paid/received. Must be >= 0.
legs[].quantitybodyno1Number of contracts. Must be > 0.
minUnderlyingbodynoderivedLower bound of the underlying-price curve. If omitted (or not strictly below maxUnderlying), the range is derived from the leg strikes ±30%.
maxUnderlyingbodynoderivedUpper bound of the curve. See minUnderlying.
pointsbodyno81Number 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
legsarrayEchoes the request body verbatim
pnl_curvearraySampled payoff points, each { underlying, pnl }
breakevensarrayUnderlying prices where P&L crosses zero (may be empty)
max_profitnumber/nullBounded maximum profit, or null when unbounded on that side
max_lossnumber/nullBounded maximum loss, or null when unbounded on that side

Errors

Status Error When
400empty_legslegs is missing or empty.
400invalid_actionleg[i].action is not buy/sell (or long/short).
400invalid_typeleg[i].type is not call/put (or c/p).
400invalid_strikeleg[i].strike <= 0.
400invalid_premiumleg[i].premium < 0.
400invalid_quantityleg[i].quantity <= 0.
403tier_restrictedFree 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_curve points for any custom spread, condor, or butterfly
  • Surface exact breakevens before placing a multi-leg order so you know where the trade turns profitable
  • Read max_profit and max_loss to confirm a structure is defined-risk and size the position to your risk budget
  • Detect unbounded exposure when max_profit or max_loss comes back null, flagging naked legs before you trade them
  • Compute reward-to-risk from max_profit over max_loss to rank candidate structures side by side without any market data
  • Set profit-target and stop levels off the breakevens and curve kinks for an exit plan that matches the payoff
  • Validate a structure's shape across the supplied minUnderlying/maxUnderlying range before committing capital

Related reading

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 with FlashAlpha?

Get your free API key and start pulling live options data in 30 seconds.

No credit card required Setup in 60 seconds Secure & reliable