Risk Engine API (Open Beta) - Position Risk Flags, Hedges, VaR | FlashAlpha
  1. Risk Engine

Risk Engine API: Position Risk Flags, Hedges & VaR

Post your option structures or delta-1 (CFD/shares) positions and get back machine-readable risk flags, sized hedge suggestions, VaR and stress tests - in one synchronous call. You supply only what you hold; the engine resolves spot and implied vol from live FlashAlpha data.

OPEN BETA
Open beta: any authenticated FlashAlpha API key works - every plan, including Free, at no extra charge. When the beta ends, the Risk Engine becomes part of the Growth plan (and above) - beta users on lower tiers get notice first. Requests are rate limited to at least 60/minute per key (enforced per serving node - design for 60). During the beta, analyzed requests are recorded (key hash, posted positions, results) to guide what we build next. The machine-readable canonical reference lives at /docs/risk-engine.md.

Endpoint

POST https://lab.flashalpha.com/v1/risk/analyze

Authenticate with your API key in the X-Api-Key header (find it on your profile page). The call is stateless: nothing about your positions is stored between calls apart from the beta telemetry noted above. Body limit 256 KB; up to 25 positions, 50 legs per position, 200 legs total, 20 distinct symbols per request.

Quick Start

Analyze a 10-lot short put. Note what is not in this request: no spot, no impliedVol. The engine resolves both from live data, nets your legs, computes dollar greeks and raises flags:

cURL
curl -X POST "https://lab.flashalpha.com/v1/risk/analyze" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "positions": [{
      "symbol": "SPY",
      "legs": [{
        "action": "sell", "type": "put", "strike": 440,
        "expiry": "2027-12-17", "quantity": 10
      }]
    }]
  }'

The response carries flags (stable codes, never prose to parse), hedges, and a portfolio rollup:

Response
{
  "status": "OK",
  "as_of": "2026-10-30T13:46:42.3254082Z",
  "flag_schema": "risk.flags.v1",
  "flags": [
    {
      "code": "uncovered_short_put",
      "category": "coverage",
      "severity": "high",
      "position_id": "position[0]",
      "symbol": "SPY",
      "message": "Net short put(s) not covered by long puts - large downside obligation (floored at 0).",
      "data": {
        "uncovered_contracts": 10
      }
    },
    {
      "code": "undefined_risk_position",
      "category": "structure",
      "severity": "high",
      "position_id": "position[0]",
      "symbol": "SPY",
      "message": "Position has at least one naked short leg; maximum loss is not bounded by the legs.",
      "data": null
    }
  ],
  "hedges": [
    {
      "ref": "portfolio",
      "symbol": "SPY",
      "feasible": true,
      "action": "sell",
      "instrument": "underlying",
      "quantity": 38,
      "est_cost": -28893.87,
      "residual_dollar_delta": -234.861,
      "rationale": "Sell 38 SPY to move SPY's net dollar-delta from 28,659 toward 0.",
      "basis": "reference"
    }
  ],
  "portfolio": {
    "by_symbol": [
      {
        "symbol": "SPY",
        "dollar_delta": 28659.01,
        "dollar_gamma": -1694.79,
        "dollar_vega": -662.2451,
        "dollar_theta": 24.5759,
        "positions": 1
      }
    ],
    "dollar_delta": 28659.01,
    "dollar_gamma": -1694.79,
    "dollar_vega": -662.2451,
    "dollar_theta": 24.5759,
    "beta_weighted_dollar_delta": 28659.01,
    "gross_dollar_delta": 28659.01
  }
}

You Only Supply Positions

spot and per-leg impliedVol are optional. Omit them and the engine resolves the live spot for each symbol and the live implied vol for each strike from FlashAlpha's own market data, using your API key so your plan's data entitlements apply. That is the whole point: you describe what you hold, the engine sources everything else.

Supply them explicitly whenever you want to pin a scenario - a what-if, a back-test, a stress at a level that is not the current market - and the engine uses your values untouched. If a value is omitted and cannot be resolved you get a 400 naming exactly which input to provide: spot_unavailable or iv_unavailable.

