# VRP + 1% VXX overlay: how the combined book is calculated

This note is for **agents** maintaining or reproducing the **post-hoc merge** of a VRP trade log with a VXX sleeve. “**1% VXX**” here means **1% of total portfolio capital allocated as the VXX sleeve’s broker-risk budget** in the merge step, not “1% of NAV in VXX shares.”

**Canonical VRP log (latest bundle):** `RenTech/data/logs/vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl` — this is the default `--vrp-trades` for `portfolio_vrp_plus_vxx.py`.

## What is being combined

1. **VRP** — Closed trades from the VRP Theta backtest, written as JSONL with at least `exit_date` and `pnl_usd` per row (see `export_theta_full_trade_log.py` / `run_vrp_low_dd_vxx_bundle.py`). Use the canonical file above unless you intentionally compare another export.
2. **VXX sleeve** — Two JSONL trade logs, usually:
   - Bear **call credit spread** on VXX
   - Long **OTM call** on VXX  

   Produced by the VXX backtest path (e.g. `optimize_vxx_portfolio.py` and related scripts). Each row should include `exit_date` and `pnl_total`, and ideally `broker_risk_usd` for consistent scaling.

The merge **does not** re-run options pricing. It **rescales** realized PnL streams from fixed engine runs so the **same trade history** can represent different portfolio risk budgets.

## Where the math lives

- **Basis construction:** `load_portfolio_pnl_basis()` in `RenTech/strategy_stack/portfolio_vrp_plus_vxx.py`
- **Combined equity:** `merged_full_equity()` in the same file
- **CLI / report:** `portfolio_vrp_plus_vxx.py`, and the bundled runner `run_vrp_low_dd_vxx_bundle.py` (IV overlays forced to zero there by default)

## Notation (single account)

| Symbol | Meaning |
|--------|--------|
| \(E_0\) | Starting equity = `total_portfolio_capital` (e.g. 100,000) |
| \(C_{\mathrm{vrp}}\) | VRP PnL scale numerator = `capital_vrp` (default \(E_0\)) |
| \(R_{\mathrm{vrp}}\) | `vrp_ref` (default 100,000) |
| \(C_{\mathrm{vxx}}\) | Total VXX broker-risk budget in USD — for “1% VXX”, \(C_{\mathrm{vxx}} = 0.01 \times E_0\) |
| \(w_b, w_c\) | VXX split weights (default **90%** bear spread, **10%** long call), from `--vxx-bear-pct` / `--vxx-call-pct` |

## Daily PnL basis

On the common trading calendar, the code builds cumulative building blocks from JSONLs:

- **VRP:** \(B_v(t) = \dfrac{\mathrm{VRP\_pnl\_on\_day}(t)}{R_{\mathrm{vrp}}}\)  
  So VRP dollar PnL on the book is \(C_{\mathrm{vrp}} \cdot B_v(t)\) per day (then cumulated).

- **VXX bear / call:** Raw overlay daily PnL series \(B_{vb}(t)\), \(B_{vc}(t)\) (sum of `pnl_total` on days trades exit, else 0).

Each sleeve has a **reference risk** \(R_{vb}\), \(R_{vc}\) (USD) computed from the JSONL — when every trade has `broker_risk_usd`, the reference is the **sum** of those values over the log (total modeled risk deployed in that run); otherwise a median/inferred fallback is used. See `_overlay_sleeve_risk_reference_usd()` in `portfolio_vrp_plus_vxx.py`.

## VXX 1%: split and scale

Total VXX budget:

\[
C_{\mathrm{vxx}} = 0.01 \times E_0 \quad\text{(when using `--capital-vxx-pct 0.01`)}
\]

Allocate to legs (defaults):

\[
C_b = C_{\mathrm{vxx}} \times \frac{w_b}{100}, \qquad
C_c = C_{\mathrm{vxx}} \times \frac{w_c}{100}
\]

