use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use super::account::AccountPositions;
use super::common::Response;
use super::market::{Depth, QuoteFull, Trade};
use super::order::Order;
use super::{
Balance, ComplexGroupInfo, ComplexGroups, FutureInfo, OptionGroupInfo, OrderFill, Position,
RiskInfo, SecurityDefinition, SecurityMarginAndValue, SecurityStatus, Spread, Symbol,
SymbolInfo, TraderInfo, UserInfo, option_timestamp_ms,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthorizationResponse {
pub status: super::ResponseStatus,
#[serde(default)]
pub message: Option<String>,
#[serde(default)]
pub token: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AccountBalanceResponse {
#[serde(default)]
pub balances: Vec<Balance>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PositionsResponse {
#[serde(rename = "accountId", default)]
pub account_id: Option<String>,
#[serde(default)]
pub positions: Vec<Position>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AccountsPositionsResponse {
#[serde(default)]
pub positions: Vec<AccountPositions>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AccountRiskResponse {
#[serde(default)]
pub risks: Vec<RiskInfo>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AccountFillsResponse {
#[serde(default)]
pub fills: Vec<OrderFill>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AllAccountsResponse {
#[serde(default)]
pub accounts: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OrderBaseResponse {
#[serde(rename = "orderId", default)]
pub order_id: Option<String>,
#[serde(rename = "strategyId", default)]
pub strategy_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OrdersResponse {
#[serde(default)]
pub orders: Vec<Order>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OrdersFillsResponse {
#[serde(default)]
pub fills: Vec<OrderFill>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct QuotesResponse {
#[serde(alias = "Quotes", default)]
pub quotes: Vec<QuoteFull>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DepthResponse {
#[serde(alias = "Depths", default)]
pub depths: Vec<Depth>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TradesResponse {
#[serde(default)]
pub traders: Vec<Trade>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityDefinitionsResponse {
#[serde(rename = "securityDefinitions", default)]
pub security_definitions: Vec<SecurityDefinition>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityMarginAndValueResponse {
#[serde(rename = "securityMarginAndValues", default)]
pub security_margin_and_values: Vec<SecurityMarginAndValue>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityStatusResponse {
#[serde(rename = "securityStatuses", default)]
pub security_statuses: Vec<SecurityStatus>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SymbolsResponse {
#[serde(default)]
pub symbols: Vec<SymbolInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExchangeSourcesResponse {
#[serde(default)]
pub exchanges: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ComplexesResponse {
#[serde(rename = "marketComplexes", default)]
pub market_complexes: Vec<ComplexGroups>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ComplexGroupsResponse {
#[serde(rename = "symbolGroups", default)]
pub symbol_groups: Vec<ComplexGroupInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SymbolFuturesResponse {
#[serde(default)]
pub symbols: Vec<FutureInfo>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SymbolOptionsResponse {
#[serde(default)]
pub groups: Vec<String>,
#[serde(rename = "optionGroups", default)]
pub option_groups: Vec<OptionGroupInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SymbolSearchOptionsResponse {
#[serde(rename = "symbolOptions", default)]
pub symbol_options: Vec<Symbol>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SymbolOptionSpreadsResponse {
#[serde(rename = "symbolSpreads", default)]
pub symbol_spreads: Vec<Spread>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StrategyIdResponse {
#[serde(alias = "Id")]
pub id: i64,
#[serde(alias = "Minimum")]
pub minimum: i64,
#[serde(alias = "Maximum")]
pub maximum: i64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TraderInfoResponse {
#[serde(flatten)]
pub info: TraderInfo,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserInfoResponse {
#[serde(flatten)]
pub info: UserInfo,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SimulatedTraderCreateResponse {
#[serde(rename = "TraderId")]
pub trader_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SimulatedTraderAddAccountResponse {
#[serde(rename = "AccountId")]
pub account_id: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CashReportEntry {
#[serde(default)]
pub amount: Option<f64>,
#[serde(rename = "entryDate", default, with = "option_timestamp_ms")]
pub entry_date: Option<OffsetDateTime>,
#[serde(rename = "availableDate", default, with = "option_timestamp_ms")]
pub available_date: Option<OffsetDateTime>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SimulatedAccountCashReportResponse {
#[serde(rename = "AccountId", default)]
pub account_id: Option<String>,
#[serde(rename = "CashReport", default)]
pub cash_report: Vec<CashReportEntry>,
}
pub type SimulationSuccessResponse = Response;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn auth_response_deserialize() {
let json = r#"{"status":"OK","message":"Authenticated","token":"abc123"}"#;
let r: AuthorizationResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.token.as_deref(), Some("abc123"));
}
#[test]
fn quotes_response_pascal_case() {
let json = r#"{"Quotes":[{"s":"XCME:ES.U16","l":4500.0}]}"#;
let r: QuotesResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.quotes.len(), 1);
}
#[test]
fn trades_response_typo_preserved() {
let json = r#"{"traders":[{"symbol":"XCME:ES.U16","price":4500.0}]}"#;
let r: TradesResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.traders.len(), 1);
}
#[test]
fn strategy_id_pascal_case() {
let json = r#"{"Id":12345,"Minimum":10000,"Maximum":20000}"#;
let r: StrategyIdResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.id, 12345);
}
#[test]
fn strategy_id_lowercase() {
let json = r#"{"id":99,"minimum":1,"maximum":100,"status":"OK","message":"OK"}"#;
let r: StrategyIdResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.id, 99);
assert_eq!(r.minimum, 1);
assert_eq!(r.maximum, 100);
}
#[test]
fn order_base_response() {
let json = r#"{"orderId":"ORD001","strategyId":100}"#;
let r: OrderBaseResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.order_id.as_deref(), Some("ORD001"));
assert_eq!(r.strategy_id, Some(100));
}
}