From 6f85b9b0e82beb13a0c742f68ee1e267e774e034 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Wed, 14 Feb 2024 18:53:58 +0000 Subject: [PATCH] Fix string to number deserialization Signed-off-by: Nikolaos Karaolidis --- Cargo.lock | 12 ++++++++ Cargo.toml | 1 + src/threads/trading/mod.rs | 2 +- src/types/alpaca/api/incoming/account.rs | 29 +++++++++++++++++-- src/types/alpaca/api/incoming/asset.rs | 2 ++ src/types/alpaca/api/incoming/position.rs | 13 +++++++++ src/types/alpaca/shared/order.rs | 11 +++++++ .../websocket/trading/incoming/order.rs | 5 ++++ 8 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b5e6a2..e965978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1672,6 +1672,7 @@ dependencies = [ "reqwest", "rust-bert", "serde", + "serde-aux", "serde_json", "serde_repr", "time", @@ -2008,6 +2009,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-aux" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86348501c129f3ad50c2f4635a01971f76974cd8a3f335988a0f1581c082765" +dependencies = [ + "chrono", + "serde", + "serde_json", +] + [[package]] name = "serde-value" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 89e2f46..2f2b11e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ log4rs = "1.2.0" serde = "1.0.188" serde_json = "1.0.105" serde_repr = "0.1.18" +serde-aux = "4.4.0" futures-util = "0.3.28" reqwest = { version = "0.11.20", features = [ "json", diff --git a/src/threads/trading/mod.rs b/src/threads/trading/mod.rs index a68ab1c..725c9a6 100644 --- a/src/threads/trading/mod.rs +++ b/src/threads/trading/mod.rs @@ -48,7 +48,7 @@ pub async fn check_account(config: &Arc) { warn!( "qrust active with {}{}, avoid transferring funds without shutting down.", - account.currency, account.cash + account.cash, account.currency ); } diff --git a/src/types/alpaca/api/incoming/account.rs b/src/types/alpaca/api/incoming/account.rs index c84af77..8c2eeec 100644 --- a/src/types/alpaca/api/incoming/account.rs +++ b/src/types/alpaca/api/incoming/account.rs @@ -2,6 +2,9 @@ use backoff::{future::retry_notify, ExponentialBackoff}; use log::warn; use reqwest::Error; use serde::Deserialize; +use serde_aux::field_attributes::{ + deserialize_number_from_string, deserialize_option_number_from_string, +}; use std::{sync::Arc, time::Duration}; use time::OffsetDateTime; use uuid::Uuid; @@ -25,15 +28,23 @@ pub enum Status { pub struct Account { pub id: Uuid, #[serde(rename = "account_number")] - pub number: i64, + pub number: String, pub status: Status, pub currency: String, + #[serde(deserialize_with = "deserialize_number_from_string")] pub cash: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub non_marginable_buying_power: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub accrued_fees: f64, - pub pending_transfer_in: f64, - pub pending_transfer_out: f64, + #[serde(default)] + #[serde(deserialize_with = "deserialize_option_number_from_string")] + pub pending_transfer_in: Option, + #[serde(default)] + #[serde(deserialize_with = "deserialize_option_number_from_string")] + pub pending_transfer_out: Option, pub pattern_day_trader: bool, + #[serde(default)] pub trade_suspend_by_user: bool, pub trading_blocked: bool, pub transfers_blocked: bool, @@ -42,18 +53,30 @@ pub struct Account { #[serde(with = "time::serde::rfc3339")] pub created_at: OffsetDateTime, pub shorting_enabled: bool, + #[serde(deserialize_with = "deserialize_number_from_string")] pub long_market_value: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub short_market_value: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub equity: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub last_equity: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub multiplier: i8, + #[serde(deserialize_with = "deserialize_number_from_string")] pub buying_power: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub initial_margin: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub maintenance_margin: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub sma: f64, pub daytrade_count: i64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub last_maintenance_margin: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub daytrading_buying_power: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub regt_buying_power: f64, } diff --git a/src/types/alpaca/api/incoming/asset.rs b/src/types/alpaca/api/incoming/asset.rs index d6d4872..e29be72 100644 --- a/src/types/alpaca/api/incoming/asset.rs +++ b/src/types/alpaca/api/incoming/asset.rs @@ -10,6 +10,7 @@ use backoff::{future::retry_notify, ExponentialBackoff}; use log::warn; use reqwest::Error; use serde::Deserialize; +use serde_aux::field_attributes::deserialize_option_number_from_string; use std::{sync::Arc, time::Duration}; use uuid::Uuid; @@ -27,6 +28,7 @@ pub struct Asset { pub shortable: bool, pub easy_to_borrow: bool, pub fractionable: bool, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub maintenance_margin_requirement: Option, pub attributes: Option>, } diff --git a/src/types/alpaca/api/incoming/position.rs b/src/types/alpaca/api/incoming/position.rs index ee4fa27..07dc820 100644 --- a/src/types/alpaca/api/incoming/position.rs +++ b/src/types/alpaca/api/incoming/position.rs @@ -9,6 +9,7 @@ use crate::{ use backoff::{future::retry_notify, ExponentialBackoff}; use log::warn; use serde::Deserialize; +use serde_aux::field_attributes::deserialize_number_from_string; use std::{sync::Arc, time::Duration}; use uuid::Uuid; @@ -35,18 +36,30 @@ pub struct Position { pub symbol: String, pub exchange: Exchange, pub asset_class: Class, + #[serde(deserialize_with = "deserialize_number_from_string")] pub avg_entry_price: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub qty: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub qty_available: f64, pub side: Side, + #[serde(deserialize_with = "deserialize_number_from_string")] pub market_value: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub cost_basis: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub unrealized_pl: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub unrealized_plpc: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub unrealized_intraday_pl: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub unrealized_intraday_plpc: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub current_price: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub lastday_price: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] pub change_today: f64, pub asset_marginable: bool, } diff --git a/src/types/alpaca/shared/order.rs b/src/types/alpaca/shared/order.rs index 9464dc3..8685a9c 100644 --- a/src/types/alpaca/shared/order.rs +++ b/src/types/alpaca/shared/order.rs @@ -1,5 +1,8 @@ use crate::{impl_from_enum, types}; use serde::{Deserialize, Serialize}; +use serde_aux::field_attributes::{ + deserialize_number_from_string, deserialize_option_number_from_string, +}; use time::OffsetDateTime; use uuid::Uuid; @@ -136,21 +139,29 @@ pub struct Order { pub asset_id: Uuid, pub symbol: String, pub asset_class: super::asset::Class, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub notional: Option, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub qty: Option, + #[serde(deserialize_with = "deserialize_number_from_string")] pub filled_qty: f64, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub filled_avg_price: Option, pub order_class: Class, #[serde(rename = "type")] pub order_type: Type, pub side: Side, pub time_in_force: TimeInForce, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub limit_price: Option, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub stop_price: Option, pub status: Status, pub extended_hours: bool, pub legs: Option>, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub trail_percent: Option, + #[serde(deserialize_with = "deserialize_option_number_from_string")] pub trail_price: Option, pub hwm: Option, } diff --git a/src/types/alpaca/websocket/trading/incoming/order.rs b/src/types/alpaca/websocket/trading/incoming/order.rs index f589778..e5f012b 100644 --- a/src/types/alpaca/websocket/trading/incoming/order.rs +++ b/src/types/alpaca/websocket/trading/incoming/order.rs @@ -1,5 +1,6 @@ use crate::types::alpaca::shared; use serde::Deserialize; +use serde_aux::prelude::deserialize_number_from_string; use time::OffsetDateTime; use uuid::Uuid; @@ -12,12 +13,16 @@ pub enum Event { New, Fill { timestamp: OffsetDateTime, + #[serde(deserialize_with = "deserialize_number_from_string")] position_qty: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] price: f64, }, PartialFill { timestamp: OffsetDateTime, + #[serde(deserialize_with = "deserialize_number_from_string")] position_qty: f64, + #[serde(deserialize_with = "deserialize_number_from_string")] price: f64, }, Canceled {