# Long-short book (long_short_book)

Desk: Equities. Page: https://hedgefund.md/models/long_short_book

**What it asks.** How much of this book's risk is factor bets, which names carry it, and what would it take to flatten the first factor?

Splits a long-short book into gross, net, factor exposures and each position's share of variance, adds hypothetical carry, and sizes the hedge that takes the first factor to zero. Weights, betas, vols and rates all come from the caller. It is arithmetic on those numbers, not an optimizer, a forecast or a trade idea.

Results are hypothetical: arithmetic on the numbers sent, a made-up template or a stated default. Nobody achieved them, and they aren't a forecast, a recommendation, an offer or a record of real trading. Don't show any output to investors or clients, or use it to market an investment. Terms: https://hedgefund.md/terms

## Inputs

| Input | Type | Range | Required | What it is |
| --- | --- | --- | --- | --- |
| `positions` | array | 1 to 200 items | yes | The book, one line per name. |
| `positions[].name` | string |  | yes | A label for the position, such as Stock A. |
| `positions[].weight_pct` | number | -1000 to 1000 | yes | Signed share of NAV. 30 is long 30% of NAV, -30 is short 30%. |
| `positions[].betas` | array | 1 to 12 items | yes | One beta per factor, in the order of factors. |
| `positions[].idio_vol_pct` | number | 0 to 500 | yes | Annual volatility not explained by the factors, in percent. |
| `positions[].expected_alpha_pct` | number | -500 to 500 | no | The stock's own hypothetical annual alpha, in percent. A short earns when this is negative. Default 0. |
| `positions[].borrow_bps` | number | 0 to 100000 | no | Annual borrow fee on a short, in basis points of the short. Ignored on longs. Default 0. |
| `factors` | array | 1 to 12 items | yes | The factors, in the order of each position's betas. |
| `factors[].name` | string |  | yes | A label for the factor, such as Market. |
| `factors[].vol_pct` | number | 0 to 500 | yes | Annual factor volatility, in percent. |
| `factor_corr` | array | 1 to 12 items | no | Optional factor correlation matrix. Default is identity: factors independent. |
| `cash_rate_pct` | number | -10 to 100 | yes | Annual rate earned on what longs leave of NAV, in percent. |
| `financing_rate_pct` | number | -10 to 100 | yes | Annual rate paid on longs above 100% of NAV, in percent. |
| `max_gross_pct` | number | 0 to 10000 | no | Optional limit on gross, in percent of NAV. |
| `max_net_pct` | number | 0 to 10000 | no | Optional limit on the size of net, in percent of NAV. |
| `max_factor_share_pct` | number | 0 to 100 | no | Optional limit on the factor share of variance, in percent. |

## Template

Made-up numbers that run as they stand, so you can see the shape of a result. They aren't market levels, typical values or estimates, and the names in them don't exist. Replace every number before you read anything into a run.

```json
{
  "positions": [
    {
      "name": "Stock A",
      "weight_pct": 30,
      "betas": [1.3, -0.2, 0.5],
      "idio_vol_pct": 30,
      "expected_alpha_pct": 6
    },
    {
      "name": "Stock B",
      "weight_pct": 25,
      "betas": [1.2, -0.1, 0.4],
      "idio_vol_pct": 28,
      "expected_alpha_pct": 5
    },
    {
      "name": "Stock C",
      "weight_pct": 25,
      "betas": [1.4, -0.3, 0.6],
      "idio_vol_pct": 35,
      "expected_alpha_pct": 4
    },
    {
      "name": "Stock D",
      "weight_pct": 20,
      "betas": [1.1, 0.2, 0.2],
      "idio_vol_pct": 25,
      "expected_alpha_pct": 3
    },
    {
      "name": "Stock E",
      "weight_pct": 20,
      "betas": [1, 0.3, 0.1],
      "idio_vol_pct": 22,
      "expected_alpha_pct": 2
    },
    {
      "name": "Stock F",
      "weight_pct": -30,
      "betas": [0.7, 0.4, -0.2],
      "idio_vol_pct": 20,
      "expected_alpha_pct": -3,
      "borrow_bps": 30
    },
    {
      "name": "Stock G",
      "weight_pct": -30,
      "betas": [0.8, 0.3, -0.3],
      "idio_vol_pct": 24,
      "expected_alpha_pct": -4,
      "borrow_bps": 50
    },
    {
      "name": "Stock H",
      "weight_pct": -25,
      "betas": [0.6, 0.5, -0.1],
      "idio_vol_pct": 18,
      "expected_alpha_pct": -2,
      "borrow_bps": 25
    },
    {
      "name": "Stock I",
      "weight_pct": -15,
      "betas": [0.9, 0.1, -0.4],
      "idio_vol_pct": 40,
      "expected_alpha_pct": -6,
      "borrow_bps": 800
    }
  ],
  "factors": [
    { "name": "Market", "vol_pct": 16 },
    { "name": "Value", "vol_pct": 8 },
    { "name": "Momentum", "vol_pct": 10 }
  ],
  "factor_corr": [
    [1, 0.1, -0.1],
    [0.1, 1, -0.3],
    [-0.1, -0.3, 1]
  ],
  "cash_rate_pct": 4,
  "financing_rate_pct": 6,
  "max_gross_pct": 250,
  "max_net_pct": 30,
  "max_factor_share_pct": 25
}
```

