use crate::{Asset, Balance};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Holding {
pub asset: Asset,
pub balance: Balance,
}
impl Holding {
pub fn new(asset: Asset, balance: Balance) -> Self {
Self { asset, balance }
}
pub fn quantity(&self) -> f64 {
self.asset.to_display(self.balance.total)
}
pub fn value(&self, rate: f64) -> f64 {
self.quantity() * rate
}
}
#[derive(Debug, Clone)]
pub struct Portfolio {
holdings: Vec<Holding>,
}
impl Portfolio {
pub fn new(holdings: Vec<Holding>) -> Self {
Self { holdings }
}
pub fn holdings(&self) -> &[Holding] {
&self.holdings
}
pub fn len(&self) -> usize {
self.holdings.len()
}
pub fn is_empty(&self) -> bool {
self.holdings.is_empty()
}
pub fn get(&self, asset_code: &str) -> Option<&Holding> {
self.holdings.iter().find(|h| h.asset.code == asset_code)
}
pub fn value(&self, rates: &HashMap<&str, f64>) -> f64 {
self.holdings
.iter()
.map(|h| {
let rate = rates.get(h.asset.code.as_str()).copied().unwrap_or(0.0);
h.value(rate)
})
.sum()
}
pub fn sort_by_largest(&mut self) {
self.holdings.sort_by(|a, b| {
b.quantity()
.partial_cmp(&a.quantity())
.unwrap_or(std::cmp::Ordering::Equal)
});
}
pub fn sort_by_smallest(&mut self) {
self.holdings.sort_by(|a, b| {
a.quantity()
.partial_cmp(&b.quantity())
.unwrap_or(std::cmp::Ordering::Equal)
});
}
pub fn sort_by_value_desc(&mut self, rates: &HashMap<&str, f64>) {
self.holdings.sort_by(|a, b| {
let a_rate = rates.get(a.asset.code.as_str()).copied().unwrap_or(0.0);
let b_rate = rates.get(b.asset.code.as_str()).copied().unwrap_or(0.0);
b.value(b_rate)
.partial_cmp(&a.value(a_rate))
.unwrap_or(std::cmp::Ordering::Equal)
});
}
pub fn sort_by_value_asc(&mut self, rates: &HashMap<&str, f64>) {
self.holdings.sort_by(|a, b| {
let a_rate = rates.get(a.asset.code.as_str()).copied().unwrap_or(0.0);
let b_rate = rates.get(b.asset.code.as_str()).copied().unwrap_or(0.0);
a.value(a_rate)
.partial_cmp(&b.value(b_rate))
.unwrap_or(std::cmp::Ordering::Equal)
});
}
}
impl From<Vec<Holding>> for Portfolio {
fn from(holdings: Vec<Holding>) -> Self {
Self::new(holdings)
}
}
impl IntoIterator for Portfolio {
type Item = Holding;
type IntoIter = std::vec::IntoIter<Holding>;
fn into_iter(self) -> Self::IntoIter {
self.holdings.into_iter()
}
}