Skip to content

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

EDO Logic

This file documents the current EDO calculation engine implementation.

Status

  • Scope: current EDO engine and the shared annual-accumulation family
  • Implementation status: active in production code
  • Code path:
  • annual-accumulation.ts: src/app/domain/bond-engine/strategies/annual-accumulation.ts
  • edo.ts: src/app/domain/bond-engine/strategies/edo.ts
  • Test path:
  • edo.strategy.test.ts: tests/edo.strategy.test.ts
  • annual-accumulation.strategy.test.ts: tests/annual-accumulation.strategy.test.ts
  • excel-accumulation-alignment.test.ts: tests/excel-accumulation-alignment.test.ts
  • Visual diagrams:
  • EDO_interest_flow_diagram.md - Flow diagrams and algorithm visualization

Product Rules

  • Bond: EDO
  • Duration: 10 years
  • Year 1 rate: 5.35%
  • Years 2-10 rate: inflation + 2.00%
  • Capitalization: yearly
  • Interest payout: only on redemption
  • Early redemption cost: 3 zł per bond
  • Exchange price used on rollover: catalog-driven; the current catalog and Excel-aligned scenario both use 99.90
  • Bond unit price: 100 zł
  • Tax rate: 19%

Strategy Family

EDO is a thin specialization of the shared annual-accumulation family.

It configures:

  • strategyId = annual-accumulation-edo
  • cycleLengthYears = 10
  • rate resolver:
  • cycleYear === 1 -> 5.35%
  • cycleYear >= 2 -> inflation + 2.00%

Runtime Model

The engine tracks:

  • the active EDO batch
  • yearly capitalization inside that batch
  • a residual cash account that does not earn interest (unlike non-capitalizing bonds)
  • rollover after natural maturity using exchangePrice

This is the part that keeps long-horizon EDO results aligned with the workbook after the first 10-year cycle.

Important: For this capitalizing bond, the residual cash account: - accumulates leftover amounts after bond purchases - accumulates residues after rollover redemptions - does not earn monthly interest to prevent incorrect OKO balance reporting - only grows from purchase or redemption remainders

Natural Redemption And Rollover

At natural maturity:

grossValue = capitalized batch value after 10 years
tax = (grossValue - principal) * 0.19
netRedemption = grossValue - tax
nextBondCount = floor(netRedemption / exchangePrice)
residue = netRedemption - nextBondCount * exchangePrice

The next EDO batch starts from nextBondCount * 100.

residue is transferred to the residual cash account. Since EDO is capitalizing, this residue does not earn monthly interest.

Final Early Redemption

If the simulation ends before year 10:

earlyCost = bondCount * 3 zł
taxableProfit = max(0, grossValue - principal - earlyCost)
tax = taxableProfit * 0.19
netLiquidation = grossValue - earlyCost - tax

Public Result Semantics

The EDO public result includes:

  • liquidation-aware yearly rows
  • bondValue
  • cashAccountBalance
  • yearly account-interest and account-tax postings
  • purchase and redemption histories

Covered Tests

Current automated EDO tests cover:

  • first-year fixed rate
  • switch to inflation + 2.00%
  • natural 10-year maturity
  • early redemption after 1, 2, and 5 years
  • rollover after natural maturity
  • residual cash-account balance after rollover
  • public result contract
  • Excel alignment across 12 yearly checkpoints

Change Rules

If EDO logic changes, update together:

  • annual-accumulation.ts: src/app/domain/bond-engine/strategies/annual-accumulation.ts
  • annual_accumulation_logic.md
  • edo.ts: src/app/domain/bond-engine/strategies/edo.ts
  • edo.strategy.test.ts: tests/edo.strategy.test.ts
  • excel-accumulation-alignment.test.ts: tests/excel-accumulation-alignment.test.ts
  • EDO_logic.md