Prefer clicking to typing? The interactive playground builds a book from live option-chain dropdowns, runs it through the engine, and shows you the exact JSON it sent.

Request Shape

Each position carries a symbol and either option legs or a delta-1 exposure (shares/CFD). Everything else is optional: spot and per-leg impliedVol (resolved live when omitted), today (valuation date, defaults to the current US-Eastern trading date), rate, dividendYield, multiplier (default 100), beta. Optional per request:

  • thresholds - absolute dollar-greek limits; breaches come back as delta_breach / gamma_breach / vega_breach / theta_breach flags.
  • mandate.deltaTarget - a book-level target (even 0). Every position's dollar delta is netted and compared once, so one deviation flag is raised for the whole book, not one per position.
  • include - any of risks, hedges, portfolio (defaults on) and metrics (opt-in: VaR, Monte Carlo, stress grid, breakevens, assignment probabilities).

The full field-by-field schema with every validation rule is in the canonical reference, /docs/risk-engine.md.

Request body

Name In Type Required Default Description
positionsbodyarrayrequired - 1 to 25 positions, at most 20 distinct symbols.
positions[].idbodystringposition[N]Must be unique across the request.
positions[].symbolbodystringrequired - Underlying symbol.
positions[].spotbodynumberlive spotOmit to use the live spot. If supplied: finite and greater than 0.
positions[].todaybodydatecurrent US-Eastern trading dateValuation date, yyyy-MM-dd. A malformed value returns 400 invalid_today.
positions[].ratebodynumber0.045Risk-free rate, -1 to 1.
positions[].dividendYieldbodynumber0.013Dividend yield, 0 to 1.
positions[].multiplierbodynumber100Contract multiplier, greater than 0.
positions[].betabodynumber1.0Absolute value at most 10.
positions[].legsbodyarray - Option legs. Each position needs legs or exposure. At most 50 per position and 200 per request.
positions[].legs[].actionbodyenumrequired - buy / long or sell / short.
positions[].legs[].typebodyenumrequired - call / c or put / p.
positions[].legs[].strikebodynumberrequired - Finite and greater than 0.
positions[].legs[].expirybodydaterequired - yyyy-MM-dd, not before today.
positions[].legs[].impliedVolbodynumberlive IVOmit to use the live IV for the strike. If supplied: above 0, at most 5.
positions[].legs[].quantitybodyintegerrequired - 1 to 1,000,000.
positions[].exposurebodyobject - Delta-1 underlying, CFD or shares.
positions[].exposure.quantitybodynumber - Signed; absolute value at most 1e7.
positions[].exposure.multiplierbodynumber1Greater than 0.
thresholdsbodyobject - Absolute dollar limits, each greater than 0: maxAbsDollarDelta, maxAbsDollarGamma, maxAbsDollarVega, maxAbsDollarTheta.
mandate.deltaTargetbodynumber - Book-level dollar-delta target (0 is a valid target).
includebodyarray["risks","hedges","portfolio"]Any of risks, hedges, portfolio, metrics.
metrics.horizonDaysbodyinteger - 1 to 90. Read only when metrics is included.
metrics.confidencebodynumber - At least 0.5, below 1.
metrics.mcPathsbodyinteger - 100 to 20,000.
metrics.mcSeedbodyinteger - Monte Carlo seed; results are deterministic per seed.
metrics.annualVolbodynumber - Above 0, at most 5. Required for VaR on positions without legs.

Response Fields

Measured on 2026-10-30 with all four include groups.

