Raxx · internal docs

internal · gated

ETF NAV Discount Strategy — Data Schema

Strategy ID: etf-nav-discount Version: 0.1 (research)


1. StrategyDefinition

The user-authored strategy record, as stored in the database after DSL parsing.

{
  "strategy_id": "string (uuid4)",
  "user_id": "string (uuid4, foreign key to users table)",
  "name": "string (user-provided label, e.g. 'Buy SPY at discount')",
  "nl_input": "string (original natural-language string the user typed)",
  "dsl": {
    "ticker": "string",
    "trigger": {
      "metric": "string (price_vs_nav | price_vs_sma_N | rsi_below | custom)",
      "operator": "string (lt | gt | lte | gte)",
      "threshold_pct": "number (signed; negative = discount)"
    },
    "action": {
      "side": "string (buy | sell)",
      "qty": "integer (shares)",
      "order_type": "string (market | limit)",
      "limit_price_rule": "string (nav | bid | ask | mid | null)"
    },
    "schedule": {
      "day_of_week": "string (Monday | Tuesday | Wednesday | Thursday | Friday | any)",
      "time_utc": "string (HH:MM, must be 14:30–21:00)"
    }
  },
  "dsl_parse_confidence": "number (0.0–1.0, from Claude parse call)",
  "dsl_version": "string (semver, e.g. '1.0')",
  "status": "string (draft | confirmed | active | paused | archived)",
  "paper_only": "boolean",
  "max_notional_usd": "number (hard cap per execution)",
  "created_at": "string (ISO 8601 datetime UTC)",
  "confirmed_at": "string (ISO 8601 datetime UTC, nullable — set when user confirms parse)",
  "last_modified_at": "string (ISO 8601 datetime UTC)"
}

Status transitions: - draft — parsed but not yet confirmed by user - confirmed — user confirmed the parsed DSL; awaiting first scheduled window - active — at least one execution has occurred; scheduled - paused — user or system suspended execution - archived — strategy deleted; retained for audit


2. ConditionEvaluation

Created on every scheduled evaluation window, whether or not the condition was met.

{
  "eval_id": "string (uuid4)",
  "strategy_id": "string (fk → StrategyDefinition)",
  "eval_datetime_utc": "string (ISO 8601 datetime UTC)",
  "ticker": "string",
  "market_price": "number (USD, ask or last trade at eval time)",
  "nav_per_share": "number (USD, most recent available NAV)",
  "nav_date": "string (ISO 8601 date)",
  "nav_lag_hours": "number (hours between nav_date close and eval_datetime_utc)",
  "discount_pct": "number (computed: (market_price - nav_per_share) / nav_per_share * 100)",
  "threshold_pct": "number (configured threshold at time of eval)",
  "condition_met": "boolean",
  "data_quality_flags": ["array of strings: stale_nav | market_closed | quote_stale | nav_unavailable"],
  "execution_id": "string (fk → ExecutionRecord, nullable — set if order fired)"
}

3. ExecutionRecord

Created when the condition is met and an order is submitted. One record per order, even if the order is rejected or fails.

{
  "execution_id": "string (uuid4)",
  "strategy_id": "string (fk → StrategyDefinition)",
  "eval_id": "string (fk → ConditionEvaluation)",
  "order_submitted_at": "string (ISO 8601 datetime UTC)",
  "ticker": "string",
  "side": "string (buy | sell)",
  "qty_requested": "integer",
  "qty_filled": "integer (nullable until fill confirmed)",
  "order_type": "string (market | limit)",
  "limit_price": "number (nullable for market orders)",
  "fill_price": "number (nullable until filled)",
  "fill_datetime_utc": "string (nullable)",
  "notional_requested": "number (qty_requested × market_price at submission)",
  "notional_filled": "number (nullable)",
  "alpaca_order_id": "string (nullable — Alpaca's order UUID)",
  "order_status": "string (pending | filled | partial | cancelled | rejected | error)",
  "rejection_reason": "string (nullable)",
  "mode": "string (paper | live)",
  "confirm_required": "boolean",
  "confirmed_at": "string (nullable — set if human confirm step was required and given)"
}

4. HumanConfirmRequest

For the first execution of each strategy (and optionally for all executions if the user opts in), a confirm request is created before the order fires.

{
  "confirm_id": "string (uuid4)",
  "strategy_id": "string (fk → StrategyDefinition)",
  "eval_id": "string (fk → ConditionEvaluation)",
  "created_at": "string (ISO 8601 datetime UTC)",
  "expires_at": "string (ISO 8601 datetime UTC, default: 4 hours after creation)",
  "summary_text": "string (plain-English description of what will happen, e.g. 'Every Friday at 17:00 UTC: if SPY trades more than 0.5% below NAV, buy 10 shares at market.')",
  "condition_snapshot": {
    "market_price": "number",
    "nav_per_share": "number",
    "discount_pct": "number"
  },
  "user_action": "string (null | confirmed | rejected | expired)",
  "user_action_at": "string (nullable)"
}

5. NAVRecord

Cache of NAV data fetched from fund family sites. Point-in-time preserved for backtesting reproducibility.

{
  "nav_record_id": "string (uuid4)",
  "ticker": "string",
  "nav_date": "string (ISO 8601 date, the business day this NAV applies to)",
  "nav_per_share": "number (USD)",
  "source": "string (spdr_site | ishares_site | vanguard_site | etf_dot_com | manual)",
  "fetched_at": "string (ISO 8601 datetime UTC)",
  "is_estimated": "boolean (true for iNAV; false for official end-of-day NAV)"
}

Retention: NAV records are append-only; never overwritten. If a corrected NAV is published, a new record is inserted with the correction flag.


6. ParseAttempt

Audit log of every call to the Claude DSL parse endpoint. Supports debugging, cost tracking, and hallucination analysis.

{
  "parse_id": "string (uuid4)",
  "user_id": "string (uuid4)",
  "nl_input": "string (verbatim user input)",
  "prompt_tokens": "integer",
  "completion_tokens": "integer",
  "model": "string (e.g. 'claude-haiku-3-5')",
  "latency_ms": "integer",
  "raw_response": "object (full structured output from Claude)",
  "parsed_dsl": "object (nullable — null if parse failed)",
  "confidence": "number (0.0–1.0)",
  "error_code": "string (nullable: parse_failed | unsupported_metric | ambiguous_action | ...)",
  "error_message": "string (nullable)",
  "attempted_at": "string (ISO 8601 datetime UTC)",
  "strategy_id_created": "string (nullable — set if this parse resulted in a saved strategy)"
}

7. Backtest Run Artifact Manifest

Every backtest run produces the following files under docs/data-science/backtests/etf-nav-discount/<YYYY-MM-DD-run-id>/:

File Description
config.json Full backtest config snapshot (copy of backtest-config.json + runtime params)
nav_records.csv All NAV data points used (date, ticker, nav_per_share, source)
evaluations.csv One row per weekly evaluation (eval_datetime, ticker, market_price, nav, discount_pct, condition_met)
trades.csv One row per triggered order (entry_date, ticker, qty, entry_price, exit_date, exit_price if exit defined)
equity_curve.csv Weekly portfolio value mark-to-market
equity_curve.png Equity curve chart (matplotlib, cumulative)
signal_distribution.png Histogram of discount_pct at trigger time
baseline_comparison.csv Buy-and-hold and random-entry baseline metrics alongside strategy metrics
summary.json Aggregate metrics (Sharpe, CAGR, max drawdown, win rate, signal count, avg days held)
git_sha.txt Git commit hash at time of run