oanda_rs/models/transaction/
mod.rs1mod account_tx;
5mod fill_cancel_tx;
6mod misc_tx;
7mod order_tx;
8
9pub use account_tx::*;
10pub use fill_cancel_tx::*;
11pub use misc_tx::*;
12pub use order_tx::*;
13
14use serde::{Deserialize, Serialize};
15
16use crate::models::{AccountId, DateTime, RequestId, TransactionId};
17
18macro_rules! for_each_transaction {
21 ($tx:expr, $inner:ident => $body:expr, $unknown:expr) => {
22 match $tx {
23 Transaction::Create($inner) => $body,
24 Transaction::Close($inner) => $body,
25 Transaction::Reopen($inner) => $body,
26 Transaction::ClientConfigure($inner) => $body,
27 Transaction::ClientConfigureReject($inner) => $body,
28 Transaction::TransferFunds($inner) => $body,
29 Transaction::TransferFundsReject($inner) => $body,
30 Transaction::MarketOrder($inner) => $body,
31 Transaction::MarketOrderReject($inner) => $body,
32 Transaction::FixedPriceOrder($inner) => $body,
33 Transaction::LimitOrder($inner) => $body,
34 Transaction::LimitOrderReject($inner) => $body,
35 Transaction::StopOrder($inner) => $body,
36 Transaction::StopOrderReject($inner) => $body,
37 Transaction::MarketIfTouchedOrder($inner) => $body,
38 Transaction::MarketIfTouchedOrderReject($inner) => $body,
39 Transaction::TakeProfitOrder($inner) => $body,
40 Transaction::TakeProfitOrderReject($inner) => $body,
41 Transaction::StopLossOrder($inner) => $body,
42 Transaction::StopLossOrderReject($inner) => $body,
43 Transaction::TrailingStopLossOrder($inner) => $body,
44 Transaction::TrailingStopLossOrderReject($inner) => $body,
45 Transaction::OrderFill($inner) => $body,
46 Transaction::OrderCancel($inner) => $body,
47 Transaction::OrderCancelReject($inner) => $body,
48 Transaction::OrderClientExtensionsModify($inner) => $body,
49 Transaction::OrderClientExtensionsModifyReject($inner) => $body,
50 Transaction::TradeClientExtensionsModify($inner) => $body,
51 Transaction::TradeClientExtensionsModifyReject($inner) => $body,
52 Transaction::MarginCallEnter($inner) => $body,
53 Transaction::MarginCallExtend($inner) => $body,
54 Transaction::MarginCallExit($inner) => $body,
55 Transaction::DelayedTradeClosure($inner) => $body,
56 Transaction::DailyFinancing($inner) => $body,
57 Transaction::ResetResettablePL($inner) => $body,
58 Transaction::DividendAdjustment($inner) => $body,
59 Transaction::Unknown(_) => $unknown,
60 }
61 };
62}
63
64#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
71#[serde(tag = "type")]
72#[non_exhaustive]
73#[allow(clippy::large_enum_variant)] pub enum Transaction {
75 #[serde(rename = "CREATE")]
77 Create(CreateTransaction),
78 #[serde(rename = "CLOSE")]
80 Close(CloseTransaction),
81 #[serde(rename = "REOPEN")]
83 Reopen(ReopenTransaction),
84 #[serde(rename = "CLIENT_CONFIGURE")]
86 ClientConfigure(ClientConfigureTransaction),
87 #[serde(rename = "CLIENT_CONFIGURE_REJECT")]
89 ClientConfigureReject(ClientConfigureRejectTransaction),
90 #[serde(rename = "TRANSFER_FUNDS")]
92 TransferFunds(TransferFundsTransaction),
93 #[serde(rename = "TRANSFER_FUNDS_REJECT")]
95 TransferFundsReject(TransferFundsRejectTransaction),
96 #[serde(rename = "MARKET_ORDER")]
98 MarketOrder(MarketOrderTransaction),
99 #[serde(rename = "MARKET_ORDER_REJECT")]
101 MarketOrderReject(MarketOrderRejectTransaction),
102 #[serde(rename = "FIXED_PRICE_ORDER")]
104 FixedPriceOrder(FixedPriceOrderTransaction),
105 #[serde(rename = "LIMIT_ORDER")]
107 LimitOrder(LimitOrderTransaction),
108 #[serde(rename = "LIMIT_ORDER_REJECT")]
110 LimitOrderReject(LimitOrderRejectTransaction),
111 #[serde(rename = "STOP_ORDER")]
113 StopOrder(StopOrderTransaction),
114 #[serde(rename = "STOP_ORDER_REJECT")]
116 StopOrderReject(StopOrderRejectTransaction),
117 #[serde(rename = "MARKET_IF_TOUCHED_ORDER")]
119 MarketIfTouchedOrder(MarketIfTouchedOrderTransaction),
120 #[serde(rename = "MARKET_IF_TOUCHED_ORDER_REJECT")]
122 MarketIfTouchedOrderReject(MarketIfTouchedOrderRejectTransaction),
123 #[serde(rename = "TAKE_PROFIT_ORDER")]
125 TakeProfitOrder(TakeProfitOrderTransaction),
126 #[serde(rename = "TAKE_PROFIT_ORDER_REJECT")]
128 TakeProfitOrderReject(TakeProfitOrderRejectTransaction),
129 #[serde(rename = "STOP_LOSS_ORDER")]
131 StopLossOrder(StopLossOrderTransaction),
132 #[serde(rename = "STOP_LOSS_ORDER_REJECT")]
134 StopLossOrderReject(StopLossOrderRejectTransaction),
135 #[serde(rename = "TRAILING_STOP_LOSS_ORDER")]
137 TrailingStopLossOrder(TrailingStopLossOrderTransaction),
138 #[serde(rename = "TRAILING_STOP_LOSS_ORDER_REJECT")]
140 TrailingStopLossOrderReject(TrailingStopLossOrderRejectTransaction),
141 #[serde(rename = "ORDER_FILL")]
143 OrderFill(OrderFillTransaction),
144 #[serde(rename = "ORDER_CANCEL")]
146 OrderCancel(OrderCancelTransaction),
147 #[serde(rename = "ORDER_CANCEL_REJECT")]
149 OrderCancelReject(OrderCancelRejectTransaction),
150 #[serde(rename = "ORDER_CLIENT_EXTENSIONS_MODIFY")]
152 OrderClientExtensionsModify(OrderClientExtensionsModifyTransaction),
153 #[serde(rename = "ORDER_CLIENT_EXTENSIONS_MODIFY_REJECT")]
155 OrderClientExtensionsModifyReject(OrderClientExtensionsModifyRejectTransaction),
156 #[serde(rename = "TRADE_CLIENT_EXTENSIONS_MODIFY")]
158 TradeClientExtensionsModify(TradeClientExtensionsModifyTransaction),
159 #[serde(rename = "TRADE_CLIENT_EXTENSIONS_MODIFY_REJECT")]
161 TradeClientExtensionsModifyReject(TradeClientExtensionsModifyRejectTransaction),
162 #[serde(rename = "MARGIN_CALL_ENTER")]
164 MarginCallEnter(MarginCallEnterTransaction),
165 #[serde(rename = "MARGIN_CALL_EXTEND")]
167 MarginCallExtend(MarginCallExtendTransaction),
168 #[serde(rename = "MARGIN_CALL_EXIT")]
170 MarginCallExit(MarginCallExitTransaction),
171 #[serde(rename = "DELAYED_TRADE_CLOSURE")]
173 DelayedTradeClosure(DelayedTradeClosureTransaction),
174 #[serde(rename = "DAILY_FINANCING")]
176 DailyFinancing(DailyFinancingTransaction),
177 #[serde(rename = "RESET_RESETTABLE_PL")]
179 ResetResettablePL(ResetResettablePLTransaction),
180 #[serde(rename = "DIVIDEND_ADJUSTMENT")]
182 DividendAdjustment(DividendAdjustmentTransaction),
183 #[serde(untagged)]
186 Unknown(serde_json::Value),
187}
188
189impl Transaction {
190 pub fn id(&self) -> Option<&TransactionId> {
192 for_each_transaction!(self, t => t.id.as_ref(), None)
193 }
194
195 pub fn time(&self) -> Option<&DateTime> {
197 for_each_transaction!(self, t => t.time.as_ref(), None)
198 }
199
200 pub fn account_id(&self) -> Option<&AccountId> {
202 for_each_transaction!(self, t => t.account_id.as_ref(), None)
203 }
204
205 pub fn batch_id(&self) -> Option<&TransactionId> {
207 for_each_transaction!(self, t => t.batch_id.as_ref(), None)
208 }
209
210 pub fn request_id(&self) -> Option<&RequestId> {
212 for_each_transaction!(self, t => t.request_id.as_ref(), None)
213 }
214
215 pub fn user_id(&self) -> Option<i64> {
217 for_each_transaction!(self, t => t.user_id, None)
218 }
219
220 pub fn type_name(&self) -> Option<&str> {
223 match self {
224 Transaction::Create(_) => Some("CREATE"),
225 Transaction::Close(_) => Some("CLOSE"),
226 Transaction::Reopen(_) => Some("REOPEN"),
227 Transaction::ClientConfigure(_) => Some("CLIENT_CONFIGURE"),
228 Transaction::ClientConfigureReject(_) => Some("CLIENT_CONFIGURE_REJECT"),
229 Transaction::TransferFunds(_) => Some("TRANSFER_FUNDS"),
230 Transaction::TransferFundsReject(_) => Some("TRANSFER_FUNDS_REJECT"),
231 Transaction::MarketOrder(_) => Some("MARKET_ORDER"),
232 Transaction::MarketOrderReject(_) => Some("MARKET_ORDER_REJECT"),
233 Transaction::FixedPriceOrder(_) => Some("FIXED_PRICE_ORDER"),
234 Transaction::LimitOrder(_) => Some("LIMIT_ORDER"),
235 Transaction::LimitOrderReject(_) => Some("LIMIT_ORDER_REJECT"),
236 Transaction::StopOrder(_) => Some("STOP_ORDER"),
237 Transaction::StopOrderReject(_) => Some("STOP_ORDER_REJECT"),
238 Transaction::MarketIfTouchedOrder(_) => Some("MARKET_IF_TOUCHED_ORDER"),
239 Transaction::MarketIfTouchedOrderReject(_) => Some("MARKET_IF_TOUCHED_ORDER_REJECT"),
240 Transaction::TakeProfitOrder(_) => Some("TAKE_PROFIT_ORDER"),
241 Transaction::TakeProfitOrderReject(_) => Some("TAKE_PROFIT_ORDER_REJECT"),
242 Transaction::StopLossOrder(_) => Some("STOP_LOSS_ORDER"),
243 Transaction::StopLossOrderReject(_) => Some("STOP_LOSS_ORDER_REJECT"),
244 Transaction::TrailingStopLossOrder(_) => Some("TRAILING_STOP_LOSS_ORDER"),
245 Transaction::TrailingStopLossOrderReject(_) => Some("TRAILING_STOP_LOSS_ORDER_REJECT"),
246 Transaction::OrderFill(_) => Some("ORDER_FILL"),
247 Transaction::OrderCancel(_) => Some("ORDER_CANCEL"),
248 Transaction::OrderCancelReject(_) => Some("ORDER_CANCEL_REJECT"),
249 Transaction::OrderClientExtensionsModify(_) => Some("ORDER_CLIENT_EXTENSIONS_MODIFY"),
250 Transaction::OrderClientExtensionsModifyReject(_) => {
251 Some("ORDER_CLIENT_EXTENSIONS_MODIFY_REJECT")
252 }
253 Transaction::TradeClientExtensionsModify(_) => Some("TRADE_CLIENT_EXTENSIONS_MODIFY"),
254 Transaction::TradeClientExtensionsModifyReject(_) => {
255 Some("TRADE_CLIENT_EXTENSIONS_MODIFY_REJECT")
256 }
257 Transaction::MarginCallEnter(_) => Some("MARGIN_CALL_ENTER"),
258 Transaction::MarginCallExtend(_) => Some("MARGIN_CALL_EXTEND"),
259 Transaction::MarginCallExit(_) => Some("MARGIN_CALL_EXIT"),
260 Transaction::DelayedTradeClosure(_) => Some("DELAYED_TRADE_CLOSURE"),
261 Transaction::DailyFinancing(_) => Some("DAILY_FINANCING"),
262 Transaction::ResetResettablePL(_) => Some("RESET_RESETTABLE_PL"),
263 Transaction::DividendAdjustment(_) => Some("DIVIDEND_ADJUSTMENT"),
264 Transaction::Unknown(value) => value.get("type").and_then(serde_json::Value::as_str),
265 }
266 }
267}
268#[derive(Debug, Clone, PartialEq)]
271#[non_exhaustive]
272#[allow(clippy::large_enum_variant)] pub enum TransactionStreamItem {
274 Transaction(Transaction),
276 Heartbeat(TransactionHeartbeat),
278}
279
280impl serde::Serialize for TransactionStreamItem {
281 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
282 match self {
283 TransactionStreamItem::Transaction(tx) => tx.serialize(serializer),
284 TransactionStreamItem::Heartbeat(heartbeat) => heartbeat.serialize(serializer),
285 }
286 }
287}
288
289impl<'de> serde::Deserialize<'de> for TransactionStreamItem {
290 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
291 let value = serde_json::Value::deserialize(deserializer)?;
292 let is_heartbeat =
293 value.get("type").and_then(serde_json::Value::as_str) == Some("HEARTBEAT");
294 if is_heartbeat {
295 serde_json::from_value(value)
296 .map(TransactionStreamItem::Heartbeat)
297 .map_err(serde::de::Error::custom)
298 } else {
299 serde_json::from_value(value)
300 .map(TransactionStreamItem::Transaction)
301 .map_err(serde::de::Error::custom)
302 }
303 }
304}