From 72901540258ba56b2e342d5f02d76bb6e7f1000e Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 25 Jul 2026 18:20:22 +0200 Subject: [PATCH] Strategy formatting --- pulse-wire/src/terminal.rs | 19 +++++++++++ src/terminal/formatting.rs | 66 ++++++++++++++++++++++++++++++-------- src/terminal/main.rs | 27 +++++++++++++++- 3 files changed, 97 insertions(+), 15 deletions(-) diff --git a/pulse-wire/src/terminal.rs b/pulse-wire/src/terminal.rs index 16e422b..5b26c2c 100644 --- a/pulse-wire/src/terminal.rs +++ b/pulse-wire/src/terminal.rs @@ -125,3 +125,22 @@ impl std::fmt::Display for AlertLevel { } } } + +impl std::fmt::Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Auto => write!(f, "\x1b[96mAUTO\x1b[0m"), + Self::Manual => write!(f, "\x1b[97mMANUAL\x1b[0m"), + } + } +} + +impl std::fmt::Display for ItemState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Running => write!(f, "\x1b[92mRUNNING\x1b[0m"), + Self::Off => write!(f, "\x1b[90mOFF\x1b[0m"), + Self::Error => write!(f, "\x1b[91mERROR\x1b[0m"), + } + } +} diff --git a/src/terminal/formatting.rs b/src/terminal/formatting.rs index 66190b3..0978493 100644 --- a/src/terminal/formatting.rs +++ b/src/terminal/formatting.rs @@ -110,16 +110,16 @@ impl Formatted for Position { } } -struct Property(&'static str, String); +struct Pair<'a>(&'a str, &'a str); impl Formatted for MarketOverview { fn get_formatted(&self) -> Vec { let mut o = vec![ - Property("TREND", format!("{}", self.trend)), - Property("VOLATILITY", format!("{}", self.volatility)), - Property( + Pair("TREND", &format!("{}", self.trend)), + Pair("VOLATILITY", &format!("{}", self.volatility)), + Pair( "PRESSURE", - if self.pressure.is_sign_positive() { + &if self.pressure.is_sign_positive() { format!("\x1b[32m{:.3}\x1b[0m", self.pressure) } else { format!("\x1b[31m{:.3}\x1b[0m", self.pressure) @@ -140,21 +140,44 @@ impl Formatted for MarketOverview { impl Formatted for Status { fn get_formatted(&self) -> Vec { vec![ - Property("Feed", format!("{:?}", self.feed)), - Property("Exchange", self.exchange.clone()), - Property("DEX", self.dex.clone()), - Property("Latency", format!("{} ms", self.latency)), + Pair("Feed", &format!("{:?}", self.feed)), + Pair("Exchange", &self.exchange.clone()), + Pair("DEX", &self.dex.clone()), + Pair("Latency", &format!("{} ms", self.latency)), ] .get_formatted() } } -impl Formatted for Property { +impl<'a> Formatted for Pair<'a> { fn get_formatted(&self) -> Vec { - vec![self.0.to_string(), self.1.clone()] + vec![self.0.to_string(), self.1.to_string()] } } +fn visible_len(s: &str) -> usize { + let mut len = 0; + let mut chars = s.chars().peekable(); + + while let Some(c) = chars.next() { + if c == '\x1b' { + if chars.peek() == Some(&'[') { + chars.next(); + + while let Some(c) = chars.next() { + if c.is_ascii_alphabetic() { + break; + } + } + } + } else { + len += c.len_utf8(); + } + } + + len +} + impl Formatted for Vec { fn get_formatted(&self) -> Vec { let mut output = Vec::new(); @@ -171,7 +194,7 @@ impl Formatted for Vec { for row in &rows { for (i, col) in row.iter().enumerate() { - widths[i] = widths[i].max(col.len()); + widths[i] = widths[i].max(visible_len(col)); } } @@ -181,7 +204,8 @@ impl Formatted for Vec { for (col_idx, col) in row.iter().enumerate() { let width = widths[col_idx]; - row_out.push_str(&format!("{: Formatted for Vec { impl Formatted for Strategy { fn get_formatted(&self) -> Vec { - vec![format!("1"), format!("2")] + vec![ + Pair("", ""), + Pair("\x1b[2mName\x1b[0m", "\x1b[2mRisk\x1b[0m"), + Pair(&self.strategy.name.to_string(), &self.risk.name.to_string()), + Pair("", ""), + Pair("\x1b[2mMode\x1b[0m", "\x1b[2mState\x1b[0m"), + Pair(&self.mode.to_string(), &self.state.to_string()), + Pair("", ""), + Pair("\x1b[2mCooldown\x1b[0m", "\x1b[2mTimeframes\x1b[0m"), + Pair( + &format!("{:?} ({:?} rec)", self.cooldown, self.risk.cooldown), + &format!("{:?}", self.strategy.timeframes), + ), + ] + .get_formatted() } } diff --git a/src/terminal/main.rs b/src/terminal/main.rs index 1a3c8e4..5555e58 100644 --- a/src/terminal/main.rs +++ b/src/terminal/main.rs @@ -181,7 +181,32 @@ async fn main() -> tokio::io::Result<()> { signals: ctx.use_state(Vec::new()), logs: ctx.use_state(Vec::new()), inspect: ctx.use_state(InspectTarget::None), - strategy: ctx.use_state(None), + strategy: ctx.use_state(Some(Strategy { + strategy: StrategyManifest { + name: "Liquidity Sweep".to_string(), + description: + "Detects liquidity grabs around key support and resistance levels." + .to_string(), + author: "Klesty Selimaj".to_string(), + version: "1.0.0".to_string(), + + timeframes: vec![TimeFrame::M5, TimeFrame::M15, TimeFrame::H1], + }, + + risk: RiskManifest { + name: "Aggressive".to_string(), + description: "High-risk profile with larger position sizing.".to_string(), + author: "Klesty Selimaj".to_string(), + version: "1.0.0".to_string(), + + max_loss: 5, + cooldown: TimeFrame::M15, + }, + + mode: Mode::Auto, + state: ItemState::Running, + cooldown: TimeFrame::M15, + })), status: ctx.use_state(None), }) })