1#![allow(unused)]
2use rand::SeedableRng;
5use rand::rngs::StdRng;
6use rust_decimal::Decimal;
7use rust_decimal::prelude::FromPrimitive;
8use crate::algorithms::RandomWalkGenerator;
9use crate::config::GeneratorConfig;
10use crate::types::{OHLC, Tick};
11use std::time::{SystemTime, UNIX_EPOCH};
12
13#[cfg(feature = "regimes")]
14use crate::regimes::{RegimeDetector, RegimeState, RegimeConfig, RegimeTracker, VolatilityRegimeDetector, RegimeController, RegimeSchedule, ScheduleInfo};
15
16pub struct MarketDataGenerator {
18 rng: StdRng,
20 config: GeneratorConfig,
22 price_generator: RandomWalkGenerator,
24 current_timestamp: i64,
26 #[cfg(feature = "regimes")]
28 regime_detector: Option<Box<dyn RegimeDetector>>,
29 #[cfg(feature = "regimes")]
31 regime_tracker: Option<RegimeTracker>,
32 #[cfg(feature = "regimes")]
34 data_buffer: Vec<OHLC>,
35 #[cfg(feature = "regimes")]
37 regime_controller: Option<RegimeController>,
38}
39
40impl MarketDataGenerator {
41 pub fn new() -> Self {
43 Self::with_config(GeneratorConfig::default()).expect("Default config should be valid")
44 }
45
46 pub fn with_config(config: GeneratorConfig) -> Result<Self, String> {
48 config.validate()
50 .map_err(|e| format!("Invalid configuration: {e}"))?;
51
52 let rng = match config.seed {
54 Some(seed) => StdRng::seed_from_u64(seed),
55 None => StdRng::from_entropy(),
56 };
57
58 let price_generator = RandomWalkGenerator::new(config.clone())?;
60
61 let current_timestamp = SystemTime::now()
63 .duration_since(UNIX_EPOCH)
64 .map_err(|e| format!("Failed to get system time: {e}"))?
65 .as_millis() as i64;
66
67 Ok(Self {
68 rng,
69 config: config.clone(),
70 price_generator,
71 current_timestamp,
72 #[cfg(feature = "regimes")]
73 regime_detector: None,
74 #[cfg(feature = "regimes")]
75 regime_tracker: None,
76 #[cfg(feature = "regimes")]
77 data_buffer: Vec::with_capacity(100),
78 #[cfg(feature = "regimes")]
79 regime_controller: None,
80 })
81 }
82
83 pub fn generate_ohlc(&mut self) -> OHLC {
85 #[cfg(feature = "regimes")]
87 self.update_regime_controller();
88
89 let (open, high, low, close) = self.price_generator.generate_ohlc(&mut self.rng, 10);
91
92 let volume = self.price_generator.generate_volume(&mut self.rng);
94
95 let timestamp = self.current_timestamp;
97
98 self.current_timestamp += self.config.time_interval.millis() as i64;
100
101 let candle = OHLC::new(open, high, low, close, volume, timestamp);
102
103 #[cfg(feature = "regimes")]
105 self.update_regime_detection(&candle);
106
107 candle
108 }
109
110 #[deprecated(since = "0.2.0", note = "Use generate_ohlc() instead")]
112 pub fn generate_candle(&mut self) -> OHLC {
113 self.generate_ohlc()
114 }
115
116 pub fn generate_series(&mut self, count: usize) -> Vec<OHLC> {
118 let mut candles = Vec::with_capacity(count);
119 for _ in 0..count {
120 candles.push(self.generate_ohlc());
121 }
122 candles
123 }
124
125 pub fn generate_tick(&mut self) -> Tick {
127 let price = self.price_generator.next_price(&mut self.rng);
128 let volume = self.price_generator.generate_volume(&mut self.rng);
129 let timestamp = self.current_timestamp;
130
131 self.current_timestamp += 1000;
133
134 let spread = Decimal::from_f64(0.001).unwrap(); let half_spread = price * spread / Decimal::from(2);
137
138 Tick::with_spread(
139 price,
140 volume,
141 timestamp,
142 price - half_spread,
143 price + half_spread,
144 )
145 }
146
147 pub fn generate_ticks(&mut self, count: usize) -> Vec<Tick> {
149 let mut ticks = Vec::with_capacity(count);
150 for _ in 0..count {
151 ticks.push(self.generate_tick());
152 }
153 ticks
154 }
155
156 pub fn reset(&mut self) {
158 self.price_generator.reset();
159 self.current_timestamp = SystemTime::now()
160 .duration_since(UNIX_EPOCH)
161 .unwrap_or_default()
162 .as_millis() as i64;
163
164 if let Some(seed) = self.config.seed {
166 self.rng = StdRng::seed_from_u64(seed);
167 }
168 }
169
170 pub fn set_timestamp(&mut self, timestamp: i64) {
172 self.current_timestamp = timestamp;
173 }
174
175 pub fn config(&self) -> &GeneratorConfig {
177 &self.config
178 }
179
180 pub fn set_config(&mut self, config: GeneratorConfig) -> Result<(), String> {
182 config.validate()
183 .map_err(|e| format!("Invalid configuration: {e}"))?;
184
185 self.config = config.clone();
187
188 self.price_generator = RandomWalkGenerator::new(config)?;
190
191 if let Some(seed) = self.config.seed {
193 self.rng = StdRng::seed_from_u64(seed);
194 }
195
196 Ok(())
197 }
198
199 #[cfg(feature = "csv_export")]
201 pub fn generate_to_csv_ohlc<P: AsRef<std::path::Path>>(
202 &mut self,
203 count: usize,
204 path: P,
205 ) -> Result<(), Box<dyn std::error::Error>> {
206 let data = self.generate_series(count);
207 crate::export::to_csv_ohlc(&data, path)?;
208 Ok(())
209 }
210
211 #[cfg(feature = "csv_export")]
213 pub fn generate_to_csv_ticks<P: AsRef<std::path::Path>>(
214 &mut self,
215 count: usize,
216 path: P,
217 ) -> Result<(), Box<dyn std::error::Error>> {
218 let data = self.generate_ticks(count);
219 crate::export::to_csv_ticks(&data, path)?;
220 Ok(())
221 }
222
223 #[cfg(feature = "csv_export")]
225 pub fn stream_generate_to_csv_ohlc<P: AsRef<std::path::Path>>(
226 &mut self,
227 count: usize,
228 path: P,
229 ) -> Result<usize, Box<dyn std::error::Error>> {
230 use crate::export::csv::CsvExporter;
231
232 let exporter = CsvExporter::default();
233
234 let iter = (0..count).map(|_| self.generate_ohlc());
236
237 Ok(exporter.stream_ohlc(iter, path)?)
238 }
239
240 #[cfg(feature = "csv_export")]
242 pub fn stream_generate_to_csv_ticks<P: AsRef<std::path::Path>>(
243 &mut self,
244 count: usize,
245 path: P,
246 ) -> Result<usize, Box<dyn std::error::Error>> {
247 use crate::export::csv::CsvExporter;
248
249 let exporter = CsvExporter::default();
250
251 let iter = (0..count).map(|_| self.generate_tick());
253
254 Ok(exporter.stream_ticks(iter, path)?)
255 }
256
257}
258
259#[cfg(feature = "regimes")]
261impl MarketDataGenerator {
262 pub fn enable_volatility_regime_detection(&mut self, window_size: usize) {
266 self.regime_detector = Some(Box::new(VolatilityRegimeDetector::new(window_size)));
267 self.regime_tracker = Some(RegimeTracker::new(1000));
268 }
269
270 pub fn disable_regime_detection(&mut self) {
272 self.regime_detector = None;
273 self.regime_tracker = None;
274 self.data_buffer.clear();
275 }
276
277 pub fn current_regime(&self) -> Option<&RegimeState> {
279 self.regime_tracker.as_ref()?.current()
280 }
281
282 pub fn regime_analytics(&self) -> Option<RegimeAnalytics> {
284 let tracker = self.regime_tracker.as_ref()?;
285 Some(RegimeAnalytics {
286 current_regime: tracker.current().cloned(),
287 transitions: tracker.transitions,
288 average_duration: tracker.average_duration(),
289 regime_distribution: tracker.regime_distribution(),
290 })
291 }
292
293 fn update_regime_detection(&mut self, candle: &OHLC) {
295 self.data_buffer.push(candle.clone());
297
298 while self.data_buffer.len() > 200 {
300 self.data_buffer.remove(0);
301 }
302
303 if let Some(ref mut detector) = self.regime_detector {
305 let config = RegimeConfig::default();
306 if let Some(state) = detector.update(candle, &config) {
307 if let Some(ref mut tracker) = self.regime_tracker {
308 tracker.record(state);
309 }
310 }
311 }
312 }
313
314 pub fn generate_regime_aware_series(&mut self, count: usize, _regime_config: RegimeConfig) -> Vec<RegimeOHLC> {
316 let mut series = Vec::with_capacity(count);
317
318 for _ in 0..count {
319 let candle = self.generate_ohlc();
320 let current_regime = self.current_regime().cloned();
321 series.push(RegimeOHLC {
322 ohlc: candle,
323 regime_state: current_regime,
324 });
325 }
326
327 series
328 }
329
330 pub fn generate_controlled_regime_series(&mut self, count: usize) -> Vec<ControlledRegimeOHLC> {
332 let mut series = Vec::with_capacity(count);
333
334 for _ in 0..count {
335 let schedule_info = self.regime_control_info();
336 let candle = self.generate_ohlc();
337
338 series.push(ControlledRegimeOHLC {
339 ohlc: candle,
340 schedule_info: schedule_info.clone(),
341 });
342 }
343
344 series
345 }
346
347 pub fn data_buffer(&self) -> &[OHLC] {
349 &self.data_buffer
350 }
351
352 pub fn detect_regime_on_buffer(&mut self) -> Option<RegimeState> {
354 if let Some(ref mut detector) = self.regime_detector {
355 let config = RegimeConfig::default();
356 detector.detect(&self.data_buffer, &config)
357 } else {
358 None
359 }
360 }
361
362 pub fn enable_regime_control(&mut self, schedule: RegimeSchedule) {
364 let base_config = self.config.clone();
365 self.regime_controller = Some(RegimeController::new(schedule, base_config));
366 }
367
368 pub fn disable_regime_control(&mut self) {
370 self.regime_controller = None;
371 }
372
373 pub fn regime_control_info(&self) -> Option<ScheduleInfo> {
375 self.regime_controller.as_ref().map(|c| c.schedule_info())
376 }
377
378 pub fn force_regime(&mut self, regime: crate::regimes::MarketRegime, duration: usize, transition_duration: Option<usize>) {
380 if let Some(ref mut controller) = self.regime_controller {
381 controller.force_regime(regime, duration, transition_duration);
382 }
383 }
384
385 pub fn add_regime_segment(&mut self, segment: crate::regimes::RegimeSegment) {
387 if let Some(ref mut controller) = self.regime_controller {
388 controller.add_segment(segment);
389 }
390 }
391
392 pub fn reset_regime_schedule(&mut self) {
394 if let Some(ref mut controller) = self.regime_controller {
395 controller.reset();
396 }
397 }
398
399 fn update_regime_controller(&mut self) {
401 if let Some(ref mut controller) = self.regime_controller {
402 controller.advance();
403
404 let new_config = controller.current_config().clone();
406 if let Ok(new_price_generator) = RandomWalkGenerator::new(new_config.clone()) {
407 self.config = new_config;
408 self.price_generator = new_price_generator;
409 }
410 }
411 }
412}
413
414#[cfg(feature = "regimes")]
416#[derive(Debug, Clone)]
417pub struct RegimeOHLC {
418 pub ohlc: OHLC,
420 pub regime_state: Option<RegimeState>,
422}
423
424#[cfg(feature = "regimes")]
426#[derive(Debug, Clone)]
427pub struct ControlledRegimeOHLC {
428 pub ohlc: OHLC,
430 pub schedule_info: Option<ScheduleInfo>,
432}
433
434#[cfg(feature = "regimes")]
436#[derive(Debug, Clone)]
437pub struct RegimeAnalytics {
438 pub current_regime: Option<RegimeState>,
440 pub transitions: usize,
442 pub average_duration: Decimal,
444 pub regime_distribution: (Decimal, Decimal, Decimal),
446}
447
448impl Default for MarketDataGenerator {
449 fn default() -> Self {
450 Self::new()
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457 use crate::TrendDirection;
458 use crate::config::ConfigBuilder;
459
460 #[test]
461 fn test_generator_creation() {
462 let generator = MarketDataGenerator::new();
463 assert_eq!(generator.config().starting_price, Decimal::from_f64(100.0).unwrap());
464 }
465
466 #[test]
467 fn test_generator_with_config() {
468 let config = ConfigBuilder::new()
469 .starting_price_f64(50.0)
470 .volatility_f64(0.03)
471 .seed(42)
472 .build()
473 .unwrap();
474
475 let generator = MarketDataGenerator::with_config(config);
476 assert!(generator.is_ok());
477 }
478
479 #[test]
480 fn test_candle_generation() {
481 let config = ConfigBuilder::new()
482 .seed(42)
483 .build()
484 .unwrap();
485
486 let mut generator = MarketDataGenerator::with_config(config).unwrap();
487 let candle = generator.generate_ohlc();
488
489 assert!(candle.is_valid());
490 assert!(candle.volume.value() > 0);
491 }
492
493 #[test]
494 fn test_series_generation() {
495 let config = ConfigBuilder::new()
496 .seed(42)
497 .num_points(10)
498 .build()
499 .unwrap();
500
501 let mut generator = MarketDataGenerator::with_config(config).unwrap();
502 let series = generator.generate_series(10);
503
504 assert_eq!(series.len(), 10);
505
506 for i in 1..series.len() {
508 assert!(series[i].timestamp > series[i-1].timestamp);
509 }
510 }
511
512 #[test]
513 fn test_tick_generation() {
514 let mut generator = MarketDataGenerator::new();
515 let tick = generator.generate_tick();
516
517 assert!(tick.price > Decimal::ZERO);
518 assert!(tick.volume.value() > 0);
519 assert!(tick.bid.is_some());
520 assert!(tick.ask.is_some());
521
522 if let (Some(bid), Some(ask)) = (tick.bid, tick.ask) {
523 assert!(ask > bid); }
525 }
526
527 #[test]
528 fn test_deterministic_generation() {
529 let config = ConfigBuilder::new()
530 .seed(42)
531 .build()
532 .unwrap();
533
534 let mut gen1 = MarketDataGenerator::with_config(config.clone()).unwrap();
535 let mut gen2 = MarketDataGenerator::with_config(config).unwrap();
536
537 let candles1 = gen1.generate_series(5);
538 let candles2 = gen2.generate_series(5);
539
540 for (c1, c2) in candles1.iter().zip(candles2.iter()) {
542 assert_eq!(c1.open, c2.open);
543 assert_eq!(c1.close, c2.close);
544 }
545 }
546
547 #[test]
548 fn test_reset() {
549 let config = ConfigBuilder::new()
550 .seed(42)
551 .starting_price_f64(100.0)
552 .build()
553 .unwrap();
554
555 let mut generator = MarketDataGenerator::with_config(config).unwrap();
556
557 let candle1 = generator.generate_ohlc();
558 generator.reset();
559 let candle2 = generator.generate_ohlc();
560
561 assert_eq!(candle1.open, candle2.open);
563 }
564
565 #[cfg(feature = "regimes")]
566 #[test]
567 fn test_regime_control_basic() {
568 use crate::regimes::{RegimeSchedule, RegimeSegment, MarketRegime};
569 use crate::config::TrendDirection;
570
571 let config = ConfigBuilder::new()
572 .seed(42)
573 .build()
574 .unwrap();
575
576 let mut generator = MarketDataGenerator::with_config(config).unwrap();
577
578 let segments = vec![
580 RegimeSegment::new(MarketRegime::Bull, 5),
581 RegimeSegment::new(MarketRegime::Bear, 5),
582 ];
583 let schedule = RegimeSchedule::new(segments);
584
585 generator.enable_regime_control(schedule);
586
587 let bull_candles = generator.generate_series(5);
589 let info = generator.regime_control_info().unwrap();
590 assert_eq!(info.current_regime, Some(MarketRegime::Bear)); let bear_candles = generator.generate_series(5);
594 let info = generator.regime_control_info().unwrap();
595 assert!(info.is_complete); assert_eq!(bull_candles.len(), 5);
599 assert_eq!(bear_candles.len(), 5);
600
601 for candle in &bull_candles {
602 assert!(candle.is_valid());
603 }
604 for candle in &bear_candles {
605 assert!(candle.is_valid());
606 }
607 }
608
609 #[cfg(feature = "regimes")]
610 #[test]
611 fn test_regime_control_parameter_changes() {
612 use crate::regimes::{RegimeSchedule, RegimeSegment, MarketRegime};
613
614 let config = ConfigBuilder::new()
615 .seed(42)
616 .trend_f64(TrendDirection::Sideways, 0.001) .build()
618 .unwrap();
619
620 let mut generator = MarketDataGenerator::with_config(config).unwrap();
621
622 let segments = vec![
624 RegimeSegment::new(MarketRegime::Bull, 3),
625 RegimeSegment::new(MarketRegime::Sideways, 3),
626 ];
627 let schedule = RegimeSchedule::new(segments);
628
629 generator.enable_regime_control(schedule);
630
631 let config1 = generator.config().clone();
633 generator.generate_ohlc();
634 generator.generate_ohlc();
635
636 assert_eq!(generator.config().trend_direction, TrendDirection::Bullish);
638
639 generator.generate_ohlc();
641
642 let config2 = generator.config().clone();
644 assert_eq!(config2.trend_direction, TrendDirection::Sideways);
645 assert_ne!(config1.trend_strength, config2.trend_strength); }
647
648 #[cfg(feature = "regimes")]
649 #[test]
650 fn test_regime_control_force_regime() {
651 use crate::regimes::{RegimeSchedule, RegimeSegment, MarketRegime};
652
653 let config = ConfigBuilder::new()
654 .seed(42)
655 .build()
656 .unwrap();
657
658 let mut generator = MarketDataGenerator::with_config(config).unwrap();
659
660 let segments = vec![
662 RegimeSegment::new(MarketRegime::Bull, 10),
663 ];
664 let schedule = RegimeSchedule::new(segments);
665 generator.enable_regime_control(schedule);
666
667 let info = generator.regime_control_info().unwrap();
669 assert_eq!(info.current_regime, Some(MarketRegime::Bull));
670
671 generator.force_regime(MarketRegime::Bear, 5, None);
673
674 let info = generator.regime_control_info().unwrap();
676 assert_eq!(info.current_regime, Some(MarketRegime::Bear));
677 }
678
679 #[cfg(feature = "regimes")]
680 #[test]
681 fn test_controlled_regime_series() {
682 use crate::regimes::{RegimeSchedule, RegimeSegment, MarketRegime};
683
684 let config = ConfigBuilder::new()
685 .seed(42)
686 .build()
687 .unwrap();
688
689 let mut generator = MarketDataGenerator::with_config(config).unwrap();
690
691 let segments = vec![
692 RegimeSegment::new(MarketRegime::Bull, 3),
693 RegimeSegment::new(MarketRegime::Bear, 2),
694 ];
695 let schedule = RegimeSchedule::new(segments);
696 generator.enable_regime_control(schedule);
697
698 let series = generator.generate_controlled_regime_series(5);
700
701 assert_eq!(series.len(), 5);
702
703 for i in 0..3 {
705 if let Some(ref info) = series[i].schedule_info {
706 assert_eq!(info.current_regime, Some(MarketRegime::Bull));
707 }
708 }
709
710 for i in 3..5 {
712 if let Some(ref info) = series[i].schedule_info {
713 assert_eq!(info.current_regime, Some(MarketRegime::Bear));
714 }
715 }
716 }
717
718 #[cfg(feature = "regimes")]
719 #[test]
720 fn test_regime_schedule_reset() {
721 use crate::regimes::{RegimeSchedule, RegimeSegment, MarketRegime};
722
723 let config = ConfigBuilder::new()
724 .seed(42)
725 .build()
726 .unwrap();
727
728 let mut generator = MarketDataGenerator::with_config(config).unwrap();
729
730 let segments = vec![
731 RegimeSegment::new(MarketRegime::Bull, 2),
732 RegimeSegment::new(MarketRegime::Bear, 2),
733 ];
734 let schedule = RegimeSchedule::new(segments);
735 generator.enable_regime_control(schedule);
736
737 generator.generate_series(4);
739 let info = generator.regime_control_info().unwrap();
740 assert!(info.is_complete);
741
742 generator.reset_regime_schedule();
744 let info = generator.regime_control_info().unwrap();
745 assert!(!info.is_complete);
746 assert_eq!(info.current_regime, Some(MarketRegime::Bull)); }
748}