use pretty_simple_display::{DebugPretty, DisplaySimple};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Serialize, Deserialize)]
pub struct MovePositionTrade {
pub instrument_name: String,
pub amount: f64,
pub price: Option<f64>,
}
impl MovePositionTrade {
pub fn new(instrument_name: impl Into<String>, amount: f64) -> Self {
Self {
instrument_name: instrument_name.into(),
amount,
price: None,
}
}
pub fn with_price(instrument_name: impl Into<String>, amount: f64, price: f64) -> Self {
Self {
instrument_name: instrument_name.into(),
amount,
price: Some(price),
}
}
#[must_use]
pub fn price(mut self, price: f64) -> Self {
self.price = Some(price);
self
}
}
#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Serialize, Deserialize)]
pub struct MovePositionsRequest {
pub currency: String,
pub source_uid: i64,
pub target_uid: i64,
pub trades: Vec<MovePositionTrade>,
}
impl MovePositionsRequest {
pub fn new(
currency: impl Into<String>,
source_uid: i64,
target_uid: i64,
trades: Vec<MovePositionTrade>,
) -> Self {
Self {
currency: currency.into(),
source_uid,
target_uid,
trades,
}
}
pub fn add_trade(&mut self, trade: MovePositionTrade) {
self.trades.push(trade);
}
pub fn trade_count(&self) -> usize {
self.trades.len()
}
pub fn has_trades(&self) -> bool {
!self.trades.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_move_position_trade_new() {
let trade = MovePositionTrade::new("BTC-PERPETUAL", 100.0);
assert_eq!(trade.instrument_name, "BTC-PERPETUAL");
assert_eq!(trade.amount, 100.0);
assert!(trade.price.is_none());
}
#[test]
fn test_move_position_trade_with_price() {
let trade = MovePositionTrade::with_price("BTC-PERPETUAL", 100.0, 35800.0);
assert_eq!(trade.instrument_name, "BTC-PERPETUAL");
assert_eq!(trade.amount, 100.0);
assert_eq!(trade.price, Some(35800.0));
}
#[test]
fn test_move_positions_request_new() {
let trades = vec![MovePositionTrade::new("BTC-PERPETUAL", 100.0)];
let request = MovePositionsRequest::new("BTC", 3, 23, trades);
assert_eq!(request.currency, "BTC");
assert_eq!(request.source_uid, 3);
assert_eq!(request.target_uid, 23);
assert_eq!(request.trade_count(), 1);
}
#[test]
fn test_move_positions_request_serialization() {
let trades = vec![
MovePositionTrade::with_price("BTC-PERPETUAL", 110.0, 35800.0),
MovePositionTrade::new("BTC-28JAN22-32500-C", 0.1),
];
let request = MovePositionsRequest::new("BTC", 3, 23, trades);
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("BTC-PERPETUAL"));
assert!(json.contains("source_uid"));
assert!(json.contains("target_uid"));
}
}