Better signal formatting

This commit is contained in:
2026-08-02 00:19:47 +02:00
parent 51998aad68
commit 05cf081339
3 changed files with 117 additions and 118 deletions
+80 -78
View File
@@ -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::<Vec<_>>()
.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::<Vec<_>>()
// .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")
+20 -22
View File
@@ -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<Vec<OrderIds>>,
pub orders: Mutex<Vec<EngineOrder>>,
pub handle: Mutex<ConnectionHandle>,
pub state: Mutex<RiskState>,
pub engine: Weak<Engine>,
@@ -154,18 +145,25 @@ impl RiskEngine {
Ok(under_max_losses)
}
pub async fn create_order(&self) -> tokio::io::Result<OrderIds> {
pub async fn create_order(&self, signal: &Signal) -> tokio::io::Result<EngineOrder> {
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);
}
+17 -18
View File
@@ -54,31 +54,22 @@ impl Formatted for EventLog {
impl Formatted for SignalStatus {
fn get_formatted(&self) -> Vec<String> {
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();