From f9f218ad802445320202d4f429ad3f203736b039 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 2 Aug 2026 00:51:12 +0200 Subject: [PATCH] Signal execution --- src/engine/engine/execution.rs | 192 +++++++++++++++------------------ src/engine/engine/strategy.rs | 5 +- 2 files changed, 88 insertions(+), 109 deletions(-) diff --git a/src/engine/engine/execution.rs b/src/engine/engine/execution.rs index e8f3b51..db94da3 100644 --- a/src/engine/engine/execution.rs +++ b/src/engine/engine/execution.rs @@ -6,121 +6,103 @@ use pulse_sdk::prelude::*; use crate::engine::Engine; impl Engine { - pub async fn execute_signal(&self, signal: &Signal) -> tokio::io::Result<()> { + pub async fn execute_signal(&self, signal: &Signal) -> anyhow::Result<()> { let client = hypercore::mainnet(); let accounts = self.accounts.lock().await; - if let Some(acc) = accounts.get_active() { - let Some(asset_id) = self - .watch_list - .lock() - .await - .name_to_index - .get(&signal.symbol) - .cloned() - else { - self.terminal_server - .error( - "self::order", - &format!( - "Invalid Symbol: {:?}, Unable to get asset id", - signal.symbol - ), - ) - .await?; + let acc = accounts + .get_active() + .ok_or_else(|| anyhow::anyhow!("Unable to get active account"))?; - return Ok(()); - }; + let Some(asset_id) = self + .watch_list + .lock() + .await + .name_to_index + .get(&signal.symbol) + .cloned() + else { + return Err(anyhow::anyhow!( + "Invalid Symbol: {:?}, Unable to get asset id", + signal.symbol + )); + }; - let order_ids = self.risk_engine.create_order(signal).await?; + let engine_order = self.risk_engine.create_order(signal).await?; - println!("{order_ids:?}"); + let order = BatchOrder { + orders: vec![ + OrderRequest { + asset: asset_id, + is_buy: matches!(signal.side, Side::Bid), + limit_px: signal.entry_price, + sz: engine_order.size, + reduce_only: false, + order_type: OrderTypePlacement::Limit { + tif: TimeInForce::Gtc, + }, + cloid: engine_order.entry, + }, + OrderRequest { + asset: asset_id, + is_buy: matches!(signal.side, Side::Bid), + limit_px: signal.entry_price, + sz: engine_order.size, + reduce_only: true, + order_type: OrderTypePlacement::Trigger { + is_market: true, + trigger_px: signal.take_profit, + tpsl: hypercore::TpSl::Tp, + }, + cloid: engine_order.take_profit, + }, + OrderRequest { + asset: asset_id, + is_buy: matches!(signal.side, Side::Bid), + limit_px: signal.entry_price, + sz: engine_order.size, + reduce_only: true, + order_type: OrderTypePlacement::Trigger { + is_market: true, + trigger_px: signal.stop_loss, + tpsl: hypercore::TpSl::Sl, + }, + cloid: engine_order.stop_loss, + }, + ], + grouping: hypercore::OrderGrouping::Na, + builder: None, + }; - // let order = BatchOrder { - // orders: vec![ - // OrderRequest { - // asset: asset_id, - // is_buy: matches!(signal.side, Side::Bid), - // limit_px: signal.entry_price, - // sz: 0.into(), - // reduce_only: false, - // order_type: OrderTypePlacement::Limit { - // tif: TimeInForce::Gtc, - // }, - // cloid: order_ids.entry, - // }, - // OrderRequest { - // asset: asset_id, - // is_buy: matches!(signal.side, Side::Bid), - // limit_px: signal.entry_price, - // sz: 0.into(), - // reduce_only: true, - // order_type: OrderTypePlacement::Trigger { - // is_market: true, - // trigger_px: signal.take_profit, - // tpsl: hypercore::TpSl::Tp, - // }, - // cloid: order_ids.take_profit, - // }, - // OrderRequest { - // asset: asset_id, - // is_buy: matches!(signal.side, Side::Bid), - // limit_px: signal.entry_price, - // sz: 0.into(), - // reduce_only: true, - // order_type: OrderTypePlacement::Trigger { - // is_market: true, - // trigger_px: signal.stop_loss, - // tpsl: hypercore::TpSl::Sl, - // }, - // cloid: order_ids.stop_loss, - // }, - // ], - // grouping: hypercore::OrderGrouping::Na, - // builder: None, - // }; + let nonce = chrono::Utc::now().timestamp_millis() as u64; - // let nonce = chrono::Utc::now().timestamp_millis() as u64; + match client + .place(&acc.private_key.0, order, nonce, None, None) + .await + { + Ok(o) if o.iter().any(|o| matches!(o, OrderResponseStatus::Error(_))) => { + self.risk_engine.order_placed(engine_order).await; + } - // match client - // .place(&acc.private_key.0, order, nonce, None, None) - // .await - // { - // Ok(o) if o.iter().any(|o| matches!(o, OrderResponseStatus::Error(_))) => { - // self.risk_engine.order_placed(order_ids).await; - // } + Ok(e) => { + return Err(anyhow::anyhow!( + "order rejected: {}", + e.into_iter() + .filter_map(|res| { + if let OrderResponseStatus::Error(e) = res { + Some(e) + } else { + None + } + }) + .collect::>() + .join(", ") + )); + } - // Ok(e) => { - // self.terminal_server - // .error( - // "self::order", - // &format!( - // "order rejected: {}", - // e.into_iter() - // .filter_map(|res| { - // if let OrderResponseStatus::Error(e) = res { - // Some(e) - // } else { - // None - // } - // }) - // .collect::>() - // .join(", ") - // ), - // ) - // .await?; - // } - - // Err(e) => { - // self.terminal_server - // .error("self::order", &e.to_string()) - // .await?; - // } - // } - } else { - self.terminal_server - .error("Engine::order", "Unable to get active account") - .await?; + e => { + e?; + } } Ok(()) diff --git a/src/engine/engine/strategy.rs b/src/engine/engine/strategy.rs index 88e02e1..552149a 100644 --- a/src/engine/engine/strategy.rs +++ b/src/engine/engine/strategy.rs @@ -169,10 +169,7 @@ impl StrategyEngine { engine .terminal_server - .error( - "engine::strategy", - &format!("Failed to execute signal: {e}"), - ) + .error("engine::order", &format!("Failed to execute signal: {e}")) .await? } }