## What the template gives

On these numbers, the book is 220% gross and 20% net, runs 24.05% annual vol, and 31.73% of its variance comes from factors. Taking Market to zero would take a hedge of -72.5% of NAV, which is arithmetic, not a trade to make.

- Gross: 220% of NAV (ok)
- Net: 20% of NAV (ok)
- Annual vol: 24.05%
- Factor share of variance: 31.73% (breach)
- Exposure to Market: 72.5% of NAV
- Hedge to take Market to zero: -72.5% of NAV
- Largest risk share: Stock A: 27.51%
- Hypothetical carry: 5.8475% of NAV a year

Where it flips, with the other inputs held:

- `hedge_on_first_factor_pct` at -17.7025: A Market hedge of this size, as a percent of NAV, puts factor share exactly at the 25% limit.
- `factors.0.vol_pct` at 12.0932: At this Market vol, factor share sits exactly at the 25% limit, with weights unchanged.
- `financing_rate_pct` at 35.2375: At this financing rate the hypothetical carry is zero. Above it, carry is negative.

## Formula

e_k = sum w_i beta_ik. F_jk = corr_jk vol_j vol_k. variance = e' F e + sum (w_i sigma_i)^2. share_i = w_i (beta_i' F e + w_i sigma_i^2) / variance. carry = sum w_i alpha_i - sum over shorts |w_i| borrow_i - max(0, long - 1) financing + max(0, 1 - long) cash.

## Assumptions

- Weights are signed shares of NAV. Vols, alphas and rates are annual.
- Idiosyncratic risks are independent of the factors and of each other.
- expected_alpha_pct is the stock's own alpha, so the book's alpha is the sum of signed weight times alpha, and a short earns when alpha is negative.
- Financing is charged only on longs above 100% of NAV. Cash earns only on what longs leave of NAV. Short sale proceeds earn nothing and fund nothing.
- Risk shares are each position's weight times its covariance with the book, over book variance, so they add to 100%, and a share below zero means the position offsets the rest.
- The first-factor hedge is a pure instrument: beta 1 to that factor, 0 to the others, no idiosyncratic risk, no cost. Its size adds to gross and to net.

## Not modeled

- Short rebate: sale proceeds earn nothing here. The note on the carry reading shows what a rebate at the cash rate would add.
- Recall risk on borrowed names, and borrow rates that move.
- Fat tails and stress: this is variance only, with no skew and no gap moves.
- Betas and factor vols that change over time.
- Margin requirements, liquidity, and the time it takes to close a position.
- Slippage, commissions, fees and taxes.

## Call it

Every result has the same fields: summary, readings, tables, charts, flags, flips, formula, assumptions, not_modeled, hypothetical and inputs_hash. Read flags, flips and not_modeled with the summary, and pass them along together.

### HTTP

No key. The tools keep nothing you send. Send positions by POST, because a URL can land in a server log.

