Skip to main content

nash_protocol/protocol/subscriptions/updated_account_orders/
response.rs

1use super::super::super::{DataResponse, ResponseOrError};
2use super::request::SubscribeAccountOrders;
3use crate::errors::{ProtocolError, Result};
4use crate::types::{
5    BuyOrSell, Order, OrderCancellationPolicy, OrderCancellationReason,
6    OrderStatus, OrderType,
7};
8use crate::graphql::updated_account_orders;
9use crate::protocol::state::State;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use bigdecimal::BigDecimal;
13use chrono::{DateTime, Utc};
14use std::str::FromStr;
15
16/// Order book updates pushed over a subscription consist of a list of bid orders and
17/// a list of ask orders.
18#[derive(Clone, Debug)]
19pub struct AccountOrdersResponse {
20    pub orders: Vec<Order>,
21}
22
23// FIXME: if possible, remove duplication with orderbook query
24impl SubscribeAccountOrders {
25    pub async fn response_from_graphql(
26        &self,
27        response: ResponseOrError<updated_account_orders::ResponseData>,
28        _state: Arc<RwLock<State>>
29    ) -> Result<ResponseOrError<AccountOrdersResponse>> {
30        match response {
31            ResponseOrError::Response(data) => {
32                let response = data.data;
33
34                let mut orders = Vec::new();
35                for order_data in response.updated_account_orders {
36                    let market = order_data.market.name.clone();
37                    let amount_placed = BigDecimal::from_str(&order_data.amount.amount)?;
38                    let amount_remaining = BigDecimal::from_str(&order_data.amount_remaining.amount)?;
39                    let amount_executed = BigDecimal::from_str(&order_data.amount_executed.amount)?;
40                    let limit_price = match &order_data.limit_price {
41                        Some(price) => Some(BigDecimal::from_str(&price.amount)?),
42                        None => None,
43                    };
44                    let stop_price = match &order_data.stop_price {
45                        Some(price) => Some(BigDecimal::from_str(&price.amount)?),
46                        None => None,
47                    };
48                    let placed_at = DateTime::<Utc>::from_str(&order_data.placed_at)
49                        .map_err(|_| ProtocolError("Could not convert value to DateTime"))?;
50                    orders.push(Order {
51                        id: order_data.id.clone(),
52                        client_order_id: order_data.client_order_id.clone(),
53                        market,
54                        amount_placed,
55                        amount_remaining,
56                        amount_executed,
57                        limit_price,
58                        stop_price,
59                        placed_at,
60                        trades: Vec::new(),
61                        cancellation_policy: (&order_data).into(),
62                        cancellation_reason: order_data.cancellation_reason.as_ref().map(|x| x.into()),
63                        buy_or_sell: order_data.buy_or_sell.into(),
64                        order_type: order_data.type_.into(),
65                        status: order_data.status.into(),
66                    })
67                }
68                Ok(ResponseOrError::Response(DataResponse {
69                    data: AccountOrdersResponse {
70                        orders,
71                    },
72                }))
73            }
74            ResponseOrError::Error(error) => Ok(ResponseOrError::Error(error)),
75        }
76    }
77}
78
79impl From<updated_account_orders::OrderBuyOrSell> for BuyOrSell {
80    fn from(response: updated_account_orders::OrderBuyOrSell) -> Self {
81        match response {
82            updated_account_orders::OrderBuyOrSell::BUY => Self::Buy,
83            updated_account_orders::OrderBuyOrSell::SELL => Self::Sell,
84            _ => panic!("Unexpected value in BuyOrSell enum"),
85        }
86    }
87}
88
89impl From<updated_account_orders::OrderType> for OrderType {
90    fn from(response: updated_account_orders::OrderType) -> Self {
91        match response {
92            updated_account_orders::OrderType::MARKET => Self::Market,
93            updated_account_orders::OrderType::LIMIT => Self::Limit,
94            updated_account_orders::OrderType::STOP_MARKET => Self::StopMarket,
95            updated_account_orders::OrderType::STOP_LIMIT => Self::StopLimit,
96            _ => panic!("Unexpected value in OrderType enum"),
97        }
98    }
99}
100
101impl From<updated_account_orders::OrderStatus> for OrderStatus {
102    fn from(response: updated_account_orders::OrderStatus) -> Self {
103        match response {
104            updated_account_orders::OrderStatus::PENDING => OrderStatus::Pending,
105            updated_account_orders::OrderStatus::OPEN => OrderStatus::Open,
106            updated_account_orders::OrderStatus::CANCELLED => OrderStatus::Canceled,
107            updated_account_orders::OrderStatus::FILLED => OrderStatus::Filled,
108            _ => panic!("Unexpected value in OrderStatus enum"),
109        }
110    }
111}
112
113impl From<&updated_account_orders::OrderCancellationReason> for OrderCancellationReason {
114    fn from(cancellation_reason: &updated_account_orders::OrderCancellationReason) -> Self {
115        match cancellation_reason {
116            updated_account_orders::OrderCancellationReason::ADMIN_CANCELED => {
117                OrderCancellationReason::AdminCancelled
118            }
119            updated_account_orders::OrderCancellationReason::EXPIRATION => {
120                OrderCancellationReason::Expiration
121            }
122            updated_account_orders::OrderCancellationReason::USER => OrderCancellationReason::User,
123            updated_account_orders::OrderCancellationReason::NO_FILL => {
124                OrderCancellationReason::NoFill
125            }
126            updated_account_orders::OrderCancellationReason::INVALID_FOR_ORDERBOOK_STATE => {
127                OrderCancellationReason::InvalidForOrderbookState
128            }
129            _ => panic!("Unsupported OrderCancellationReason"),
130        }
131    }
132}
133
134impl From<&updated_account_orders::UpdatedAccountOrdersUpdatedAccountOrders>
135    for Option<OrderCancellationPolicy>
136{
137    fn from(order: &updated_account_orders::UpdatedAccountOrdersUpdatedAccountOrders) -> Self {
138        if let Some(cancellation_policy) = &order.cancellation_policy {
139            Some(match cancellation_policy {
140                updated_account_orders::OrderCancellationPolicy::FILL_OR_KILL => {
141                    OrderCancellationPolicy::FillOrKill
142                }
143                updated_account_orders::OrderCancellationPolicy::GOOD_TIL_CANCELLED => {
144                    OrderCancellationPolicy::GoodTilCancelled
145                }
146                updated_account_orders::OrderCancellationPolicy::GOOD_TIL_TIME => {
147                    // This unwrap is safe
148                    let cancel_at =
149                        DateTime::<Utc>::from_str(&order.cancel_at.as_ref().unwrap()).unwrap();
150                    OrderCancellationPolicy::GoodTilTime(cancel_at)
151                }
152                updated_account_orders::OrderCancellationPolicy::IMMEDIATE_OR_CANCEL => {
153                    OrderCancellationPolicy::ImmediateOrCancel
154                }
155                _ => panic!("Unsupported OrderCancellationPolicy"),
156            })
157        } else {
158            None
159        }
160    }
161}