Bond Portfolio Service API
Handles bond registrations, transactions, pricing, and accrued interest calculations. The service still throws standard Error objects; it is scheduled to migrate to Result signatures in Phase 2 of the neverthrow rollout.
Location: worker/services/portfolio/bond/service.ts
Dependencies
BondPortfolioRepository– persistence for bonds, holdings, transactions, and stored pricesFundService– verifies fund ownership and organization contextdseApi– shared client for Dhaka Stock Exchange bond endpoints- Shared financial constants – coupon rate scaling, time conversions, and day-count helpers
Core Operations
registerBond(input: BondRegistration): Promise<{ id: string; dayCountConvention: string }>
: Normalizes identifiers, enforces uniqueness (scrip code + ISIN), and persists the bond. Throws descriptive errors when validation fails.
recordTransaction(input: BondTransaction): Promise<void>
: Validates fund ownership via FundService.getFundById, ensures bonds exist, verifies saleable quantity for sells, and records the transaction. Throws on violations.
Business Rule: All bond transactions can only be recorded on the calendar day after the last EOD date. If EOD was done for 2025-07-01, transactions can only be recorded for 2025-07-02. This validation is enforced automatically and throws a BusinessRuleViolation error if the transaction date is not allowed.
generateDailySnapshot(input: BondSnapshot): Promise<void>
: Aggregates transactions, calculates accrued interest, fetches prices from DSE (falling back to stored prices), and persists holdings with accrued interest/market value. Throws when upstream calls fail.
getHoldingsForDate(input: BondSnapshot): Promise<BondHolding[]>
: Returns holdings for a specific fund/date pair.
upsertHoldingsForMigration(organizationId: string, snapshots: MigrationBondHoldingSnapshot[]): Promise<void>
: Validates organization/fund ownership, numeric invariants, and persists migration holdings. Throws descriptive errors on violations.
getBondsByIds(bondIds: string[]): Promise<BondEntity[]>
getTickersForBonds(bondIds: string[]): Promise<Array<{ id: string; ticker: string }>>
: Repository helpers used by EOD workflows.
fetchBondPrices(request: FetchBondPricesRequest): Promise<FetchBondPricesResult> (internal)
: Called by generateDailySnapshot to retrieve daily prices. Errors bubble up as thrown exceptions today.
Day Count & Accrued Interest Helpers
calculateDayCountFactor(convention, valuationDate, settlementDate): numbercalculateAccruedInterest(bondId, valuationDate): Promise<number>calculateCleanAndDirtyPrice(...)(see source for full signature)
These helpers support multiple conventions (ACT_365, ACT_360, THIRTY_360), convert coupon rates from basis points, and are used by EOD orchestration.
Migration Notes
- All public methods still throw exceptions. Wrap calls with
try/catchat the tRPC layer and convert errors toDomainErroruntil the migration replaces these withResultsignatures. - The migration plan tracks this service under Portfolio Services (Phase 2). Once migrated, expect parity with the Equity Portfolio service’s error handling.
Last Validated: 2025-11-10 against commit
0342a62e