1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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),
}
}
}
|