Generated file. Source:
docs/TOS_logic.mdEdit the source document and runnpm run docs:syncto refresh this published copy.
TOS Logic¶
This file documents the current TOS calculation engine implementation.
Status¶
- Scope: current
TOSengine 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.tstos.ts: src/app/domain/bond-engine/strategies/tos.ts- Test path:
tos.strategy.test.ts: tests/tos.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:
- TOS_interest_flow_diagram.md - Flow diagrams and algorithm visualization
Product Rules¶
- Bond:
TOS - Duration:
3 years - Annual rate:
4.40%fixed for the whole cycle - Capitalization: yearly
- Interest payout: only on redemption
- Early redemption cost:
1 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¶
TOS is a specialization of the shared annual-accumulation family documented in:
The TOS module contributes only:
strategyId = annual-accumulation-toscycleLengthYears = 3- fixed yearly rate resolver returning
4.40%
Runtime Model¶
The engine keeps:
- active bonds of the current
TOSbatch - a residual cash account that does not earn interest (unlike non-capitalizing bonds)
- purchase and redemption event ledgers
This is critical: for capitalizing bonds like TOS, 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
Important:
TOSdoes not pay interest during the cycle- after natural maturity the next batch may be purchased using
exchangePrice - any leftover amount that cannot buy another full bond is moved to the residual cash account instead of being discarded
Natural Redemption¶
For a naturally redeemed TOS batch:
V1 = P * (1 + 0.0465)
V2 = V1 * (1 + 0.0465)
V3 = V2 * (1 + 0.0465)
tax = (V3 - P) * 0.19
netRedemption = V3 - tax
If the horizon continues:
nextBondCount = floor(netRedemption / exchangePrice)
residue = netRedemption - nextBondCount * exchangePrice
residue is transferred to the residual cash account and then grows monthly with the configured account rate.
Final Early Redemption¶
If the horizon stops before 3 years:
earlyCost = bondCount * 1 zł
taxableProfit = max(0, grossValue - principal - earlyCost)
tax = taxableProfit * 0.19
netLiquidation = grossValue - earlyCost - tax
Public Result Semantics¶
The TOS public result includes:
bondValue- value of the active bonds or redeemed/liquidated bondscashAccountBalance- only contains purchase remainders and rollover residues; no earned interest- yearly
taxPaid- tax on redemption only, applied at maturity - yearly
earlyRedemptionCost- early redemption fee if applicable - purchase and redemption histories in
simulationDetails
After a rollover year, cashAccountBalance is positive only if there was a leftover residue after purchasing the next batch at exchangePrice.
Covered Tests¶
Current automated TOS tests cover:
- full
3-yearnatural cycle - early redemption after
1and2years - rollover after natural maturity
- residual cash-account balance after rollover
- public result contract and strategy id
- long-horizon stability
- Excel alignment across
12yearly checkpoints
Change Rules¶
If TOS logic changes, update together:
annual-accumulation.ts: src/app/domain/bond-engine/strategies/annual-accumulation.ts- annual_accumulation_logic.md
tos.ts: src/app/domain/bond-engine/strategies/tos.tstos.strategy.test.ts: tests/tos.strategy.test.tsexcel-accumulation-alignment.test.ts: tests/excel-accumulation-alignment.test.ts- TOS_logic.md