tokenomics_simulator/
engine_config.rs

1//! # Engine configuration module
2//!
3//! This module contains the configuration for the simulation engine.
4//! It includes the input parameters for the simulation and the builder to create the configuration.
5
6use rust_decimal::{prelude::*, Decimal};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{SimulationError, SimulationInterval};
11
12/// Input parameters for a simulation.
13#[derive(Debug, Clone, PartialEq)]
14#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
15pub struct SimulationOptions {
16    /// Duration of the simulation, depending on the interval type.
17    /// For daily interval, this is the number of days.
18    pub duration: u64,
19
20    /// Number of users in the simulation.
21    /// This is the total number of users that will be simulated.
22    pub total_users: u64,
23
24    /// Volatility level. 0.0 is no volatility, 1.0 is maximum volatility.
25    /// This is used to simulate the price volatility in the market.
26    #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float"))]
27    pub market_volatility: Decimal,
28
29    /// Decimal precision for the simulation.
30    /// Default value is 4.
31    pub decimal_precision: u32,
32
33    /// Interval type for the simulation.
34    /// This is the interval at which the simulation will run.
35    pub interval_type: SimulationInterval,
36
37    /// Transaction fee for each trade, in percentage.
38    /// This is the fee that will be charged for each trade in the simulation.
39    #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float_option"))]
40    pub transaction_fee_percentage: Option<Decimal>,
41
42    /// Rate at which users adopt the token.
43    /// This is the rate at which users will adopt the token.
44    #[cfg_attr(feature = "serde", serde(with = "rust_decimal::serde::float_option"))]
45    pub adoption_rate: Option<Decimal>,
46
47    /// Valuation model for the token.
48    /// This is the model used to calculate the valuation of the token.
49    pub valuation_model: Option<ValuationModel>,
50}
51
52/// Builder for creating a new simulation options.
53#[derive(Debug, Default, PartialEq)]
54#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
55pub struct SimulationOptionsBuilder {
56    /// Duration of the simulation, depending on the interval type.
57    pub duration: Option<u64>,
58
59    /// Number of users in the simulation.
60    pub total_users: Option<u64>,
61
62    /// Volatility level. 0.0 is no volatility, 1.0 is maximum volatility.
63    /// This is used to simulate the price volatility in the market.
64    pub market_volatility: Option<f64>,
65
66    /// Decimal precision for the simulation.
67    /// Default value is 4.
68    pub decimal_precision: Option<u32>,
69
70    /// Interval type for the simulation.
71    pub interval_type: Option<SimulationInterval>,
72
73    /// Transaction fee for each trade, in percentage.
74    pub transaction_fee_percentage: Option<f64>,
75
76    /// Rate at which users adopt the token.
77    pub adoption_rate: Option<f64>,
78
79    /// Valuation model for the token.
80    pub valuation_model: Option<ValuationModel>,
81}
82
83/// Valuation model for the token.
84#[derive(Debug, Clone, PartialEq)]
85#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
86pub enum ValuationModel {
87    /// Linear valuation model: valuation = users * initial_price.
88    Linear,
89
90    /// Exponential valuation model: valuation = initial_price * e^(users / factor).
91    /// The factor is a parameter that controls the rate of growth.
92    /// A higher factor will result in a slower growth rate.
93    Exponential(f64),
94}
95
96impl SimulationOptionsBuilder {
97    /// Create a new simulation options builder to configure the simulation.
98    ///
99    /// # Returns
100    ///
101    /// New simulation options builder.
102    pub fn new() -> Self {
103        SimulationOptionsBuilder::default()
104    }
105
106    /// Set the duration of the simulation.
107    ///
108    /// # Arguments
109    ///
110    /// * `duration` - Duration of the simulation.
111    ///
112    /// # Returns
113    ///
114    /// The simulation options builder.
115    pub fn duration(mut self, duration: u64) -> Self {
116        self.duration = Some(duration);
117        self
118    }
119
120    /// Set the total number of users in the simulation.
121    ///
122    /// # Arguments
123    ///
124    /// * `total_users` - Total number of users in the simulation.
125    ///
126    /// # Returns
127    ///
128    /// The simulation options builder.
129    pub fn total_users(mut self, total_users: u64) -> Self {
130        self.total_users = Some(total_users);
131        self
132    }
133
134    /// Set the market volatility level.
135    ///
136    /// # Arguments
137    ///
138    /// * `market_volatility` - Market volatility level.
139    ///
140    /// # Returns
141    ///
142    /// The simulation options builder.
143    pub fn market_volatility(mut self, market_volatility: f64) -> Self {
144        self.market_volatility = Some(market_volatility);
145        self
146    }
147
148    /// Set the decimal precision for the simulation.
149    ///
150    /// # Arguments
151    ///
152    /// * `decimal_precision` - Decimal precision for the simulation.
153    ///
154    /// # Returns
155    ///
156    /// The simulation options builder.
157    pub fn decimal_precision(mut self, decimal_precision: u32) -> Self {
158        self.decimal_precision = Some(decimal_precision);
159        self
160    }
161
162    /// Set the interval type for the simulation.
163    ///
164    /// # Arguments
165    ///
166    /// * `interval_type` - Interval type for the simulation.
167    ///
168    /// # Returns
169    ///
170    /// The simulation options builder.
171    pub fn interval_type(mut self, interval_type: SimulationInterval) -> Self {
172        self.interval_type = Some(interval_type);
173        self
174    }
175
176    /// Set the transaction fee for each trade.
177    ///
178    /// # Arguments
179    ///
180    /// * `transaction_fee_percentage` - Transaction fee for each trade, in percentage.
181    ///
182    /// # Returns
183    ///
184    /// The simulation options builder.
185    pub fn transaction_fee_percentage(mut self, transaction_fee: f64) -> Self {
186        self.transaction_fee_percentage = Some(transaction_fee);
187        self
188    }
189
190    /// Set the rate at which users adopt the token.
191    ///
192    /// # Arguments
193    ///
194    /// * `adoption_rate` - Rate at which users adopt the token.
195    ///
196    /// # Returns
197    ///
198    /// The simulation options builder.
199    pub fn adoption_rate(mut self, adoption_rate: f64) -> Self {
200        self.adoption_rate = Some(adoption_rate);
201        self
202    }
203
204    /// Set the valuation model for the token.
205    ///
206    /// # Arguments
207    ///
208    /// * `valuation_model` - Valuation model for the token.
209    ///
210    /// # Returns
211    ///
212    /// The simulation options builder.
213    pub fn valuation_model(mut self, valuation_model: ValuationModel) -> Self {
214        self.valuation_model = Some(valuation_model);
215        self
216    }
217
218    /// Build the simulation options.
219    ///
220    /// # Returns
221    ///
222    /// Built simulation options or an error if required fields are missing.
223    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}