barter/statistic/summary/
mod.rs1use crate::{
2 engine::state::{asset::AssetStates, instrument::InstrumentStates, position::PositionExited},
3 statistic::{
4 summary::{
5 asset::{TearSheetAsset, TearSheetAssetGenerator},
6 instrument::{TearSheet, TearSheetGenerator},
7 },
8 time::TimeInterval,
9 },
10};
11use barter_execution::balance::AssetBalance;
12use barter_instrument::{
13 asset::{AssetIndex, ExchangeAsset, name::AssetNameInternal},
14 instrument::{InstrumentIndex, name::InstrumentNameInternal},
15};
16use barter_integration::{collection::FnvIndexMap, snapshot::Snapshot};
17use chrono::{DateTime, TimeDelta, Utc};
18use derive_more::Constructor;
19use rust_decimal::Decimal;
20use serde::{Deserialize, Serialize};
21
22pub mod asset;
23pub mod dataset;
24pub mod display;
25pub mod instrument;
26pub mod pnl;
27
28#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Constructor)]
29pub struct TradingSummary<Interval> {
30 pub time_engine_start: DateTime<Utc>,
32
33 pub time_engine_end: DateTime<Utc>,
35
36 pub instruments: FnvIndexMap<InstrumentNameInternal, TearSheet<Interval>>,
41
42 pub assets: FnvIndexMap<ExchangeAsset<AssetNameInternal>, TearSheetAsset>,
44}
45
46impl<Interval> TradingSummary<Interval> {
47 pub fn trading_duration(&self) -> TimeDelta {
49 self.time_engine_end
50 .signed_duration_since(self.time_engine_start)
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Constructor)]
56pub struct TradingSummaryGenerator {
57 pub risk_free_return: Decimal,
61
62 pub time_engine_start: DateTime<Utc>,
64
65 pub time_engine_now: DateTime<Utc>,
68
69 pub instruments: FnvIndexMap<InstrumentNameInternal, TearSheetGenerator>,
74
75 pub assets: FnvIndexMap<ExchangeAsset<AssetNameInternal>, TearSheetAssetGenerator>,
77}
78
79impl TradingSummaryGenerator {
80 pub fn init<InstrumentData>(
83 risk_free_return: Decimal,
84 time_engine_start: DateTime<Utc>,
85 time_engine_now: DateTime<Utc>,
86 instruments: &InstrumentStates<InstrumentData>,
87 assets: &AssetStates,
88 ) -> Self {
89 Self {
90 risk_free_return,
91 time_engine_start,
92 time_engine_now,
93 instruments: instruments
94 .0
95 .values()
96 .map(|state| {
97 (
98 state.instrument.name_internal.clone(),
99 state.tear_sheet.clone(),
100 )
101 })
102 .collect(),
103 assets: assets
104 .0
105 .iter()
106 .map(|(asset, state)| (asset.clone(), state.statistics.clone()))
107 .collect(),
108 }
109 }
110
111 pub fn update_time_now(&mut self, time_now: DateTime<Utc>) {
113 self.time_engine_now = time_now;
114 }
115
116 pub fn update_from_position<AssetKey, InstrumentKey>(
118 &mut self,
119 position: &PositionExited<AssetKey, InstrumentKey>,
120 ) where
121 Self: InstrumentTearSheetManager<InstrumentKey>,
122 {
123 if self.time_engine_now < position.time_exit {
124 self.time_engine_now = position.time_exit;
125 }
126
127 self.instrument_mut(&position.instrument)
128 .update_from_position(position)
129 }
130
131 pub fn update_from_balance<AssetKey>(&mut self, balance: Snapshot<&AssetBalance<AssetKey>>)
133 where
134 Self: AssetTearSheetManager<AssetKey>,
135 {
136 if self.time_engine_now < balance.0.time_exchange {
137 self.time_engine_now = balance.0.time_exchange;
138 }
139
140 self.asset_mut(&balance.0.asset)
141 .update_from_balance(balance)
142 }
143
144 pub fn generate<Interval>(&mut self, interval: Interval) -> TradingSummary<Interval>
149 where
150 Interval: TimeInterval,
151 {
152 let instruments = self
153 .instruments
154 .iter_mut()
155 .map(|(instrument, tear_sheet)| {
156 (
157 instrument.clone(),
158 tear_sheet.generate(self.risk_free_return, interval),
159 )
160 })
161 .collect();
162
163 let assets = self
164 .assets
165 .iter_mut()
166 .map(|(asset, tear_sheet)| (asset.clone(), tear_sheet.generate()))
167 .collect();
168
169 TradingSummary {
170 time_engine_start: self.time_engine_start,
171 time_engine_end: self.time_engine_now,
172 instruments,
173 assets,
174 }
175 }
176}
177
178pub trait InstrumentTearSheetManager<InstrumentKey> {
179 fn instrument(&self, key: &InstrumentKey) -> &TearSheetGenerator;
180 fn instrument_mut(&mut self, key: &InstrumentKey) -> &mut TearSheetGenerator;
181}
182
183impl InstrumentTearSheetManager<InstrumentNameInternal> for TradingSummaryGenerator {
184 fn instrument(&self, key: &InstrumentNameInternal) -> &TearSheetGenerator {
185 self.instruments
186 .get(key)
187 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
188 }
189
190 fn instrument_mut(&mut self, key: &InstrumentNameInternal) -> &mut TearSheetGenerator {
191 self.instruments
192 .get_mut(key)
193 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
194 }
195}
196
197impl InstrumentTearSheetManager<InstrumentIndex> for TradingSummaryGenerator {
198 fn instrument(&self, key: &InstrumentIndex) -> &TearSheetGenerator {
199 self.instruments
200 .get_index(key.index())
201 .map(|(_key, state)| state)
202 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
203 }
204
205 fn instrument_mut(&mut self, key: &InstrumentIndex) -> &mut TearSheetGenerator {
206 self.instruments
207 .get_index_mut(key.index())
208 .map(|(_key, state)| state)
209 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
210 }
211}
212
213pub trait AssetTearSheetManager<AssetKey> {
214 fn asset(&self, key: &AssetKey) -> &TearSheetAssetGenerator;
215 fn asset_mut(&mut self, key: &AssetKey) -> &mut TearSheetAssetGenerator;
216}
217
218impl AssetTearSheetManager<AssetIndex> for TradingSummaryGenerator {
219 fn asset(&self, key: &AssetIndex) -> &TearSheetAssetGenerator {
220 self.assets
221 .get_index(key.index())
222 .map(|(_key, state)| state)
223 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
224 }
225
226 fn asset_mut(&mut self, key: &AssetIndex) -> &mut TearSheetAssetGenerator {
227 self.assets
228 .get_index_mut(key.index())
229 .map(|(_key, state)| state)
230 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key}"))
231 }
232}
233
234impl AssetTearSheetManager<ExchangeAsset<AssetNameInternal>> for TradingSummaryGenerator {
235 fn asset(&self, key: &ExchangeAsset<AssetNameInternal>) -> &TearSheetAssetGenerator {
236 self.assets
237 .get(key)
238 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key:?}"))
239 }
240
241 fn asset_mut(
242 &mut self,
243 key: &ExchangeAsset<AssetNameInternal>,
244 ) -> &mut TearSheetAssetGenerator {
245 self.assets
246 .get_mut(key)
247 .unwrap_or_else(|| panic!("TradingSummaryGenerator does not contain: {key:?}"))
248 }
249}