docs: add PORTFOLIO and DISPLAY roadmap items for multi-position mode switching
This commit is contained in:
@@ -13,12 +13,19 @@ notes:
|
||||
- Pre-alpha policy: we may cut or replace old features without backward compatibility until alpha is declared.
|
||||
- Alpha migration policy: once alpha is declared, compatibility only needs to move forward; backward migrations are not required.
|
||||
priority_queue:
|
||||
- PORTFOLIO-001
|
||||
- DISPLAY-001
|
||||
- DISPLAY-002
|
||||
- EXEC-002
|
||||
- PORTFOLIO-002
|
||||
- PORTFOLIO-003
|
||||
- CONV-001
|
||||
- DATA-002A
|
||||
- DATA-001A
|
||||
- OPS-001
|
||||
- BT-003
|
||||
- BT-002A
|
||||
- GCF-001
|
||||
recently_completed:
|
||||
- DATA-004
|
||||
- PRICING-003
|
||||
@@ -41,12 +48,19 @@ recently_completed:
|
||||
- CORE-002B
|
||||
states:
|
||||
backlog:
|
||||
- PORTFOLIO-001
|
||||
- DISPLAY-001
|
||||
- DISPLAY-002
|
||||
- EXEC-002
|
||||
- PORTFOLIO-002
|
||||
- PORTFOLIO-003
|
||||
- CONV-001
|
||||
- DATA-002A
|
||||
- DATA-001A
|
||||
- OPS-001
|
||||
- BT-003
|
||||
- BT-002A
|
||||
- GCF-001
|
||||
in_progress: []
|
||||
done:
|
||||
- DATA-004
|
||||
|
||||
25
docs/roadmap/backlog/CONV-001-historical-gld-backing.yaml
Normal file
25
docs/roadmap/backlog/CONV-001-historical-gld-backing.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
id: CONV-001
|
||||
title: Historical GLD Backing Lookup
|
||||
status: backlog
|
||||
priority: P1
|
||||
size: S
|
||||
depends_on:
|
||||
- PRICING-001
|
||||
tags: [conversion, historical]
|
||||
summary: Support lookups of GLD ounces-per-share for historical dates.
|
||||
acceptance_criteria:
|
||||
- `gld_ounces_per_share(entry_date)` returns accurate backing for any date
|
||||
- Formula validates against known points (launch 2004, current 2026)
|
||||
- Conversion between GLD shares and gold oz uses entry_date backing
|
||||
- Error handling for dates outside GLD lifetime (pre-2004)
|
||||
- Cache-friendly for repeated lookups
|
||||
notes:
|
||||
- GLD launched Nov 2004 with 0.10 oz/share
|
||||
- Current backing ~0.0916 oz/share (2026)
|
||||
- Formula: `0.10 × e^(-0.004 × years_since_2004)`
|
||||
- Future enhancement: fetch actual NAV/ounce from spdrgoldshares.com
|
||||
implementation_hints:
|
||||
- Already implemented for current date in `app/domain/instruments.py`
|
||||
- Extend to accept `date` parameter
|
||||
- Clamp dates to GLD lifetime (Nov 2004 to present)
|
||||
- Add historical validation tests
|
||||
@@ -0,0 +1,31 @@
|
||||
id: DISPLAY-001
|
||||
title: Underlying Mode Switching
|
||||
status: backlog
|
||||
priority: P0
|
||||
size: M
|
||||
depends_on:
|
||||
- PORTFOLIO-001
|
||||
- DATA-004
|
||||
tags: [ui, display-mode]
|
||||
summary: Allow the entire app to switch between GLD, GC=F, and XAU display modes.
|
||||
acceptance_criteria:
|
||||
- Settings page has "Display Mode" selector: GLD shares, Gold Ounces, Gold Grams, GC=F contracts
|
||||
- In GLD mode: GLD positions show direct values, other positions converted using entry-date GLD backing
|
||||
- In Gold mode: All positions converted to equivalent oz/g using entry-date conversions
|
||||
- In GC=F mode: GC=F positions show direct values, others converted
|
||||
- Overview shows collateral in display mode units
|
||||
- Hedge page shows protection in display mode units
|
||||
- Backtests show results in display mode units
|
||||
- Mode persists per workspace
|
||||
notes:
|
||||
- Conversion uses GLD_ounces_per_share(entry_date) for historical accuracy
|
||||
- GC=F contract size is fixed at 100 oz
|
||||
- XAU grams to oz conversion: 31.1035 g/oz
|
||||
- Mode switching is a display concern, not a data concern
|
||||
- Position data remains in original units
|
||||
implementation_hints:
|
||||
- Add `display_mode: "GLD" | "XAU_OZ" | "XAU_G" | "GCF"` to `PortfolioConfig`
|
||||
- Add `convert_to_display(position, display_mode, reference_date)` in `app/domain/conversions.py`
|
||||
- Reuse existing `gld_ounces_per_share(date)` for historical conversion
|
||||
- Overview/hedge/backtests use display conversion layer
|
||||
- Settings page saves display_mode preference
|
||||
27
docs/roadmap/backlog/DISPLAY-002-gld-mode-no-conversion.yaml
Normal file
27
docs/roadmap/backlog/DISPLAY-002-gld-mode-no-conversion.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
id: DISPLAY-002
|
||||
title: GLD Mode Shows Real GLD Pricing
|
||||
status: backlog
|
||||
priority: P0
|
||||
size: S
|
||||
depends_on:
|
||||
- DISPLAY-001
|
||||
tags: [ui, gld-mode]
|
||||
summary: In GLD display mode, show real GLD share prices without conversion to physical gold.
|
||||
acceptance_criteria:
|
||||
- GLD mode shows position quantity as "shares" not "oz"
|
||||
- GLD mode shows position value as `shares × GLD_price` not converted to gold
|
||||
- Entry price shown as GLD share price at time of purchase
|
||||
- P&L calculated as `(current_GLD_price - entry_GLD_price) × shares`
|
||||
- LTV calculated using GLD position value as collateral
|
||||
- Options strike selection in GLD mode uses GLD share prices directly
|
||||
- Hedge cost shown as $/share or $/position, not $/oz
|
||||
notes:
|
||||
- This is the key insight: GLD mode should NOT convert to gold
|
||||
- User bought shares, they think in shares, they should see share metrics
|
||||
- GLD backing decay is irrelevant in GLD mode (baked into price)
|
||||
- Only when switching to XAU mode is conversion needed
|
||||
implementation_hints:
|
||||
- GLD mode short-circuits conversion logic
|
||||
- Overview in GLD mode: position value = shares × GLD_price
|
||||
- Hedge in GLD mode: strike = GLD_share_price × strike_pct
|
||||
- Add `position.is_gld()` helper to check display treatment
|
||||
25
docs/roadmap/backlog/GCF-001-gcf-options-data.yaml
Normal file
25
docs/roadmap/backlog/GCF-001-gcf-options-data.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
id: GCF-001
|
||||
title: GC=F Options Data Source
|
||||
status: backlog
|
||||
priority: P2
|
||||
size: L
|
||||
depends_on:
|
||||
- DATA-004
|
||||
tags: [data-source, options, futures]
|
||||
summary: Wire GC=F futures options data for users who choose GC=F as primary underlying.
|
||||
acceptance_criteria:
|
||||
- GC=F underlying fetches live options chain from CME or equivalent source
|
||||
- Options chain includes: strikes, expirations, bid/ask, IV, delta
|
||||
- Options displayed in futures contract units (100 oz per contract)
|
||||
- Strike selection in GC=F mode uses futures prices directly
|
||||
- Fallback to estimated options if live data unavailable
|
||||
notes:
|
||||
- GC=F is COMEX Gold Futures, contract size = 100 troy oz
|
||||
- Options on futures have different quoting than equity options
|
||||
- May need paid data feed (CME, ICE, broker API)
|
||||
- Alternative: estimate from GLD options + basis
|
||||
implementation_hints:
|
||||
- Add `get_gcf_options_chain()` to `DataService`
|
||||
- Contract size: 100 oz per futures option
|
||||
- Explore yfinance GC=F options (limited) vs paid sources
|
||||
- Cache aggressively to minimize API calls
|
||||
26
docs/roadmap/backlog/PORTFOLIO-001-position-entries.yaml
Normal file
26
docs/roadmap/backlog/PORTFOLIO-001-position-entries.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
id: PORTFOLIO-001
|
||||
title: Position-Level Portfolio Entries
|
||||
status: backlog
|
||||
priority: P0
|
||||
size: M
|
||||
depends_on: []
|
||||
tags: [portfolio, domain-model]
|
||||
summary: Evolve from single-quantity portfolio to multi-position entries with individual entry dates and prices.
|
||||
acceptance_criteria:
|
||||
- User can add a position entry with underlying type (GLD shares, GC=F contracts, XAU grams/oz)
|
||||
- Each position has its own entry_price, entry_date, quantity
|
||||
- Portfolio page shows list of positions with individual P&L
|
||||
- Portfolio total collateral is sum of all position values in display currency
|
||||
- Backward compatible: existing single-entry portfolios migrate to one position entry
|
||||
- Settings page has "Add Position" and "Remove Position" controls
|
||||
- Position CRUD persists to workspace storage
|
||||
notes:
|
||||
- This is foundational for mode switching between GLD/GC=F/physical gold
|
||||
- Entry_date matters for conversion lookups (GLD backing varies by date)
|
||||
- Single-quantity legacy portfolios should auto-migrate to one position
|
||||
implementation_hints:
|
||||
- Add `Position` dataclass in `app/models/portfolio.py`
|
||||
- Add `positions: List[Position]` to `PortfolioConfig` (migrate `gold_ounces`/`entry_price` to first position)
|
||||
- Position underlying defaults to "GLD" for backward compat
|
||||
- Entry_date defaults to position creation date if not specified
|
||||
- Storage costs deferred to PORTFOLIO-002
|
||||
@@ -0,0 +1,26 @@
|
||||
id: PORTFOLIO-002
|
||||
title: Position Storage Costs
|
||||
status: backlog
|
||||
priority: P1
|
||||
size: S
|
||||
depends_on:
|
||||
- PORTFOLIO-001
|
||||
tags: [portfolio, costs]
|
||||
summary: Allow users to configure storage costs for portfolio positions.
|
||||
acceptance_criteria:
|
||||
- Each position can have optional storage_cost_basis (annual % or fixed amount)
|
||||
- Storage cost period selectable: annual, monthly
|
||||
- Overview page shows aggregate storage cost impact on net equity
|
||||
- Hedge recommendations account for storage drag
|
||||
- Physical gold positions default to typical vault storage (e.g., 0.12% annual for allocated)
|
||||
- GLD positions note that expense ratio is already baked into price
|
||||
notes:
|
||||
- For GLD: expense ratio decay is implicit, no separate storage cost needed
|
||||
- For GC=F: roll costs (contango) are the primary storage analog
|
||||
- For physical XAU: vault storage is explicit cost
|
||||
- Storage costs affect LTV calculations (reduce effective equity)
|
||||
implementation_hints:
|
||||
- Add `storage_cost_basis: Decimal | None` to `Position`
|
||||
- Add `storage_cost_period: "annual" | "monthly" | None` to `Position`
|
||||
- Compute annualized storage cost for equity/P&L display
|
||||
- Add storage cost breakdown to overview page
|
||||
@@ -0,0 +1,31 @@
|
||||
id: PORTFOLIO-003
|
||||
title: Physical Gold Premium and Spread
|
||||
status: backlog
|
||||
priority: P1
|
||||
size: S
|
||||
depends_on:
|
||||
- PORTFOLIO-001
|
||||
tags: [portfolio, physical-gold]
|
||||
summary: Support dealer premium and bid/ask spread for physical gold positions.
|
||||
acceptance_criteria:
|
||||
- Position can specify `purchase_premium` (dealer markup over spot)
|
||||
- Position can specify `bid_ask_spread` (expected sale discount below spot)
|
||||
- True cost basis = entry_price + purchase_premium
|
||||
- Effective exit value = spot - bid_ask_spread
|
||||
- P&L shows both paper P&L and realized P&L accounting for spread
|
||||
- Default premium/spread values for common products (coins, bars)
|
||||
- Settings page exposes premium/spread inputs for XAU positions
|
||||
notes:
|
||||
- Common gold products:
|
||||
- Gold ETF (GLD): 0% premium (market price), spread ~0.1%
|
||||
- Gold coins (1oz): 3-5% premium, 2-4% spread
|
||||
- Gold bars (1kg): 1-2% premium, 1-2% spread
|
||||
- Allocated storage (Goldmoney, BullionVault): 0.1% premium, 0.3% spread
|
||||
- Premium lowers effective entry price
|
||||
- Spread lowers effective exit price
|
||||
implementation_hints:
|
||||
- Add `purchase_premium: Decimal | None` to `Position` (percentage)
|
||||
- Add `bid_ask_spread: Decimal | None` to `Position` (percentage)
|
||||
- Cost basis formula: `effective_entry = spot_at_entry × (1 + premium)`
|
||||
- Exit value formula: `effective_exit = current_spot × (1 - spread)`
|
||||
- Add premium/spread presets to settings UI
|
||||
Reference in New Issue
Block a user