Example: \(E_0 = 100{,}000\), 1% VXX → \(C_{\mathrm{vxx}} = 1{,}000\); with 90/10 → **$900** bear spread budget, **$100** long-call budget.

**Daily merged PnL** (full book, with IV overlays included if non-zero):

\[
\Delta E(t) =
C_{\mathrm{vrp}} B_v(t)
+ \frac{C_{\mathrm{put}}}{R_p} B_p(t)
+ \frac{C_{\mathrm{str}}}{R_s} B_s(t)
+ \frac{C_{\mathrm{rr}}}{R_r} B_r(t)
+ \frac{C_b}{R_{vb}} B_{vb}(t)
+ \frac{C_c}{R_{vc}} B_{vc}(t)
\]

**Equity curve:**

\[
E(t) = E_0 + \sum_{\tau \le t} \Delta E(\tau)
\]

So “1% VXX” enters **only** through \(C_{\mathrm{vxx}}\) (and the 90/10 split). The **engine** JSONLs were generated with their own internal sizing (`--broker-risk-pct-of-portfolio` on the VXX runner); the merge **re-scales** their PnL so that the sleeve’s risk budget on your book is exactly \(C_{\mathrm{vxx}}\) relative to the JSONL’s reference risk.

## Important distinctions for agents

1. **Merge % vs engine %** — The VXX backtest might use e.g. 1% broker risk **inside that backtest’s account model**. The merge’s `--capital-vxx-pct 0.01` is the **portfolio** sleeve size vs \(E_0\). They are related conceptually (both are “small fraction of capital”) but **not the same variable** unless you set them to match on purpose.
2. **VRP-only vs full** — `execute_portfolio_merge` reports `eq_vrp_only`, `eq_vxx_sleeve`, and `eq_full_portfolio` so you can compare drawdowns. VXX PnL is **additive** on the merged daily series after scaling.
3. **IV overlays** — Set `capital_put`, `capital_straddle`, `capital_risk_reversal` to `0` if you want **VRP + VXX only** (as `run_vrp_low_dd_vxx_bundle.py` does).

## Copy-paste commands

**Merge only** (VRP JSONL + VXX JSONLs, 1% VXX, IV off):

```bash
cd /Users/robzingale/trading_bot
if test -x .venv/bin/python; then PY=.venv/bin/python; else PY=python3; fi
$PY RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
  --total-capital 100000 \
  --vrp-trades RenTech/data/logs/vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl \
  --capital-put 0 --capital-straddle 0 --capital-risk-reversal 0 \
  --capital-vxx-pct 0.01 \
  --vxx-bear-pct 90 --vxx-call-pct 10 \
  --vxx-bear-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_bear_call.jsonl \
  --vxx-call-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_long_call.jsonl \
  --no-vxx-sweep \
  --out-csv RenTech/data/logs/portfolio_vrp_vxx_1pct_equity.csv
```

Adjust `--vrp-trades` and VXX JSONL paths to the artifacts you are actually using.

**Same 1% VXX engine logs + literature legacy4 IV overlays** (put + risk-reversal JSONLs at 1:1 raw PnL vs ref 1, straddle off):

```bash
cd /Users/robzingale/trading_bot
if test -x .venv/bin/python; then PY=.venv/bin/python; else PY=python3; fi
$PY RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
  --total-capital 100000 \
  --vrp-trades RenTech/data/logs/vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl \
  --put-trades RenTech/data/logs/legacy4_put_overlay.jsonl \
  --risk-reversal-trades RenTech/data/logs/legacy4_rr_overlay.jsonl \
  --straddle-trades RenTech/data/logs/__straddle_disabled__.jsonl \
  --capital-put 1 --put-risk-ref 1 \
  --capital-risk-reversal 1 --rr-risk-ref 1 \
  --capital-straddle 0 \
  --capital-vxx-pct 0.01 \
  --vxx-bear-pct 90 --vxx-call-pct 10 \
  --vxx-bear-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_bear_call.jsonl \
  --vxx-call-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_long_call.jsonl \
  --no-vxx-sweep \
  --out-csv RenTech/data/logs/vrp_legacy4_vxx1pct_engine_merge_equity.csv
```

