diff --git a/src/engine/engine/execution.rs b/src/engine/engine/execution.rs index 5eded2c..e8f3b51 100644 --- a/src/engine/engine/execution.rs +++ b/src/engine/engine/execution.rs @@ -32,89 +32,91 @@ impl Engine { return Ok(()); }; - let order_ids = self.risk_engine.create_order().await?; + let order_ids = self.risk_engine.create_order(signal).await?; - 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, - }; + println!("{order_ids:?}"); - let nonce = chrono::Utc::now().timestamp_millis() as u64; + // 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, + // }; - 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; - } + // let nonce = chrono::Utc::now().timestamp_millis() as u64; - 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?; - } + // 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; + // } - Err(e) => { - self.terminal_server - .error("self::order", &e.to_string()) - .await?; - } - } + // 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") diff --git a/src/engine/engine/risk.rs b/src/engine/engine/risk.rs index cee9b65..1993247 100644 --- a/src/engine/engine/risk.rs +++ b/src/engine/engine/risk.rs @@ -14,22 +14,13 @@ use tokio::sync::Mutex; use crate::{engine::Engine, store::config::RiskConfig}; #[derive(Debug, Clone)] -pub struct OrderIds { +pub struct EngineOrder { + pub risk_equity: Decimal, + pub size: Decimal, + pub entry: Cloid, pub take_profit: Cloid, pub stop_loss: Cloid, - pub risk_equity: Decimal, -} - -impl OrderIds { - pub fn new(risk_equity: Decimal) -> Self { - Self { - entry: Cloid::random(), - take_profit: Cloid::random(), - stop_loss: Cloid::random(), - risk_equity, - } - } } pub struct RiskState { @@ -40,7 +31,7 @@ pub struct RiskState { pub struct RiskEngine { // Orders made by the engine - pub orders: Mutex>, + pub orders: Mutex>, pub handle: Mutex, pub state: Mutex, pub engine: Weak, @@ -154,18 +145,25 @@ impl RiskEngine { Ok(under_max_losses) } - pub async fn create_order(&self) -> tokio::io::Result { + pub async fn create_order(&self, signal: &Signal) -> tokio::io::Result { let state = self.state.lock().await; - Ok(OrderIds::new( - self.get_risk_config() - .await? - .risk_per_trade - .get(state.starting_equity), - )) + let risk = self + .get_risk_config() + .await? + .risk_per_trade + .get(state.starting_equity); + + Ok(EngineOrder { + entry: Cloid::random(), + take_profit: Cloid::random(), + stop_loss: Cloid::random(), + risk_equity: risk, + size: risk / (signal.entry_price - signal.stop_loss).abs(), + }) } - pub async fn order_placed(&self, order: OrderIds) { + pub async fn order_placed(&self, order: EngineOrder) { self.orders.lock().await.push(order); } diff --git a/src/terminal/formatting.rs b/src/terminal/formatting.rs index 17bd12e..13313c1 100644 --- a/src/terminal/formatting.rs +++ b/src/terminal/formatting.rs @@ -54,31 +54,22 @@ impl Formatted for EventLog { impl Formatted for SignalStatus { fn get_formatted(&self) -> Vec { match self { - Ok(signal) => { + Ok(signal) | Err(signal) => { vec![ - format!("\x1b[33mOK\x1b[0m"), - if matches!(signal.side, Side::Ask) { + if matches!(self, Ok(_)) { + format!("\x1b[34mOK\x1b[0m") + } else { + format!("\x1b[31mREJ\x1b[0m") + }, + if matches!(signal.side, Side::Bid) { format!("\x1b[32mBUY\x1b[0m") } else { format!("\x1b[31mSELL\x1b[0m") }, format_symbol(&signal.symbol), format_usd(signal.entry_price.as_f64()), - format!("\x1b[33mAPR {}\x1b[0m", signal.confidence), - ] - } - - Err(signal) => { - vec![ - format!("\x1b[31mERR\x1b[0m"), - if matches!(signal.side, Side::Ask) { - format!("\x1b[32mBUY\x1b[0m") - } else { - format!("\x1b[31mSELL\x1b[0m") - }, - format_symbol(&signal.symbol), - format_usd(signal.entry_price.as_f64()), - format!("\x1b[33mAPR {}\x1b[0m", signal.confidence), + format_usd(signal.take_profit.as_f64()), + format_usd_reverse(signal.stop_loss.as_f64()), ] } } @@ -274,6 +265,14 @@ pub fn format_usd(value: f64) -> String { } } +pub fn format_usd_reverse(value: f64) -> String { + if value.is_sign_positive() { + format!("\x1b[31m${}\x1b[0m", format_f64(value)) + } else { + format!("\x1b[32m${}\x1b[0m", format_f64(value)) + } +} + pub fn format_f64(value: f64) -> String { let abs = value.abs();