use uuid::Uuid;
use crate::{
client::rest::KuCoinClient,
types::{
KuCoinResponse,
spot::{
BatchOrderResult, BatchSpotContract, CancelAllRes, Side, SpotCancelRequest,
SpotCanceledData, SpotData, SpotDatum, SpotOrderRequest, Stp, TimeInForce, TradeType,
},
},
utils::errors::KucoinResults,
};
pub struct SpotHandler<'a> {
pub client: &'a KuCoinClient,
}
impl SpotOrderRequest {
pub fn new(trade_type: TradeType, symbol: &str, side: Side) -> Self {
SpotOrderRequest {
client_oid: Some(Uuid::new_v4().to_string()),
spot_contract_type: trade_type,
symbol: symbol.to_string(),
side,
allow_max_time_window: None,
cancel_after: None,
client_timestamp: None,
funds: None,
hidden: None,
iceberg: None,
post_only: None,
price: None,
remark: None,
size: None,
stp: None,
tags: None,
time_in_force: None,
visible_size: None,
}
}
pub fn set_size(mut self, size: f64) -> Self {
self.size = Some(size.to_string());
self
}
pub fn set_price(mut self, price: f64) -> Self {
self.price = Some(price.to_string());
self
}
pub fn set_funds(mut self, funds: f64) -> Self {
self.funds = Some(funds.to_string());
self
}
pub fn set_time_in_force(mut self, time_in_force: TimeInForce) -> Self {
self.time_in_force = Some(time_in_force);
self
}
pub fn set_post_only(mut self, post_only: bool) -> Self {
self.post_only = Some(post_only);
self
}
pub fn set_hidden(mut self, hidden: bool) -> Self {
self.hidden = Some(hidden);
self
}
pub fn set_iceberg(mut self, iceberg: bool) -> Self {
self.iceberg = Some(iceberg);
self
}
pub fn set_visible_size(mut self, visible_size: f64) -> Self {
self.visible_size = Some(visible_size.to_string());
self
}
pub fn set_remark(mut self, remark: &str) -> Self {
self.remark = Some(remark.to_string());
self
}
pub fn set_stp(mut self, stp: Stp) -> Self {
self.stp = Some(stp);
self
}
pub fn set_cancel_after(mut self, cancel_after: i64) -> Self {
self.cancel_after = Some(cancel_after);
self
}
}
impl BatchSpotContract {
pub fn new() -> Self {
BatchSpotContract {
order_list: Vec::new(),
}
}
pub fn add_order(mut self, contract: SpotOrderRequest) -> Self {
self.order_list.push(contract);
self
}
}
impl SpotCancelRequest {
pub fn new(order_id: &str, cancel_size: f64, symbol: &str) -> Self {
SpotCancelRequest {
order_id: order_id.to_string(),
cancel_size: cancel_size.to_string(),
symbol: symbol.to_string(),
}
}
}
impl<'a> SpotHandler<'a> {
pub async fn place_order(
&self,
order: SpotOrderRequest,
) -> KucoinResults<KuCoinResponse<SpotData>> {
let endpoint = "/api/v1/hf/orders";
let body = serde_json::to_string(&order)?;
let res = self
.client
.send::<KuCoinResponse<SpotData>>("POST", &body, endpoint)
.await?;
Ok(res)
}
pub async fn place_multi_orders(
&self,
orders: BatchSpotContract,
) -> KucoinResults<BatchOrderResult> {
let endpoint = "/api/v1/hf/orders/multi";
let body = serde_json::to_string(&orders)?;
let res = self
.client
.send::<BatchOrderResult>("POST", &body, endpoint)
.await?;
Ok(res)
}
pub async fn cancel_order(
&self,
req: SpotCancelRequest,
) -> KucoinResults<KuCoinResponse<SpotCanceledData>> {
let endpoint = format!(
"/api/v1/hf/orders/cancel/{}?symbol={}&cancelSize={}",
req.order_id, req.symbol, req.cancel_size
);
let res = self
.client
.send::<KuCoinResponse<SpotCanceledData>>("DELETE", "", &endpoint)
.await?;
Ok(res)
}
pub async fn list_orders_open(
&self,
ticker: &str,
) -> KucoinResults<KuCoinResponse<Vec<SpotDatum>>> {
let endpoint = format!("/api/v1/hf/orders/active?symbol={}", ticker);
let res = self
.client
.send::<KuCoinResponse<Vec<SpotDatum>>>("GET", "", &endpoint)
.await?;
Ok(res)
}
pub async fn close_all(&self) -> KucoinResults<KuCoinResponse<CancelAllRes>> {
let endpoint = format!("/api/v1/hf/orders/cancelAll");
let res = self
.client
.send::<KuCoinResponse<CancelAllRes>>("DELETE", "", &endpoint)
.await?;
Ok(res)
}
}
#[cfg(test)]
mod test {
use crate::client::rest::Credentials;
use super::*;
use std::env;
#[tokio::test]
async fn test_send_order() {
let credentials = Credentials::new(
&env::var("api_key").unwrap(),
&env::var("api_secret").unwrap(),
&env::var("api_passphrase").unwrap(),
);
let client = KuCoinClient::new(credentials);
let open_long_btc = SpotOrderRequest::new(TradeType::Market, "BTC-USDT", Side::Buy)
.set_funds(0.0)
.set_remark("syndicate");
match client.spot().place_order(open_long_btc).await {
Ok(res) => println!("Trade Order: {:#?}", res),
Err(e) => println!("Err: {:?}", e),
}
}
#[tokio::test]
async fn test_send_multi_orders() {
let credentials = Credentials::new(
&env::var("api_key").unwrap(),
&env::var("api_secret").unwrap(),
&env::var("api_passphrase").unwrap(),
);
let client = KuCoinClient::new(credentials);
let btc_contract = SpotOrderRequest::new(TradeType::Market, "BTC-USDT", Side::Buy)
.set_funds(0.0)
.set_remark("syndicate");
let sol_contract = SpotOrderRequest::new(TradeType::Market, "SOL-USDT", Side::Buy)
.set_funds(0.0)
.set_remark("syndicate2");
let orders = BatchSpotContract::new()
.add_order(btc_contract)
.add_order(sol_contract);
match client.spot().place_multi_orders(orders).await {
Ok(res) => println!("Trade Orders: {:#?}", res),
Err(e) => println!("Multi Orders Err: {:?}", e),
}
}
#[tokio::test]
async fn test_cancel_partial_order() {
let credentials = Credentials::new(
&env::var("api_key").unwrap(),
&env::var("api_secret").unwrap(),
&env::var("api_passphrase").unwrap(),
);
let client = KuCoinClient::new(credentials);
let query = SpotCancelRequest::new("x", 0.01, "BTC-USDT");
match client.spot().cancel_order(query).await {
Ok(res) => println!("Spot Canceled res: {:#?}", res),
Err(e) => println!("Spot Canceled Err: {:?}", e),
}
}
}