diff options
| author | Kevin Hoerr <kjhoerr@submelon.dev> | 2026-04-16 17:07:14 -0400 |
|---|---|---|
| committer | Kevin Hoerr <kjhoerr@submelon.dev> | 2026-04-16 17:07:14 -0400 |
| commit | f6c34724c49de095055f0861128682440af9bd74 (patch) | |
| tree | f1cc221e946b3619d0dc8df84298a79eb0a2176a /src/app/store | |
| parent | 223a91e938bc019cad1566753eb6bb61c3cec779 (diff) | |
| download | equity-tracker-f6c34724c49de095055f0861128682440af9bd74.tar.gz equity-tracker-f6c34724c49de095055f0861128682440af9bd74.tar.bz2 equity-tracker-f6c34724c49de095055f0861128682440af9bd74.zip | |
ledger.rs: Compile change events for account + symbol
Diffstat (limited to 'src/app/store')
| -rw-r--r-- | src/app/store/ledger.rs | 56 | ||||
| -rw-r--r-- | src/app/store/mod.rs | 2 |
2 files changed, 58 insertions, 0 deletions
diff --git a/src/app/store/ledger.rs b/src/app/store/ledger.rs new file mode 100644 index 0000000..841f7b3 --- /dev/null +++ b/src/app/store/ledger.rs @@ -0,0 +1,56 @@ +use bigdecimal::{BigDecimal, Zero}; +use crate::app::store::records::{EquityChangeEvent, EquitySymbol, FiduciaryAccount, ROUNDING_MODE}; + +/// An estimated ledger is the effective sum of all the equity change events +/// derived from record for a particular fiduciary account and equity symbol. +pub struct EstimatedLedger<'a> { + pub fiduciary_account: &'a FiduciaryAccount, + pub equity_symbol: &'a EquitySymbol, + pub equity_change_events: Vec<&'a EquityChangeEvent>, + pub account_symbol_quantity: BigDecimal, + pub account_symbol_cost_basis_price: BigDecimal, + pub account_symbol_cost_basis_total_usd: BigDecimal, + pub account_symbol_last_effective_price: BigDecimal, + pub account_symbol_last_update_timestamp: chrono::DateTime<chrono::Utc>, +} + +impl EstimatedLedger<'_> { + + /// Takes a list of all change events, a fiduciary account, and an equity + /// symbol for which to create a ledger. + /// + /// All values are taken by reference, so they need to be maintained elsewhere + pub fn compile_change_events<'a>(fiduciary_account: &'a FiduciaryAccount, equity_symbol: &'a EquitySymbol, events: Vec<&'a EquityChangeEvent>) -> EstimatedLedger<'a> { + let mut acsym_events = vec![]; + let mut quantity = BigDecimal::zero(); + let mut cost_basis_total = BigDecimal::zero(); + let mut last_event: Option<&EquityChangeEvent> = None; + + for event in events { + if event.fiduciary_account_id != fiduciary_account.fiduciary_account_id || event.equity_symbol_id != equity_symbol.equity_symbol_id { + continue; + } + + if last_event.is_none() || last_event.unwrap().equity_change_timestamp < event.equity_change_timestamp { + last_event = Some(event); + } + + quantity += event.scored_quantity(); + cost_basis_total += event.scored_cost_basis(); + + acsym_events.push(event); + } + + EstimatedLedger { + fiduciary_account, + equity_symbol, + equity_change_events: acsym_events, + account_symbol_quantity: quantity.clone(), + account_symbol_cost_basis_price: (cost_basis_total.clone() / quantity).with_scale_round(2, ROUNDING_MODE), + account_symbol_cost_basis_total_usd: cost_basis_total.with_scale_round(2, ROUNDING_MODE), + account_symbol_last_effective_price: last_event.map_or_else(|| BigDecimal::zero().with_scale(2), |ev| ev.estimated_price()), + account_symbol_last_update_timestamp: last_event.map_or_else(|| chrono::DateTime::<chrono::Utc>::MIN_UTC, |ev| ev.equity_change_timestamp), + } + } + +}
\ No newline at end of file diff --git a/src/app/store/mod.rs b/src/app/store/mod.rs index d038167..da01fba 100644 --- a/src/app/store/mod.rs +++ b/src/app/store/mod.rs @@ -1,4 +1,6 @@ mod sqlite; +mod records; +mod ledger; use sqlite::{SQLiteStore}; use miette::{Diagnostic, Result}; |
