Skip to main content

brokapi_alor/map/
execution.rs

1//! Fill mapping: ALOR trades of the portfolio to `brokapi-core` executions.
2
3use std::time::Instant;
4
5use brokapi_alor_protocol::http::models::TradeRecord;
6use brokapi_core::{BrokerOrderId, ClientOrderId, Execution, Money, Price, Qty};
7
8use super::market::side_of;
9use super::{parse_time, timestamps};
10use crate::util::instrument_id;
11
12/// A fill. `cid` is the client order id the connector found for the order of the trade (`None` for an order that
13/// is not ours). `None` if the record has no pieces quantity or no side.
14pub fn execution(r: &TradeRecord, cid: Option<ClientOrderId>, now: Instant) -> Option<Execution> {
15    let qty = Qty::new(r.qty_units?);
16    Some(Execution {
17        cid,
18        broker_order_id: BrokerOrderId::new(r.orderno.clone().unwrap_or_default()),
19        instrument: instrument_id(&r.symbol, r.board.as_deref().unwrap_or_default()),
20        side: side_of(r.side.as_deref())?,
21        price: Price::new(r.price),
22        qty,
23        commission: Money::new(r.commission.unwrap_or_default()),
24        trade_id: r.id.clone(),
25        ts: timestamps(now, parse_time(r.date.as_deref())),
26    })
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32
33    #[test]
34    fn a_trade_becomes_an_execution_in_pieces() {
35        let r: TradeRecord = serde_json::from_str(
36            r#"{"id":"T1","orderno":"77","symbol":"SBER","board":"TQBR","qtyUnits":20,"qty":2,"price":100.50,"side":"buy","commission":0.05,"date":"2026-10-22T10:00:00Z"}"#,
37        )
38        .unwrap();
39        let e = execution(&r, None, Instant::now()).unwrap();
40        assert_eq!(e.qty, Qty::from(20));
41        assert_eq!(e.price.to_string(), "100.50");
42        assert_eq!(e.trade_id, "T1");
43        assert_eq!(e.broker_order_id.as_str(), "77");
44        assert_eq!(e.commission.to_string(), "0.05");
45    }
46}