---
title: "(internal/legacy) Decompose a position into four additive bets with hedge ratios"
method: POST
path: "/decompose"
tags: ["Risk Metrics"]
---

# (internal/legacy) Decompose a position into four additive bets with hedge ratios

`POST /decompose`

## Request

- Base URL: `https://riskmodels.app/api`
- URL: `https://riskmodels.app/api/decompose`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://riskmodels.app/oauth/authorize`, token URL `https://riskmodels.app/api/oauth/token`, scopes: `mcp:read`)

**Per Snapshot Architecture v3, prefer `POST /snapshot` with `type: "ticker"` for new clients.** This endpoint remains callable as an internal building block.
Returns the simplified four-layer ERM3 exposure for a single ticker: `market`, `sector`, `subsector`, and `residual`. Each tradable layer (market / sector / subsector) maps to a hedge ETF from `ticker_metadata`; `residual` is stock-specific and not tradable. The response also includes a top-level `hedge` map of ETF → dollar ratio. Each value is the layer hedge ratio itself: the ETF dollar position per $1 long stock, negative = short the ETF. A stock with positive market beta carries a negative market `hr` (e.g. `l1_mkt_hr` ≈ -`l1_mkt_beta`), so the hedge shorts SPY.

The response also carries `style` and `stock_specific`: a diagnostic FF2 (SMB + HML) split of `exposure.residual` into a non-tradable style share and the doubly-cleaned stock-selection residual, on the `hedge_levels` basis. See `POST /v4/decompose` for the same split expressed as named blocks.

Same billing profile as `GET /metrics/{ticker}` — this is a thin semantic wrapper that flattens the L3 metrics into an agent-friendly shape. For the full L1/L2/L3 snapshot (all six HR names), use `GET /metrics/{ticker}`.

**Authentication:** Required (API Key or OAuth2)
**Billing:** $0.005 per request
**Rate Limit:** 120 requests/minute (default)

## Request body

- DecomposeRequest: Request body for `POST /decompose`.
  - `ticker` string, required: Stock ticker symbol (case-insensitive; trimmed and upper-cased).

## Response `200`

Four-layer decomposition with hedge map.

