Skip to content

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

COI Logic

This file documents the current COI calculation engine implementation.

Status

  • Scope: current COI engine 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.ts
  • coi.ts: src/app/domain/bond-engine/strategies/coi.ts
  • Test path:
  • annual-payout.strategy.test.ts: tests/annual-payout.strategy.test.ts
  • coi.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-coi
  • cycleLengthYears = 4
  • rate resolver:
  • cycleYear === 1 -> 5.00%
  • cycleYear >= 2 -> inflation + 1.50%

State Model

The engine tracks:

  • cash
  • positions
  • purchaseEvents
  • payoutEvents
  • redemptionEvents
  • yearSnapshots
  • yearlyResults

Each active position contains:

  • bonds
  • purchaseYear

Simulation Flow

The engine works on yearly steps.

For each year:

  1. Pay annual interest for all active positions.
  2. Tax the paid interest immediately.
  3. Add net interest to cash.
  4. Redeem positions that reached natural maturity (4 years) and return principal.
  5. Reinvest available cash into full new bonds if the horizon continues.
  6. If this is the final year, early-redeem all still-active positions.
  7. 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:

  • grossValue means 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.purchaseEvents
  • simulationDetails.payoutEvents
  • simulationDetails.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.ts
  • annual-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:

  • COI and 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.ts
  • coi.strategy.test.ts: tests/coi.strategy.test.ts
  • COI_logic.md
  • init_prompt.md: ai/init_prompt.md