将已确认应收股息计入权益并验证支付资产守恒
This commit is contained in:
@@ -765,16 +765,38 @@ mod tests {
|
|||||||
assert_eq!(records[0].payable_date, payment);
|
assert_eq!(records[0].payable_date, payment);
|
||||||
let mut book = conversion_book();
|
let mut book = conversion_book();
|
||||||
let mut notes = Vec::new();
|
let mut notes = Vec::new();
|
||||||
|
let equity_before = book.total_equity();
|
||||||
apply(date(), &data, &mut book, &mut notes, true, true).unwrap();
|
apply(date(), &data, &mut book, &mut notes, true, true).unwrap();
|
||||||
assert_eq!(book.cash(), 1000.);
|
assert_eq!(book.cash(), 1000.);
|
||||||
assert_eq!(book.cash_receivables().len(), 1);
|
assert_eq!(book.cash_receivables().len(), 1);
|
||||||
assert_eq!(book.cash_receivables()[0].amount, 50.);
|
assert_eq!(book.cash_receivables()[0].amount, 50.);
|
||||||
|
assert_eq!(book.cash_receivable_value(), 50.);
|
||||||
|
assert_eq!(book.total_equity(), equity_before);
|
||||||
|
assert_eq!(book.unit_net_value(), equity_before / book.units());
|
||||||
settle_receivables(date().succ_opt().unwrap(), &data, &mut book, &mut notes, false, None).unwrap();
|
settle_receivables(date().succ_opt().unwrap(), &data, &mut book, &mut notes, false, None).unwrap();
|
||||||
assert_eq!(book.cash(), 1000.);
|
assert_eq!(book.cash(), 1000.);
|
||||||
assert_eq!(book.cash_receivables().len(), 1);
|
assert_eq!(book.cash_receivables().len(), 1);
|
||||||
|
assert_eq!(book.total_equity(), equity_before);
|
||||||
settle_receivables(payment, &data, &mut book, &mut notes, false, None).unwrap();
|
settle_receivables(payment, &data, &mut book, &mut notes, false, None).unwrap();
|
||||||
assert_eq!(book.cash(), 1050.);
|
assert_eq!(book.cash(), 1050.);
|
||||||
assert!(book.cash_receivables().is_empty());
|
assert!(book.cash_receivables().is_empty());
|
||||||
|
assert_eq!(book.cash_receivable_value(), 0.);
|
||||||
|
assert_eq!(book.total_equity(), equity_before);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dividend_receivable_survives_a_flat_position_without_becoming_spendable_cash() {
|
||||||
|
let mut account = PortfolioState::new(1000.);
|
||||||
|
account.add_cash_receivable(CashReceivable { symbol: "000001.SZ".into(),
|
||||||
|
ex_date: date(), payable_date: date().succ_opt().unwrap(), amount: 50., reason: "registered dividend".into() });
|
||||||
|
account.prune_flat_positions();
|
||||||
|
assert_eq!(account.market_value(), 0.);
|
||||||
|
assert_eq!(account.cash(), 1000.);
|
||||||
|
assert_eq!(account.total_equity(), 1050.);
|
||||||
|
assert!(account.deposit_withdraw(-1001.).is_err());
|
||||||
|
settle_receivables(date().succ_opt().unwrap(), &data(false), &mut account, &mut Vec::new(), false, None).unwrap();
|
||||||
|
assert_eq!(account.cash(), 1050.);
|
||||||
|
assert_eq!(account.total_equity(), 1050.);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1485,6 +1485,16 @@ impl PortfolioState {
|
|||||||
&self.cash_receivables
|
&self.cash_receivables
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cash_receivable_value(&self) -> f64 {
|
||||||
|
self.cash_receivables.iter().try_fold(FixedMoney::ZERO, |total, receivable| {
|
||||||
|
let amount = fixed_money(receivable.amount, "cash receivable asset")?;
|
||||||
|
if amount < FixedMoney::ZERO {
|
||||||
|
return Err("cash receivable asset cannot be negative".to_string());
|
||||||
|
}
|
||||||
|
total.checked_add(amount).ok_or_else(|| "cash receivable asset overflow".to_string())
|
||||||
|
}).expect("cash receivable asset must be valid fixed-point money").to_f64()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn begin_trading_day(&mut self) {
|
pub fn begin_trading_day(&mut self) {
|
||||||
self.day_sold_symbols.clear();
|
self.day_sold_symbols.clear();
|
||||||
for position in self.positions.values_mut() {
|
for position in self.positions.values_mut() {
|
||||||
@@ -1589,7 +1599,8 @@ impl PortfolioState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_equity(&self) -> f64 {
|
pub fn total_equity(&self) -> f64 {
|
||||||
self.cash.to_f64() + self.market_value() - self.cash_liabilities.to_f64()
|
self.cash.to_f64() + self.market_value() + self.cash_receivable_value()
|
||||||
|
- self.cash_liabilities.to_f64()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_value(&self) -> f64 {
|
pub fn total_value(&self) -> f64 {
|
||||||
|
|||||||
Reference in New Issue
Block a user