use serde::Deserialize;
use serde_json::Value;
use super::ExtraFields;
use crate::model::NumberString;
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct OrderUpdate {
#[serde(default)]
pub inst_type: String,
#[serde(default)]
pub inst_id: String,
#[serde(default)]
pub tgt_ccy: String,
#[serde(default)]
pub ccy: String,
#[serde(default)]
pub ord_id: String,
#[serde(default)]
pub cl_ord_id: String,
#[serde(default)]
pub tag: String,
#[serde(default)]
pub px: NumberString,
#[serde(default)]
pub sz: NumberString,
#[serde(default)]
pub notional_usd: NumberString,
#[serde(default)]
pub ord_type: String,
#[serde(default)]
pub side: String,
#[serde(default)]
pub pos_side: String,
#[serde(default)]
pub td_mode: String,
#[serde(default)]
pub acc_fill_sz: NumberString,
#[serde(default)]
pub fill_px: NumberString,
#[serde(default)]
pub trade_id: String,
#[serde(default)]
pub fill_sz: NumberString,
#[serde(default)]
pub fill_time: NumberString,
#[serde(default)]
pub fill_pnl: NumberString,
#[serde(default)]
pub fill_fee: NumberString,
#[serde(default)]
pub fill_fee_ccy: String,
#[serde(default)]
pub fill_notional_usd: NumberString,
#[serde(default)]
pub fill_px_vol: NumberString,
#[serde(default)]
pub fill_px_usd: NumberString,
#[serde(default)]
pub fill_mark_vol: NumberString,
#[serde(default)]
pub fill_fwd_px: NumberString,
#[serde(default)]
pub fill_mark_px: NumberString,
#[serde(default)]
pub fill_idx_px: NumberString,
#[serde(default)]
pub exec_type: String,
#[serde(default)]
pub avg_px: NumberString,
#[serde(default)]
pub state: String,
#[serde(default)]
pub lever: NumberString,
#[serde(default)]
pub attach_algo_cl_ord_id: String,
#[serde(default)]
pub tp_trigger_px: NumberString,
#[serde(default)]
pub tp_trigger_px_type: String,
#[serde(default)]
pub tp_ord_px: NumberString,
#[serde(default)]
pub sl_trigger_px: NumberString,
#[serde(default)]
pub sl_trigger_px_type: String,
#[serde(default)]
pub sl_ord_px: NumberString,
#[serde(default)]
pub fee_ccy: String,
#[serde(default)]
pub fee: NumberString,
#[serde(default)]
pub rebate_ccy: String,
#[serde(default)]
pub rebate: NumberString,
#[serde(default)]
pub pnl: NumberString,
#[serde(default)]
pub source: String,
#[serde(default)]
pub category: String,
#[serde(default)]
pub reduce_only: String,
#[serde(default)]
pub is_tp_limit: String,
#[serde(default)]
pub cancel_source: String,
#[serde(default)]
pub algo_cl_ord_id: String,
#[serde(default)]
pub algo_id: String,
#[serde(default)]
pub amend_source: String,
#[serde(default)]
pub amend_result: String,
#[serde(default)]
pub req_id: String,
#[serde(default)]
pub code: String,
#[serde(default)]
pub msg: String,
#[serde(default)]
pub px_type: String,
#[serde(default)]
pub px_usd: NumberString,
#[serde(default)]
pub px_vol: NumberString,
#[serde(default)]
pub linked_algo_ord: Value,
#[serde(default)]
pub attach_algo_ords: Vec<Value>,
#[serde(default)]
pub stp_mode: String,
#[serde(default)]
pub trade_quote_ccy: String,
#[serde(default)]
pub last_px: NumberString,
#[serde(default)]
pub outcome: String,
#[serde(default)]
pub c_time: NumberString,
#[serde(default)]
pub u_time: NumberString,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct FillUpdate {
#[serde(default)]
pub inst_id: String,
#[serde(default)]
pub fill_sz: NumberString,
#[serde(default)]
pub fill_px: NumberString,
#[serde(default)]
pub side: String,
#[serde(default)]
pub ts: NumberString,
#[serde(default)]
pub ord_id: String,
#[serde(default)]
pub cl_ord_id: String,
#[serde(default)]
pub trade_id: String,
#[serde(default)]
pub exec_type: String,
#[serde(default)]
pub count: NumberString,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct PlaceOrderResult {
#[serde(default)]
pub ord_id: String,
#[serde(default)]
pub cl_ord_id: String,
#[serde(default)]
pub tag: String,
#[serde(default)]
pub ts: NumberString,
#[serde(default)]
pub s_code: String,
#[serde(default)]
pub s_msg: String,
#[serde(default)]
pub sub_code: String,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct CancelOrderResult {
#[serde(default)]
pub ord_id: String,
#[serde(default)]
pub cl_ord_id: String,
#[serde(default)]
pub ts: NumberString,
#[serde(default)]
pub s_code: String,
#[serde(default)]
pub s_msg: String,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct AmendOrderResult {
#[serde(default)]
pub ord_id: String,
#[serde(default)]
pub cl_ord_id: String,
#[serde(default)]
pub ts: NumberString,
#[serde(default)]
pub req_id: String,
#[serde(default)]
pub s_code: String,
#[serde(default)]
pub s_msg: String,
#[serde(default)]
pub sub_code: String,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct MassCancelOperationResult {
#[serde(default)]
pub result: bool,
#[serde(flatten, default)]
pub extra: ExtraFields,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_order_update() {
let row: OrderUpdate = serde_json::from_str(
r#"{
"accFillSz":"0.001","algoClOrdId":"","algoId":"","amendResult":"","amendSource":"",
"avgPx":"31527.1","cancelSource":"","category":"normal","ccy":"","clOrdId":"",
"code":"0","cTime":"1654084334977","execType":"M","fee":"-0.02522168","feeCcy":"USDT",
"fillFee":"-0.02522168","fillFeeCcy":"USDT","fillNotionalUsd":"31.50818374",
"fillPx":"31527.1","fillSz":"0.001","fillPnl":"0.01","fillTime":"1654084353263",
"fillPxVol":"","fillPxUsd":"","fillMarkVol":"","fillFwdPx":"","fillMarkPx":"",
"fillIdxPx":"","instId":"BTC-USDT","instType":"SPOT","lever":"0","msg":"",
"notionalUsd":"31.50818374","ordId":"452197707845865472","ordType":"limit","pnl":"0",
"posSide":"","px":"31527.1","pxUsd":"","pxVol":"","pxType":"","quickMgnType":"",
"rebate":"0","rebateCcy":"BTC","reduceOnly":"false","reqId":"","side":"sell",
"attachAlgoClOrdId":"","slOrdPx":"","slTriggerPx":"","slTriggerPxType":"last",
"source":"","state":"filled","stpId":"","stpMode":"","sz":"0.001","tag":"",
"tdMode":"cash","tgtCcy":"","tpOrdPx":"","tpTriggerPx":"","tpTriggerPxType":"last",
"attachAlgoOrds":[],"tradeId":"242589207","tradeQuoteCcy":"USDT","lastPx":"38892.2",
"uTime":"1654084353264","isTpLimit":"false","linkedAlgoOrd":{"algoId":""}
}"#,
)
.unwrap();
assert_eq!(row.ord_id, "452197707845865472");
assert_eq!(row.state, "filled");
assert_eq!(row.fill_notional_usd.as_str(), "31.50818374");
assert_eq!(row.last_px.as_str(), "38892.2");
assert_eq!(row.is_tp_limit, "false");
assert!(row.extra.contains_key("stpId"));
assert!(row.extra.contains_key("quickMgnType"));
}
#[test]
fn parses_fill_update() {
let row: FillUpdate = serde_json::from_str(
r#"{
"instId":"BTC-USDT-SWAP","fillSz":"100","fillPx":"70000","side":"buy",
"ts":"1705449605015","ordId":"680800019749904384","clOrdId":"1234567890",
"tradeId":"12345","execType":"T","count":"10"
}"#,
)
.unwrap();
assert_eq!(row.inst_id, "BTC-USDT-SWAP");
assert_eq!(row.exec_type, "T");
assert_eq!(row.count.as_str(), "10");
}
#[test]
fn parses_place_order_result() {
let row: PlaceOrderResult = serde_json::from_str(
r#"{"clOrdId":"","ordId":"12345689","tag":"","ts":"1695190491421","sCode":"0","sMsg":"","subCode":""}"#,
)
.unwrap();
assert_eq!(row.ord_id, "12345689");
assert_eq!(row.s_code, "0");
assert_eq!(row.ts.as_str(), "1695190491421");
}
#[test]
fn parses_cancel_order_result() {
let row: CancelOrderResult = serde_json::from_str(
r#"{"clOrdId":"","ordId":"2510789768709120","ts":"1695190491421","sCode":"0","sMsg":""}"#,
)
.unwrap();
assert_eq!(row.ord_id, "2510789768709120");
assert_eq!(row.s_code, "0");
}
#[test]
fn parses_amend_order_result() {
let row: AmendOrderResult = serde_json::from_str(
r#"{"clOrdId":"","ordId":"2510789768709120","ts":"1695190491421","reqId":"b12344","sCode":"0","sMsg":"","subCode":""}"#,
)
.unwrap();
assert_eq!(row.ord_id, "2510789768709120");
assert_eq!(row.req_id, "b12344");
assert_eq!(row.s_code, "0");
}
}