longportwhale/trade/
push_types.rs1use std::str::FromStr;
2
3use longport_proto::trade::Notification;
4use prost::Message;
5use rust_decimal::Decimal;
6use serde::Deserialize;
7use strum_macros::{Display, EnumString};
8use time::OffsetDateTime;
9
10use crate::{
11 serde_utils,
12 trade::{cmd_code, OrderSide, OrderStatus, OrderTag, OrderType, TriggerStatus},
13 Error, Result,
14};
15
16#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
18pub enum TopicType {
19 #[strum(serialize = "private")]
21 Private,
22}
23
24#[derive(Debug, Deserialize)]
26pub struct PushOrderChanged {
27 pub side: OrderSide,
29 pub stock_name: String,
31 #[serde(with = "serde_utils::int64_str")]
33 pub submitted_quantity: i64,
34 pub symbol: String,
36 pub order_type: OrderType,
38 pub submitted_price: Decimal,
40 #[serde(with = "serde_utils::int64_str")]
42 pub executed_quantity: i64,
43 #[serde(with = "serde_utils::decimal_opt_0_is_none")]
45 pub executed_price: Option<Decimal>,
46 pub order_id: String,
48 pub currency: String,
50 pub status: OrderStatus,
52 #[serde(with = "serde_utils::timestamp")]
54 pub submitted_at: OffsetDateTime,
55 #[serde(with = "serde_utils::timestamp")]
57 pub updated_at: OffsetDateTime,
58 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
60 pub trigger_price: Option<Decimal>,
61 pub msg: String,
63 pub tag: OrderTag,
65 #[serde(with = "serde_utils::trigger_status")]
67 pub trigger_status: Option<TriggerStatus>,
68 #[serde(with = "serde_utils::timestamp_opt")]
70 pub trigger_at: Option<OffsetDateTime>,
71 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
73 pub trailing_amount: Option<Decimal>,
74 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
76 pub trailing_percent: Option<Decimal>,
77 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
79 pub limit_offset: Option<Decimal>,
80 pub account_no: String,
82 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
84 pub last_share: Option<Decimal>,
85 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
87 pub last_price: Option<Decimal>,
88 pub remark: String,
90}
91
92#[derive(Debug, Deserialize)]
94#[serde(tag = "event", content = "data")]
95pub enum PushEvent {
96 #[serde(rename = "order_changed_lb")]
98 OrderChanged(PushOrderChanged),
99}
100
101impl PushEvent {
102 pub(crate) fn parse(command_code: u8, data: &[u8]) -> Result<Option<PushEvent>> {
103 if command_code == cmd_code::PUSH_NOTIFICATION {
104 let notification = Notification::decode(data)?;
105 if let Ok(TopicType::Private) = TopicType::from_str(¬ification.topic) {
106 Ok(Some(serde_json::from_slice::<PushEvent>(
107 ¬ification.data,
108 )?))
109 } else {
110 Ok(None)
111 }
112 } else {
113 Err(Error::UnknownCommand(command_code))
114 }
115 }
116}