Ronnie_Fund is a single-account, long-only systematic strategy that runs once
per trading day. It evaluates a fixed equity universe through a multi-agent
LLM pipeline, applies a deterministic risk layer, and submits market orders
against either a paper ledger or a mirrored Charles Schwab brokerage account.
This page documents the rules. They are sourced from
RiskPolicy and the daily-cycle scheduler at request time, not
hardcoded into the page.
1 · Daily cycle
A single launchd job (com.tradingagents.daily-cycle) fires at
12:30 PM ET on weekdays. The cycle is idempotent for a
given trading day: a second invocation without --force exits
cleanly. Same-day re-runs are explicitly opted into.
The cycle, end to end:
universe.txt → agent graph (per ticker, sequential) → bundle written to reports/<TKR>_<TS>/ → signal_extractor parses 5_portfolio/decision.md → Allocator emits OrderProposal candidates → stop-loss generator emits exit proposals → RiskEngine accepts / resizes / rejects each proposal → MirrorRouter routes to PaperBroker (always) and SchwabBroker (if live) → ledger updated · NAV marked · macOS notification
Per-ticker errors do not poison the cycle. A failing graph run for one
symbol is recorded as cycle_ticker_error in the audit log
and the cycle continues with the next ticker.
2 · Universe
The active universe lives at data/universes/active.txt — one
ticker per line, # introduces a comment. Edits take effect on
the next cycle; no restart required. The current list reflects the
Aschenbrenner thesis (compute, power, electrical infrastructure,
hyperscalers, defense, BTC sleeve) — the strategic backbone is documented
separately in docs/strategy/aschenbrenner-thesis.md.
3 · From signal to proposal
For each ticker the agent graph produces a structured decision bundle.
The 5_portfolio/decision.md file is parsed for a rating of
Buy, Hold, or Sell, plus a horizon and rationale.
Holds emit no proposal. Buys and sells are handed to the Allocator.
The Allocator maps each signal to a target weight as a fraction of NAV. The mapping is presently coarse — a single default target per direction, bounded above by the per-name cap — and is the layer most likely to evolve as conviction-tier signal output stabilizes. Per-position sizing is always re-checked by the RiskEngine before any order leaves the pipeline.
4 · Risk gates
Every proposal is evaluated by the RiskEngine, which can accept,
resize, or reject it. Each decision is written to
the audit log as a risk_decision row before any order leaves
the engine.
4.1 Per-name concentration
CAP 12% OF NAV
No single ticker may exceed 12% of NAV after the proposal would fill. Proposals that breach are resized to the cap; if the resize falls below the minimum lot, the proposal is rejected.
4.2 Theme caps
AI_INFRA ≤ 60%
DEFENSE ≤ 5%
Aggregate exposure to a theme is bounded above by its cap, measured as a fraction of total NAV (not the equity sleeve net of BTC). With a 30% BTC sleeve target, the practical ceiling on AI-infra names is 60% of total NAV, which corresponds to roughly 86% of the actively-traded equity sleeve at full BTC deployment. The defense cap of 5% caps a deliberately small sleeve. Themes outside the cap dictionary are uncapped via this mechanism; the per-name 12% cap still applies.
4.3 BTC sleeve
TARGET 30% ± 5% · MSTR ≤ 6%
BTC exposure is held at a target weight of 30% of NAV inside a ±5% band via the IBIT spot ETF and an actively-traded MSTR position. MSTR is independently capped at 6% of NAV given its embedded leverage to BTC. Proposals that would push the sleeve above the band's upper edge are resized; below the lower edge, a buy is favored.
4.4 Stop-loss (per position)
TRIGGER AT -8.0%
Every cycle, before evaluating new buy/sell signals, the stop-loss generator inspects each open position. If the unrealized return on a position is at or below -8.0% from the position's average cost basis, an exit proposal is emitted. Stops do not trail and are not measured against a high-water mark — a position that appreciates materially and then reverses will not trigger the stop unless the decline breaches the original cost basis.
4.5 Drawdown circuit breaker
HALT NEW BUYS BELOW -15% YTD
If the fund's calendar-year-to-date NAV is at or below -15% versus its January 1 opening NAV, the engine rejects all new buy proposals for the remainder of the calendar year. Exit proposals (sells, stops) continue to be processed normally. The breaker resets on January 1 regardless of inception date — a fund that goes live in Q4 has only a partial first-year window before its first reset, after which the next-year baseline is the January 1 NAV that follows.
4.6 Uninvested cash reserve
CASH ≥ $0
The cash floor specifies a minimum idle balance the engine will protect. A buy proposal whose cost would consume that reserve is rejected outright, not resized down. The current floor of $0 means buys are bounded only by the actual cash balance; raising the floor is the standard mechanism for reserving liquidity for redemptions, planned contributions, or risk-event cash. When buys hit this gate, the smart-rebalance funder (§5) can free cash by trimming a low-conviction position so the next cycle can re-attempt the buy.
4.7 Earnings blackout
BUY rejected when next-earnings is within 5 calendar days
The fund's typical horizon (3–6 months) doesn't justify paying the IV
ramp into a binary print. New BUY proposals on a ticker reporting
within the blackout window are rejected at the gate. SELLs are
unaffected — the operator must always be able to exit before
a print if the thesis breaks. Set the field to 0 on the policy to
disable. Earnings dates are refreshed each cycle from the market-data
adapter and cached in earnings_calendar.
4.8 Wash-sale lookback
BUY rejected within 30-day window after a loss-realizing sell of the same ticker
IRS §1091 disallows a loss when a substantially-identical security is
bought within 30 calendar days of the sale; the disallowed amount is
added to the replacement lot's basis. The gate prevents the foot-gun
pre-trade by querying tax_lot_consumptions for recent
loss-sells on the proposal's ticker. Active windows surface on the
Tax page and on each affected position
drilldown. Coverage limits: ticker-exact match only (no
"substantially identical" fuzzy matching), single-fund only, and no
post-trade basis adjustment if a wash slips through. Smart-rebalance
funding sells are exempt from this gate by design — they're already
operator-visible.
4.9 Cross-asset hedge floor
Aggregate value of TLT, GLD ≥ 0% of NAV
An opt-in defensive sleeve to dampen concentration risk. When the
aggregate market value of hedge_tickers falls below
hedge_floor_pct × NAV, the cycle emits a buy proposal on
the first hedge ticker sized to close the gap. The buy goes through
the same RiskEngine, so per-name caps still apply. The system
never auto-sells hedges — the operator owns the unwind
decision (insurance isn't auto-trimmed when it's working). Disabled
by default (0%).
5 · Smart-rebalance funder
When a BUY hits cash_floor, emit ≤ 2 funding sells of 25% of a low-conviction position
Cycle 3 (2026-05-08) ended 47 signals → 28 buy proposals → 0 fills, all 28 rejected for cash_floor (fund 99.6% deployed). Without a mechanism to free cash, every high-conviction buy dies on contact with the gate. The funder closes that loop deterministically.
- Trigger: any buy rejected with reason containing "cash floor".
- Selection: open positions sorted by unrealized return (most-negative first — cut losers); tiebreak by smaller notional. Skips BTC sleeve tickers (owned by §4.3), tickers already being sold or bought this cycle, and operator-pinned tickers.
-
Sizing:
floor(quantity × funding_sell_pct_of_position), with a 1-share floor. - Outcome: generated sells fill same-cycle if accepted; the buys they fund get a fresh chance the next cycle with freed cash. Two-cycle latency is acceptable for a daily fund and avoids paired-batch broker semantics.
Off via smart_rebalance_enabled = false. Operator-pinned
tickers are excluded entirely — see the Pin button on each position
drilldown.
6 · Order construction & fills
Accepted proposals become orders rows with order_type
= market and time_in_force = day.
The cycle fires at 12:30 PM ET; market data for sizing checks, paper
fills, and end-of-cycle NAV marks is fetched from the market-data
adapter at cycle time, not from prior close or next open. Two execution
paths exist:
- PaperBroker — always runs. Uses a realistic fill model: last quote bid/ask, spread-half slippage in basis points scaled by notional, and a flat commission. Fills are written immediately as the cycle does not wait for asynchronous broker state.
-
SchwabBroker — only runs when
live_trading_enabledis set insystem_state. Submits via the Schwab Trader API and writes a synthetic fill keyed to the venue order id; the actual settled fill is reconciled separately (deferred to Phase 7d).
The MirrorRouter always sends to paper and conditionally forwards to Schwab.
7 · NAV mark and lifecycle
At the end of each cycle the fund's NAV is recomputed from cash plus
mark-to-market position value (last quote × quantity, falling back to
cost basis when the market data adapter cannot quote). One
NavSnapshot row is written per trading day; the value flows
into every chart and statistic on the rest of the terminal.
8 · Return calculation conventions
Return statistics are computed from NAV snapshots starting at the date of the first fill — not from the date the fund record was created. The intent is to avoid annualizing across a ramp-up period when most capital was uninvested, which would produce arithmetic noise rather than a meaningful figure; it is not a presentation choice to flatter returns.
- Total Return is the realized change in NAV from inception to the most recent snapshot.
- CAGR and Calmar are reported only when post-inception history exceeds 30 days. Below that threshold, annualization is statistical noise and both fields render as n/a.
- Sharpe and Sortino are computed on daily NAV returns, annualized at √252, with a risk-free rate of zero. This convention overstates both ratios relative to any calculation that uses the contemporaneous T-bill rate; figures here are not directly comparable to published fund metrics.
- Performance numbers presented on this site are not prepared in accordance with GIPS or any other recognized performance-reporting standard.
9 · Tax-lot accounting
Every BUY fill writes a row to tax_lots capturing
acquisition date, price, and quantity. Every SELL fill consumes
lots in FIFO order (oldest acquisition first),
writing one tax_lot_consumptions row per (sell × lot)
pair with computed realized P&L, holding period, and ST/LT
classification (holding > 365 days = long-term).
FIFO is the U.S. federal default convention and matches how Schwab reports on Form 1099-B when no specific lot is identified at sale. Year-end Form 8949 export is available via:
tradingagents tax export --fund-id N --year YYYY
Output lands in reports/tax/<fund>/form-8949-YYYY.csv.
The Tax page (/terminal/tax) shows
realized YTD/all-time KPIs, year-by-year breakdown, and the wash-sale
window roster.
Glossary
- NAV
- Net Asset Value. Cash balance plus the mark-to-market value of all open positions at the most recent quote.
- Inception
- The date of the first fill executed by the fund. All return statistics are anchored here, not at fund creation.
- Total Return
- (NAVt / NAVinception) − 1, expressed as a percent.
- CAGR
- Compound annual growth rate. (1 + Total Return)(365.25 / span_days) − 1. Suppressed when span_days < 30.
- Volatility (ann.)
- Standard deviation of daily NAV returns × √252.
- Sharpe
- (mean daily return × 252) ÷ annualized volatility. Risk-free rate assumed to be zero.
- Sortino
- Same as Sharpe but the denominator uses only downside deviation (semi-deviation of negative returns).
- Max Drawdown
- Largest peak-to-trough decline in NAV over the post-inception window, expressed as a negative percent.
- Calmar
- CAGR ÷ |Max Drawdown|. Suppressed when CAGR is unavailable.
- Signal
- The structured output of the multi-agent graph for a given ticker on a given date — at minimum a Buy / Hold / Sell rating and rationale. Holds emit no proposal.
- Conviction
- The strength of a signal expressed as a target weight in NAV. Currently coarse (one default per direction); intended to evolve into a tiered mapping as agent output stabilizes.
- Sleeve
- A bounded sub-portfolio defined by purpose — e.g., the BTC sleeve (IBIT + MSTR, target 30% of NAV) or the equity sleeve (everything other than BTC).
- Theme
- Coarse classification of a ticker (AI Infra, BTC Sleeve, Defense,
Other). Used for cap enforcement only — does not affect signal
generation. Mapping lives in
tradingagents/portfolio/themes.py. - Per-name cap
- Maximum fraction of NAV any single position may occupy. (12% default).
- Drawdown breaker
- YTD drawdown threshold below which new buy orders are rejected. (-15% default; resets Jan 1.)
- Stop-loss
- Position-level return threshold at which an exit proposal is emitted. (-8.0% default.)
- Mirror router
- Routing layer that always sends orders to the paper ledger and optionally forwards to Schwab when live trading is enabled.
- Slippage (bps)
- Modeled execution cost above mid-quote, measured in basis points (1 bp = 0.01%). Scales with notional in the paper fill model.
- Audit log
- Append-only event log capturing every cycle event, risk decision, order, and fill.
- Tax lot
- One row in
tax_lotsfor each BUY fill capturing acquisition date, price, and quantity. SELL fills consume lots in FIFO order; the resulting consumptions carry realized P&L and ST/LT classification. - FIFO
- First-In-First-Out — the U.S. federal default tax-lot consumption order. Schwab and other retail brokerages apply FIFO when no specific lot is identified at sale.
- Form 8949
- The IRS form for reporting capital gains and losses from
securities sales. The CLI export
(
tradingagents tax export) produces one row per consumption with the columns the form requires. - Wash sale
- An IRS §1091 disallowance triggered when a substantially-identical security is bought within 30 days of a loss-realizing sell. The risk gate prevents wash sales pre-trade by rejecting BUYs on tickers in the lookback window. Active windows surface on the Tax page and on the affected position drilldown.
- Smart-rebalance funder
- The cycle helper that emits funding sells of low-conviction
positions when buys are rejected for cash floor. Picks the
worst-performing non-BTC, non-pinned position to trim. Off via
smart_rebalance_enabled = false. - Hedge sleeve
- A bounded sub-portfolio of negatively-correlated holdings (e.g.,
TLT for rate moves, GLD for tail risk). The hedge floor policy
ensures aggregate market value of
hedge_tickersstays ≥hedge_floor_pct× NAV. Defaults to disabled. - Risk Watch
- Proactive alerts surfaced on the morning memo: stop-near-trigger, concentration approaching cap, drawdown approaching breaker, stale signal (no agent report in 14+ days).