Calculating portfolio value

The total value of an InvestorAccount:

TotalPortfolioValue = TotalAssetValue + TotalCashValue

This page builds both parts from the balances of Ledgers and Balances.

Step 1 - units per asset

Take the Asset ledgers of the account (ownerType = 'InvestorAccount', ownerId = the account). Each subTypeReferenceId names the Asset, ledgerSubType names the role:

units(account, asset) = balance(Normal ledger)       # units actually held
                      + balance(Reserved ledger)     # set aside for a pending trade
                      + balance(Dividend ledger)     # stock dividends

Use only the Normal ledger if you want the freely available units instead of the full economic position - either is valid, but state which definition you use.

Step 2 - latest price per asset

From common_c_data_duplication_assetpriceitem_changed: keep, per assetId, the price with the most recent dateTimeOfPrice.

Step 3 - asset value

TotalAssetValue = sum over assets ( units(account, asset) * latestPrice(asset) )

Step 4 - cash value

Sum the balances of the account’s Cash ledgers (ownerType = 'InvestorAccount', ownerId = the account).

Worked example

Investor account PENGINEER-1 holds one asset, FUND-A.

Ledger table (from ledgeritem_changed):

ledger ledgerType / subType subTypeReferenceId
UNITS-FUND-A Asset / Normal FUND-A
RESERVED-FUND-A Asset / Reserved FUND-A
CASH-EUR Cash / Normal EUR

Balances (from ledger_e_journal_entry_added, credits minus debits):

UNITS-FUND-A    : 100 + 25 - 10 = 115 units
RESERVED-FUND-A :               =   0 units
CASH-EUR        :               = 250.00 EUR

Latest price of FUND-A: 12.50.

TotalAssetValue     = (115 + 0) * 12.50 = 1,437.50
TotalCashValue      =                      250.00
TotalPortfolioValue =                    1,687.50

Common mistakes

  • Summing all Asset ledgers without the owner filter - always yields 0; see Ledgers and Balances.
  • Reading units or value fields from portfolio events - portfolioitem events carry the structure of a portfolio, not current figures; those fields are not populated. Balances always come from journal entries.
  • Not expanding the journal entry lines. The ledger_e_journal_entry_added events contain journal entries, so you must expand each entry into its individual lines. See an example.

Back to top

© 2026 Pengine.