use std::{num::NonZeroU64, sync::Arc};
use async_trait::async_trait;
use chrono::{DateTime, SecondsFormat, Utc};
use hyper::Method;
use serde_json::json;
use uuid::Uuid;
use crate::shared::{
models::{
quantity::Quantity,
trade::{TradeExecution, TradeSide},
},
rest::{error::Result, lnm::base::LnmRestBase},
};
use super::{
super::{
models::{
client_id::ClientId,
cross_leverage::CrossLeverage,
funding::CrossFunding,
page::Page,
trade::{CrossOrder, CrossPosition, FuturesCrossOrderBody},
transfer::CrossTransfer,
},
repositories::FuturesCrossRepository,
},
path::RestPathV3,
signature::SignatureGeneratorV3,
};
pub(in crate::api_v3) struct LnmFuturesCrossRepository {
base: Arc<LnmRestBase<SignatureGeneratorV3>>,
}
impl LnmFuturesCrossRepository {
pub fn new(base: Arc<LnmRestBase<SignatureGeneratorV3>>) -> Self {
Self { base }
}
}
impl crate::sealed::Sealed for LnmFuturesCrossRepository {}
#[async_trait]
impl FuturesCrossRepository for LnmFuturesCrossRepository {
async fn cancel_all_orders(&self) -> Result<Vec<CrossOrder>> {
self.base
.make_request_without_params(
Method::POST,
RestPathV3::FuturesCrossOrdersCancelAll,
true,
)
.await
}
async fn cancel_order(&self, id: Uuid) -> Result<CrossOrder> {
self.base
.make_request_with_body(
Method::POST,
RestPathV3::FuturesCrossOrderCancel,
json!({ "id": id }),
true,
)
.await
}
async fn place_order(
&self,
side: TradeSide,
quantity: Quantity,
execution: TradeExecution,
client_id: Option<ClientId>,
) -> Result<CrossOrder> {
let body = FuturesCrossOrderBody::new(side, quantity, execution, client_id);
self.base
.make_request_with_body(Method::POST, RestPathV3::FuturesCrossOrder, body, true)
.await
}
async fn get_open_orders(&self) -> Result<Vec<CrossOrder>> {
self.base
.make_request_without_params(Method::GET, RestPathV3::FuturesCrossOrdersOpen, true)
.await
}
async fn get_position(&self) -> Result<CrossPosition> {
self.base
.make_request_without_params(Method::GET, RestPathV3::FuturesCrossPosition, true)
.await
}
async fn get_filled_orders(
&self,
from: Option<DateTime<Utc>>,
to: Option<DateTime<Utc>>,
limit: Option<NonZeroU64>,
cursor: Option<DateTime<Utc>>,
) -> Result<Page<CrossOrder>> {
let mut query_params = Vec::new();
if let Some(from) = from {
query_params.push(("from", from.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(to) = to {
query_params.push(("to", to.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(limit) = limit {
query_params.push(("limit", limit.to_string()));
}
if let Some(cursor) = cursor {
query_params.push((
"cursor",
cursor.to_rfc3339_opts(SecondsFormat::Millis, true),
));
}
self.base
.make_request_with_query_params(
Method::GET,
RestPathV3::FuturesCrossOrdersFilled,
query_params,
true,
)
.await
}
async fn close_position(&self) -> Result<CrossOrder> {
self.base
.make_request_without_params(Method::POST, RestPathV3::FuturesCrossPositionClose, true)
.await
}
async fn get_funding_fees(
&self,
from: Option<DateTime<Utc>>,
to: Option<DateTime<Utc>>,
limit: Option<NonZeroU64>,
cursor: Option<DateTime<Utc>>,
) -> Result<Page<CrossFunding>> {
let mut query_params = Vec::new();
if let Some(from) = from {
query_params.push(("from", from.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(to) = to {
query_params.push(("to", to.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(limit) = limit {
query_params.push(("limit", limit.to_string()));
}
if let Some(cursor) = cursor {
query_params.push((
"cursor",
cursor.to_rfc3339_opts(SecondsFormat::Millis, true),
));
}
self.base
.make_request_with_query_params(
Method::GET,
RestPathV3::FuturesCrossFundingFees,
query_params,
true,
)
.await
}
async fn get_transfers(
&self,
from: Option<DateTime<Utc>>,
to: Option<DateTime<Utc>>,
limit: Option<NonZeroU64>,
cursor: Option<DateTime<Utc>>,
) -> Result<Page<CrossTransfer>> {
let mut query_params = Vec::new();
if let Some(from) = from {
query_params.push(("from", from.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(to) = to {
query_params.push(("to", to.to_rfc3339_opts(SecondsFormat::Millis, true)));
}
if let Some(limit) = limit {
query_params.push(("limit", limit.to_string()));
}
if let Some(cursor) = cursor {
query_params.push((
"cursor",
cursor.to_rfc3339_opts(SecondsFormat::Millis, true),
));
}
self.base
.make_request_with_query_params(
Method::GET,
RestPathV3::FuturesCrossGetTransfers,
query_params,
true,
)
.await
}
async fn deposit(&self, amount: NonZeroU64) -> Result<CrossPosition> {
self.base
.make_request_with_body(
Method::POST,
RestPathV3::FuturesCrossDeposit,
json!({ "amount": amount }),
true,
)
.await
}
async fn set_leverage(&self, leverage: CrossLeverage) -> Result<CrossPosition> {
self.base
.make_request_with_body(
Method::PUT,
RestPathV3::FuturesCrossPositionSetLeverage,
json!({ "leverage": leverage }),
true,
)
.await
}
async fn withdraw(&self, amount: NonZeroU64) -> Result<CrossPosition> {
self.base
.make_request_with_body(
Method::POST,
RestPathV3::FuturesCrossWithdraw,
json!({ "amount": amount }),
true,
)
.await
}
}
#[cfg(test)]
mod tests;