finance_query/models/chart/
events.rs1use crate::Provider;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::OnceLock;
9
10#[derive(Debug, Default, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub(crate) struct ChartEvents {
17 #[serde(default)]
19 pub dividends: HashMap<String, DividendEvent>,
20 #[serde(default)]
22 pub splits: HashMap<String, SplitEvent>,
23 #[serde(default)]
25 pub capital_gains: HashMap<String, CapitalGainEvent>,
26
27 #[serde(skip)]
29 dividends_cache: OnceLock<Vec<Dividend>>,
30 #[serde(skip)]
32 splits_cache: OnceLock<Vec<Split>>,
33 #[serde(skip)]
35 capital_gains_cache: OnceLock<Vec<CapitalGain>>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub(crate) struct DividendEvent {
41 pub amount: f64,
43 pub date: i64,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub(crate) struct SplitEvent {
51 pub date: i64,
53 pub numerator: f64,
55 pub denominator: f64,
57 pub split_ratio: String,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub(crate) struct CapitalGainEvent {
64 pub amount: f64,
66 pub date: i64,
68}
69
70#[non_exhaustive]
74#[derive(Debug, Clone, Serialize, Deserialize)]
75#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
76pub struct Dividend {
77 pub timestamp: i64,
79 pub amount: f64,
81
82 #[serde(skip_serializing_if = "Option::is_none", default)]
84 pub provider_id: Option<Provider>,
85}
86
87#[non_exhaustive]
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
93pub struct Split {
94 pub timestamp: i64,
96 pub numerator: f64,
98 pub denominator: f64,
100 pub ratio: String,
102
103 #[serde(skip_serializing_if = "Option::is_none", default)]
105 pub provider_id: Option<Provider>,
106}
107
108#[non_exhaustive]
112#[derive(Debug, Clone, Serialize, Deserialize)]
113#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
114pub struct CapitalGain {
115 pub timestamp: i64,
117 pub amount: f64,
119
120 #[serde(skip_serializing_if = "Option::is_none", default)]
122 pub provider_id: Option<Provider>,
123}
124
125impl Clone for ChartEvents {
126 fn clone(&self) -> Self {
127 fn clone_cache<T: Clone>(cache: &OnceLock<T>) -> OnceLock<T> {
129 let new_cache = OnceLock::new();
130 if let Some(value) = cache.get() {
131 let _ = new_cache.set(value.clone());
132 }
133 new_cache
134 }
135
136 Self {
137 dividends: self.dividends.clone(),
138 splits: self.splits.clone(),
139 capital_gains: self.capital_gains.clone(),
140 dividends_cache: clone_cache(&self.dividends_cache),
141 splits_cache: clone_cache(&self.splits_cache),
142 capital_gains_cache: clone_cache(&self.capital_gains_cache),
143 }
144 }
145}
146
147impl ChartEvents {
148 pub(crate) fn to_dividends(&self) -> Vec<Dividend> {
150 self.dividends_cache
151 .get_or_init(|| {
152 let mut dividends: Vec<Dividend> = self
153 .dividends
154 .values()
155 .map(|d| Dividend {
156 timestamp: d.date,
157 amount: d.amount,
158 provider_id: None,
159 })
160 .collect();
161 dividends.sort_by_key(|d| d.timestamp);
162 dividends
163 })
164 .clone()
165 }
166
167 pub(crate) fn to_splits(&self) -> Vec<Split> {
169 self.splits_cache
170 .get_or_init(|| {
171 let mut splits: Vec<Split> = self
172 .splits
173 .values()
174 .map(|s| Split {
175 timestamp: s.date,
176 numerator: s.numerator,
177 denominator: s.denominator,
178 ratio: s.split_ratio.clone(),
179 provider_id: None,
180 })
181 .collect();
182 splits.sort_by_key(|s| s.timestamp);
183 splits
184 })
185 .clone()
186 }
187
188 pub(crate) fn to_capital_gains(&self) -> Vec<CapitalGain> {
190 self.capital_gains_cache
191 .get_or_init(|| {
192 let mut gains: Vec<CapitalGain> = self
193 .capital_gains
194 .values()
195 .map(|g| CapitalGain {
196 timestamp: g.date,
197 amount: g.amount,
198 provider_id: None,
199 })
200 .collect();
201 gains.sort_by_key(|g| g.timestamp);
202 gains
203 })
204 .clone()
205 }
206}