use kestrel_chartkit::indicator::bos_choch::BosChochEngine;
use kestrel_chartkit::indicator::wyckoff::{WyckoffBias, WyckoffPhase, WyckoffStateMachine};
use kestrel_chartkit::indicator::Indicator;
use kestrel_chartkit::synthetic::{
bos_choch_swing_bars, random_walk_bars, trending_bars, wyckoff_schematic_bars, SwingDirection,
WyckoffGeneratorConfig,
};
use kestrel_chartkit::{build_checked, QualifiedBar};
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== 1. Synthetic Random Walk & Trending Bars ===");
let seed = 42;
let walk = random_walk_bars(seed, 10, 100.0, 0.1, 0.5, 1000.0);
println!("Generated {} random walk bars (seed={seed}):", walk.len());
for (i, QualifiedBar { bar, quality }) in walk.iter().enumerate().take(5) {
println!(
" bar {i:>2}: O={:.2} H={:.2} L={:.2} C={:.2} V={:.0} (synthetic={}, vol_avail={})",
bar.open,
bar.high,
bar.low,
bar.close,
bar.volume,
quality.is_synthetic,
quality.volume_available
);
}
println!(" ... [{} more bars]", walk.len() - 5);
let trend = trending_bars(123, 8, 50.0, 0.75, 0.2, 500.0);
let start_c = trend.first().unwrap().bar.close;
let end_c = trend.last().unwrap().bar.close;
println!(
"\nGenerated 8 trending bars: start close={start_c:.2} -> end close={end_c:.2} (+{:.2})\n",
end_c - start_c
);
let mut rsi_params = HashMap::new();
rsi_params.insert("rsi_len".to_string(), 5.0);
let mut rsi = build_checked("rsi", &rsi_params)?;
println!("Streaming trending bars through RSI(5):");
for (i, qb) in trend.iter().enumerate() {
match rsi.on_bar(&qb.bar) {
Some(out) => println!(" bar {i}: close={:.2} RSI={:.2}", qb.bar.close, out.value),
None => println!(" bar {i}: close={:.2} RSI=<warming up>", qb.bar.close),
}
}
println!("\n=== 2. Calibrated Wyckoff Schematic Sequence ===");
let wyckoff_config = WyckoffGeneratorConfig {
center_price: 100.0,
range_lookback: 20,
spread: 2.0,
base_volume: 100.0,
};
let wyckoff_bars = wyckoff_schematic_bars(777, WyckoffBias::Accumulation, wyckoff_config);
println!(
"Generated {} bars for Wyckoff Accumulation schematic",
wyckoff_bars.len()
);
let mut wyckoff_machine = WyckoffStateMachine::new(20, 5.0, 3);
let mut prev_phase = WyckoffPhase::Undefined;
for (i, qb) in wyckoff_bars.iter().enumerate() {
wyckoff_machine.on_bar(&qb.bar);
let curr_phase = wyckoff_machine.phase();
if curr_phase != prev_phase && curr_phase != WyckoffPhase::Undefined {
println!(
" bar {i:>2}: Transition to Phase {:?} (close={:.2}, vol={:.0})",
curr_phase, qb.bar.close, qb.bar.volume
);
for alert in wyckoff_machine.alerts() {
println!(" Alert: [{}] {}", alert.kind, alert.note);
}
prev_phase = curr_phase;
}
}
let score = wyckoff_machine.score();
println!(
"Wyckoff Final: Bias={:?}, Phase={:?}, Cause Score={:.2}, Sequence Quality={:.2}\n",
wyckoff_machine.bias().unwrap(),
wyckoff_machine.phase(),
score.cause_score,
score.sequence_quality
);
println!("=== 3. Market Structure Break (BOS / CHoCH) ===");
let pivot_len = 3;
let swing_bars = bos_choch_swing_bars(999, SwingDirection::Bearish, pivot_len);
println!(
"Generated {} bars for Bearish Swing Breakout (pivot_len={pivot_len}):",
swing_bars.len()
);
let mut bos_engine = BosChochEngine::new(pivot_len);
for (i, qb) in swing_bars.iter().enumerate() {
if let Some(out) = bos_engine.on_bar(&qb.bar) {
let event_desc = if (out.value - 1.0).abs() < 1e-6 {
"Bullish BOS (+1.0)"
} else if (out.value - 2.0).abs() < 1e-6 {
"Bullish CHoCH (+2.0)"
} else if (out.value - (-1.0)).abs() < 1e-6 {
"Bearish BOS (-1.0)"
} else if (out.value - (-2.0)).abs() < 1e-6 {
"Bearish CHoCH (-2.0)"
} else {
"None (0.0)"
};
println!(
" bar {i:>2}: close={:.2} -> Event Code={:+.1} ({event_desc})",
qb.bar.close, out.value
);
for alert in bos_engine.alerts() {
println!(" Alert: [{}] {}", alert.kind, alert.note);
}
} else {
println!(
" bar {i:>2}: close={:.2} -> <warming up window>",
qb.bar.close
);
}
}
println!("\nSynthetic market patterns demonstration completed successfully.");
Ok(())
}