📅 Scheduled Investment Provider (scheduled_investment)
A synthetic, deterministic provider that calculates the value of an asset based on a predefined interest schedule. It makes no external calls and requires no DB access for calculation. It is one of the Asset Providers.
📖 User Guide: Scheduled Investment — User Manual
⚙️ Configuration Schema
The asset's value is determined entirely by provider_params, which follow the FAScheduledInvestmentSchedule schema:
| Field | Type | Required | Description |
|---|---|---|---|
initial_value |
Currency |
✅ | Principal / face value (e.g., {"code": "EUR", "amount": 10000}) |
interest_type |
SIMPLE \| COMPOUND |
— | Global interest method (default: SIMPLE) |
day_count |
ACT/365 \| ACT/360 \| ACT/ACT \| 30/360 |
— | Day count convention (default: ACT/365) |
schedule |
FAInterestRatePeriod[] |
✅ | List of interest rate periods (non-overlapping, contiguous) |
late_interest |
FALateInterestConfig |
— | Optional penalty rate after maturity |
asset_events |
FAAssetEventPoint[] |
— | Manually defined asset events |
📊 Interest Rate Period (FAInterestRatePeriod)
| Field | Type | Default | Description |
|---|---|---|---|
start_date |
date |
— | Period start (inclusive) |
end_date |
date |
— | Period end (inclusive) |
annual_rate |
Decimal |
— | Annual rate as decimal (e.g., 0.05 for 5%) |
maturation_frequency |
MaturationFrequency |
DAILY |
Emission granularity: DAILY, WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL, ANNUAL |
generate_interest |
bool |
false |
Auto-generate INTEREST events at each maturation date |
📐 Calculation Engine
Price formula:
- SIMPLE:
I = P₀ × r × Δt— interest always on initial principal - COMPOUND:
I_day = V_{t-1} × r × Δt— interest on running accumulated value
Emission: Price points are emitted only at maturation dates (not every day), matching the maturation_frequency. Start and end dates of each period always produce a point regardless.
🔄 Auto-Generated Events (generate_interest)
When generate_interest = True on a period:
- At each maturation date, the engine checks if accrued interest is positive
- If positive, generates an 💵 INTEREST event:
value = current_value - initial_value - After the event:
total_interest = 0,event_adjustment = 0→ value resets toinitial_value - Interest accrual restarts from zero on the next day
Coupon Reset Behavior
The INTEREST event represents a "coupon payout" — the accumulated interest is crystallized and paid out, resetting the running value back to the original principal.
🏁 MATURITY_SETTLEMENT Event
Auto-generated when:
- The last schedule period has
generate_interest = Trueand nolate_interestis configured - Or
late_interesthasgenerate_interest = True(settlement at the last late maturation date)
After settlement, the engine is "off" — get_current_value() returns the settlement value for all future dates.
See Asset Events for the full event type reference.
⏰ Late Interest (FALateInterestConfig)
Applied after the asset's maturity date (last period end_date):
| Field | Type | Default | Description |
|---|---|---|---|
annual_rate |
Decimal |
— | Annual late interest rate |
grace_period_days |
int |
0 |
Days after maturity before late interest starts |
interest_type |
SIMPLE \| COMPOUND |
COMPOUND |
Late interest compounds by default (penalties grow) |
maturation_frequency |
MaturationFrequency |
DAILY |
Emission frequency for late period |
generate_interest |
bool |
false |
Auto-generate INTEREST + MATURITY_SETTLEMENT events |
Skip Formula Optimization
SIMPLE late interest uses a closed-form calculation for efficiency. COMPOUND late interest uses day-by-day accumulation only within the late sub-period, not from asset start.
⚡ Caching & Invalidation
The engine caches the full schedule computation as a tuple[dict, list[FAAssetEventPoint]]:
- Key: Hash of the entire
provider_paramsJSON. - Invalidation: Cache is invalidated when
provider_paramschanges (i.e., the user reconfigures the schedule via the frontendScheduledInvestmentEditor). - Hit behavior: On cache hit,
get_history_value()slices the pre-computed dict to the requested date range — O(1) per point. - Miss behavior: Full schedule recomputation from
initial_valuethrough all periods. This is deterministic and fast (no I/O), typically < 10ms even for multi-year schedules.
The cache lives in the provider instance (in-memory, per-process). It survives across multiple sync calls but is cleared on server restart.
🔧 Internal State Variables
During computation, the engine tracks these internal variables per day:
| Variable | Description | Reset behavior |
|---|---|---|
total_interest |
Cumulative accrued interest since last coupon/start | Reset to 0 after INTEREST event |
event_adjustment |
Net sum of PRICE_ADJUSTMENT events | Reset to 0 after INTEREST event |
running_value |
initial_value + total_interest + event_adjustment |
Computed per-day |
These variables are NOT persisted — they exist only during computation.
📋 Use Cases
- P2P/Crowdfunding Loans: Model a loan with fixed interest rate and periodic coupon payouts.
- Fixed-Rate Bonds: Calculate bond value including accrued interest and coupon payments.
- Any asset with predictable, deterministic cash flows.
📐 Example
A P2P loan of €10,000 with 5% simple annual interest, monthly coupons (generate_interest: true):
- Day 1–30: value grows from €10,000 to ~€10,041
- Month end (maturation): 💵 INTEREST event of €41 → value resets to €10,000
- Month 2: value grows again from €10,000
- Maturity: 🏁 MATURITY_SETTLEMENT event → engine stops
🔧 Technical Notes
financial_math.pyeliminated: All financial math functions (calculate_day_count_fraction,calculate_simple_interest,_compute_maturation_dates) are now insidescheduled_investment.pyas a# Financial Mathsection.identifier_type: AlwaysAUTO_GENERATED— the engine generates its own UUID identifier.params_schema: Exposes a complex schema with_ui_component: "ScheduledInvestmentEditor"hint for the frontend to render a dedicated editor component.supports_events = True: The provider returns both price points and events viaFAHistoricalData.
🔗 Related Documentation
- 📖 Scheduled Investment — User Guide — End-user configuration guide
- 📅 Asset Events — Event types, dedup strategy, MATURITY_SETTLEMENT
- 📐 Day Count Conventions — ACT/365, ACT/360, 30/360, ACT/ACT
- 📊 Asset Types — CROWDFUND_LOAN, BOND, etc.
- 💰 Asset Architecture — Sync pipeline and event persistence
- 📦 Providers Overview — All available providers