Better signal formatting
This commit is contained in:
@@ -32,89 +32,91 @@ impl Engine {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let order_ids = self.risk_engine.create_order().await?;
|
let order_ids = self.risk_engine.create_order(signal).await?;
|
||||||
|
|
||||||
let order = BatchOrder {
|
println!("{order_ids:?}");
|
||||||
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 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
|
// let nonce = chrono::Utc::now().timestamp_millis() as u64;
|
||||||
.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) => {
|
// match client
|
||||||
self.terminal_server
|
// .place(&acc.private_key.0, order, nonce, None, None)
|
||||||
.error(
|
// .await
|
||||||
"self::order",
|
// {
|
||||||
&format!(
|
// Ok(o) if o.iter().any(|o| matches!(o, OrderResponseStatus::Error(_))) => {
|
||||||
"order rejected: {}",
|
// self.risk_engine.order_placed(order_ids).await;
|
||||||
e.into_iter()
|
// }
|
||||||
.filter_map(|res| {
|
|
||||||
if let OrderResponseStatus::Error(e) = res {
|
|
||||||
Some(e)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(e) => {
|
// Ok(e) => {
|
||||||
self.terminal_server
|
// self.terminal_server
|
||||||
.error("self::order", &e.to_string())
|
// .error(
|
||||||
.await?;
|
// "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 {
|
} else {
|
||||||
self.terminal_server
|
self.terminal_server
|
||||||
.error("Engine::order", "Unable to get active account")
|
.error("Engine::order", "Unable to get active account")
|
||||||
|
|||||||
+18
-20
@@ -14,22 +14,13 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{engine::Engine, store::config::RiskConfig};
|
use crate::{engine::Engine, store::config::RiskConfig};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OrderIds {
|
pub struct EngineOrder {
|
||||||
|
pub risk_equity: Decimal,
|
||||||
|
pub size: Decimal,
|
||||||
|
|
||||||
pub entry: Cloid,
|
pub entry: Cloid,
|
||||||
pub take_profit: Cloid,
|
pub take_profit: Cloid,
|
||||||
pub stop_loss: 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 {
|
pub struct RiskState {
|
||||||
@@ -40,7 +31,7 @@ pub struct RiskState {
|
|||||||
|
|
||||||
pub struct RiskEngine {
|
pub struct RiskEngine {
|
||||||
// Orders made by the engine
|
// Orders made by the engine
|
||||||
pub orders: Mutex<Vec<OrderIds>>,
|
pub orders: Mutex<Vec<EngineOrder>>,
|
||||||
pub handle: Mutex<ConnectionHandle>,
|
pub handle: Mutex<ConnectionHandle>,
|
||||||
pub state: Mutex<RiskState>,
|
pub state: Mutex<RiskState>,
|
||||||
pub engine: Weak<Engine>,
|
pub engine: Weak<Engine>,
|
||||||
@@ -154,18 +145,25 @@ impl RiskEngine {
|
|||||||
Ok(under_max_losses)
|
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;
|
let state = self.state.lock().await;
|
||||||
|
|
||||||
Ok(OrderIds::new(
|
let risk = self
|
||||||
self.get_risk_config()
|
.get_risk_config()
|
||||||
.await?
|
.await?
|
||||||
.risk_per_trade
|
.risk_per_trade
|
||||||
.get(state.starting_equity),
|
.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);
|
self.orders.lock().await.push(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-18
@@ -54,31 +54,22 @@ impl Formatted for EventLog {
|
|||||||
impl Formatted for SignalStatus {
|
impl Formatted for SignalStatus {
|
||||||
fn get_formatted(&self) -> Vec<String> {
|
fn get_formatted(&self) -> Vec<String> {
|
||||||
match self {
|
match self {
|
||||||
Ok(signal) => {
|
Ok(signal) | Err(signal) => {
|
||||||
vec![
|
vec![
|
||||||
format!("\x1b[33mOK\x1b[0m"),
|
if matches!(self, Ok(_)) {
|
||||||
if matches!(signal.side, Side::Ask) {
|
format!("\x1b[34mOK\x1b[0m")
|
||||||
|
} else {
|
||||||
|
format!("\x1b[31mREJ\x1b[0m")
|
||||||
|
},
|
||||||
|
if matches!(signal.side, Side::Bid) {
|
||||||
format!("\x1b[32mBUY\x1b[0m")
|
format!("\x1b[32mBUY\x1b[0m")
|
||||||
} else {
|
} else {
|
||||||
format!("\x1b[31mSELL\x1b[0m")
|
format!("\x1b[31mSELL\x1b[0m")
|
||||||
},
|
},
|
||||||
format_symbol(&signal.symbol),
|
format_symbol(&signal.symbol),
|
||||||
format_usd(signal.entry_price.as_f64()),
|
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()),
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 {
|
pub fn format_f64(value: f64) -> String {
|
||||||
let abs = value.abs();
|
let abs = value.abs();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user