Status and positions linked

This commit is contained in:
2026-08-01 23:01:24 +02:00
parent 8f4c984486
commit cab27466f2
6 changed files with 41 additions and 29 deletions
+1
View File
@@ -66,6 +66,7 @@ pub struct EngineStatus {
pub perps_equity: Decimal, pub perps_equity: Decimal,
pub strategy_mode: Mode, pub strategy_mode: Mode,
pub strategy_state: ItemState, pub strategy_state: ItemState,
pub positions: Vec<Position>,
} }
impl std::fmt::Display for MarketTrend { impl std::fmt::Display for MarketTrend {
-3
View File
@@ -11,9 +11,6 @@ pub enum TerminalServerMessage {
// WatchList // WatchList
WatchListUpdated(Vec<MarketItem>), WatchListUpdated(Vec<MarketItem>),
// Positions
PositionsUpdated(Vec<Position>),
// Configuration // Configuration
ConfigUpdated(EngineConfig), ConfigUpdated(EngineConfig),
+1
View File
@@ -69,6 +69,7 @@ impl Engine {
perps_equity: 0.into(), perps_equity: 0.into(),
strategy_mode: Mode::Auto, strategy_mode: Mode::Auto,
strategy_state: ItemState::Stopped, strategy_state: ItemState::Stopped,
positions: Vec::new(),
})), })),
watch_list: Arc::new(Mutex::new(WatchList { watch_list: Arc::new(Mutex::new(WatchList {
name_to_index: HashMap::new(), name_to_index: HashMap::new(),
+8 -9
View File
@@ -227,13 +227,10 @@ impl TerminalServer {
if let Some(acc) = engine.accounts.lock().await.get_active() { if let Some(acc) = engine.accounts.lock().await.get_active() {
match client.clearinghouse_state(acc.address, None).await { match client.clearinghouse_state(acc.address, None).await {
Ok(state) => { Ok(state) => {
engine.status.lock().await.perps_equity = let mut status = engine.status.lock().await;
state.margin_summary.account_value;
engine.update_status().await?; status.perps_equity = state.margin_summary.account_value;
status.positions = state
self.broadcast(TerminalServerMessage::PositionsUpdated(
state
.asset_positions .asset_positions
.into_iter() .into_iter()
.map(|position| Position { .map(|position| Position {
@@ -242,9 +239,11 @@ impl TerminalServer {
entry_price: position.position.entry_px.unwrap_or_default(), entry_price: position.position.entry_px.unwrap_or_default(),
pnl: position.position.unrealized_pnl, pnl: position.position.unrealized_pnl,
}) })
.collect(), .collect();
))
.await?; drop(status);
engine.update_status().await?;
} }
Err(e) => { Err(e) => {
self.error("orders", &format!("Unable to get open orders: {e}")) self.error("orders", &format!("Unable to get open orders: {e}"))
+24 -3
View File
@@ -33,7 +33,6 @@ pub struct PulseTradeApp {
status: State<Option<EngineStatus>>, status: State<Option<EngineStatus>>,
watch_list: State<Vec<MarketItem>>, watch_list: State<Vec<MarketItem>>,
active_positions: State<Vec<Position>>,
logs: State<Vec<EventLog>>, logs: State<Vec<EventLog>>,
signals: State<Vec<SignalStatus>>, signals: State<Vec<SignalStatus>>,
inspect: State<InspectTarget>, inspect: State<InspectTarget>,
@@ -128,7 +127,10 @@ impl App for PulseTradeApp {
( (
LayoutItem::Widget(Size::Flex(1)), LayoutItem::Widget(Size::Flex(1)),
Box::new( Box::new(
advanced_draw(&self.scroll, 1, "POSITIONS", &self.active_positions).await, advanced_draw_map(&self.scroll, 1, "POSITIONS", &self.status, |status| {
&status.positions
})
.await,
), ),
), ),
( (
@@ -177,7 +179,6 @@ async fn main() -> tokio::io::Result<()> {
command: ctx.use_state(InputState::new()), command: ctx.use_state(InputState::new()),
scroll: ctx.use_state(ScrollState(1, [0; 7])), scroll: ctx.use_state(ScrollState(1, [0; 7])),
watch_list: ctx.use_state(Vec::new()), watch_list: ctx.use_state(Vec::new()),
active_positions: ctx.use_state(Vec::new()),
signals: ctx.use_state(Vec::new()), signals: ctx.use_state(Vec::new()),
logs: ctx.use_state(Vec::new()), logs: ctx.use_state(Vec::new()),
inspect: ctx.use_state(InspectTarget::None), inspect: ctx.use_state(InspectTarget::None),
@@ -190,6 +191,26 @@ async fn main() -> tokio::io::Result<()> {
Ok(()) Ok(())
} }
pub async fn advanced_draw_map<const N: usize, T, B: Formatted>(
scroll: &State<ScrollState<N>>,
index: usize,
title: &'static str,
state: &State<Option<T>>,
m: impl for<'a> FnOnce(&'a T) -> &'a B,
) -> ScrollText {
let scroll = scroll.lock().await;
scroll.scroll(
index,
format!(" {}{title}\x1b[0m", scroll.get_selected(index)),
if let Some(state) = &*state.lock().await {
apply_padding(m(state).get_formatted()).join("\n")
} else {
" Loading..".to_string()
},
)
}
pub async fn advanced_draw<const N: usize, T: Formatted>( pub async fn advanced_draw<const N: usize, T: Formatted>(
scroll: &State<ScrollState<N>>, scroll: &State<ScrollState<N>>,
index: usize, index: usize,
-7
View File
@@ -46,7 +46,6 @@ impl TerminalClient {
let reader = reader.expect("Reader failed to swap"); let reader = reader.expect("Reader failed to swap");
let watch_list = app.watch_list.clone(); let watch_list = app.watch_list.clone();
let active_positions = app.active_positions.clone();
let logs = app.logs.clone(); let logs = app.logs.clone();
let signals = app.signals.clone(); let signals = app.signals.clone();
let market_overview = app.config.clone(); let market_overview = app.config.clone();
@@ -57,7 +56,6 @@ impl TerminalClient {
if let Err(v) = Self::run_client( if let Err(v) = Self::run_client(
reader, reader,
watch_list, watch_list,
active_positions,
logs, logs,
signals, signals,
market_overview, market_overview,
@@ -99,7 +97,6 @@ impl TerminalClient {
mut reader: OwnedReadHalf, mut reader: OwnedReadHalf,
watch_list: State<Vec<MarketItem>>, watch_list: State<Vec<MarketItem>>,
active_positions: State<Vec<Position>>,
logs: State<Vec<EventLog>>, logs: State<Vec<EventLog>>,
signals: State<Vec<SignalStatus>>, signals: State<Vec<SignalStatus>>,
config: State<Option<EngineConfig>>, config: State<Option<EngineConfig>>,
@@ -127,10 +124,6 @@ impl TerminalClient {
*watch_list.lock().await = v; *watch_list.lock().await = v;
} }
TerminalServerMessage::PositionsUpdated(v) => {
*active_positions.lock().await = v;
}
TerminalServerMessage::ConfigUpdated(v) => { TerminalServerMessage::ConfigUpdated(v) => {
*config.lock().await = Some(v); *config.lock().await = Some(v);
} }