FieldTypeDescription
statusstringOK on success
as_ofstringTimestamp of the analysis (ISO 8601, UTC)
flag_schemastringFlag contract version, risk.flags.v1
flagsarrayRisk flags raised for the request. See Risk Flags
flags[].codestringStable flag code
flags[].categorystringFlag category, for example greeks or coverage
flags[].severitystringinfo, warn, high or critical
flags[].position_idstringThe position the flag refers to, or portfolio for the whole book
flags[].symbolstringUnderlying symbol
flags[].messagestringHuman-readable explanation
flags[].dataobject | nullNumbers behind the flag, for example uncovered_contracts, dollar_gamma, dollar_vega, dollar_theta. Keys depend on the flag; null when it has none
hedgesarrayHedge suggestions. See Hedge Suggestions
hedges[].refstringWhat the hedge applies to, for example portfolio
hedges[].symbolstringSymbol to trade
hedges[].feasiblebooleanfalse when no delta-1 trade can address the problem
hedges[].actionstringbuy or sell
hedges[].instrumentstringInstrument to trade, for example underlying
hedges[].quantitynumberQuantity to trade
hedges[].est_costnumberEstimated cost in USD; negative when the trade brings in cash
hedges[].residual_dollar_deltanumberDollar delta left after the hedge
hedges[].rationalestringWhy the hedge is proposed
hedges[].basisstringBasis used to size the hedge
metricsarrayPer-position metrics. Only returned when include has metrics. See Metrics
metrics[].position_idstringPosition identifier
metrics[].symbolstringUnderlying symbol
metrics[].modelstringPricing model used
metrics[].max_lossnumber | nullMaximum loss; null means unbounded
metrics[].max_profitnumber | nullMaximum profit; null means unbounded
metrics[].breakevensarray of numberBreakeven prices, measured against today's model mark
metrics[].assignmentarrayRisk-neutral assignment probabilities per net-short strike
metrics[].assignment[].strikenumberStrike price
metrics[].assignment[].expirystringExpiration date (yyyy-MM-dd)
metrics[].assignment[].kindstringOption kind
metrics[].assignment[].prob_itm_at_expirynumberProbability of finishing in the money at expiry
metrics[].varobjectValue at risk
metrics[].var.horizon_daysnumberHorizon in days
metrics[].var.confidencenumberConfidence level
metrics[].var.valuenumberRisk value in USD
metrics[].var.methodstringCalculation method
metrics[].mc_varobjectMonte Carlo value at risk
metrics[].mc_var.horizon_daysnumberHorizon in days
metrics[].mc_var.confidencenumberConfidence level
metrics[].mc_var.valuenumberRisk value in USD
metrics[].mc_var.methodstringCalculation method
metrics[].mc_cvarobjectMonte Carlo conditional value at risk
metrics[].mc_cvar.horizon_daysnumberHorizon in days
metrics[].mc_cvar.confidencenumberConfidence level
metrics[].mc_cvar.valuenumberRisk value in USD
metrics[].mc_cvar.methodstringCalculation method
metrics[].stressarrayStress grid of spot and IV shocks
metrics[].stress[].spot_pctnumberSpot shock in percent
metrics[].stress[].iv_ptsnumberIV shock in vol points
metrics[].stress[].pnlnumberProfit or loss in USD under the shock
portfolioobjectPortfolio rollup. Returned by default; leave portfolio out of include to drop it
portfolio.by_symbolarrayRollup per symbol
portfolio.by_symbol[].symbolstringUnderlying symbol
portfolio.by_symbol[].dollar_deltanumberDollar delta
portfolio.by_symbol[].dollar_gammanumberDollar gamma
portfolio.by_symbol[].dollar_veganumberDollar vega
portfolio.by_symbol[].dollar_thetanumberDollar theta
portfolio.by_symbol[].positionsnumberNumber of positions
portfolio.dollar_deltanumberBook dollar delta
portfolio.dollar_gammanumberBook dollar gamma
portfolio.dollar_veganumberBook dollar vega
portfolio.dollar_thetanumberBook dollar theta
portfolio.beta_weighted_dollar_deltanumberBook dollar delta weighted by beta
portfolio.gross_dollar_deltanumberSum of absolute dollar deltas

Risk Flags

Flags are stable enum codes under the risk.flags.v1 contract - codes are added over time, never renamed. Severities: info, warn, high, critical. Currently emitted families:

  • Coverage - uncovered_short_call, uncovered_short_put, covered_call, naked_short_underlying, non_coterminal_coverage (a protective long that expires before the short it covers).
  • Structure - unbounded_loss, undefined_risk_position, defined_risk_position.
  • Expiry - expired_leg_present, expiring_today_position, short_leg_expiring_today, near_expiry_position, multi_expiry_position.
  • Assignment & pin - short_strike_through_spot, itm_short_near_expiry, atm_short_near_expiry_pin, pin_risk_short_strike.
  • Greek posture - net_short_gamma, net_long_gamma, net_short_vega, net_long_vega, negative_theta, positive_theta, short_gamma_short_vega.
  • Thresholds & mandate - delta_breach, gamma_breach, vega_breach, theta_breach, delta_target_deviation.

