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 strategy family it uses - 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:
annual-accumulation.strategy.test.ts: tests/annual-accumulation.strategy.test.tsrod.strategy.test.ts: tests/rod.strategy.test.ts- Last reviewed against code: 2026-03-23
Product Rules¶
- Bond:
ROD - Duration:
12 years - Year 1 rate:
5.85% - Years 2-12 rate:
inflation + 2.50% - Capitalization: yearly
- Interest payout: only on redemption
- Early redemption cost:
3 złper bond - Bond unit price:
100 zł - Tax rate:
19% - Availability: only for investors receiving
800+
Strategy Family¶
ROD does not use the generic yearly calculator anymore.
It is implemented as a specialization of the shared annual-accumulation family for bonds that:
- capitalize annually
- do not pay cash during the cycle
- allow reinvestment only after redemption
- may end with early redemption of unfinished batches
That same family is currently used by:
TOSEDOROS
ROD Specialization¶
ROD configures the shared engine with:
strategyId = annual-accumulation-rodcycleLengthYears = 12- rate resolver:
cycleYear === 1->5.85%cycleYear >= 2->inflation + 2.50%
So the ROD module contains only product-specific rate policy, while yearly batch mechanics remain shared.
State Model¶
The engine tracks:
cashpositionspurchaseEventsredemptionEventsyearSnapshotsyearlyResults
Each active position contains:
bondspurchaseYear
Simulation Flow¶
The engine works on yearly steps.
For each year:
- Redeem positions that reached natural maturity (
12 years). - Add redeemed net cash to
cash. - Reinvest available
cashinto full new bonds if the horizon continues. - If this is the final year, early-redeem all still-active positions.
- Build yearly carried-value and liquidation snapshots.
Natural Redemption¶
For a naturally redeemed batch:
- Start with nominal principal.
- Apply yearly compounding for
12years:
V1 = P * (1 + 0.0585)
V2 = V1 * (1 + inflation + 0.025)
...
V12 = V11 * (1 + inflation + 0.025)
- Compute gross profit:
grossProfit = V12 - P
- Compute tax:
tax = grossProfit * 0.19
- Add net redemption value to cash:
netRedemption = V12 - tax
Final Early Redemption¶
If the investment horizon ends before a batch reaches 12 years:
- Compute accumulated value for the current age in full years.
- Compute tax on total accrued gain.
- Subtract early redemption cost:
earlyCost = bondCount * 3 zł
- Add final net liquidation value to
cash.
Reinvestment¶
ROD does not reinvest during a cycle.
Reinvestment may happen only after natural redemption, using:
reinvestedBondCount = floor(cash / 100)
Any remainder stays as cash.
The engine records:
- initial allocation purchase event
- each reinvestment purchase event
- natural redemption events
- final early redemption events
Snapshot Semantics¶
grossValue¶
For each year:
grossValuemeans year-end portfolio value before all taxes and costs realized so far- it includes:
- carried portfolio value
- taxes already realized in previous completed cycles
- early-redemption costs already realized, if any
netValue¶
- intermediate years:
netValue = carried portfolio value- no forced liquidation is applied
- final year:
netValue = liquidationValue- all taxes and early redemption costs are fully settled
Rounding Policy¶
Current implementation follows project policy:
- internal calculations:
0.001 zł - final public values:
0.01 zł
Public Contract¶
The ROD public result includes:
- yearly results
- final totals
simulationDetails.strategy = "annual-accumulation-rod"simulationDetails.purchaseEventssimulationDetails.redemptionEvents
Covered Tests¶
Current automated ROD tests cover:
- first-year fixed
5.85%rate - switch to
inflation + 2.50% - natural 12-year redemption
- early redemption after 1, 2, 6, and 11 years through direct and golden references
- no reinvestment before maturity
- reinvestment after natural redemption
- public result contract and strategy id
- long-horizon large-principal stability
- shared annual-accumulation invariant grid
Traceability¶
- product duration, redemption, tax, reinvestment:
rod.strategy.test.ts: tests/rod.strategy.test.ts- first-year fixed rate:
ROD first year uses the dedicated 5.85% rate before the inflation-indexed years begin
- later-year inflation + margin rule:
ROD switches from year-one fixed rate to inflation + 2.50% in later years
- natural maturity:
ROD natural 12-year maturity capitalizes annually and taxes only on redemption
- final early redemption:
ROD early redemption after eleven years remains on the shared annual-accumulation liquidation path
- reinvestment after maturity:
ROD reinvests after natural maturity and stores the second-cycle purchase event
- shared carried-value vs liquidation semantics:
annual-accumulation.strategy.test.ts: tests/annual-accumulation.strategy.test.ts- purchase and redemption history retention:
rod.strategy.test.ts: tests/rod.strategy.test.tsannual-accumulation.strategy.test.ts: tests/annual-accumulation.strategy.test.ts
Eligibility Boundary¶
ROD is a special bond available only to investors receiving 800+, but this rule is intentionally not implemented inside the calculation strategy.
Eligibility is handled outside the engine in:
selection.ts: src/app/domain/bond-engine/selection.ts
This separation is part of the architecture:
- strategy modules model financial behavior
- selection/eligibility modules control whether a bond may be chosen
Do not move 800+ availability checks into the annual-accumulation engine or the ROD strategy module.
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.ts- ROD_logic.md
init_prompt.md: ai/init_prompt.md