1use rust_decimal::{prelude::*, Decimal};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{SimulationError, SimulationInterval};
11
12#[derive(Debug, Clone, PartialEq)]
14#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
15pub struct SimulationOptions {
16 pub duration: u64,
19
20 pub total_users: u64,
23
24 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
27 pub market_volatility: Decimal,
28
29 pub decimal_precision: u32,
32
33 pub interval_type: SimulationInterval,
36
37 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float_option"))]
40 pub transaction_fee_percentage: Option<Decimal>,
41
42 #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float_option"))]
45 pub adoption_rate: Option<Decimal>,
46
47 pub valuation_model: Option<ValuationModel>,
50}
51
52#[derive(Debug, Default, PartialEq)]
54#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
55pub struct SimulationOptionsBuilder {
56 pub duration: Option<u64>,
58
59 pub total_users: Option<u64>,
61
62 pub market_volatility: Option<f64>,
65
66 pub decimal_precision: Option<u32>,
69
70 pub interval_type: Option<SimulationInterval>,
72
73 pub transaction_fee_percentage: Option<f64>,
75
76 pub adoption_rate: Option<f64>,
78
79 pub valuation_model: Option<ValuationModel>,
81}
82
83#[derive(Debug, Clone, PartialEq)]
85#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
86pub enum ValuationModel {
87 Linear,
89
90 Exponential(f64),
94}
95
96impl SimulationOptionsBuilder {
97 pub fn new() -> Self {
103 SimulationOptionsBuilder::default()
104 }
105
106 pub fn duration(mut self, duration: u64) -> Self {
116 self.duration = Some(duration);
117 self
118 }
119
120 pub fn total_users(mut self, total_users: u64) -> Self {
130 self.total_users = Some(total_users);
131 self
132 }
133
134 pub fn market_volatility(mut self, market_volatility: f64) -> Self {
144 self.market_volatility = Some(market_volatility);
145 self
146 }
147
148 pub fn decimal_precision(mut self, decimal_precision: u32) -> Self {
158 self.decimal_precision = Some(decimal_precision);
159 self
160 }
161
162 pub fn interval_type(mut self, interval_type: SimulationInterval) -> Self {
172 self.interval_type = Some(interval_type);
173 self
174 }
175
176 pub fn transaction_fee_percentage(mut self, transaction_fee: f64) -> Self {
186 self.transaction_fee_percentage = Some(transaction_fee);
187 self
188 }
189
190 pub fn adoption_rate(mut self, adoption_rate: f64) -> Self {
200 self.adoption_rate = Some(adoption_rate);
201 self
202 }
203
204 pub fn valuation_model(mut self, valuation_model: ValuationModel) -> Self {
214 self.valuation_model = Some(valuation_model);
215 self
216 }
217
218 pub fn build(self) -> Result<SimulationOptions, SimulationError> {
224 Ok(SimulationOptions {
225 duration: self.duration.unwrap_or(7),
226 total_users: self.total_users.ok_or(SimulationError::MissingTotalUsers)?,
227 market_volatility: Decimal::from_f64(self.market_volatility.unwrap_or(0.5)).unwrap(),
228 decimal_precision: self.decimal_precision.unwrap_or(4),
229 interval_type: self.interval_type.unwrap_or(SimulationInterval::Daily),
230 transaction_fee_percentage: match self.transaction_fee_percentage {
231 Some(fee) => Some(Decimal::from_f64(fee).ok_or(SimulationError::InvalidDecimal)?),
232 None => None,
233 },
234 adoption_rate: match self.adoption_rate {
235 Some(rate) => Some(Decimal::from_f64(rate).ok_or(SimulationError::InvalidDecimal)?),
236 None => None,
237 },
238 valuation_model: self.valuation_model,
239 })
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use crate::SimulationInterval;
246 use rust_decimal::Decimal;
247
248 use super::*;
249
250 #[test]
251 fn test_new_simulation_options_builder() {
252 let builder = SimulationOptionsBuilder::new();
253
254 assert_eq!(builder.duration, None);
255 assert_eq!(builder.total_users, None);
256 assert_eq!(builder.market_volatility, None);
257 assert_eq!(builder.decimal_precision, None);
258 assert_eq!(builder.interval_type, None);
259 assert_eq!(builder.transaction_fee_percentage, None);
260 assert_eq!(builder.adoption_rate, None);
261 assert_eq!(builder.valuation_model, None);
262 }
263
264 #[test]
265 fn test_build_simulation_options_with_only_required() {
266 let builder = SimulationOptionsBuilder::new();
267 let options = builder
268 .total_users(100)
269 .market_volatility(0.5)
270 .build()
271 .unwrap();
272
273 assert_eq!(options.duration, 7);
274 assert_eq!(options.total_users, 100);
275 assert_eq!(options.decimal_precision, 4);
276 assert_eq!(options.market_volatility, Decimal::new(5, 1));
277 assert_eq!(options.interval_type, SimulationInterval::Daily);
278 assert_eq!(options.transaction_fee_percentage, None);
279 assert_eq!(options.adoption_rate, None);
280 assert_eq!(options.valuation_model, None);
281 }
282 #[test]
283 fn test_build_simulation_options() {
284 let builder = SimulationOptionsBuilder::new();
285 let options = builder
286 .adoption_rate(1.0)
287 .duration(10)
288 .decimal_precision(2)
289 .interval_type(SimulationInterval::Daily)
290 .transaction_fee_percentage(0.01)
291 .valuation_model(ValuationModel::Linear)
292 .total_users(100)
293 .market_volatility(0.5)
294 .build()
295 .unwrap();
296
297 assert_eq!(options.duration, 10);
298 assert_eq!(options.total_users, 100);
299 assert_eq!(options.decimal_precision, 2);
300 assert_eq!(options.market_volatility, Decimal::new(5, 1));
301 assert_eq!(options.interval_type, SimulationInterval::Daily);
302 assert_eq!(options.transaction_fee_percentage, Some(Decimal::new(1, 2)));
303 assert_eq!(options.adoption_rate, Some(Decimal::new(1, 0)));
304 assert_eq!(options.valuation_model, Some(ValuationModel::Linear));
305 }
306
307 #[test]
308 fn test_build_simulation_options_missing_total_users() {
309 let builder = SimulationOptionsBuilder::new();
310 let result = builder.build();
311
312 assert_eq!(result, Err(SimulationError::MissingTotalUsers));
313 }
314}