(`__straddle_disabled__.jsonl` is intentionally missing so the straddle sleeve contributes zero PnL; the merge prints a skip notice.)

**Legacy4 + same `--capital-*-pct` as the IV engine Sharpe/DD run** — bridge sleeve refs to `engine_iv_*_ivx1.jsonl`:

Raw `legacy4_put_overlay.jsonl` / `legacy4_rr_overlay.jsonl` usually have no `broker_risk_usd`, so `load_portfolio_pnl_basis()` falls back to **ref ≈ $1** and optimizer fractions (e.g. `--capital-put-pct 0.00523407`) scale PnL by hundreds — invalid. **`bridge_legacy4_overlay_iv_engine_risk.py`** copies the IV engine’s sleeve reference risk (same rule as `portfolio_vrp_plus_vxx`: sum of `broker_risk_usd` when fully documented) and writes **one equal `broker_risk_usd` per legacy trade** so the **sum** matches that IV ref. **PnL stays the literature 1-lot stream**; this is a merge bookkeeping bridge, not a repriced book.

```bash
cd /Users/robzingale/trading_bot
if test -x .venv/bin/python; then PY=.venv/bin/python; else PY=python3; fi
$PY RenTech/strategy_stack/bridge_legacy4_overlay_iv_engine_risk.py
$PY RenTech/strategy_stack/portfolio_vrp_plus_vxx.py \
  --total-capital 100000 \
  --vrp-trades RenTech/data/logs/vrp_low_dd_ov2_vxxbundle_vrp_trades.jsonl \
  --put-trades RenTech/data/logs/legacy4_put_overlay_ivbridged.jsonl \
  --straddle-trades RenTech/data/logs/__straddle_disabled__.jsonl \
  --risk-reversal-trades RenTech/data/logs/legacy4_rr_overlay_ivbridged.jsonl \
  --vxx-bear-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_bear_call.jsonl \
  --vxx-call-trades RenTech/data/logs/overall_portfolio_trade_audits/engine_vxx_1pct_2016_2026/vxx_portfolio_long_call.jsonl \
  --capital-put-pct 0.00523407 \
  --capital-straddle 0 \
  --capital-risk-reversal-pct 0.03388598 \
  --capital-vxx-pct 0.23201529 \
  --vxx-bear-pct 90 --vxx-call-pct 10 \
  --no-vxx-sweep \
  --out-csv RenTech/data/logs/portfolio_opt_10dd_sharpe_legacy4vrp_ivbridged.csv
```

Meta: `RenTech/data/logs/legacy4_ivbridge_meta.json` (per-sleeve IV ref, row count, USD per row).

**Bundle** (re-run low-DD overlap VRP, export logs, merge with `--capital-vxx-pct 0.01`):

```bash
cd /Users/robzingale/trading_bot
PYTHONUNBUFFERED=1 .venv/bin/python RenTech/strategy_stack/run_vrp_low_dd_vxx_bundle.py \
  --capital 100000 --capital-vxx-pct 0.01 --overlap-slice-contracts 2
```

(Paths inside the bundle script point at default log locations; inspect its argparse defaults if you change layouts.)

## Related

- `RenTech/strategy_stack/bridge_legacy4_overlay_iv_engine_risk.py` — build `legacy4_*_ivbridged.jsonl` for merged runs with IV-engine-aligned sleeve refs.
- Module docstring at top of `portfolio_vrp_plus_vxx.py` describes the **risk-budget scaling** model and optimizer flags (`--optimize-sharpe`, `--sharpe-fixed-vxx-pct`, etc.).
- `AGENTS.md` (repo root) — general workflow expectations for this repository.