Hedge Suggestions

A delta-1 underlying hedge is proposed only for delta problems: a posted mandate, or a delta threshold breach (hedged toward flat).

Mandate hedges are book-level. If the whole book is one symbol, you get one concrete trade sized to move the book to the target. If it spans several symbols there is no single delta-1 instrument that closes the gap, so the engine returns an explicit feasible: false entry naming the shortfall rather than a set of per-position trades that would each overshoot the target. Threshold breaches stay per position, because a breach belongs to the position that breached it.

Gamma/vega/theta-only breaches return an explicit feasible: false entry instead of a wrong trade. Expiry-day (0DTE) legs stay live in the greeks rather than dropping to zero.

Metrics (opt-in)

Include "metrics" to get, per position: max loss / max profit (null = unbounded), breakevens, risk-neutral assignment probabilities per net-short strike, quantile VaR (full revaluation across the confidence band, so long-straddle-style interior losses are measured correctly), seeded Monte Carlo VaR/CVaR (deterministic per seed), and a 7×3 spot × IV stress grid. Model: Black-Scholes on your supplied IVs, GBM paths.

Errors

Engine errors use { "status": "ERROR", "error": "<code>", "message": "..." }. A body that is not parseable JSON gets an RFC 7807 problem-details body instead.

Status Error When
400spot_unavailable / iv_unavailableYou omitted spot or impliedVol and the engine could not resolve it live. The message names the symbol (and expiry / strike) to supply, for example "No live implied vol for SPY 2026-09-18 440 P. Supply "impliedVol" explicitly for this leg."
400empty_requestNo positions posted ("Provide at least one position.").
400too_many_positions / too_many_legs / too_many_symbols / duplicate_position_idRequest-level limits: more than 25 positions, 200 legs (or 50 in one position), 20 distinct symbols, or two positions with the same id.
400invalid_threshold / invalid_mandate / invalid_metrics_optionsA threshold, mandate.deltaTarget or a metrics option is out of range.
400invalid_symbol / invalid_spot / invalid_today / invalid_rate / invalid_dividend_yield / invalid_multiplier / invalid_beta / empty_position / invalid_exposureA position field is invalid. The message names the position id.
400invalid_action / invalid_type / invalid_strike / invalid_iv / invalid_quantity / invalid_expiry / expiry_in_pastA leg field is invalid, for example "position[0].legs[0].action must be 'buy' or 'sell'." The message names the position and leg.
400-A query value has the wrong type, or a required value is missing. The body is an RFC 7807 problem-details object with errors.<param>.
401missing_api_key / invalid_api_keyNo X-Api-Key header, or the key is not valid.
413-Request body over 256 KB.
429rate_limitedMore than 60 requests this minute for your key. Honor Retry-After.
429Quota exceededDaily quota used up. Retry-After gives the seconds until the reset at 00:00 UTC. Rejected requests (including 403) count toward the quota.
500internal_errorUnhandled server fault. Retry; contact support if it persists.
503auth_unavailableAccount verification is degraded. Your key was not rejected: retry, do not rotate keys.

All 24 validation codes with their exact conditions are tabulated in the canonical reference, /docs/risk-engine.md.

Common Use Cases

  • Pre-trade checks: catch naked tails, undefined risk, and non-coterminal "protection" before an order goes out
  • End-of-day book scan: pin risk and assignment exposure on everything expiring this week
  • Delta-mandate monitoring: post a target once, alert on delta_target_deviation
  • CFD / delta-1 books: dollar-delta rollups, beta-weighted exposure, stress grids - no option legs required

Ready to build with FlashAlpha?

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

No credit card required Setup in 60 seconds Secure & reliable