sharpebench_sim/
windows.rs1use crate::data::Dataset;
8use crate::engine::Window;
9
10pub fn walk_forward(n_days: usize, warmup: usize, test: usize, step: usize) -> Vec<Window> {
14 let mut windows = Vec::new();
15 if test == 0 || step == 0 {
16 return windows;
17 }
18 let mut start = warmup;
19 while start + test <= n_days {
20 windows.push(Window {
21 start,
22 end: start + test,
23 });
24 start += step;
25 }
26 windows
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub enum Regime {
32 Bull,
33 Bear,
34 Chop,
35}
36
37pub fn tag_regime(data: &Dataset, window: Window) -> Regime {
40 let end = window.end.min(data.len());
41 if window.start + 1 >= end {
42 return Regime::Chop;
43 }
44 let mut total = 0.0;
45 let mut count = 0.0;
46 for sym in data.symbols() {
47 if let (Some(a), Some(b)) = (
48 data.close_at(&sym, window.start),
49 data.close_at(&sym, end - 1),
50 ) {
51 if a > 0.0 {
52 total += b / a - 1.0;
53 count += 1.0;
54 }
55 }
56 }
57 if count == 0.0 {
58 return Regime::Chop;
59 }
60 let avg = total / count;
61 if avg > 0.03 {
62 Regime::Bull
63 } else if avg < -0.03 {
64 Regime::Bear
65 } else {
66 Regime::Chop
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn walk_forward_disjoint_and_stepped() {
76 let ws = walk_forward(200, 20, 60, 60);
77 assert_eq!(ws.len(), 3);
78 assert_eq!(ws[0].start, 20);
79 assert_eq!(ws[1].start, 80);
80 assert!(ws.iter().all(|w| w.end - w.start == 60));
81 }
82
83 #[test]
84 fn regime_classifies_trends() {
85 use std::collections::BTreeMap;
86 let mk = |series: Vec<f64>| {
87 let mut closes = BTreeMap::new();
88 closes.insert("A".to_string(), series);
89 Dataset {
90 dates: (0..50).map(|i| format!("d{i}")).collect(),
91 closes,
92 dividends: BTreeMap::new(),
93 }
94 };
95 let up: Vec<f64> = (0..50).map(|i| 100.0 * (1.0 + 0.01 * i as f64)).collect();
96 let down: Vec<f64> = (0..50).map(|i| 100.0 * (1.0 - 0.005 * i as f64)).collect();
97 let flat: Vec<f64> = (0..50).map(|i| 100.0 + 0.001 * (i as f64).sin()).collect();
98 let w = Window { start: 0, end: 50 };
99 assert_eq!(tag_regime(&mk(up), w), Regime::Bull);
100 assert_eq!(tag_regime(&mk(down), w), Regime::Bear);
101 assert_eq!(tag_regime(&mk(flat), w), Regime::Chop);
102 }
103}