```bash
curl -s https://hedgefund.md/api/v1/long_short_book \
  -H 'content-type: application/json' \
  -d '{"positions":[{"name":"Stock A","weight_pct":30,"betas":[1.3,-0.2,0.5],"idio_vol_pct":30,"expected_alpha_pct":6},{"name":"Stock B","weight_pct":25,"betas":[1.2,-0.1,0.4],"idio_vol_pct":28,"expected_alpha_pct":5},{"name":"Stock C","weight_pct":25,"betas":[1.4,-0.3,0.6],"idio_vol_pct":35,"expected_alpha_pct":4},{"name":"Stock D","weight_pct":20,"betas":[1.1,0.2,0.2],"idio_vol_pct":25,"expected_alpha_pct":3},{"name":"Stock E","weight_pct":20,"betas":[1,0.3,0.1],"idio_vol_pct":22,"expected_alpha_pct":2},{"name":"Stock F","weight_pct":-30,"betas":[0.7,0.4,-0.2],"idio_vol_pct":20,"expected_alpha_pct":-3,"borrow_bps":30},{"name":"Stock G","weight_pct":-30,"betas":[0.8,0.3,-0.3],"idio_vol_pct":24,"expected_alpha_pct":-4,"borrow_bps":50},{"name":"Stock H","weight_pct":-25,"betas":[0.6,0.5,-0.1],"idio_vol_pct":18,"expected_alpha_pct":-2,"borrow_bps":25},{"name":"Stock I","weight_pct":-15,"betas":[0.9,0.1,-0.4],"idio_vol_pct":40,"expected_alpha_pct":-6,"borrow_bps":800}],"factors":[{"name":"Market","vol_pct":16},{"name":"Value","vol_pct":8},{"name":"Momentum","vol_pct":10}],"factor_corr":[[1,0.1,-0.1],[0.1,1,-0.3],[-0.1,-0.3,1]],"cash_rate_pct":4,"financing_rate_pct":6,"max_gross_pct":250,"max_net_pct":30,"max_factor_share_pct":25}' \
  | jq '{summary, flags, flips, not_modeled, inputs_hash}'
```

### MCP

The tool is `long_short_book` on the server at https://hedgefund.md/mcp.

```bash
curl -s https://hedgefund.md/mcp \
  -H 'content-type: application/json' -H 'accept: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"long_short_book","arguments":{"positions":[{"name":"Stock A","weight_pct":30,"betas":[1.3,-0.2,0.5],"idio_vol_pct":30,"expected_alpha_pct":6},{"name":"Stock B","weight_pct":25,"betas":[1.2,-0.1,0.4],"idio_vol_pct":28,"expected_alpha_pct":5},{"name":"Stock C","weight_pct":25,"betas":[1.4,-0.3,0.6],"idio_vol_pct":35,"expected_alpha_pct":4},{"name":"Stock D","weight_pct":20,"betas":[1.1,0.2,0.2],"idio_vol_pct":25,"expected_alpha_pct":3},{"name":"Stock E","weight_pct":20,"betas":[1,0.3,0.1],"idio_vol_pct":22,"expected_alpha_pct":2},{"name":"Stock F","weight_pct":-30,"betas":[0.7,0.4,-0.2],"idio_vol_pct":20,"expected_alpha_pct":-3,"borrow_bps":30},{"name":"Stock G","weight_pct":-30,"betas":[0.8,0.3,-0.3],"idio_vol_pct":24,"expected_alpha_pct":-4,"borrow_bps":50},{"name":"Stock H","weight_pct":-25,"betas":[0.6,0.5,-0.1],"idio_vol_pct":18,"expected_alpha_pct":-2,"borrow_bps":25},{"name":"Stock I","weight_pct":-15,"betas":[0.9,0.1,-0.4],"idio_vol_pct":40,"expected_alpha_pct":-6,"borrow_bps":800}],"factors":[{"name":"Market","vol_pct":16},{"name":"Value","vol_pct":8},{"name":"Momentum","vol_pct":10}],"factor_corr":[[1,0.1,-0.1],[0.1,1,-0.3],[-0.1,-0.3,1]],"cash_rate_pct":4,"financing_rate_pct":6,"max_gross_pct":250,"max_net_pct":30,"max_factor_share_pct":25}}}' \
  | jq '.result.structuredContent | {summary, flags, flips, not_modeled, inputs_hash}'
```

### The library

The same code on your own machine, with no dependencies, and nothing is sent anywhere.

```bash
curl -fsSL https://hedgefund.md/hedgefund.mjs -o hedgefund.mjs   # read it before you run it
node hedgefund.mjs template long_short_book > mine.json           # replace every number in it
node hedgefund.mjs run long_short_book mine.json | jq '{summary, flags, flips, not_modeled, inputs_hash}'
```

In a script:

```js
import { run, template } from "./hedgefund.mjs";

const inputs = template("long_short_book"); // replace every number in it
const { summary, flags, flips, not_modeled } = run("long_short_book", inputs);
```
