1use chrono::Utc;
7use rust_decimal::Decimal;
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11use crate::User;
12
13#[derive(Debug)]
15#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
16pub struct SimulationReport {
17 pub interval: i64,
19
20 #[cfg_attr(feature = "serde", serde(skip))]
23 pub users: Option<Vec<User>>,
24
25 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
28 pub profit_loss: Decimal,
29
30 pub trades: u64,
33
34 pub successful_trades: u64,
37
38 pub failed_trades: u64,
41
42 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
45 pub market_volatility: Decimal,
46
47 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
50 pub liquidity: Decimal,
51
52 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
55 pub adoption_rate: Decimal,
56
57 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
59 pub total_burned: Decimal,
60
61 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
64 pub burn_rate: Decimal,
65
66 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
69 pub inflation_rate: Decimal,
70
71 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
74 pub user_retention: Decimal,
75
76 pub network_activity: u64,
79
80 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
83 pub token_price: Decimal,
84
85 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
87 pub total_new_tokens: Decimal,
88}
89
90impl Default for SimulationReport {
91 fn default() -> Self {
97 Self {
98 users: None,
99 interval: Utc::now().timestamp(),
100 profit_loss: Decimal::default(),
101 trades: 0,
102 successful_trades: 0,
103 failed_trades: 0,
104 market_volatility: Decimal::default(),
105 liquidity: Decimal::default(),
106 adoption_rate: Decimal::default(),
107 total_burned: Decimal::default(),
108 burn_rate: Decimal::default(),
109 inflation_rate: Decimal::default(),
110 user_retention: Decimal::default(),
111 token_price: Decimal::default(),
112 total_new_tokens: Decimal::default(),
113 network_activity: 0,
114 }
115 }
116}
117
118impl SimulationReport {
119 pub fn calculate_liquidity(
132 &self,
133 trades: Decimal,
134 interval_duration: Decimal,
135 decimals: u32,
136 ) -> Decimal {
137 #[cfg(feature = "log")]
138 log::debug!(
139 "Calculating liquidity: trades={}, interval_duration={}",
140 trades,
141 interval_duration
142 );
143
144 (trades / interval_duration).round_dp(decimals)
145 }
146
147 pub fn calculate_adoption_rate(&self, users: &[User], decimals: u32) -> Decimal {
159 #[cfg(feature = "log")]
160 log::debug!("Calculating adoption rate: users={:?}", users.len());
161
162 let total_users = Decimal::new(users.len() as i64, 0);
163 let new_users = Decimal::new(
164 users
165 .iter()
166 .filter(|u| u.balance > Decimal::default())
167 .count() as i64,
168 0,
169 );
170
171 (new_users / total_users).round_dp(decimals)
172 }
173
174 pub fn calculate_burn_rate(
187 &self,
188 total_burned: Decimal,
189 total_users: Decimal,
190 decimals: u32,
191 ) -> Decimal {
192 #[cfg(feature = "log")]
193 log::debug!(
194 "Calculating burn rate: total_burned={}, total_users={}",
195 total_burned,
196 total_users
197 );
198
199 (total_burned / total_users).round_dp(decimals)
200 }
201
202 pub fn calculate_inflation_rate(
215 &self,
216 total_new_tokens: Decimal,
217 total_users: Decimal,
218 decimals: u32,
219 ) -> Decimal {
220 #[cfg(feature = "log")]
221 log::debug!(
222 "Calculating inflation rate: total_new_tokens={}, total_users={}",
223 total_new_tokens,
224 total_users
225 );
226
227 (total_new_tokens / total_users).round_dp(decimals)
228 }
229
230 pub fn calculate_user_retention(&self, users: &[User], decimals: u32) -> Decimal {
242 #[cfg(feature = "log")]
243 log::debug!("Calculating user retention rate: users={:?}", users.len());
244
245 let total_users = Decimal::new(users.len() as i64, 0);
246 let retained_users = Decimal::new(
247 users
248 .iter()
249 .filter(|u| u.balance > Decimal::default())
250 .count() as i64,
251 0,
252 );
253
254 (retained_users / total_users).round_dp(decimals)
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use uuid::Uuid;
261
262 use super::*;
263
264 #[test]
265 fn test_default() {
266 let report = SimulationReport::default();
267
268 assert!(report.users.is_none());
269 assert_eq!(report.profit_loss, Decimal::default());
270 assert_eq!(report.trades, 0);
271 assert_eq!(report.successful_trades, 0);
272 assert_eq!(report.failed_trades, 0);
273 assert_eq!(report.market_volatility, Decimal::default());
274 assert_eq!(report.liquidity, Decimal::default());
275 assert_eq!(report.adoption_rate, Decimal::default());
276 assert_eq!(report.burn_rate, Decimal::default());
277 assert_eq!(report.inflation_rate, Decimal::default());
278 assert_eq!(report.user_retention, Decimal::default());
279 assert_eq!(report.network_activity, 0);
280 }
281
282 #[test]
283 fn test_calculate_liquidity() {
284 let report = SimulationReport::default();
285 let trades = Decimal::new(100, 0);
286 let interval_duration = Decimal::new(10, 0);
287
288 assert_eq!(
289 report.calculate_liquidity(trades, interval_duration, 4),
290 Decimal::new(10, 0)
291 );
292 }
293
294 #[test]
295 fn test_calculate_adoption_rate() {
296 let report = SimulationReport::default();
297 let users = vec![
298 User::new(Uuid::new_v4(), Decimal::default()),
299 User::new(Uuid::new_v4(), Decimal::new(10, 0)),
300 User::new(Uuid::new_v4(), Decimal::default()),
301 User::new(Uuid::new_v4(), Decimal::new(5, 0)),
302 ];
303
304 assert_eq!(
305 report.calculate_adoption_rate(&users, 4),
306 Decimal::new(5, 1),
307 );
308 }
309
310 #[test]
311 fn test_calculate_burn_rate() {
312 let report = SimulationReport::default();
313 let total_burned = Decimal::new(100, 0);
314 let total_users = Decimal::new(10, 0);
315
316 assert_eq!(
317 report.calculate_burn_rate(total_burned, total_users, 4),
318 Decimal::new(10, 0)
319 );
320 }
321
322 #[test]
323 fn test_calculate_inflation_rate() {
324 let report = SimulationReport::default();
325 let total_new_tokens = Decimal::new(100, 0);
326 let total_users = Decimal::new(10, 0);
327
328 assert_eq!(
329 report.calculate_inflation_rate(total_new_tokens, total_users, 4),
330 Decimal::new(10, 0)
331 );
332 }
333
334 #[test]
335 fn test_calculate_user_retention() {
336 let report = SimulationReport::default();
337 let users = vec![
338 User::new(Uuid::new_v4(), Decimal::default()),
339 User::new(Uuid::new_v4(), Decimal::new(10, 0)),
340 User::new(Uuid::new_v4(), Decimal::default()),
341 User::new(Uuid::new_v4(), Decimal::new(5, 0)),
342 ];
343
344 assert_eq!(
345 report.calculate_user_retention(&users, 4),
346 Decimal::new(5, 1),
347 );
348 }
349}