Generated file. Source:
docs/COI_logic.mdEdit the source document and runnpm run docs:syncto refresh this published copy.
COI Logic¶
This file documents the current COI calculation engine implementation.
Status¶
- Scope: current
COIengine and the shared annual-payout strategy family it uses - Implementation status: active in production code
- Code path:
annual-payout.ts: src/app/domain/bond-engine/strategies/annual-payout.tscoi.ts: src/app/domain/bond-engine/strategies/coi.ts- Test path:
annual-payout.strategy.test.ts: tests/annual-payout.strategy.test.tscoi.strategy.test.ts: tests/coi.strategy.test.ts- Last reviewed against code: 2026-03-23
Product Rules¶
- Bond:
COI - Duration:
4 years - Year 1 rate:
5.00% - Years 2-4 rate:
inflation + 1.50% - Capitalization: none
- Interest payout: yearly
- Early redemption cost:
3 złper bond - Bond unit price:
100 zł - Tax rate:
19%
Strategy Family¶
COI does not use the generic yearly calculator anymore.
It is implemented as the first specialization of the shared annual-payout family for bonds that:
- pay annual interest out to cash
- do not capitalize interest inside the batch
- may reinvest accumulated cash into new batches
- redeem principal at cycle end
- may finish with final early redemption of unfinished batches
COI Specialization¶
COI configures the shared engine with:
strategyId = annual-payout-coicycleLengthYears = 4- rate resolver:
cycleYear === 1->5.00%cycleYear >= 2->inflation + 1.50%
State Model¶
The engine tracks:
cashpositionspurchaseEventspayoutEventsredemptionEventsyearSnapshotsyearlyResults
Each active position contains:
bondspurchaseYear
Simulation Flow¶
The engine works on yearly steps.
For each year:
- Pay annual interest for all active positions.
- Tax the paid interest immediately.
- Add net interest to cash.
- Redeem positions that reached natural maturity (
4 years) and return principal. - Reinvest available cash into 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.
Interest Formula¶
For one batch in one year:
grossInterest = bonds * 100 * annualRate
taxPaid = grossInterest * 0.19
netInterest = grossInterest - taxPaid
cash += netInterest
annualRate depends on the year inside the 4-year cycle.
Redemption Rules¶
Natural redemption:
- happens when
ageInYears === 4 - returns only principal, because interest for the final year was already paid in that same yearly step
Final early redemption:
- happens only in the terminal year
- returns principal
- subtracts
3 złper active bond - does not add extra interest beyond the yearly payout already recognized for that year
Reinvestment¶
COI can reinvest because annual net interest is added to cash.
Reinvestment uses:
reinvestedBondCount = floor(cash / 100)
Reinvestment may happen:
- from accumulated annual net payouts
- from natural redemptions
- from both together
The engine records:
- initial allocation purchase event
- each reinvestment purchase event
- annual payout events
- 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 paid in earlier payout years
- early-redemption costs already realized, if any
netValue¶
- intermediate years:
netValue = carried portfolio value after already realized taxes and costs- final year:
netValue = liquidationValue
This differs from annual-capitalization products because there is no unrealized compounded value inside the active principal itself.
Rounding Policy¶
Current implementation follows project policy:
- internal calculations:
0.001 zł - final public values:
0.01 zł
Public Contract¶
The COI public result includes:
- yearly results
- final totals
simulationDetails.strategy = "annual-payout-coi"simulationDetails.purchaseEventssimulationDetails.payoutEventssimulationDetails.redemptionEvents
Covered Tests¶
Current automated COI tests cover:
- first-year fixed
5.00%rate - switch to
inflation + 1.50% - annual payout taxation
- lack of capitalization inside the same batch
- natural 4-year redemption
- early redemption after 1, 2, and 3 years through direct and golden references
- reinvestment from accumulated annual cash
- public result contract and strategy id
- long-horizon stability
- shared annual-payout invariant grid
Traceability¶
- product duration, payout, tax, reinvestment:
coi.strategy.test.ts: tests/coi.strategy.test.ts- first-year fixed payout rate:
COI first year uses the dedicated 5.00% rate and pays taxed interest into cash
- later-year inflation + margin payout:
COI switches from year-one fixed rate to inflation + 1.50% in later years
- no capitalization rule:
COI pays out annual interest instead of capitalizing it into the same batch
- natural maturity:
COI natural 4-year redemption returns principal after annual payouts without early cost
- reinvestment from cash pool:
COI reinvests accumulated annual net payouts and redeemed principal into new batches
- shared carried-value vs liquidation semantics:
annual-payout.strategy.test.ts: tests/annual-payout.strategy.test.ts- purchase, payout, and redemption history retention:
coi.strategy.test.ts: tests/coi.strategy.test.tsannual-payout.strategy.test.ts: tests/annual-payout.strategy.test.ts
Contract Boundary¶
COI uses payoutEvents, which are part of the shared simulation contract in:
bonds.ts: src/app/types/bonds.ts
This is intentional:
COIand future annual-payout products need explicit payout history- annual-accumulation products do not
- monthly-income products use different event families instead
Keep this as an optional event branch in the shared simulation contract rather than forcing all strategies to expose identical event shapes.
Change Rules¶
If COI logic changes, update together:
annual-payout.ts: src/app/domain/bond-engine/strategies/annual-payout.ts- annual_payout_logic.md
coi.ts: src/app/domain/bond-engine/strategies/coi.tscoi.strategy.test.ts: tests/coi.strategy.test.ts- COI_logic.md
init_prompt.md: ai/init_prompt.md