Generated file. Source:
docs/ROD_logic.mdEdit the source document and runnpm run docs:syncto refresh this published copy.
ROD Logic¶
This file documents the current ROD calculation engine implementation.
Status¶
- Scope: current
RODengine 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.tsrod.ts: src/app/domain/bond-engine/strategies/rod.ts- Test path:
rod.strategy.test.ts: tests/rod.strategy.test.tsannual-accumulation.strategy.test.ts: tests/annual-accumulation.strategy.test.tsexcel-accumulation-alignment.test.ts: tests/excel-accumulation-alignment.test.ts- Visual diagrams:
- ROD_interest_flow_diagram.md - Flow diagrams and algorithm visualization
Product Rules¶
- Bond:
ROD - Duration:
12 years - Year
1rate:5.60% - Years
2-12rate:inflation + 2.50% - Capitalization: yearly
- Interest payout: only on redemption
- Early redemption cost:
3 złper bond - Exchange price used on rollover: catalog-driven; both the production catalog and the workbook-aligned regression scenario currently use
100 - Bond unit price:
100 zł - Tax rate:
19% - Availability: only for investors receiving
800+
Strategy Family¶
ROD is a specialization of the shared annual-accumulation family.
It configures:
strategyId = annual-accumulation-rodcycleLengthYears = 12- rate resolver:
cycleYear === 1->5.60%cycleYear >= 2->inflation + 2.50%
Runtime Model¶
The engine models:
- yearly capitalization inside the active
RODbatch - tax only on redemption
- rollover after natural maturity
- a residual cash account that does not earn interest (unlike non-capitalizing bonds)
For ROD, workbook alignment depends on both the rollover and the residual-account behavior. Since ROD is capitalizing, the residual account does not earn monthly interest to prevent incorrect OKO balance reporting, even when exchangePrice is effectively 100.
Natural Redemption And Rollover¶
At natural maturity:
tax = (grossValue - principal) * 0.19
netRedemption = grossValue - tax
nextBondCount = floor(netRedemption / exchangePrice)
residue = netRedemption - nextBondCount * exchangePrice
residue is transferred to the residual cash account. Since ROD is capitalizing, this residue does not earn monthly interest.
Final Early Redemption¶
If the simulation ends before year 12:
earlyCost = bondCount * 3 zł
taxableProfit = max(0, grossValue - principal - earlyCost)
tax = taxableProfit * 0.19
netLiquidation = grossValue - earlyCost - tax
Public Result Semantics¶
The ROD public result includes:
bondValuecashAccountBalance- yearly tax and early-redemption postings
- purchase and redemption histories
Covered Tests¶
Current automated ROD tests cover:
- first-year fixed
5.60% - switch to
inflation + 2.50% - natural
12-yearmaturity - early redemption after
1,2, and6years - rollover after natural maturity
- residual cash-account balance after rollover
- public result contract
- Excel alignment across
12yearly checkpoints
Eligibility Boundary¶
ROD remains available only to investors receiving 800+, but that rule stays outside the strategy itself.
Change Rules¶
If ROD logic changes, update together:
annual-accumulation.ts: src/app/domain/bond-engine/strategies/annual-accumulation.ts- annual_accumulation_logic.md
rod.ts: src/app/domain/bond-engine/strategies/rod.tsrod.strategy.test.ts: tests/rod.strategy.test.tsexcel-accumulation-alignment.test.ts: tests/excel-accumulation-alignment.test.ts- ROD_logic.md