- DecomposeResponse: Wire response for `POST /decompose`. Semantic four-layer shape; each tradable layer maps to one ETF. The top-level `hedge` map is the layer `hr` keyed by ETF: the ETF dollar position per $1 long stock (negative = short the ETF), summed when two layers share one ETF.
  - `ticker` string, required
  - `symbol` string, required: Canonical symbol key in V3 registry.
  - `data_as_of` string, date, required: Latest trading day the metrics apply to.
  - `teo` string, date, required: V3 observation date (time-end) for this row.
  - `exposure` object, required
    - `market` DecomposeLayer, required: One layer of the four-bet decomposition. `er` is a variance fraction in [0, 1]. `hr` is a dollar-ratio hedge ratio (dollars of ETF per $1 of stock). `residual` has no tradable ETF, so `hr` and `hedge_etf` are null for that layer.
      - `er` number, nullable, required: Explained-risk variance fraction for this layer.
      - `hr` number, nullable, required: Hedge ratio (dollar ratio) for this layer. Null for residual.
      - `hedge_etf` string, nullable, required: Tradable ETF for this layer. Null for residual.
    - `sector` DecomposeLayer, required: One layer of the four-bet decomposition. `er` is a variance fraction in [0, 1]. `hr` is a dollar-ratio hedge ratio (dollars of ETF per $1 of stock). `residual` has no tradable ETF, so `hr` and `hedge_etf` are null for that layer.
      - `er` number, nullable, required: Explained-risk variance fraction for this layer.
      - `hr` number, nullable, required: Hedge ratio (dollar ratio) for this layer. Null for residual.
      - `hedge_etf` string, nullable, required: Tradable ETF for this layer. Null for residual.
    - `subsector` DecomposeLayer, required: One layer of the four-bet decomposition. `er` is a variance fraction in [0, 1]. `hr` is a dollar-ratio hedge ratio (dollars of ETF per $1 of stock). `residual` has no tradable ETF, so `hr` and `hedge_etf` are null for that layer.
      - `er` number, nullable, required: Explained-risk variance fraction for this layer.
      - `hr` number, nullable, required: Hedge ratio (dollar ratio) for this layer. Null for residual.
      - `hedge_etf` string, nullable, required: Tradable ETF for this layer. Null for residual.
    - `residual` DecomposeLayer, required: One layer of the four-bet decomposition. `er` is a variance fraction in [0, 1]. `hr` is a dollar-ratio hedge ratio (dollars of ETF per $1 of stock). `residual` has no tradable ETF, so `hr` and `hedge_etf` are null for that layer.
      - `er` number, nullable, required: Explained-risk variance fraction for this layer.
      - `hr` number, nullable, required: Hedge ratio (dollar ratio) for this layer. Null for residual.
      - `hedge_etf` string, nullable, required: Tradable ETF for this layer. Null for residual.
  - `hedge` object, required: Map of hedge-ETF → dollar ratio (= the layer `hr`: ETF dollars per $1 long stock, negative = short the ETF). If two layers share the same ETF (e.g. subsector falls back to the sector ETF), the values are summed so each ETF appears once.
  - `hedge_levels` HedgeLevelsBlock: Canonical L1/L2/L3 hedge snapshots (additive on metrics, decompose, batch success rows). Prefer this block over parsing flat `l*_mkt_hr` wire keys when comparing cascade levels.
    - `L1` LevelHedgeSnapshot, required: One hierarchical level (L1, L2, or L3) as a standalone hedge solution — HR and ER for each populated leg plus resolved ETF mnemonics. Null legs indicate that leg is not part of this level.
      - `market_hr` number, nullable, required: Dollar-ratio HR (ETF notional per $1 stock).
      - `sector_hr` number, nullable, required
      - `subsector_hr` number, nullable, required
      - `market_er` number, nullable, required: Explained-risk variance fraction where defined for this level.
      - `sector_er` number, nullable, required
      - `subsector_er` number, nullable, required
      - `residual_er` number, nullable, required
      - `hedge_etfs` object, required
        - `market` string, required
        - `sector` string, nullable, required
        - `subsector` string, nullable, required
    - `L2` LevelHedgeSnapshot, required: One hierarchical level (L1, L2, or L3) as a standalone hedge solution — HR and ER for each populated leg plus resolved ETF mnemonics. Null legs indicate that leg is not part of this level.
      - `market_hr` number, nullable, required: Dollar-ratio HR (ETF notional per $1 stock).
      - `sector_hr` number, nullable, required
      - `subsector_hr` number, nullable, required
      - `market_er` number, nullable, required: Explained-risk variance fraction where defined for this level.
      - `sector_er` number, nullable, required
      - `subsector_er` number, nullable, required
      - `residual_er` number, nullable, required
      - `hedge_etfs` object, required
        - `market` string, required
        - `sector` string, nullable, required
        - `subsector` string, nullable, required
    - `L3` LevelHedgeSnapshot, required: One hierarchical level (L1, L2, or L3) as a standalone hedge solution — HR and ER for each populated leg plus resolved ETF mnemonics. Null legs indicate that leg is not part of this level.
      - `market_hr` number, nullable, required: Dollar-ratio HR (ETF notional per $1 stock).
      - `sector_hr` number, nullable, required
      - `subsector_hr` number, nullable, required
      - `market_er` number, nullable, required: Explained-risk variance fraction where defined for this level.
      - `sector_er` number, nullable, required
      - `subsector_er` number, nullable, required
      - `residual_er` number, nullable, required
      - `hedge_etfs` object, required
        - `market` string, required
        - `sector` string, nullable, required
        - `subsector` string, nullable, required
    - `recommended_level` 'L1' | 'L2' | 'L3', nullable: Economic recommendation when emitted (user-segment hedge gate).
    - `statistical_lstar` 'L1' | 'L2' | 'L3', nullable: Orthogonal cascade statistical layer pick.
  - `style` object, nullable: FF2 (SMB + HML) diagnostic split of the `exposure.residual` variance — attribution only, never a tradable hedge (`hedgeable` is always `false`). `explained_variance` is a variance-ratio share on the `hedge_levels` basis named by `hedge_levels.statistical_lstar` (style + `stock_specific` ≈ that level's residual share). See `POST /v4/decompose` for the named-block form of this same split.
    - `explained_variance` number, nullable
    - `hedgeable` boolean
    - `role` string
  - `stock_specific` object, nullable: Doubly-cleaned skill residual — `exposure.residual` after the FF2 `style` strip. The stock-selection basis (skills-paper skill metric); not a tradable hedge.
    - `explained_variance` number, nullable
    - `hedgeable` boolean
  - `_metadata` object: Lineage, billing code, and freshness (same shape as `/metrics`).
  - `_data_health` object
    - `er_populated` boolean
    - `er_sum` number, nullable: Sum of L3 ER layers (should be ≈ 1 within tolerance).

## Other responses

- `400`: Malformed ticker or invalid JSON body.
- `401`: Missing or invalid Bearer token.
- `402`: Insufficient balance.
- `404`: Symbol not found or no metrics row.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/riskmodels/apis/riskmodels-api.md) · [All operations](https://skmtc.dev/riskmodels/apis/riskmodels-api/llms.txt) · [OpenAPI document](https://skmtc.dev/riskmodels/apis/riskmodels-api/revisions/1a034cad408a?raw)
