Raxx · internal docs

internal · gated

ETF NAV Discount Strategy — Specification

Strategy ID: etf-nav-discount Version: 0.1 (research) Status: research Date Added: 2026-05-12 UTC Source: User feedback #479 (2026-04-29 UTC iMessage) Data-Science Author: Raxx data-scientist agent


1. Plain-Language Description

When an ETF's market price falls below its net asset value (NAV) by at least a configurable threshold, buy a fixed number of shares at a scheduled time (e.g., noon on Fridays). The hypothesis is that ETF price-to-NAV discounts are mean-reverting: persistent discounts are arbitraged away by authorized participants (APs), making entries near discount peaks statistically favorable on a days-to-weeks horizon.

This is the exact strategy described in the user feedback that seeded issue #479. It is documented here as a concrete specimen of what the natural-language authoring surface must be capable of parsing and executing — it is not a recommended trade.


2. Formal Definition

2.1 Trigger Condition

condition: price_vs_nav
operator:  less_than
threshold: configurable (default: -0.50%, i.e. ETF trades ≥ 0.5% below NAV)

The discount is computed as:

discount_pct = (market_price - nav_per_share) / nav_per_share * 100

A negative discount_pct means the ETF trades at a discount. The condition fires when discount_pct <= -threshold_pct.

2.2 Action

side:      buy
qty:       user-specified integer (e.g. 10 shares)
order_type: market (MVP) or limit at NAV (future)

2.3 Schedule

frequency:    weekly
day_of_week:  Friday (configurable)
time_utc:     17:00 UTC (noon US Eastern, configurable)

At the scheduled time, the condition is evaluated against a real-time or near-real-time quote. If the condition is met, the order is submitted. If the condition is not met, no action is taken and the strategy waits for the next scheduled window.

2.4 Exit

Not defined in MVP. Positions accumulate. A future version may add a price_vs_nav > +X% exit condition to close the accumulated shares when the premium normalizes.


3. Universe

Instrument class: US-listed ETFs (equity, bond, commodity).

Initial candidates for testing:

Ticker Category NAV data availability
SPY US large-cap equity End-of-day via iNAV; real-time via SPDR site
IVV US large-cap equity Same composition as SPY; cross-check
GLD Gold commodity iNAV published by SPDR
TLT Long Treasury bond iNAV via iShares
HYG High-yield bond iNAV via iShares; discounts wider during stress

Bond ETFs (TLT, HYG) are higher-interest from a discount/premium perspective — their intraday iNAV lags mark-to-market for illiquid underlying bonds, creating apparent discounts that may not be real arbitrage. Flag as a data-quality risk.

Excluded at MVP: leveraged ETFs, inverse ETFs, closed-end funds (CEFs — structurally different discount mechanism), options strategies ETFs.


4. Data Requirements

4.1 Market Price

4.2 NAV per Share

This is the central data challenge. Three tiers exist:

Tier 1 — Intraday Indicative NAV (iNAV): - Published every 15 seconds during market hours by some fund families (SPDR, iShares) - Not available via Alpaca; requires direct scraping of issuer sites or third-party data vendors - Most reliable for intraday strategies

Tier 2 — End-of-Day NAV: - Published after market close by every ETF per SEC rules (Form N-PORT/N-CEN) - Available free from fund family websites (SPDR, iShares, Vanguard) - Available via ETF.com, Morningstar - Licensing: free for non-commercial research; commercial use requires vendor agreement - Acceptable for weekly strategies where the entry is at close or near-close prices

Tier 3 — Estimated NAV from holdings: - Reconstruct NAV from public holdings data (13F filings, fund transparency reports) - Significant lag (quarterly 13F) and tracking error - Not suitable for this strategy

MVP recommendation: use end-of-day NAV from fund family sites (Tier 2). For Friday-noon execution, compare against Thursday's closing NAV published by the fund. This introduces a ~20-hour lag but is sufficient to detect structural discounts. Real-time iNAV can be a v2 enhancement.

Data licensing flag: commercial use of iNAV data scraped from issuer sites is not clearly licensed for automated trading platforms. Flag to business-legal-researcher before productizing iNAV integration.

4.3 Required Fields per Evaluation

{
  "ticker":           "string",
  "eval_datetime_utc":"string (ISO 8601)",
  "market_price":     "number (USD)",
  "nav_per_share":    "number (USD)",
  "nav_date":         "string (ISO 8601 date, the date nav_per_share was published)",
  "discount_pct":     "number (computed: (market_price - nav_per_share) / nav_per_share * 100)",
  "condition_met":    "boolean",
  "threshold_pct":    "number (configured threshold)"
}

5. Hypothesis

Primary hypothesis: ETF price-to-NAV discounts of ≥ 0.5% on weekly close are mean-reverting within 5 trading days, producing a positive expected return on entries at the discount.

Mechanism: Authorized Participants (APs) can create/redeem ETF shares at NAV. A sustained discount creates a risk-free arbitrage for APs (buy ETF shares at discount, redeem for underlying at NAV). This mechanical arbitrage should close most discounts quickly in liquid ETFs.

Hypothesis boundary conditions: - Highly liquid ETFs (SPY, IVV): discounts are rare and brief; the signal fires infrequently but with high confidence - Less-liquid ETFs (HYG, TLT): discounts are more frequent but may persist longer during stress; mechanism is weaker when underlying bonds are illiquid - Illiquid/niche ETFs: AP arbitrage may be structurally limited; hypothesis weakens

Testable prediction: entries on days when discount_pct <= -0.5% should show statistically higher 5-day forward returns compared to random-entry baseline.


6. Parameters

Parameter Type Default Range Notes
threshold_pct float -0.50 -0.25 to -2.0 Discount required to trigger
qty int 10 1–10,000 Shares per order; notional-capped in prod
day_of_week str Friday Mon–Fri Evaluation + execution day
time_utc str 17:00 14:30–21:00 Must be within market hours
nav_lag_days int 1 0–2 Days old the NAV data is allowed to be
max_notional_usd float 5000.0 100–50,000 Hard cap per execution
paper_only bool true Live mode requires explicit opt-in + safety rails

7. Backtest Design (High-Level)

Full config: see backtest-config.json in this directory.

Note: this backtest cannot run in agent dispatch. A feature-developer or Kristerpher must run reference.py against real historical data on a machine with the Alpaca historical data subscription enabled (or an alternative data source). The config and code are provided; the execution is delegated.


8. Out-of-Scope for This Strategy Version


References