Raxx · internal docs

internal · gated ↑ index

MBT — Investor Profile Model + Educational Overlay

Status: Draft Owner: software-architect Last updated: 2026-04-22 Parent epic: #183 — Multi-tenant architecture (reframed) Related PRs: #189 (MBT engine design), #183 (parent epic) Related ADRs: 0003, 0013, 0014, 0015 Resolves MBT §14 Qs: 1 (starting cash), 2 (fill aggressiveness), 3 (interest-rate narrative)


1. Context + goal

MBT is the Raxx-native paper-trading engine. On PR #189, the three blocking open questions in §14 (starting cash default, multi-leg fill aggressiveness, interest-rate model) were answered by the user not with fixed numbers, but with a directive: build a profile-driven experience that infers sensible defaults from the user's stated goals, and teach rather than configure.

This doc specifies the investor-profile model: the onboarding question sequence that infers a profile, the three starter profiles and their per-profile MBT defaults, the educational overlay that explains every trade outcome, and the "stretch goals" cadence mechanic. It does NOT implement these — it shapes the boundary so feature-developer sub-cards can be filed.

2. Invariants that apply

These constraints are non-negotiable (ADR 0002, 0003, 0013, 0015):

  1. Education over advice. Profile adjusts Raxx-controlled defaults; it never recommends a trade, strategy, or security. Copy "Raxx recommends..." is forbidden at every layer. See §11 for the regulatory line.
  2. User-directed simulation. The user governs every order. Profile influences starting conditions and overlays; it does not auto-submit or auto-adjust positions.
  3. Paper-first gating. Profiles exist exclusively in MBT (paper). They have no bearing on live-handoff conditions, which are governed by separate paper-profitability gating.
  4. GDPR by default. Profile data is PII-lite but sensitive (financial goals, risk tolerance). Full DSR rights apply: exportable, erasable, rectifiable. See §11.
  5. No stored credentials. Profile system touches no broker credential. This constraint is restated because the onboarding flow MUST NOT embed an API-key entry step.
  6. Audit trail. Every profile creation, update, and onboarding override writes an audit_log row.
  7. Credentials into infra. Profile model has no third-party API dependency. No new secrets.

3. Profile schema — three starter profiles

