use itertools::Itertools;
use std::ops::Deref;
use std::{collections::HashMap, ops::Add};
use rotala::clock::DateTime;
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct CashValue(f64);
impl Deref for CashValue {
type Target = f64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for CashValue {
fn default() -> Self {
Self(0.0)
}
}
impl From<CashValue> for f64 {
fn from(v: CashValue) -> Self {
v.0
}
}
impl From<f64> for CashValue {
fn from(v: f64) -> Self {
CashValue(v)
}
}
impl Add<CashValue> for CashValue {
type Output = CashValue;
fn add(self, rhs: CashValue) -> Self::Output {
CashValue::from(*self + *rhs)
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct PortfolioQty(f64);
impl Deref for PortfolioQty {
type Target = f64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<f64> for PortfolioQty {
fn from(v: f64) -> Self {
Self(v)
}
}
impl From<PortfolioQty> for f64 {
fn from(v: PortfolioQty) -> Self {
*v
}
}
impl Default for PortfolioQty {
fn default() -> Self {
Self(0.0)
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Price(f64);
impl Deref for Price {
type Target = f64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for Price {
fn default() -> Self {
Self(0.0)
}
}
impl From<Price> for f64 {
fn from(v: Price) -> Self {
v.0
}
}
impl From<f64> for Price {
fn from(v: f64) -> Self {
Price(v)
}
}
#[derive(Clone, Debug)]
pub struct PortfolioHoldings(pub HashMap<String, PortfolioQty>);
impl PortfolioHoldings {
pub fn get(&self, ticker: &str) -> Option<PortfolioQty> {
self.0.get(ticker).cloned()
}
pub fn remove(&mut self, ticker: &str) {
self.0.remove(ticker);
}
pub fn keys(&self) -> Vec<String> {
self.0.keys().cloned().collect_vec()
}
pub fn insert(&mut self, ticker: &str, value: &PortfolioQty) {
self.0.insert(ticker.to_string(), value.clone());
}
pub fn new() -> Self {
let map: HashMap<String, PortfolioQty> = HashMap::new();
Self(map)
}
}
impl Default for PortfolioHoldings {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct PortfolioValues(pub HashMap<String, CashValue>);
impl PortfolioValues {
pub fn insert(&mut self, ticker: &str, value: &CashValue) {
self.0.insert(ticker.to_string(), value.clone());
}
pub fn new() -> Self {
let map: HashMap<String, CashValue> = HashMap::new();
Self(map)
}
}
impl Default for PortfolioValues {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct PortfolioWeight(f64);
impl Deref for PortfolioWeight {
type Target = f64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<PortfolioWeight> for f64 {
fn from(v: PortfolioWeight) -> Self {
v.0
}
}
impl From<f64> for PortfolioWeight {
fn from(v: f64) -> Self {
PortfolioWeight(v)
}
}
#[derive(Clone, Debug)]
pub struct PortfolioAllocation(HashMap<String, PortfolioWeight>);
impl PortfolioAllocation {
pub fn get(&self, ticker: impl AsRef<str>) -> Option<&PortfolioWeight> {
self.0.get(ticker.as_ref())
}
pub fn insert(&mut self, ticker: impl AsRef<str>, value: impl Into<PortfolioWeight>) {
self.0.insert(ticker.as_ref().to_string(), value.into());
}
pub fn keys(&self) -> Vec<String> {
self.0.keys().cloned().collect_vec()
}
pub fn new() -> Self {
let map: HashMap<String, PortfolioWeight> = HashMap::new();
Self(map)
}
}
impl Default for PortfolioAllocation {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct StrategySnapshot {
pub date: DateTime,
pub portfolio_value: CashValue,
pub net_cash_flow: CashValue,
pub inflation: f64,
}
impl StrategySnapshot {
pub fn nominal(date: DateTime, portfolio_value: CashValue, net_cash_flow: CashValue) -> Self {
Self {
date,
portfolio_value,
net_cash_flow,
inflation: 0.0,
}
}
pub fn real(
date: DateTime,
portfolio_value: CashValue,
net_cash_flow: CashValue,
inflation: f64,
) -> Self {
Self {
date,
portfolio_value,
net_cash_flow,
inflation,
}
}
}