use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::OnceLock;
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ChartEvents {
#[serde(default)]
pub dividends: HashMap<String, DividendEvent>,
#[serde(default)]
pub splits: HashMap<String, SplitEvent>,
#[serde(default)]
pub capital_gains: HashMap<String, CapitalGainEvent>,
#[serde(skip)]
dividends_cache: OnceLock<Vec<Dividend>>,
#[serde(skip)]
splits_cache: OnceLock<Vec<Split>>,
#[serde(skip)]
capital_gains_cache: OnceLock<Vec<CapitalGain>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct DividendEvent {
pub amount: f64,
pub date: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SplitEvent {
pub date: i64,
pub numerator: f64,
pub denominator: f64,
pub split_ratio: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct CapitalGainEvent {
pub amount: f64,
pub date: i64,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
pub struct Dividend {
pub timestamp: i64,
pub amount: f64,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
pub struct Split {
pub timestamp: i64,
pub numerator: f64,
pub denominator: f64,
pub ratio: String,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
pub struct CapitalGain {
pub timestamp: i64,
pub amount: f64,
}
impl Clone for ChartEvents {
fn clone(&self) -> Self {
fn clone_cache<T: Clone>(cache: &OnceLock<T>) -> OnceLock<T> {
let new_cache = OnceLock::new();
if let Some(value) = cache.get() {
let _ = new_cache.set(value.clone());
}
new_cache
}
Self {
dividends: self.dividends.clone(),
splits: self.splits.clone(),
capital_gains: self.capital_gains.clone(),
dividends_cache: clone_cache(&self.dividends_cache),
splits_cache: clone_cache(&self.splits_cache),
capital_gains_cache: clone_cache(&self.capital_gains_cache),
}
}
}
impl ChartEvents {
pub(crate) fn to_dividends(&self) -> Vec<Dividend> {
self.dividends_cache
.get_or_init(|| {
let mut dividends: Vec<Dividend> = self
.dividends
.values()
.map(|d| Dividend {
timestamp: d.date,
amount: d.amount,
})
.collect();
dividends.sort_by_key(|d| d.timestamp);
dividends
})
.clone()
}
pub(crate) fn to_splits(&self) -> Vec<Split> {
self.splits_cache
.get_or_init(|| {
let mut splits: Vec<Split> = self
.splits
.values()
.map(|s| Split {
timestamp: s.date,
numerator: s.numerator,
denominator: s.denominator,
ratio: s.split_ratio.clone(),
})
.collect();
splits.sort_by_key(|s| s.timestamp);
splits
})
.clone()
}
pub(crate) fn to_capital_gains(&self) -> Vec<CapitalGain> {
self.capital_gains_cache
.get_or_init(|| {
let mut gains: Vec<CapitalGain> = self
.capital_gains
.values()
.map(|g| CapitalGain {
timestamp: g.date,
amount: g.amount,
})
.collect();
gains.sort_by_key(|g| g.timestamp);
gains
})
.clone()
}
}