โ๏ธ Portfolio Engine โ Mathematical Model
๐ก Overview
This page formally defines the mathematical model underlying LibreFolio's portfolio calculation engine. All other metric pages (NAV, Book Value, Period P&L, Yield on Cost, WAC, Deposited Capital) reference this page for their precise computation rules.
๐ 1. Notation and Sets
| Symbol | Meaning |
|---|---|
| \(V(u)\) | All brokers visible to user \(u\) |
| \(S \subseteq V(u)\) | Selected (filtered) broker scope |
| \(A\) | Set of assets with positions |
| \(C^*\) | Target currency |
| \([t_0, t_1]\) | Requested evaluation frame |
| \(q(a,b,t)\) | Quantity of asset \(a\) at broker \(b\) on date \(t\) |
| \(p(a,t)\) | Valuation price of asset \(a\) on date \(t\) |
| \(\mathrm{fx}(c_1, c_2, t)\) | Exchange rate from currency \(c_1\) to \(c_2\) on date \(t\) |
๐ 2. Valuation Price
- The unified resolver is the single valuation brain:
MARKET โ TRADE_AVG โ CARRIED โ MISSING. CARRIEDis last-observation-carried-forward. It carriesdays_backstaleness metadata.estimated=Truemeans TRADE-origin. A stale carried MARKET quote is stale, not estimated.- Marks stay in native currency; each consumer converts to \(C^*\) at valuation date \(t\).
- Cost-basis FX remains pinned to the transaction date.
- Cash stays in the currency it was recorded in, broker by broker, and is valued at the rate of \(t\) (ยง5); each cash movement is still booked, and each external cash flow enters the capital, at the rate of its own date.
- WAC is never used as valuation price.
See Price Resolution for the resolver contract and data-quality semantics.
๐ 3. Position State
For each position \((a, b)\) with \(q(a,b,t) > 0\):
Where \(w(a,b,t)\) is the Weighted Average Cost for position \((a,b)\) at date \(t\), kept in \(C^*\) at historical rates (ยง4): the cost basis takes no exchange rate at \(t\), so for a foreign asset the exchange-rate effect is part of \(\mathrm{UGL}\).
๐ 4. WAC Iterative Update
Maintained per-position \((a,b)\) with pool state \((\hat{q}, \hat{c})\), the cost \(\hat{c}\) kept in \(C^*\):
Acquisition (qty \(> 0\), amount \(P\) paid in currency \(c\) on date \(d\)):
\(P\) is the cash paid for a BUY, or the per-unit cost basis override times \(q_{\text{tx}}\) for a TRANSFER or ADJUSTMENT; \(\mathrm{fx}(C^*, C^*, d) = 1\). When no rate exists on or before \(d\), or the acquisition has no cost basis, the quantity enters and the cost does not: the position's cost is flagged incomplete instead of counting zero.
Reduction (qty \(< 0\)):
Split (linked to a split event): \(\hat{q}\) changes, \(\hat{c}\) does not.
Ordering
Within the same date: additions processed before reductions. Ensures SELL reads the correct WAC including same-day BUYs.
๐ 5. Portfolio Aggregation
\(\mathrm{Cash}(t)\) is each broker's cash, kept in the currencies it was recorded in and valued at the rate of \(t\):
where \(N_{b,c}(t)\) is the balance of broker \(b\) in currency \(c\) after its movements dated on or before \(t\), scaled by the broker's ownership share, and \(\mathrm{fx}(c, C^*, t)\) is the latest rate on or before \(t\) (\(1\) for \(c = C^*\)). The same term is in NAV and in Book, so the exchange-rate effect on cash cancels in UGL: it is booked as an exchange result (ยง6) and belongs to the Total P&L.
๐ 6. Three-Pool Cash Model โ Per-Broker \((K_b, R_b, W)\)
Three accumulator pools track cash provenance. \(K\) and \(R\) are maintained per-broker \(b\); \(W\) is global (exits the system entirely).
| Pool | Scope | Meaning |
|---|---|---|
| \(K_b\) | Per-broker | External capital still in broker \(b\) as cash |
| \(R_b\) | Per-broker | Generated returns still in broker \(b\) as cash |
| \(W\) | Global | Returns that left the system (hidden, restorable on re-deposit) |
Key property
A BUY on broker \(b_1\) can only consume \(R_{b_1}\), never \(R_{b_2}\). Cash does not teleport between brokers โ only explicit transfers move pool balances.
๐ Update rules (per-transaction on broker \(b\), chronological)
| Icon & Type | Update Formulas | Logic & Description |
|---|---|---|
DEPOSIT \(D > 0\) |
\(r = \min(D,\, W)\) \(R_b \mathrel{+}= r\) \(W \mathrel{-}= r\) \(K_b \mathrel{+}= D - r\) |
Restores previously withdrawn returns from the global tracker \(W\) first, then adds the remainder to capital \(K_b\). |
WITHDRAWAL \(X > 0\) |
\(k = \min(X,\, K_b)\) \(K_b \mathrel{-}= k\) \(\rho = \min(X - k,\, R_b)\) \(R_b \mathrel{-}= \rho\) \(W \mathrel{+}= \rho\) |
Consumes capital \(K_b\) first, then moves remaining returns \(\rho\) to the global tracker \(W\). |
DIVIDEND / INTEREST \(I > 0\) |
\(R_b \mathrel{+}= I\) | Yields directly increase the returns pool \(R_b\). |
FEE / TAX \(F > 0\) |
\(R_b \mathrel{-}= F\) \(\text{if } R_b < 0\text{: } K_b \mathrel{+}= R_b,\; R_b = 0\) |
Consumes returns \(R_b\) first; if \(R_b\) becomes negative, it drains from capital \(K_b\). |
BUY \(B > 0\) |
\(\rho = \min(B,\, R_b)\) \(R_b \mathrel{-}= \rho\) \(K_b \mathrel{-}= (B - \rho)\) |
Consumes returns \(R_b\) first, then drains the rest from capital \(K_b\). |
SELL |
\(G = P - C\) \(K_b \mathrel{+}= C\) \(R_b \mathrel{+}= G\) \(\text{if } R_b < 0\text{: } K_b \mathrel{+}= R_b, \quad R_b = 0\) |
Cost basis $C = |
CASH TRANSFER (Internal, \(s \to d\), \(X > 0\)) |
Departure Leg (\(s\)): \(\rho = \min(X,\, R_s)\) \(R_s \mathrel{-}= \rho\) \(\kappa = X - \rho\) \(K_s \mathrel{-}= \kappa\) Arrival Leg (\(d\)): \(K_d \mathrel{+}= \kappa\) \(R_d \mathrel{+}= \rho\) |
Internal cash transfers move pool allocations (\(R_s \to R_d\), \(K_s \to K_d\)) proportional to the departure balance. The global tracker \(W\) is never touched (capital remains inside the system). |
If departure and arrival dates differ, the transfer is in-transit: subtracted from \(s\) at departure day, added to \(d\) at arrival day. Between those dates, \(\sum K_b + \sum R_b < \mathrm{Cash}_{\text{like}}\) by the in-transit amount โ handled by proportional reconciliation.
๐ฑ Exchange Result on Foreign Cash
Each cash movement enters the broker's cash, and its pools, at the rate of its own date; the balance held afterwards follows the rate (ยง5). On every day \(t\) on which the rate of a foreign currency held as cash in \(S\) changes โ its first known rate included โ after that day's cash movements and before that day's transactions update the pools, each broker \(b\) holding foreign cash is revalued:
\(\mathrm{Cash}^{\text{replay}}_b(t)\) is the cash the replay carries for \(b\): its value at the previous revaluation plus every later movement at the rate of its own date. A gain goes to the returns; a loss consumes them first and then the capital, exactly like a FEE. The capital baseline does not move: an exchange result is a result, not a contribution, so it is in NAV, Total P&L, ROI, TWRR and MWRR, never in the deposited capital.
๐งฎ Aggregation for output
โ๏ธ Reconciliation invariant
Both pools are first clamped at zero per broker. If the pools are not empty and the drift still exceeds \(0.01\), the summed pools are scaled to \(\mathrm{Cash}_{\text{like}}\), the cash plus the cash in transit โ an aggregate scaling, not a per-broker one, each result floored at zero:
Otherwise \(\mathrm{CashFromCapital}(t) = \min\bigl(\sum_b K_b(t),\, \mathrm{Cash}_{\text{like}}(t)\bigr)\) and \(\mathrm{CashFromReturns}\) is the rest, floored at zero. The exchange results on cash at rest are booked into the pools (above), so the drift left comes from in-transit timing: cash in transit โ and the move of its exchange rate while it travels โ is in no broker's pools.
๐ 7. Period Contribution
For period \([t_0, t_1]\), per-position \((a,b)\):
Contribution position set:
Portfolio-level period P&L also exposes a residual:
Since UGL cannot contain the exchange result on cash (ยง5), Other splits into each broker's exchange result over the period and what remains:
Unallocated fees/income without asset_id are grouped per broker as other period effects, and so is \(\mathrm{FXonCash}_b\): one row per broker holding foreign cash, shown when its result is not zero. See Period P&L โ FX on Cash.
๐ 8. Realized Gain/Loss
On SELL of \(|q_s|\) units from position \((a,b)\) on date \(t\):
Where \(w_{\text{pre}}\) is the WAC in \(C^*\) before the pool reduction (same value used by 3-pool SELL rule above): the units sold leave at their historical cost, with no conversion at the sale date. A sale whose proceeds cannot be converted, or drawn from a position whose cost is incomplete, is left out of Realized.
๐ 9. Pre-Frame / Frame Architecture
| Phase | Date range | Computes |
|---|---|---|
| Pre-frame | \([t_{\mathrm{first}},\ t_0)\) | Cash, qty, WAC, pools โ no market evaluation |
| Frame | \([t_0,\ t_1]\) | Full daily: prices, FX, position states, portfolio states |
Pre-frame transactions update accumulators (cash ledger, WAC pools, 3-pool K/R/W) without any market evaluation: no price is read and no position is valued. Each movement is converted at the rate of its own date, as in the frame, and on every day the rate of a held foreign currency changes, the cash is revalued at that day's rate and the exchange result enters the pools (ยง6), so the pools are correct at \(t_0\). This enables efficient range-based caching.
๐ 10. Performance Metrics (Layer 2)
Computed after daily states, as a separate pass:
| Metric | Formula | Reference |
|---|---|---|
| Total PnL | \(\mathrm{NAV}(t) - \text{CapitalBaseline}(t)\) | Deposited Capital |
| Period PnL | \(\mathrm{NAV}(t_1) - \mathrm{NAV}(t_0) - \text{ECF}_{[t_0,t_1]}\) | Period P&L |
| TWRR | \(\prod_i (1 + r_i) - 1\) (sub-period chain) | TWRR |
| MWRR | XIRR solving \(\sum \frac{CF_i}{(1+r)^{d_i/365}} = 0\) | MWRR |
| Simple ROI | \((\mathrm{NAV} - \text{NetInvested}) / \text{NetInvested}\) | ROI |
| Net annualized return | \((1+r_{\mathrm{net}})^{365/d}-1\), suppressed below 30 days | Net Annualized Return |
| Yield on Cost | Trailing-365-day gross transaction income per eligible historical unit, divided by residual unit WAC at \(t_1\) | Yield on Cost |
| Timing Effect | \(\text{MWRR}_{\text{cum}} - \text{TWRR}_{\text{cum}}\) | Timing Effect |
๐ Related
- ๐ผ NAV โ snapshot valuation
- ๐งญ Price Resolution โ unified valuation resolver
- ๐ Net Annualized Return โ holdings, period, and FIFO CAGR definitions
- ๐ธ Yield on Cost โ trailing gross recorded income relative to residual unit WAC
- ๐ Book Value โ cost basis aggregate
- ๐ Period P&L โ windowed gain/loss with contribution
- ๐ธ Deposited Capital โ 3-pool details and worked examples
- ๐ WAC โ iterative cost method
- ๐ Performance Metrics Overview โ all performance metrics at a glance