Skip to content

Generated file. Source: docs/OTS_interest_flow_diagram.md Edit the source document and run npm run docs:sync to refresh this published copy.

OTS Interest Distribution Flow Diagram

This document provides detailed visual and narrative descriptions of how interest flows through the OTS engine after the 2026-04-08 refactoring.

Monthly State Evolution

Over a 3-month quarterly cycle:

Month 1-2: Active Holding

stateDiagram-v2
    [*] --> Holding: New batch purchased

    Holding --> Holding: Interest accrues<br/>(not realized)

    note right of Holding
        Amount: 10 bonds
        Purchased: Month 0
        Age: 1-2 months

        Unrealized Gross Interest
        (would be realized at month 3)
    end note

Month 3: Quarterly Settlement and Reinvestment

flowchart TD
    A["Bonds Mature<br/>(10 bonds × €100 × 2.5% × 3/12)"] --> B["Gross Interest<br/>= €6.25"]
    B --> C["Apply 19% Tax<br/>€6.25 × 0.19 = €1.1875"]
    C --> D["Net Interest<br/>= €4.0625"]

    A --> E["Principal<br/>= €1000"]

    E --> F["Add to CASH pool<br/>(for reinvestment)"]
    D --> G["Add to OKO account<br/>(accumulated interest)"]

    F --> H["Available for Reinvestment<br/>CASH + OKO"]
    G --> H

    H --> I["Total Available<br/>= €1000 + €4.0625"]
    I --> J["Compute New Bonds<br/>floor(€1004.0625 / €100) = 10"]

    J --> K["After Purchase"]
    K --> K1["CASH = €4.0625<br/>(remainder)"]
    K --> K2["OKO = €0<br/>(merged for purchase)"]

    style E fill:#e1f5ff
    style F fill:#e1f5ff
    style D fill:#fff3e0
    style G fill:#fff3e0
    style B fill:#fff3e0
    style C fill:#ffebee

Two-Account Model Processing

sequenceDiagram
    participant B as Bond Position
    participant C as Cash Pool
    participant O as OKO Account
    participant T as Tax Counter
    participant N as New Bonds

    B->>B: Hold 3 months<br/>with invisible interest

    Note over B: Month = quarter marker

    B->>B: Calculate Gross Interest<br/>(based on annual rate)
    B->>T: Apply tax percentage<br/>Tax = Gross × 0.19
    B->>C: Principal + Gross<br/>(initially)

    Note over C,T: Interest Separation

    C->>C: Keep Principal
    C->>O: Transfer Interest portion
    O->>O: Net Interest = Gross - Tax

    Note over C,O: Reinvestment Phase

    C->>C: Existing remainder
    O->>C: Add OKO balance
    C->>N: Buy new bonds from combined pool
    O->>N: (OKO emptied after purchase)

    N->>N: Create new position<br/>for next quarter

Quarterly Cycle Example: €1,000 over 4 Quarters

Initial Setup

Metric Value
Initial Investment €1,000
Bonds Purchased 10
Annual Rate 2.5%
Tax Rate 19%
Cash Remainder €0
OKO Balance €0

Quarter 1 (Month 3)

Redemption:

Gross Interest   = 10 × 100 × 0.025 × (3/12) = 6.25
Tax              = 6.25 × 0.19 = 1.1875
Net Interest     = 6.25 - 1.1875 = 4.0625
Principal        = 1,000

Distribution:

Account Before Receipt After
Cash €0 +€1,000 principal €1,000.00
OKO €0 +€4.0625 net int. €4.0625
Tax Paid €0 +€1.1875 €1.1875

Reinvestment:

Available = 1000 + 4.0625 = 1004.0625
New Bonds = floor(1004.0625 / 100) = 10
Cash After = 4.0625 (remainder)
OKO After = 0 (merged into purchase)
Account After Reinv.
Cash €4.0625
OKO €0
Bonds 10 (active)

Quarter 2 (Month 6)

Redemption of Q1 batch:

Gross Interest = 6.25
Tax            = 1.1875  
Net Interest   = 4.0625
Principal      = 1,000

Distribution:

Account Before Receipt After
Cash €4.0625 +€1,000 principal €1,004.0625
OKO €0 +€4.0625 net int. €4.0625
Tax Paid €1.1875 +€1.1875 €2.375

Reinvestment:

Available = 1004.0625 + 4.0625 = 1008.125
New Bonds = floor(1008.125 / 100) = 10
Cash After = 8.125 (remainder, growing!)
OKO After = 0

Quarter 3 (Month 9)

By now, the cash remainder continues growing every quarter. Eventually it reaches €100 and can buy an extra bond.

Quarter 4 (Month 12)

Final settlement and consolidation:

At the final month (month 12), before computing final valuation:

Final Cash = (accumulated cash remainder)
Final OKO = (accumulated interest if not yet reinvested)

Final Consolidation:
Final Cash += Final OKO
Final OKO = 0

This ensures the final net value properly accounts for all accumulated interest.

Invariants Maintained

At Every Month End

graph LR
    GV["Gross Value<br/>Cash + OKO +<br/>Bonds Value +<br/>Accrued Interest"]

    LV["Liquidation Value<br/>Cash + OKO +<br/>Bonds Value +<br/>Accrued Interest -<br/>Early Cost - Tax"]

    GV -->|must be ≥| LV

    TB["Tax Paid<br/>must be ≥ 0"]
    OB["OKO Balance<br/>must be ≥ 0"]
    CB["Cash<br/>must be ≥ 0"]

    TB --> TB
    OB --> OB
    CB --> CB

Period Totals

  • totalTaxPaid = sum of all monthTaxPaid
  • totalCashAccountTaxPaid = sum of all taxes on interest
  • totalCashAccountInterestPaid = sum of all gross interest earned
  • Final values match last monthly snapshot

Tax Impact Timeline

xychart-beta
    title "Tax Accumulation Over 12 Months (€1,000)"
    x-axis ["Mo0", "Mo3", "Mo6", "Mo9", "Mo12"]
    y-axis "Cumulative Tax Paid (€)" 0 --> 2.50

    line [0, 1.19, 2.38, 3.57, 4.75]

    note "Q1 settlement: 1.1875€ tax"
    note "Q2 settlement: +1.1875€ more"
    note "Running total grows linearly"

Design Rationale

Why Separate Accounts?

  1. Transparency - Makes interest distinct from principal in reports
  2. Flexibility - Future strategies can implement different interest rules
  3. Accuracy - Prevents interest from "hiding" in cash pool
  4. Tax Reporting - Tax on interest is explicitly tracked

Why Consolidate at Final Month?

If OKO balance persisted in separate account at final month: - ❌ Final net value would be understated - ❌ UI would need special logic for OKO presentation - ❌ Liquidation value inconsistent

By consolidating: - ✅ Final cash accurately reflects all realized value - ✅ Gross and liquidation semantics remain clean - ✅ End-of-simulation behavior is clear

Why Both Sources Feed Reinvestment?

Interest earned should stay invested: - Better aligns with compound growth expectations - Matches user mental model of "reinvestment" - Prevents artificial cash leakage