Three profiles ship in v1. Names below are placeholders — the user must confirm final names before implementation (see §12, Open Question #1).

Attribute Trial Income Builder Diversifier
Placeholder name Trial Income Builder Diversifier
Starting cash default $10,000 $50,000 $100,000
User-overridable? Yes (within tier cap) Yes (within tier cap) Yes (within tier cap)
Risk temperament Conservative Balanced Aggressive
Primary goal family Learn mechanics Generate income Diversify existing book
Fill aggressiveness Conservative (worse-of-mid/offer) Mid (mid-price) Aggressive (mid-price + attempt at mid on touch)
Interest-rate narrative tone Teaching-heavy Balanced Assume-familiarity
Goal cadence default Weekly Monthly Monthly
Target persona New to investing, trialing on a recommendation Has savings (~$50k), wants income-generating strategies Already has a trading platform elsewhere; paper-testing here

Tier caps still apply: Free users have a lower history-retention ceiling regardless of profile. Profile does not override tier limits.

4. Onboarding flow

Onboarding is 3–5 questions. Answers derive the profile; the user can override any default immediately after. Onboarding can also be re-run from Settings at any time.

Question sequence (copy is a placeholder — requires product-writing pass):

  1. "What brings you to Raxx?" - "I'm new to options and want to learn the ropes" → signal: Trial - "I have savings I want to put to work through income strategies" → signal: Income Builder - "I already trade elsewhere and want a testing ground for new strategies" → signal: Diversifier

  2. "Have you traded options with real money before?" - No → reinforces Trial signal - Yes, occasionally → supports Income Builder signal - Yes, actively → supports Diversifier signal

  3. "What's your goal cadence — when do you want to measure your paper results?" - Daily → emphasizes Trial or very active Income Builder - Weekly → Trial or Income Builder - Monthly → Income Builder or Diversifier

  4. "What would a meaningful paper-trade win look like for you?" (optional free-form + presets) - "$100 / week income" → Income Builder - "Beat the S&P 500 in 3 months" → Diversifier - "Understand how a vertical spread works" → Trial

  5. (Derived + confirm) Show inferred profile card: starting balance, goal cadence, fill style. User accepts or selects a different profile from a dropdown. This is the override gate.

Profile derivation is a simple scoring function — no ML, no external call. Answers are weights; highest-weighted profile wins; ties break toward the more conservative profile.

5. Profile → MBT defaults mapping

Explicit mapping that resolves MBT §14 Qs 1–3:

MBT parameter (from §14) Trial Income Builder Diversifier
Starting cash balance $10,000 $50,000 $100,000
Multi-leg fill aggressiveness Conservative: fill at worse-of-mid/offer Mid: fill at combined NBBO mid Aggressive: attempt mid; fallback to mid+1 tick
Interest-rate narrative tone Teaching-heavy (full blurb on every accrual event) Balanced (abbreviated note + tax summary) Assume-familiarity (dollar amount + tax line only)
Paper history retention scope Tier cap; 90d for Free Tier cap; 3yr for Pro Tier cap; unlimited for Pro+
Goal cadence default Weekly Monthly Monthly

Fill-aggressiveness maps to the legs_fill_aggressiveness field on mbt_accounts. It is user-overridable per-order via a "Fill preference" toggle in Antlers (present but not prominent for Trial; more visible for Diversifier).

6. Educational overlay pattern

The overlay is Raptor-side logic + Antlers-side rendering. It does not require a separate service but does require a new module.

Mechanism:

After POST /api/mbt/orders produces a fill, the response envelope includes a narrative field:

{
  "data": { ...order... },
  "narrative": {
    "headline": "Your vertical spread filled at $1.42 credit",
    "body": "...",
    "learn_more_key": "vertical_spread_credit_fill",
    "tone": "teaching-heavy"
  }
}

Antlers renders the narrative block below the fill confirmation. Tone is derived from the user's profile (investor_profiles.narrative_tone). learn_more_key links to a static glossary page (v1: anchor on a /learn page; v2: in-app drawer).

Narrative service: backend_v2/api/services/narrative_service.py. The implementation sub-card will define it. The design contract is:

Templates are keyed by (trade_event, profile_tone). Nine event types × 3 tones = 27 base templates. Multi-leg events (iron condor fill, spread expiry) add another ~12 templates. Total v1 template count: ~40.

Content authorship: v1 ships with engineering placeholder copy. A product-manager or marketing-strategist follow-up card should commission polished copy before GA. See Open Question #4.

7. Margin interest — teaching moment

When MBT accrues simulated margin interest on a position (nightly Celery task mbt.accrue_margin_interest), the next Antlers session render surfaces a margin-interest card. This is triggered by a new margin_interest_accrued activity type in mbt_activities.

The card (tone: teaching-heavy) contains:

  1. The numbers: "$X.XX interest on $Y,YYY notional at Z% annualized for N days."
  2. Why it exists (plain language): "Margin means you're borrowing to trade. Like any loan, there's a cost — that's this charge. In paper trading, this is simulated; in live trading with a real broker, this would come out of your account."
  3. Tax strategy note: "Interest on investment loans may be deductible against investment income — consult your CPA. Raxx surfaces the total here so you can bring the number to that conversation. This is not tax advice."

The tax note is ALWAYS present, regardless of tone. The verbosity of points 1 and 2 scales with tone.

Regulatory note: Raxx does NOT advise on whether the user should use margin, which broker to use, or whether the deduction applies to their situation. The note surfaces the fact and defers to a CPA. This is the correct framing under §202(a)(11) — educational disclosure, not individualized advice.

8. Stretch goals mechanic

Profile sets baseline goal (e.g., "earn $100/week in paper income"). After N consecutive weeks of the user meeting or exceeding the goal, MBT surfaces a stretch prompt:

Implementation:

The stretch prompt is delivered via the activity feed as a system_nudge activity type — not email, not push. User can suppress all nudges from Settings.

9. Data model

Separate investor_profiles table (1:1 with users). Separate because: profile can grow (new fields, new tones) without touching the users table; cleaner GDPR export scope; easier to wipe on erasure.

investor_profiles
  id                    PK
  user_id               FK -> users.id ON DELETE CASCADE, UNIQUE
  profile_type          ENUM ('trial' | 'income_builder' | 'diversifier')
  starting_cash         NUMERIC(15,2)        -- user-overridable at onboarding
  narrative_tone        ENUM ('teaching_heavy' | 'balanced' | 'assume_familiarity')
  fill_aggressiveness   ENUM ('conservative' | 'mid' | 'aggressive')
  goal_target           NUMERIC(15,2) NULL   -- NULL = no goal set
  goal_cadence          ENUM ('daily' | 'weekly' | 'monthly') DEFAULT 'weekly'
  goal_streak_count     INTEGER DEFAULT 0
  goal_streak_threshold INTEGER DEFAULT 4
  onboarding_completed  BOOLEAN DEFAULT FALSE
  created_at            TIMESTAMPTZ
  updated_at            TIMESTAMPTZ

mbt_accounts.cash_balance is seeded from investor_profiles.starting_cash at account-creation time (not a live FK — a one-time copy). This preserves MBT account independence if the user later changes their profile starting cash.

Migration: additive — new table, no changes to existing mbt_accounts or users columns. Rollback: DROP TABLE investor_profiles (safe; MBT accounts already seeded fall back to their stored cash_balance).

10. Rollout plan

Feature gated behind FLAG_MBT_INVESTOR_PROFILES (independent of FLAG_MBT_PAPER_TRADING).

  1. Dark. Schema migration lands; service + API endpoints land; flag off. No user-facing change.
  2. Beta (flag on for allowlisted users). Run onboarding flow for new accounts; existing users see a "Complete your profile" banner in Settings. Collect feedback on question clarity + profile accuracy.
  3. GA. Flag on globally. Existing users without a profile are auto-assigned Diversifier ($100k) with a "Review your profile" prompt on next login — this is the safest default for existing users (they've already been operating at the $100k Alpaca-paper level).
  4. Post-GA. Copy polish pass (marketing-strategist card). Stretch-goals mechanic can ship as a separate flag (FLAG_MBT_STRETCH_GOALS) after GA if deferred.

11. Security + regulatory considerations

PII scope: investor_profiles contains financial goals and risk tolerance. This is PII-lite — not SSN, not income, not net worth — but it is sensitive. Treat with GDPR Article 9 caution (financial data is not explicitly special-category, but risk tolerance + goal is commercially sensitive).

Regulatory line — education vs advice (§202(a)(11)):

The profile system adjusts Raxx-controlled defaults based on user-stated preferences. It does NOT: - Recommend a specific security - Recommend a specific strategy - Claim to optimize the user's portfolio - Base its defaults on analysis of market conditions

The "stretch goals" mechanic nudges users toward higher self-stated targets. It does NOT tell them how to achieve those targets. The nudge is: "you said you wanted X; you exceeded it; want to aim for more?" — user-directed throughout.

The educational overlay explains what happened; it does not prescribe what to do next.

Flag for counsel (deferred): if future product iterations introduce profile-based strategy suggestions ("users with Income Builder profiles often run covered calls — here's one for you"), that crosses the §202(a)(11) line. That feature MUST NOT ship without securities-attorney sign-off. This is a standing block on all feature cards that propose profile-based strategy recommendations.

12. Open questions for the user — RESOLVED 2026-04-22

All five resolved by the user on PR #193 (2026-04-22). Decisions below are load-bearing for implementation sub-cards.

  1. Profile names.Locked: "Trial / Income Builder / Diversifier". The placeholder names are final. No rename pass from marketing.
  2. Profile count.Locked: three profiles. No fourth tier in v1. (Future "Pro" tier considered separately post-launch.)
  3. Onboarding skip.Locked: skip-path included. Users can skip the question sequence and pick a profile directly from a dropdown; defaults flow from profile selection. Question sequence remains available for users who want guided selection.
  4. Narrative copy authorship. ⚠️ Blocked on securities-attorney review. MBT v1 does not launch with engineering placeholder copy. Narrative copy must be reviewed by a securities attorney before lock — Investment Advisers Act §202(a)(11) exposure around "investment advice" framing. This creates a launch-blocking dependency: - Follow-up card: email Matthew Crosby (trademark counsel) for a securities-attorney referral - Follow-up card: "attorney review of profile narrative copy" — tracked as launch-blocker
  5. Stretch goals ship timing.Locked: ship in MBT v1. Auto-profile-promotion + profile-switch flow are in v1 scope, not deferred to v2. Adds ~2–3 architect sub-cards and extends the v1 engineering window but keeps the UX loop closed at launch.

See ADR 0015 for the decision record. See mbt-paper-trading-engine.md §14 for the original open questions — Qs 1, 2, and 3 are resolved by this doc.