use chrono::{DateTime, Utc};
#[derive(Debug, Clone, PartialEq, Default)]
pub enum ReplayAction {
#[default]
None,
Play,
Pause,
TogglePlayPause,
Stop,
Reset,
StepForward,
StepBackward,
StepForwardN(usize),
StepBackwardN(usize),
JumpToBar(usize),
JumpToDate(DateTime<Utc>),
JumpToStart,
JumpToEnd,
JumpToPercent(f32),
SetSpeed(f32),
SpeedUp,
SlowDown,
EnterReplayMode,
ExitReplayMode,
ToggleReplayMode,
LoadData {
symbol: String,
start: Option<DateTime<Utc>>,
end: Option<DateTime<Utc>>,
},
UnloadData,
SetStartDate(DateTime<Utc>),
SetEndDate(DateTime<Utc>),
SetDateRange {
start: DateTime<Utc>,
end: DateTime<Utc>,
},
AddMarker {
label: Option<String>,
color: Option<[u8; 4]>,
},
RemoveMarker(usize),
ClearMarkers,
EnableTradingSimulation,
DisableTradingSimulation,
ResetTradingSimulation,
}
impl ReplayAction {
pub fn affects_playback(&self) -> bool {
matches!(
self,
ReplayAction::Play
| ReplayAction::Pause
| ReplayAction::TogglePlayPause
| ReplayAction::Stop
| ReplayAction::SetSpeed(_)
| ReplayAction::SpeedUp
| ReplayAction::SlowDown
)
}
pub fn affects_pos(&self) -> bool {
matches!(
self,
ReplayAction::StepForward
| ReplayAction::StepBackward
| ReplayAction::StepForwardN(_)
| ReplayAction::StepBackwardN(_)
| ReplayAction::JumpToBar(_)
| ReplayAction::JumpToDate(_)
| ReplayAction::JumpToStart
| ReplayAction::JumpToEnd
| ReplayAction::JumpToPercent(_)
)
}
pub fn affects_mode(&self) -> bool {
matches!(
self,
ReplayAction::EnterReplayMode
| ReplayAction::ExitReplayMode
| ReplayAction::ToggleReplayMode
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum ReplaySpeed {
Slowest,
Slower,
Slow,
#[default]
Normal,
Fast,
Faster,
VeryFast,
Fastest,
Turbo,
Max,
Custom(f32),
}
impl ReplaySpeed {
pub fn multiplier(&self) -> f32 {
match self {
ReplaySpeed::Slowest => 0.1,
ReplaySpeed::Slower => 0.25,
ReplaySpeed::Slow => 0.5,
ReplaySpeed::Normal => 1.0,
ReplaySpeed::Fast => 2.0,
ReplaySpeed::Faster => 5.0,
ReplaySpeed::VeryFast => 10.0,
ReplaySpeed::Fastest => 25.0,
ReplaySpeed::Turbo => 50.0,
ReplaySpeed::Max => 100.0,
ReplaySpeed::Custom(v) => *v,
}
}
pub fn faster(&self) -> Self {
match self {
ReplaySpeed::Slowest => ReplaySpeed::Slower,
ReplaySpeed::Slower => ReplaySpeed::Slow,
ReplaySpeed::Slow => ReplaySpeed::Normal,
ReplaySpeed::Normal => ReplaySpeed::Fast,
ReplaySpeed::Fast => ReplaySpeed::Faster,
ReplaySpeed::Faster => ReplaySpeed::VeryFast,
ReplaySpeed::VeryFast => ReplaySpeed::Fastest,
ReplaySpeed::Fastest => ReplaySpeed::Turbo,
ReplaySpeed::Turbo | ReplaySpeed::Max => ReplaySpeed::Max,
ReplaySpeed::Custom(v) => ReplaySpeed::Custom((*v * 2.0).min(100.0)),
}
}
pub fn slower(&self) -> Self {
match self {
ReplaySpeed::Max => ReplaySpeed::Turbo,
ReplaySpeed::Turbo => ReplaySpeed::Fastest,
ReplaySpeed::Fastest => ReplaySpeed::VeryFast,
ReplaySpeed::VeryFast => ReplaySpeed::Faster,
ReplaySpeed::Faster => ReplaySpeed::Fast,
ReplaySpeed::Fast => ReplaySpeed::Normal,
ReplaySpeed::Normal => ReplaySpeed::Slow,
ReplaySpeed::Slow => ReplaySpeed::Slower,
ReplaySpeed::Slower | ReplaySpeed::Slowest => ReplaySpeed::Slowest,
ReplaySpeed::Custom(v) => ReplaySpeed::Custom((*v / 2.0).max(0.1)),
}
}
pub fn label(&self) -> String {
match self {
ReplaySpeed::Custom(v) => format!("{v:.1}x"),
_ => format!("{:.1}x", self.multiplier()),
}
}
pub fn presets() -> &'static [ReplaySpeed] {
&[
ReplaySpeed::Slowest,
ReplaySpeed::Slower,
ReplaySpeed::Slow,
ReplaySpeed::Normal,
ReplaySpeed::Fast,
ReplaySpeed::Faster,
ReplaySpeed::VeryFast,
ReplaySpeed::Fastest,
ReplaySpeed::Turbo,
ReplaySpeed::Max,
]
}
}
impl From<f32> for ReplaySpeed {
fn from(value: f32) -> Self {
for preset in Self::presets() {
if (preset.multiplier() - value).abs() < 0.01 {
return *preset;
}
}
ReplaySpeed::Custom(value)
}
}