use std::fmt;
use mexc_rs::spot::v3::account_information::AccountInformationEndpoint;
use mexc_rs::spot::v3::cancel_order::{CancelOrderEndpoint, CancelOrderOutput, CancelOrderParams};
use mexc_rs::spot::v3::klines::Kline;
use mexc_rs::spot::v3::order::{OrderEndpoint, OrderParams};
use mexc_rs::spot::v3::ping::PingEndpoint;
use mexc_rs::spot::v3::query_order::{QueryOrderEndpoint, QueryOrderOutput, QueryOrderParams};
use mexc_rs::spot::{MexcSpotApiClient, MexcSpotApiClientWithAuthentication, MexcSpotApiEndpoint};
use tracing::{debug, trace};
use super::super::{
super::clock::{Clock, TrueClock},
Balance,
};
use super::{Crypto, KlinesParams, Market, MarketError, MexcBase, MexcSymbol as _, Order};
pub struct Mexc {
client: MexcSpotApiClient,
client_auth: MexcSpotApiClientWithAuthentication,
}
impl Mexc {
pub async fn new() -> Self {
let client = MexcSpotApiClient::new(MexcSpotApiEndpoint::Base);
client.ping().await.expect("API injoignable");
let api_key = std::env::var("MEXC_API_KEY").expect("MEXC_API_KEY not set");
let secret_key = std::env::var("MEXC_SECRET_KEY").expect("MEXC_SECRET_KEY not set");
let client_auth = MexcSpotApiClientWithAuthentication::new(
MexcSpotApiEndpoint::Base,
api_key,
secret_key,
);
client_auth.ping().await.expect("Connexion impossible");
trace!("Mymexc initialised");
Mexc {
client,
client_auth,
}
}
}
impl fmt::Debug for Mexc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mexc")
.field("client", &"local client")
.field("client_auth", &"local client auth")
.finish()
}
}
impl MexcBase for Mexc {
fn client(&self) -> &MexcSpotApiClient {
&self.client
}
}
impl Market for Mexc {
async fn klines(&self, params: KlinesParams) -> Result<Vec<Kline>, MarketError> {
self.base_klines(¶ms).await
}
async fn get_balance(&self, crypto: Crypto) -> Result<Balance, MarketError> {
let account_info = self.client_auth.account_information().await?;
let mexc_balance = account_info
.balances
.iter()
.find(|balance| balance.asset == crypto.to_string())
.expect("Balance not found");
Ok(Balance {
free: mexc_balance.free,
locked: mexc_balance.locked,
})
}
async fn send_order(&self, order: &Order) -> Result<String, MarketError> {
if std::env::var("SERIOUS").unwrap_or("false".to_string()) != "true" {
Err(MarketError::SafetyError)
} else {
let (quantity, quote_order_quantity) = order.quantity().get_amounts();
let params = OrderParams {
symbol: &format!("{}{}", order.asset(), order.quote()),
side: *order.side(),
order_type: *order.order_type(),
quantity,
price: *order.price(),
quote_order_quantity,
new_client_order_id: None,
};
debug!("Order to Mexc, [{:#?}]", params);
Ok(self.client_auth.order(params).await?.order_id)
}
}
async fn cancel_order(&self, order: &Order) -> Result<CancelOrderOutput, MarketError> {
Ok(self
.client_auth
.cancel_order(CancelOrderParams {
symbol: &format!("{}{}", order.asset(), order.quote()),
order_id: Some(&order.market_id().clone().expect("Order ID should be set")),
new_client_order_id: None,
original_client_order_id: None,
})
.await?)
}
async fn update_order(&self, order: &Order) -> Result<QueryOrderOutput, MarketError> {
Ok(self
.client_auth
.query_order(QueryOrderParams {
symbol: &order.symbol(),
order_id: Some(&order.market_id().clone().expect("Order ID should be set")),
original_client_order_id: None,
})
.await?)
}
fn clock(&self) -> Box<dyn Clock> {
Box::new(TrueClock::new())
}
}