├── rustfmt.toml ├── .vscode └── settings.json ├── .gitignore ├── src ├── lib.rs ├── rest │ ├── models │ │ ├── swagger.rs │ │ ├── mod.rs │ │ ├── definitions.rs │ │ └── requests.rs │ ├── mod.rs │ └── client.rs ├── error.rs ├── consts.rs ├── websocket │ ├── command.rs │ ├── message.rs │ ├── mod.rs │ └── topic.rs └── credential.rs ├── examples ├── get_fundings.rs ├── post_chat.rs ├── ws_ping.rs ├── proxy.rs ├── ws_orderbook_trade.rs ├── ws_auth.rs ├── ws_cancel_all.rs ├── ws_subscribe.rs └── readme.rs ├── tests ├── user_event.rs ├── insurance.rs ├── funding.rs ├── apikey.rs ├── liquidation.rs ├── settlement.rs ├── order_book.rs ├── global_notification.rs ├── announcement.rs ├── leaderboard.rs ├── execution.rs ├── trade.rs ├── quote.rs ├── stats.rs ├── chat.rs ├── instrument.rs ├── position.rs ├── user.rs └── order.rs ├── .travis.yml ├── LICENSE ├── Cargo.toml ├── README.md └── utils └── parse swagger.ipynb /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.enabled": false 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /target 13 | **/*.rs.bk 14 | 15 | .env 16 | .ipynb_checkpoints -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod consts; 2 | mod credential; 3 | mod error; 4 | pub mod rest; 5 | pub mod websocket; 6 | 7 | pub use crate::error::BitMEXError; 8 | 9 | use fehler::throws; 10 | 11 | pub const API_VERSION: &str = "1.2.0"; 12 | pub const SWAGGER_URL: &str = "https://www.bitmex.com/api/explorer/swagger.json"; 13 | 14 | #[throws(failure::Error)] 15 | pub async fn check_version() -> bool { 16 | let desc = crate::rest::BitMEXRest::new().get_swagger().await?; 17 | desc.info.version == API_VERSION 18 | } 19 | -------------------------------------------------------------------------------- /examples/get_fundings.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetFundingRequest; 3 | use failure::Fallible; 4 | 5 | #[tokio::main] 6 | async fn main() -> Fallible<()> { 7 | let _ = dotenv::dotenv(); 8 | env_logger::init(); 9 | 10 | let bm = BitMEXRest::new(); 11 | let res = bm 12 | .request(GetFundingRequest { 13 | symbol: Some("XBT".to_string()), 14 | ..Default::default() 15 | }) 16 | .await?; 17 | 18 | println!("{:?}", res); 19 | Ok(()) 20 | } 21 | -------------------------------------------------------------------------------- /tests/user_event.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetUserEventRequest; 3 | use failure::Fallible; 4 | use std::env::var; 5 | use tokio::runtime::Runtime; 6 | 7 | #[test] 8 | fn get_user_event() -> Fallible<()> { 9 | let _ = dotenv::dotenv(); 10 | let _ = env_logger::try_init(); 11 | let rt = Runtime::new()?; 12 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 13 | 14 | let _ = rt.block_on(bm.request(GetUserEventRequest::default()))?; 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /src/rest/models/swagger.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | #[derive(Deserialize, Debug, Clone)] 4 | #[serde(rename_all = "camelCase")] 5 | pub struct SwaggerApiDescription { 6 | pub swagger: String, 7 | pub info: SwaggerApiDescriptionInfo, 8 | pub base_path: String, 9 | } 10 | 11 | #[derive(Deserialize, Debug, Clone)] 12 | #[serde(rename_all = "camelCase")] 13 | pub struct SwaggerApiDescriptionInfo { 14 | pub title: String, 15 | pub description: String, 16 | pub terms_of_service: String, 17 | pub version: String, 18 | } 19 | -------------------------------------------------------------------------------- /tests/insurance.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetInsuranceRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use tokio::runtime::Runtime; 6 | 7 | #[test] 8 | fn get_insurance() -> Fallible<()> { 9 | let _ = dotenv::dotenv(); 10 | let _ = env_logger::try_init(); 11 | let rt = Runtime::new()?; 12 | 13 | let bm = BitMEXRest::new(); 14 | let fut = bm.request(GetInsuranceRequest { 15 | ..Default::default() 16 | }); 17 | 18 | debug!("{:?}", rt.block_on(fut)?); 19 | 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /tests/funding.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetFundingRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use tokio::runtime::Runtime; 6 | 7 | #[test] 8 | fn get_funding() -> Fallible<()> { 9 | let _ = dotenv::dotenv(); 10 | let _ = env_logger::try_init(); 11 | 12 | let rt = Runtime::new()?; 13 | 14 | let bm = BitMEXRest::new(); 15 | let fut = bm.request(GetFundingRequest { 16 | symbol: Some("XBT".to_string()), 17 | ..Default::default() 18 | }); 19 | 20 | debug!("{:?}", rt.block_on(fut)?); 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /examples/post_chat.rs: -------------------------------------------------------------------------------- 1 | use failure::Fallible; 2 | use std::env::var; 3 | 4 | use bitmex::rest::BitMEXRest; 5 | use bitmex::rest::PostChatRequest; 6 | 7 | #[tokio::main] 8 | async fn main() -> Fallible<()> { 9 | ::dotenv::dotenv().ok(); 10 | ::env_logger::init(); 11 | 12 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 13 | let ret = bm 14 | .request(PostChatRequest { 15 | message: "hello2 from bot".to_string(), 16 | channel_id: Some(1f64), 17 | }) 18 | .await?; 19 | 20 | println!("{:?}", ret); 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /tests/apikey.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetApiKeyRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_api_key() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | 13 | let rt = Runtime::new()?; 14 | 15 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 16 | let fut = bm.request(GetApiKeyRequest { 17 | ..Default::default() 18 | }); 19 | 20 | debug!("{:?}", rt.block_on(fut)?); 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /tests/liquidation.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetLiquidationRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_liquidation() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | 14 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 15 | let fut = bm.request(GetLiquidationRequest { 16 | ..Default::default() 17 | }); 18 | 19 | debug!("{:?}", rt.block_on(fut)?); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /tests/settlement.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetSettlementRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_settlement() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 14 | let fut = bm.request(GetSettlementRequest { 15 | ..Default::default() 16 | }); 17 | let ret = rt.block_on(fut); 18 | 19 | debug!("{:?}", ret); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /tests/order_book.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetOrderBookL2Request; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_order_book_l2() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | 14 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 15 | let fut = bm.request(GetOrderBookL2Request { 16 | symbol: "XBTUSD".into(), 17 | depth: Some(1), 18 | }); 19 | 20 | debug!("{:?}", rt.block_on(fut)?); 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /examples/ws_ping.rs: -------------------------------------------------------------------------------- 1 | use bitmex::websocket::{BitMEXWebsocket, Command}; 2 | use failure::Fallible; 3 | use futures::sink::SinkExt; 4 | use futures::stream::StreamExt; 5 | use std::env::var; 6 | 7 | #[tokio::main] 8 | async fn main() -> Fallible<()> { 9 | ::dotenv::dotenv().ok(); 10 | ::env_logger::init(); 11 | 12 | let mut client = 13 | BitMEXWebsocket::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?).await?; 14 | 15 | println!("WebSocket handshake has been successfully completed"); 16 | 17 | client.send(Command::Ping).await?; 18 | 19 | while let Some(msg) = client.next().await { 20 | println!("{:?}", msg); 21 | } 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /tests/global_notification.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetGlobalNotificationRequest; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | // This will fail for error access denied 9 | #[test] 10 | fn get_global_notification() -> Fallible<()> { 11 | let _ = dotenv::dotenv(); 12 | let _ = env_logger::try_init(); 13 | 14 | let rt = Runtime::new()?; 15 | 16 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 17 | let fut = bm.request(GetGlobalNotificationRequest {}); 18 | let ret = rt.block_on(fut); 19 | 20 | debug!("{:?}", ret); 21 | assert!(ret.is_err()); 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /examples/proxy.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::GetFundingRequest; 3 | use failure::Fallible; 4 | use reqwest::{Client, Proxy}; 5 | 6 | #[tokio::main] 7 | async fn main() -> Fallible<()> { 8 | let _ = dotenv::dotenv(); 9 | env_logger::init(); 10 | 11 | let proxy = Proxy::http("https://secure.example")?; 12 | let transport = Client::builder().proxy(proxy).build()?; 13 | 14 | let bm = BitMEXRest::builder().client(transport).build().unwrap(); 15 | 16 | let res = bm 17 | .request(GetFundingRequest { 18 | symbol: Some("XBT".to_string()), 19 | ..Default::default() 20 | }) 21 | .await?; 22 | 23 | println!("{:?}", res); 24 | Ok(()) 25 | } 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | sudo: false 5 | env: 6 | global: 7 | - secure: JVnh/Wyggd59i0HKK8GCJ4iaJPYtVanqy0W87zCmEFtgqbYt92UQvioiaWAqAtQBbeHVE0/1uSSBNIvujCGxnky+ybmky378g1C1EGFkNS+AsKynJsbKl+mWkmSS59jitNo03lgtd466jWcxrwC10KcE1d7p7MBWPXXi3+CDBRKePDER2mMApDvaTiD+7aj5LGamNt98AapUbHTaDmmAjcMHCXAQEIlpg8kxRXNEA53zeagHpHed5hDRRIPrHOvIKATAmw7b4519AKqtqFUW8dtqzKGvA1yVnuxhGGfFYFZeOLsKzheXEWCI1c1EXwbC2P2RedfZ+GCM8RrY7AJ8Xu+fSQMCPYAqidqHKyKz8+mYnWC8Wfdzy7zyHPM3LEm689Uw5iKivBZgcFM5eIjwveaKMSozWzbv7vrMBTOLyNW2QNK/3iYYkL0WJEvD3xRuTBjYgT67Pyp+5gANoesRAbz1n665xkVTNg/UOTa5fn0IMSVS97h6Ew/mNBkqx94bKqRGBhcBp+GIn2DSi8vmkUWWE1E33K1+glDXHMpY4bUH4CGyk6C3/nsGltvOeMXTDog8sdB6D3x3U5rtHpyAcYbd0ZJiib5f0VVvkSgzTUQB2inqiPhS2e8GWYymCvISnmkS9YHFIc9U6dFQjaDNfW6vte+gFyBFOcSnZc14ZQ8= -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use failure::Fail; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Fail, Serialize, Deserialize, Clone)] 5 | pub enum BitMEXError { 6 | #[fail(display = "No Api key set for private api")] 7 | NoApiKeySet, 8 | #[fail(display = "{} error message from BitMEX server: {}", name, message)] 9 | RemoteError { message: String, name: String }, 10 | #[fail(display = "Websocket closed")] 11 | WebsocketClosed, 12 | #[fail(display = "Unexpected websocket binary content {:?}", _0)] 13 | UnexpectedWebsocketBinaryContent(Vec), 14 | #[fail(display = "Cannot parse topic {:?}", _0)] 15 | ParseTopicError(String), 16 | #[fail(display = "Error from websocket. {}: {}", status, error)] 17 | WebsocketError { status: i64, error: String }, 18 | } 19 | -------------------------------------------------------------------------------- /src/rest/mod.rs: -------------------------------------------------------------------------------- 1 | mod client; 2 | mod models; 3 | 4 | pub use client::{BitMEXRest, BitMEXRestBuilder}; 5 | pub use models::*; 6 | 7 | use crate::error::BitMEXError; 8 | use serde::{Deserialize, Serialize}; 9 | use std::convert::From; 10 | 11 | // The error response from bitmex; 12 | #[derive(Deserialize, Serialize, Debug, Clone)] 13 | pub(crate) struct BitMEXErrorResponse { 14 | pub(crate) error: BitMEXErrorMessage, 15 | } 16 | 17 | #[derive(Deserialize, Serialize, Debug, Clone)] 18 | pub(crate) struct BitMEXErrorMessage { 19 | pub(crate) message: String, 20 | pub(crate) name: String, 21 | } 22 | 23 | impl From for BitMEXError { 24 | fn from(msg: BitMEXErrorMessage) -> BitMEXError { 25 | BitMEXError::RemoteError { 26 | message: msg.message, 27 | name: msg.name, 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/consts.rs: -------------------------------------------------------------------------------- 1 | use std::env::var; 2 | 3 | use lazy_static::lazy_static; 4 | use log::warn; 5 | 6 | // dotenv is a must run in every test otherwise the url will be mis-loaded 7 | lazy_static! { 8 | pub static ref WS_URL: &'static str = { 9 | if var("BITMEX_TESTNET").unwrap_or_else(|_| "0".to_string()) == "0" { 10 | "wss://www.bitmex.com/realtime" 11 | } else { 12 | warn!("Your are using BitMEX testnet Websocket"); 13 | "wss://testnet.bitmex.com/realtime" 14 | } 15 | }; 16 | pub static ref REST_URL: &'static str = { 17 | if var("BITMEX_TESTNET").unwrap_or_else(|_| "0".to_string()) == "0" { 18 | "https://www.bitmex.com/api/v1" 19 | } else { 20 | warn!("Your are using BitMEX testnet Restful API"); 21 | "https://testnet.bitmex.com/api/v1" 22 | } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /examples/ws_orderbook_trade.rs: -------------------------------------------------------------------------------- 1 | use bitmex::websocket::{BitMEXWebsocket, Command, Topic}; 2 | use failure::Fallible; 3 | use futures::sink::SinkExt; 4 | use futures::stream::StreamExt; 5 | use std::env::var; 6 | 7 | #[tokio::main] 8 | async fn main() -> Fallible<()> { 9 | ::dotenv::dotenv().ok(); 10 | ::env_logger::init(); 11 | 12 | let mut client = 13 | BitMEXWebsocket::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?).await?; 14 | 15 | println!("WebSocket handshake has been successfully completed"); 16 | 17 | client 18 | .send(Command::Subscribe(vec![ 19 | // Topic::OrderBookL2_25(Some("XBTUSD".to_string())), 20 | Topic::Trade(Some("XBTUSD".to_string())), 21 | ])) 22 | .await?; 23 | 24 | while let Some(msg) = client.next().await { 25 | println!("{:?}", msg); 26 | } 27 | 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/ws_auth.rs: -------------------------------------------------------------------------------- 1 | use bitmex::websocket::{BitMEXWebsocket, Command, Topic}; 2 | use chrono::{Duration, Utc}; 3 | use failure::Fallible; 4 | use futures::sink::SinkExt; 5 | use futures::stream::StreamExt; 6 | use std::env::var; 7 | 8 | #[tokio::main] 9 | async fn main() -> Fallible<()> { 10 | ::dotenv::dotenv().ok(); 11 | ::env_logger::init(); 12 | 13 | let mut client = 14 | BitMEXWebsocket::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?).await?; 15 | 16 | println!("WebSocket handshake has been successfully completed"); 17 | let expires = (Utc::now() + Duration::seconds(30)).timestamp(); 18 | 19 | client.send(Command::authenticate(expires as u64)).await?; 20 | 21 | client 22 | .send(Command::Subscribe(vec![Topic::Position])) 23 | .await?; 24 | 25 | while let Some(msg) = client.next().await { 26 | println!("{:?}", msg); 27 | } 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/ws_cancel_all.rs: -------------------------------------------------------------------------------- 1 | use bitmex::websocket::{BitMEXWebsocket, Command}; 2 | use chrono::{Duration, Utc}; 3 | use failure::Fallible; 4 | use futures::sink::SinkExt; 5 | use futures::stream::StreamExt; 6 | use std::env::var; 7 | 8 | #[tokio::main] 9 | async fn main() -> Fallible<()> { 10 | ::dotenv::dotenv().ok(); 11 | ::env_logger::init(); 12 | 13 | let mut client = 14 | BitMEXWebsocket::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?).await?; 15 | 16 | println!("WebSocket handshake has been successfully completed"); 17 | let expires = (Utc::now() + Duration::seconds(30)).timestamp(); 18 | client.send(Command::authenticate(expires as u64)).await?; 19 | 20 | client 21 | .send(Command::CancelAllAfter(365 * 24 * 60 * 60 * 1000)) 22 | .await?; 23 | 24 | while let Some(msg) = client.next().await { 25 | println!("{:?}", msg); 26 | } 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /src/websocket/command.rs: -------------------------------------------------------------------------------- 1 | use super::Topic; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Clone, Serialize, Deserialize)] 5 | #[serde(tag = "op", content = "args")] 6 | #[serde(rename_all = "camelCase")] 7 | pub enum Command { 8 | Subscribe(Vec), 9 | Unsubscribe(Vec), 10 | #[serde(rename = "authKeyExpires")] 11 | Authenticate(Option, u64, Option), 12 | CancelAllAfter(u64), 13 | Ping, 14 | } 15 | 16 | impl Command { 17 | pub fn authenticate(expires: u64) -> Command { 18 | Command::Authenticate(None, expires, None) 19 | } 20 | pub fn subscribe(topics: Vec) -> Command { 21 | Command::Subscribe(topics) 22 | } 23 | pub fn unsubscribe(topics: Vec) -> Command { 24 | Command::Unsubscribe(topics) 25 | } 26 | pub fn cancel_all_after(millisecs: u64) -> Command { 27 | Command::CancelAllAfter(millisecs) 28 | } 29 | pub fn ping() -> Command { 30 | Command::Ping 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/announcement.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{GetAnnouncementRequest, GetAnnouncementUrgentRequest}; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_announcement() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | 13 | let rt = Runtime::new()?; 14 | 15 | let bm = BitMEXRest::new(); 16 | let fut = bm.request(GetAnnouncementRequest { 17 | ..Default::default() 18 | }); 19 | 20 | debug!("{:?}", rt.block_on(fut)?); 21 | Ok(()) 22 | } 23 | 24 | #[test] 25 | fn get_announcement_urgent() -> Fallible<()> { 26 | let _ = dotenv::dotenv(); 27 | let _ = env_logger::try_init(); 28 | 29 | let rt = Runtime::new()?; 30 | 31 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 32 | let fut = bm.request(GetAnnouncementUrgentRequest {}); 33 | 34 | debug!("{:?}", rt.block_on(fut)?); 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /tests/leaderboard.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{GetLeaderboardNameRequest, GetLeaderboardRequest}; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_leaderboard() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | 14 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 15 | let fut = bm.request(GetLeaderboardRequest { 16 | ..Default::default() 17 | }); 18 | 19 | debug!("{:?}", rt.block_on(fut)?); 20 | Ok(()) 21 | } 22 | 23 | #[test] 24 | fn get_leaderboard_name() -> Fallible<()> { 25 | let _ = dotenv::dotenv(); 26 | let _ = env_logger::try_init(); 27 | let rt = Runtime::new()?; 28 | 29 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 30 | let fut = bm.request(GetLeaderboardNameRequest {}); 31 | 32 | debug!("{:?}", rt.block_on(fut)?); 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /tests/execution.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{GetExecutionRequest, GetExecutionTradeHistoryRequest}; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_execution() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | 13 | let rt = Runtime::new()?; 14 | 15 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 16 | let fut = bm.request(GetExecutionRequest { 17 | ..Default::default() 18 | }); 19 | 20 | debug!("{:?}", rt.block_on(fut)?); 21 | Ok(()) 22 | } 23 | 24 | #[test] 25 | fn get_execution_history() -> Fallible<()> { 26 | let _ = dotenv::dotenv(); 27 | let _ = env_logger::try_init(); 28 | 29 | let rt = Runtime::new()?; 30 | 31 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 32 | let fut = bm.request(GetExecutionTradeHistoryRequest { 33 | ..Default::default() 34 | }); 35 | 36 | debug!("{:?}", rt.block_on(fut)?); 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /tests/trade.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BinSize; 2 | use bitmex::rest::BitMEXRest; 3 | use bitmex::rest::{GetTradeBucketedRequest, GetTradeRequest}; 4 | use failure::Fallible; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_trade() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 14 | 15 | let _ = rt.block_on(bm.request(GetTradeRequest { 16 | ..Default::default() 17 | }))?; 18 | Ok(()) 19 | } 20 | 21 | #[test] 22 | fn get_trade_bucketed() -> Fallible<()> { 23 | let _ = dotenv::dotenv(); 24 | let _ = env_logger::try_init(); 25 | let rt = Runtime::new()?; 26 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 27 | 28 | let _ = rt.block_on(bm.request(GetTradeBucketedRequest { 29 | partial: Some(false), 30 | bin_size: Some(BinSize::D1), 31 | count: Some(10), 32 | ..Default::default() 33 | }))?; 34 | 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Weiyüen Wu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/ws_subscribe.rs: -------------------------------------------------------------------------------- 1 | use bitmex::websocket::{BitMEXWebsocket, Command, Topic}; 2 | use failure::Fallible; 3 | use futures::sink::SinkExt; 4 | use futures::stream::StreamExt; 5 | use std::env::var; 6 | 7 | #[tokio::main] 8 | async fn main() -> Fallible<()> { 9 | ::dotenv::dotenv().ok(); 10 | ::env_logger::init(); 11 | 12 | let mut client = 13 | BitMEXWebsocket::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?).await?; 14 | 15 | println!("WebSocket handshake has been successfully completed"); 16 | 17 | client 18 | .send(Command::Subscribe(vec![ 19 | Topic::Chat, 20 | Topic::OrderBookL2(Some("XBTUSD".to_string())), 21 | Topic::Connected, 22 | Topic::Liquidation, 23 | Topic::QuoteBin1m(None), 24 | Topic::TradeBin1m(None), 25 | Topic::Trade(None), 26 | Topic::Settlement, 27 | Topic::OrderBook10(None), 28 | Topic::Announcement, 29 | ])) 30 | .await?; 31 | 32 | while let Some(msg) = client.next().await { 33 | println!("{:?}", msg); 34 | } 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /tests/quote.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BinSize; 2 | use bitmex::rest::BitMEXRest; 3 | use bitmex::rest::{GetQuoteBucketedRequest, GetQuoteRequest}; 4 | use failure::Fallible; 5 | use log::debug; 6 | use std::env::var; 7 | use tokio::runtime::Runtime; 8 | 9 | // 403 forbidden 10 | #[test] 11 | fn get_quote() -> Fallible<()> { 12 | let _ = dotenv::dotenv(); 13 | let _ = env_logger::try_init(); 14 | let rt = Runtime::new()?; 15 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 16 | let fut = bm.request(GetQuoteRequest { 17 | ..Default::default() 18 | }); 19 | let ret = rt.block_on(fut); 20 | debug!("{:?}", ret); 21 | 22 | assert!(ret.is_err()); 23 | Ok(()) 24 | } 25 | 26 | // 403 forbidden 27 | #[test] 28 | fn get_quote_bucketed() -> Fallible<()> { 29 | let _ = dotenv::dotenv(); 30 | let _ = env_logger::try_init(); 31 | let rt = Runtime::new()?; 32 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 33 | let fut = bm.request(GetQuoteBucketedRequest { 34 | partial: Some(false), 35 | bin_size: Some(BinSize::D1), 36 | ..Default::default() 37 | }); 38 | let ret = rt.block_on(fut); 39 | debug!("{:?}", ret); 40 | 41 | assert!(ret.is_err()); 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitmex" 3 | version = "0.2.2" 4 | authors = ["Weiyüen Wu "] 5 | license = "MIT OR Apache-2.0" 6 | description = "Rust Library for the BitMEX API (Async)" 7 | keywords = ["cryptocurrency", "trading", "bitmex", "async"] 8 | documentation = "https://docs.rs/crate/bitmex" 9 | repository = "https://github.com/dovahcrow/bitmex-rs" 10 | readme = "README.md" 11 | edition = "2018" 12 | categories = ["api-bindings"] 13 | 14 | [badges] 15 | travis-ci = { repository = "dovahcrow/bitmex-rs", branch = "master" } 16 | 17 | [dependencies] 18 | reqwest = { version = "0.11", features = ["json"] } 19 | hyper = "0.14" 20 | hyper-tls = "0.5" 21 | http = "0.2" 22 | 23 | url = "2" 24 | futures = "0.3" 25 | tokio = { version = "1", features = ["macros"] } 26 | pin-project = "1" 27 | 28 | failure = "0.1" 29 | fehler = "1" 30 | log = "0.4" 31 | 32 | serde = { version = "1", features = [ "derive" ] } 33 | serde_json = "1" 34 | serde_urlencoded = "0.7" 35 | serde_qs = "0.8" 36 | 37 | chrono = { version = "0.4", features = ["serde"] } 38 | 39 | hex = "0.4" 40 | ring = "0.16" 41 | 42 | uuid = { version = "0.8", features = ["serde"] } 43 | tungstenite = "0.12" 44 | tokio-tungstenite = { version = "0.13", features = ["tls"] } 45 | lazy_static = "1" 46 | derive_builder = "0.9" 47 | 48 | [dev-dependencies] 49 | dotenv = "0.15" 50 | env_logger = "0.8" 51 | tokio = { version = "1", features = ["time", "macros", "rt-multi-thread", "net"] } -------------------------------------------------------------------------------- /tests/stats.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{GetStatsHistoryRequest, GetStatsHistoryUSDRequest, GetStatsRequest}; 3 | use failure::Fallible; 4 | use log::debug; 5 | use std::env::var; 6 | use tokio::runtime::Runtime; 7 | 8 | #[test] 9 | fn get_stats() -> Fallible<()> { 10 | let _ = dotenv::dotenv(); 11 | let _ = env_logger::try_init(); 12 | let rt = Runtime::new()?; 13 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 14 | let fut = bm.request(GetStatsRequest); 15 | let ret = rt.block_on(fut); 16 | 17 | debug!("{:?}", ret); 18 | Ok(()) 19 | } 20 | 21 | #[test] 22 | fn get_stats_history() -> Fallible<()> { 23 | let _ = dotenv::dotenv(); 24 | let _ = env_logger::try_init(); 25 | let rt = Runtime::new()?; 26 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 27 | let fut = bm.request(GetStatsHistoryRequest); 28 | let ret = rt.block_on(fut); 29 | 30 | debug!("{:?}", ret); 31 | Ok(()) 32 | } 33 | 34 | #[test] 35 | fn get_stats_history_usd() -> Fallible<()> { 36 | let _ = dotenv::dotenv(); 37 | let _ = env_logger::try_init(); 38 | let rt = Runtime::new()?; 39 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 40 | let fut = bm.request(GetStatsHistoryUSDRequest); 41 | let ret = rt.block_on(fut); 42 | 43 | debug!("{:?}", ret); 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /tests/chat.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{ 3 | GetChatChannelsRequest, GetChatConnectedRequest, GetChatRequest, PostChatRequest, 4 | }; 5 | use failure::Fallible; 6 | use log::debug; 7 | use std::env::var; 8 | use tokio::runtime::Runtime; 9 | 10 | #[test] 11 | fn get_chat() -> Fallible<()> { 12 | let _ = dotenv::dotenv(); 13 | let _ = env_logger::try_init(); 14 | 15 | let rt = Runtime::new()?; 16 | 17 | let bm = BitMEXRest::new(); 18 | let fut = bm.request(GetChatRequest { 19 | count: Some(1), 20 | channel_id: Some(1.), 21 | ..Default::default() 22 | }); 23 | 24 | debug!("{:?}", rt.block_on(fut)?); 25 | Ok(()) 26 | } 27 | 28 | #[test] 29 | #[ignore] // My test account was banned from chatting on testnet 30 | fn post_chat() -> Fallible<()> { 31 | let _ = dotenv::dotenv(); 32 | let _ = env_logger::try_init(); 33 | 34 | let rt = Runtime::new()?; 35 | 36 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 37 | let fut = bm.request(PostChatRequest { 38 | message: "Hey there".into(), 39 | channel_id: Some(1.), 40 | }); 41 | 42 | debug!("{:?}", rt.block_on(fut)?); 43 | Ok(()) 44 | } 45 | 46 | #[test] 47 | fn get_chat_channels() -> Fallible<()> { 48 | let _ = dotenv::dotenv(); 49 | let _ = env_logger::try_init(); 50 | let rt = Runtime::new()?; 51 | 52 | let bm = BitMEXRest::new(); 53 | let fut = bm.request(GetChatChannelsRequest {}); 54 | 55 | debug!("{:?}", rt.block_on(fut)?); 56 | Ok(()) 57 | } 58 | 59 | #[test] 60 | fn get_chat_connected() -> Fallible<()> { 61 | let _ = dotenv::dotenv(); 62 | let _ = env_logger::try_init(); 63 | let rt = Runtime::new()?; 64 | 65 | let bm = BitMEXRest::new(); 66 | let fut = bm.request(GetChatConnectedRequest {}); 67 | 68 | debug!("{:?}", rt.block_on(fut)?); 69 | Ok(()) 70 | } 71 | -------------------------------------------------------------------------------- /examples/readme.rs: -------------------------------------------------------------------------------- 1 | use chrono::{Duration, Utc}; 2 | use failure::Fallible; 3 | use futures::sink::SinkExt; 4 | use futures::stream::StreamExt; 5 | 6 | #[tokio::main] 7 | async fn main() -> Fallible<()> { 8 | ::dotenv::dotenv().ok(); 9 | ::env_logger::init(); 10 | 11 | // This will give you a BitMEX instance, which the only purpose is to create connection. 12 | let bm = bitmex::rest::BitMEXRest::with_credential( 13 | &std::env::var("BITMEX_KEY")?, 14 | &std::env::var("BITMEX_SECRET")?, 15 | ); 16 | 17 | // All the requests to BitMEX server afterwards will go through HTTP Restful API. 18 | 19 | // The request models reside in "bitmex::models" module, with the 20 | // naming convention of "Method+camelCase(endpoint)+Request", e.g. "GET /trade/bucketed" would be 21 | // "bitmex::models::GetTradeBucketedRequest" in bitmex-rs. 22 | let req = bitmex::rest::GetTradeBucketedRequest { 23 | bin_size: Some(bitmex::rest::BinSize::D1), 24 | ..Default::default() 25 | }; 26 | 27 | // Request to BitMEX server is made by giving "BitMEX::request" the request object. 28 | // The return type of "BitMEX::request" is a future of the response so that you can await on it. 29 | let resp = bm.request(req).await?; 30 | println!("Bucketed trades: {:?}", resp); 31 | 32 | // A websocket is created by "BitMEX::websocket". 33 | let mut ws = bitmex::websocket::BitMEXWebsocket::with_credential( 34 | &std::env::var("BITMEX_KEY")?, 35 | &std::env::var("BITMEX_SECRET")?, 36 | ) 37 | .await?; 38 | 39 | // The websocket is a duplex channel which means you can send "bitmex::websocket::Command" to BitMEX and 40 | // receive "bitmex::websocket::Message" from BitMEX using it. 41 | let expires = (Utc::now() + Duration::seconds(30)).timestamp(); 42 | ws.send(bitmex::websocket::Command::authenticate(expires as u64)) 43 | .await?; 44 | 45 | // In order to get the ws messages, just poll the ws stream. 46 | while let Some(message) = ws.next().await { 47 | println!("Subscription message received {:?}", message); 48 | } 49 | 50 | Ok(()) 51 | } 52 | -------------------------------------------------------------------------------- /tests/instrument.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{ 3 | GetInstrumentActiveAndIndicesRequest, GetInstrumentActiveIntervalsRequest, 4 | GetInstrumentActiveRequest, GetInstrumentCompositeIndexRequest, GetInstrumentIndicesRequest, 5 | GetInstrumentRequest, 6 | }; 7 | use failure::Fallible; 8 | use log::debug; 9 | use tokio::runtime::Runtime; 10 | 11 | #[test] 12 | fn test_get_instrument() -> Fallible<()> { 13 | let _ = dotenv::dotenv(); 14 | let _ = env_logger::try_init(); 15 | let rt = Runtime::new()?; 16 | 17 | let bm = BitMEXRest::new(); 18 | let fut = bm.request(GetInstrumentRequest { 19 | symbol: Some("XBT".to_string()), 20 | ..Default::default() 21 | }); 22 | 23 | debug!("{:?}", rt.block_on(fut)?); 24 | Ok(()) 25 | } 26 | 27 | #[test] 28 | fn test_get_instrument_active() -> Fallible<()> { 29 | let _ = dotenv::dotenv(); 30 | let _ = env_logger::try_init(); 31 | let rt = Runtime::new()?; 32 | 33 | let bm = BitMEXRest::new(); 34 | let fut = bm.request(GetInstrumentActiveRequest {}); 35 | 36 | debug!("{:?}", rt.block_on(fut)?); 37 | 38 | Ok(()) 39 | } 40 | 41 | #[test] 42 | fn test_get_instrument_active_and_indices() -> Fallible<()> { 43 | let _ = dotenv::dotenv(); 44 | let _ = env_logger::try_init(); 45 | let rt = Runtime::new()?; 46 | 47 | let bm = BitMEXRest::new(); 48 | let fut = bm.request(GetInstrumentActiveAndIndicesRequest {}); 49 | 50 | debug!("{:?}", rt.block_on(fut)?); 51 | 52 | Ok(()) 53 | } 54 | 55 | #[test] 56 | fn get_instrument_active_interval() -> Fallible<()> { 57 | let _ = dotenv::dotenv(); 58 | let _ = env_logger::try_init(); 59 | let rt = Runtime::new()?; 60 | 61 | let bm = BitMEXRest::new(); 62 | let fut = bm.request(GetInstrumentActiveIntervalsRequest {}); 63 | 64 | debug!("{:?}", rt.block_on(fut)?); 65 | 66 | Ok(()) 67 | } 68 | 69 | #[test] 70 | fn get_instrument_composite_index() -> Fallible<()> { 71 | let _ = dotenv::dotenv(); 72 | let _ = env_logger::try_init(); 73 | let rt = Runtime::new()?; 74 | 75 | let bm = BitMEXRest::new(); 76 | let fut = bm.request(GetInstrumentCompositeIndexRequest { 77 | symbol: Some("XBT".to_string()), 78 | ..Default::default() 79 | }); 80 | 81 | debug!("{:?}", rt.block_on(fut)?); 82 | 83 | Ok(()) 84 | } 85 | 86 | #[test] 87 | fn get_instrument_indices() -> Fallible<()> { 88 | let _ = dotenv::dotenv(); 89 | let _ = env_logger::try_init(); 90 | let rt = Runtime::new()?; 91 | 92 | let bm = BitMEXRest::new(); 93 | let fut = bm.request(GetInstrumentIndicesRequest {}); 94 | 95 | debug!("{:?}", rt.block_on(fut)?); 96 | 97 | Ok(()) 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bitmex-rs [![Crates.io](https://img.shields.io/crates/v/bitmex.svg)](https://crates.io/crates/bitmex) [![Build Status](https://travis-ci.org/dovahcrow/bitmex-rs.png?branch=master)](https://travis-ci.org/dovahcrow/bitmex-rs) [![MIT licensed](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE) 2 | 3 | [BitMEX](https://www.bitmex.com/app/apiOverview) (non-official) client for rust, with async/await support! 4 | 5 | [Documentation](https://docs.rs/crate/bitmex) 6 | 7 | ## Caveat 8 | 9 | Please run the tests before you use since BitMEX often introduces breaking changes without 10 | changing their Swagger API definition. 11 | 12 | Also, the Swagger definition somehow is not aligned with BitMEX's realworld API. Since bitmex-rs 13 | auto-generates the code from swagger.json, you may experience some API breakage. Please do not 14 | hesitate to file an issue! 15 | 16 | ## Usage 17 | 18 | Add this to your Cargo.toml 19 | 20 | ```toml 21 | [dependencies] 22 | bitmex = "0.2" 23 | ``` 24 | 25 | # Basic usage 26 | 27 | ```rust 28 | // This will give you a BitMEX instance, which the only purpose is to create connection. 29 | let bm = bitmex::BitMEXRest::with_credential(&std::env::var("BITMEX_KEY")?, &std::env::var("BITMEX_SECRET")?); 30 | 31 | // All the requests to BitMEX server afterwards will go through HTTP Restful API. 32 | 33 | // The request models reside in "bitmex::models" module, with the 34 | // naming convention of "Method+camelCase(endpoint)+Request", e.g. "GET /trade/bucketed" would be 35 | // "bitmex::models::GetTradeBucketedRequest" in bitmex-rs. 36 | let req = bitmex::models::GetTradeBucketedRequest { 37 | bin_size: Some(bitmex::models::BinSize::D1), 38 | ..Default::default() 39 | }; 40 | 41 | // Request to BitMEX server is made by giving "BitMEX::request" the request object. 42 | // The return type of "BitMEX::request" is a future of the response so that you can await on it. 43 | let resp = bm.request(req).await?; 44 | println!("Bucketed trades: {:?}", resp); 45 | 46 | // A websocket is created by "BitMEX::websocket". 47 | let mut ws = bm.websocket().await?; 48 | 49 | // The websocket is a duplex channel which means you can send "bitmex::websocket::Command" to BitMEX and 50 | // receive "bitmex::websocket::Message" from BitMEX using it. 51 | let expires = (Utc::now() + Duration::seconds(30)).timestamp(); 52 | ws.send(Command::authenticate(&bm, expires).unwrap()).await?; 53 | 54 | // In order to get the ws messages, just poll the ws stream. 55 | while let Some(message) = ws.next().await { 56 | println!("Subscription message received {:?}", message); 57 | } 58 | 59 | ``` 60 | 61 | More examples located in the examples and tests folder. 62 | 63 | ## Implementation status 64 | 65 | Currently all the API features are implemented, including websocket! 66 | -------------------------------------------------------------------------------- /tests/position.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{ 3 | GetPositionRequest, PostPositionIsolateRequest, PostPositionLeverageRequest, 4 | PostPositionRiskLimitRequest, PostPositionTransferMarginRequest, 5 | }; 6 | use failure::Fallible; 7 | use log::debug; 8 | use std::env::var; 9 | use tokio::runtime::Runtime; 10 | 11 | #[test] 12 | fn get_position() -> Fallible<()> { 13 | let _ = dotenv::dotenv(); 14 | let _ = env_logger::try_init(); 15 | let _ = ::env_logger::try_init(); 16 | let rt = Runtime::new()?; 17 | 18 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 19 | let fut = bm.request(GetPositionRequest { 20 | ..Default::default() 21 | }); 22 | 23 | debug!("{:?}", rt.block_on(fut)?); 24 | Ok(()) 25 | } 26 | 27 | #[test] 28 | fn post_position_isolate() -> Fallible<()> { 29 | let _ = dotenv::dotenv(); 30 | let _ = env_logger::try_init(); 31 | let _ = ::env_logger::try_init(); 32 | let rt = Runtime::new()?; 33 | 34 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 35 | let fut = bm.request(PostPositionIsolateRequest { 36 | symbol: "XBTUSD".into(), 37 | enabled: Some(false), 38 | }); 39 | 40 | debug!("{:?}", rt.block_on(fut)?); 41 | Ok(()) 42 | } 43 | 44 | #[test] 45 | fn post_position_leverage() -> Fallible<()> { 46 | let _ = dotenv::dotenv(); 47 | let _ = env_logger::try_init(); 48 | let _ = ::env_logger::try_init(); 49 | let rt = Runtime::new()?; 50 | 51 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 52 | let fut = bm.request(PostPositionLeverageRequest { 53 | symbol: "XBTUSD".into(), 54 | leverage: 1.1, 55 | }); 56 | 57 | debug!("{:?}", rt.block_on(fut)?); 58 | Ok(()) 59 | } 60 | 61 | #[test] 62 | fn post_position_risk_limit() -> Fallible<()> { 63 | let _ = dotenv::dotenv(); 64 | let _ = env_logger::try_init(); 65 | let _ = ::env_logger::try_init(); 66 | let rt = Runtime::new()?; 67 | 68 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 69 | let fut = bm.request(PostPositionRiskLimitRequest { 70 | symbol: "XBTUSD".into(), 71 | risk_limit: 30000000000, 72 | }); 73 | 74 | let a = rt.block_on(fut)?; 75 | println!("{:?}", a); 76 | Ok(()) 77 | } 78 | 79 | #[test] 80 | #[ignore] 81 | fn post_position_transfer_margin() -> Fallible<()> { 82 | let _ = dotenv::dotenv(); 83 | let _ = env_logger::try_init(); 84 | let _ = ::env_logger::try_init(); 85 | let rt = Runtime::new()?; 86 | 87 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 88 | let fut = bm.request(PostPositionTransferMarginRequest { 89 | symbol: "XBTUSD".into(), 90 | amount: 10, 91 | }); 92 | 93 | debug!("{:?}", rt.block_on(fut)?); 94 | Ok(()) 95 | } 96 | -------------------------------------------------------------------------------- /src/rest/models/mod.rs: -------------------------------------------------------------------------------- 1 | mod definitions; 2 | mod requests; 3 | pub mod swagger; 4 | pub use self::definitions::*; 5 | pub use self::requests::*; 6 | use reqwest::Method; 7 | use serde::de::DeserializeOwned; 8 | use serde::{Deserialize, Serialize}; 9 | 10 | pub trait Request: Serialize { 11 | const METHOD: Method; 12 | const SIGNED: bool = false; 13 | const ENDPOINT: &'static str; 14 | const HAS_PAYLOAD: bool = true; 15 | type Response: DeserializeOwned; 16 | 17 | #[inline] 18 | fn no_payload(&self) -> bool { 19 | !Self::HAS_PAYLOAD 20 | } 21 | } 22 | 23 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 24 | pub enum Side { 25 | Buy, 26 | Sell, 27 | #[serde(rename = "")] 28 | Unknown, // BitMEX sometimes has empty side due to unknown reason 29 | } 30 | 31 | #[derive(Clone, Debug, Serialize, Deserialize)] 32 | pub enum BinSize { 33 | #[serde(rename = "1m")] 34 | M1, 35 | #[serde(rename = "5m")] 36 | M5, 37 | #[serde(rename = "1h")] 38 | H1, 39 | #[serde(rename = "1d")] 40 | D1, 41 | } 42 | 43 | impl Default for BinSize { 44 | fn default() -> Self { 45 | self::BinSize::D1 46 | } 47 | } 48 | 49 | /// http://fixwiki.org/fixwiki/PegPriceType 50 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 51 | pub enum PegPriceType { 52 | LastPeg, 53 | OpeningPeg, 54 | MidPricePeg, 55 | MarketPeg, 56 | PrimaryPeg, 57 | PegToVWAP, 58 | TrailingStopPeg, 59 | PegToLimitPrice, 60 | ShortSaleMinPricePeg, 61 | #[serde(rename = "")] 62 | Unknown, // BitMEX sometimes has empty due to unknown reason 63 | } 64 | 65 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 66 | pub enum OrdType { 67 | Market, 68 | Limit, 69 | Stop, 70 | StopLimit, 71 | MarketIfTouched, 72 | LimitIfTouched, 73 | MarketWithLeftOverAsLimit, 74 | Pegged, 75 | } 76 | 77 | /// https://www.onixs.biz/fix-dictionary/5.0.SP2/tagNum_59.html 78 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 79 | pub enum TimeInForce { 80 | Day, 81 | GoodTillCancel, 82 | AtTheOpening, 83 | ImmediateOrCancel, 84 | FillOrKill, 85 | GoodTillCrossing, 86 | GoodTillDate, 87 | AtTheClose, 88 | GoodThroughCrossing, 89 | AtCrossing, 90 | } 91 | 92 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 93 | pub enum ExecInst { 94 | ParticipateDoNotInitiate, 95 | AllOrNone, 96 | MarkPrice, 97 | IndexPrice, 98 | LastPrice, 99 | Close, 100 | ReduceOnly, 101 | Fixed, 102 | #[serde(rename = "")] 103 | Unknown, // BitMEX sometimes has empty due to unknown reason 104 | } 105 | 106 | #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 107 | pub enum ContingencyType { 108 | OneCancelsTheOther, 109 | OneTriggersTheOther, 110 | OneUpdatesTheOtherAbsolute, 111 | OneUpdatesTheOtherProportional, 112 | #[serde(rename = "")] 113 | Unknown, // BitMEX sometimes has empty due to unknown reason 114 | } 115 | -------------------------------------------------------------------------------- /tests/user.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{ 3 | GetUserAffiliateStatusRequest, GetUserCommissionRequest, GetUserDepositAddressRequest, 4 | GetUserRequest, GetUserWalletHistoryRequest, GetUserWalletRequest, GetUserWalletSummaryRequest, 5 | }; 6 | use failure::Fallible; 7 | use log::debug; 8 | use std::env::var; 9 | use tokio::runtime::Runtime; 10 | 11 | #[test] 12 | fn get_user() -> Fallible<()> { 13 | let _ = dotenv::dotenv(); 14 | let _ = env_logger::try_init(); 15 | let rt = Runtime::new()?; 16 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 17 | 18 | let _ = rt.block_on(bm.request(GetUserRequest))?; 19 | Ok(()) 20 | } 21 | 22 | #[test] 23 | fn get_user_affiliate_status() -> Fallible<()> { 24 | let _ = dotenv::dotenv(); 25 | let _ = env_logger::try_init(); 26 | let rt = Runtime::new()?; 27 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 28 | let fut = bm.request(GetUserAffiliateStatusRequest); 29 | 30 | debug!("{:?}", rt.block_on(fut)?); 31 | Ok(()) 32 | } 33 | 34 | #[test] 35 | fn get_user_commission() -> Fallible<()> { 36 | let _ = dotenv::dotenv(); 37 | let _ = env_logger::try_init(); 38 | let rt = Runtime::new()?; 39 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 40 | 41 | let _ = rt.block_on(bm.request(GetUserCommissionRequest))?; 42 | 43 | Ok(()) 44 | } 45 | 46 | #[test] 47 | fn get_user_deposit_address() -> Fallible<()> { 48 | let _ = dotenv::dotenv(); 49 | let _ = env_logger::try_init(); 50 | let rt = Runtime::new()?; 51 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 52 | 53 | let _ = rt.block_on(bm.request(GetUserDepositAddressRequest { 54 | ..Default::default() 55 | }))?; 56 | 57 | Ok(()) 58 | } 59 | 60 | #[test] 61 | fn get_user_wallet() -> Fallible<()> { 62 | let _ = dotenv::dotenv(); 63 | let _ = env_logger::try_init(); 64 | let rt = Runtime::new()?; 65 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 66 | 67 | let _ = rt.block_on(bm.request(GetUserWalletRequest { 68 | ..Default::default() 69 | }))?; 70 | 71 | Ok(()) 72 | } 73 | 74 | #[test] 75 | fn get_user_wallet_history() -> Fallible<()> { 76 | let _ = dotenv::dotenv(); 77 | let _ = env_logger::try_init(); 78 | let rt = Runtime::new()?; 79 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 80 | 81 | let _ = rt.block_on(bm.request(GetUserWalletHistoryRequest { 82 | ..Default::default() 83 | }))?; 84 | 85 | Ok(()) 86 | } 87 | 88 | #[test] 89 | fn get_user_wallet_summary() -> Fallible<()> { 90 | let _ = dotenv::dotenv(); 91 | let _ = env_logger::try_init(); 92 | let rt = Runtime::new()?; 93 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 94 | 95 | let _ = rt.block_on(bm.request(GetUserWalletSummaryRequest { 96 | ..Default::default() 97 | }))?; 98 | 99 | Ok(()) 100 | } 101 | -------------------------------------------------------------------------------- /src/credential.rs: -------------------------------------------------------------------------------- 1 | use fehler::throws; 2 | use hex::encode as hexify; 3 | use http::Method; 4 | use ring::hmac; 5 | use url::Url; 6 | 7 | #[derive(Clone, Debug)] 8 | pub struct Credential(pub(crate) String, pub(crate) String); 9 | impl Credential { 10 | #[throws(failure::Error)] 11 | pub(crate) fn signature( 12 | &self, 13 | method: Method, 14 | expires: u64, 15 | url: &Url, 16 | body: &str, 17 | ) -> (&str, String) { 18 | // Signature: hex(HMAC_SHA256(apiSecret, verb + path + expires + data)) 19 | let signed_key = hmac::Key::new(hmac::HMAC_SHA256, self.1.as_bytes()); 20 | let sign_message = match url.query() { 21 | Some(query) => format!( 22 | "{}{}?{}{}{}", 23 | method.as_str(), 24 | url.path(), 25 | query, 26 | expires, 27 | body 28 | ), 29 | None => format!("{}{}{}{}", method.as_str(), url.path(), expires, body), 30 | }; 31 | 32 | let signature = hexify(hmac::sign(&signed_key, sign_message.as_bytes())); 33 | (self.0.as_str(), signature) 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod test { 39 | use hyper::Method; 40 | use url::Url; 41 | 42 | use super::Credential; 43 | use failure::Fallible; 44 | 45 | #[test] 46 | fn test_signature_get() -> Fallible<()> { 47 | let tr = Credential( 48 | "LAqUlngMIQkIUjXMUreyu3qn".into(), 49 | "chNOOS4KvNXR_Xq4k4c9qsfoKWvnDecLATCRlcBwyKDYnWgO".into(), 50 | ); 51 | let (_, sig) = tr.signature( 52 | Method::GET, 53 | 1518064236, 54 | &Url::parse("http://a.com/api/v1/instrument")?, 55 | "", 56 | )?; 57 | assert_eq!( 58 | sig, 59 | "c7682d435d0cfe87c16098df34ef2eb5a549d4c5a3c2b1f0f77b8af73423bf00" 60 | ); 61 | Ok(()) 62 | } 63 | 64 | #[test] 65 | fn test_signature_get_param() -> Fallible<()> { 66 | let tr = Credential( 67 | "LAqUlngMIQkIUjXMUreyu3qn".into(), 68 | "chNOOS4KvNXR_Xq4k4c9qsfoKWvnDecLATCRlcBwyKDYnWgO".into(), 69 | ); 70 | let (_, sig) = tr.signature( 71 | Method::GET, 72 | 1518064237, 73 | &Url::parse_with_params( 74 | "http://a.com/api/v1/instrument", 75 | &[("filter", r#"{"symbol": "XBTM15"}"#)], 76 | )?, 77 | "", 78 | )?; 79 | assert_eq!( 80 | sig, 81 | "e2f422547eecb5b3cb29ade2127e21b858b235b386bfa45e1c1756eb3383919f" 82 | ); 83 | Ok(()) 84 | } 85 | 86 | #[test] 87 | fn test_signature_post() -> Fallible<()> { 88 | let tr = Credential( 89 | "LAqUlngMIQkIUjXMUreyu3qn".into(), 90 | "chNOOS4KvNXR_Xq4k4c9qsfoKWvnDecLATCRlcBwyKDYnWgO".into(), 91 | ); 92 | let (_, sig) = tr.signature( 93 | Method::POST, 94 | 1518064238, 95 | &Url::parse("http://a.com/api/v1/order")?, 96 | r#"{"symbol":"XBTM15","price":219.0,"clOrdID":"mm_bitmex_1a/oemUeQ4CAJZgP3fjHsA","orderQty":98}"#, 97 | )?; 98 | assert_eq!( 99 | sig, 100 | "1749cd2ccae4aa49048ae09f0b95110cee706e0944e6a14ad0b3a8cb45bd336b" 101 | ); 102 | Ok(()) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/websocket/message.rs: -------------------------------------------------------------------------------- 1 | use super::Command; 2 | use crate::BitMEXError; 3 | use chrono::{DateTime, Utc}; 4 | use serde::{Deserialize, Serialize}; 5 | use serde_json::Value; 6 | use std::collections::HashMap; 7 | 8 | // Text("{\"success\":true,\"subscribe\":\"chat\",\"request\":{\"args\":[\"chat\"],\"op\":\"subscribe\"}}") 9 | // Text("{\"table\":\"chat\",\"action\":\"insert\",\"keys\":[\"id\"],\"data\":[{\"channelID\":4,\"date\":\"2018-10-26T05:09:44.159Z\",\"fromBot\":false,\"html\":\"ㅋㅋㅋㅋㅋ ETF 드립 ㅈㄴ웃기네\\n\",\"id\":21699228,\"message\":\"ㅋㅋㅋㅋㅋ ETF 드립 ㅈㄴ웃기네\",\"user\":\"xixixiaqs\"}],\"filterKey\":\"channelID\"}") 10 | // Text("{\"info\":\"Welcome to the BitMEX Realtime API.\",\"version\":\"2018-10-23T18:33:47.000Z\",\"timestamp\":\"2018-10-26T05:09:14.006Z\",\"docs\":\"https://www.bitmex.com/app/wsAPI\",\"limit\":{\"remaining\":38}}") 11 | // {"success":true,"unsubscribe":"chat","request":{"op":"unsubscribe","args":["chat"]}} 12 | // {"status":400,"error":"Failed to decode incoming data: Unexpected token a in JSON at position 0. Please see the documentation at https://www.bitmex.com/app/wsAPI.","meta":{}} 13 | 14 | #[derive(Clone, Debug, Deserialize)] 15 | #[serde(untagged)] 16 | pub enum Message { 17 | Success(SuccessMessage), 18 | Error(ErrorMessage), 19 | Table(Box>), 20 | Info(InfoMessage), 21 | CancelAllAfter(CancelAllAfterMessage), 22 | Welcome(WelcomeMessage), 23 | Pong, 24 | Ping, 25 | } 26 | 27 | #[derive(Debug, Clone, Serialize, Deserialize)] 28 | pub struct SuccessMessage { 29 | pub success: bool, 30 | pub subscribe: Option, 31 | pub request: Command, 32 | } 33 | 34 | #[derive(Debug, Clone, Serialize, Deserialize)] 35 | #[serde(rename_all = "camelCase")] 36 | pub struct CancelAllAfterMessage { 37 | pub now: DateTime, 38 | pub cancel_time: DateTime, 39 | pub request: Command, 40 | } 41 | 42 | #[derive(Debug, Clone, Serialize, Deserialize)] 43 | pub struct InfoMessage { 44 | pub info: String, 45 | pub version: DateTime, 46 | pub timestamp: DateTime, 47 | pub docs: String, 48 | pub limit: Limit, 49 | } 50 | 51 | #[derive(Debug, Clone, Serialize, Deserialize)] 52 | pub struct Limit { 53 | pub remaining: i64, 54 | } 55 | 56 | #[derive(Debug, Clone, Serialize, Deserialize)] 57 | pub struct ErrorMessage { 58 | pub status: i64, 59 | pub error: String, 60 | pub request: Option, 61 | pub meta: Value, 62 | } 63 | 64 | impl From for BitMEXError { 65 | fn from(e: ErrorMessage) -> BitMEXError { 66 | BitMEXError::WebsocketError { 67 | status: e.status, 68 | error: e.error, 69 | } 70 | } 71 | } 72 | 73 | #[derive(Debug, Clone, Serialize, Deserialize)] 74 | #[serde(rename_all = "camelCase")] 75 | pub struct WelcomeMessage { 76 | info: String, 77 | version: String, 78 | timestamp: String, 79 | docs: String, 80 | heartbeat_enabled: bool, 81 | limit: Limit, 82 | } 83 | 84 | //Text("{\"table\":\"chat\",\"action\":\"insert\",\"keys\":[\"id\"],\"data\":[{\"channelID\":4,\"date\":\"2018-10-26T05:09:44.159Z\",\"fromBot\":false,\"html\":\"ㅋㅋㅋㅋㅋ ETF 드립 ㅈㄴ웃기네\\n\",\"id\":21699228,\"message\":\"ㅋㅋㅋㅋㅋ ETF 드립 ㅈㄴ웃기네\",\"user\":\"xixixiaqs\"}],\"filterKey\":\"channelID\"}") 85 | 86 | #[derive(Debug, Clone, Serialize, Deserialize)] 87 | #[serde(rename_all = "camelCase")] 88 | pub struct TableMessage { 89 | pub table: String, 90 | pub action: Action, 91 | pub data: Vec, 92 | pub keys: Option>, 93 | pub foreign_keys: Option>, 94 | pub types: Option>, 95 | pub filter: Option, 96 | pub attributes: Option>, 97 | } 98 | 99 | #[derive(Debug, Clone, Serialize, Deserialize)] 100 | #[serde(rename_all = "camelCase")] 101 | pub struct TableFilter { 102 | pub account: Option, 103 | pub symbol: Option, 104 | } 105 | 106 | #[derive(Debug, Clone, Serialize, Deserialize)] 107 | #[serde(rename_all = "camelCase")] 108 | pub enum Action { 109 | Insert, 110 | Partial, 111 | Update, 112 | Delete, 113 | } 114 | -------------------------------------------------------------------------------- /src/rest/client.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | models::{swagger::SwaggerApiDescription, Request}, 3 | BitMEXErrorResponse, 4 | }; 5 | use crate::consts::REST_URL; 6 | use crate::credential::Credential; 7 | use crate::error::BitMEXError; 8 | use crate::SWAGGER_URL; 9 | use chrono::{Duration, Utc}; 10 | use derive_builder::Builder; 11 | use fehler::{throw, throws}; 12 | use hyper::Method; 13 | use log::error; 14 | use reqwest::{Client, Response}; 15 | use serde::de::DeserializeOwned; 16 | use serde_json::{from_str, to_string as to_jstring}; 17 | use serde_urlencoded::to_string as to_ustring; 18 | use url::Url; 19 | 20 | const EXPIRE_DURATION: i64 = 5; 21 | 22 | #[derive(Clone, Builder)] 23 | pub struct BitMEXRest { 24 | client: Client, 25 | #[builder(default, setter(strip_option))] 26 | credential: Option, 27 | } 28 | 29 | impl Default for BitMEXRest { 30 | fn default() -> Self { 31 | Self::new() 32 | } 33 | } 34 | 35 | impl BitMEXRest { 36 | pub fn new() -> Self { 37 | BitMEXRest { 38 | client: Client::new(), 39 | credential: None, 40 | } 41 | } 42 | 43 | pub fn with_credential(api_key: &str, api_secret: &str) -> Self { 44 | BitMEXRest { 45 | client: Client::new(), 46 | credential: Some(Credential(api_key.into(), api_secret.into())), 47 | } 48 | } 49 | 50 | pub fn builder() -> BitMEXRestBuilder { 51 | BitMEXRestBuilder::default() 52 | } 53 | 54 | #[throws(failure::Error)] 55 | pub async fn request(&self, req: R) -> R::Response 56 | where 57 | R: Request, 58 | R::Response: DeserializeOwned, 59 | { 60 | let url = format!("{}{}", &*REST_URL, R::ENDPOINT); 61 | let mut url = Url::parse(&url)?; 62 | if matches!(R::METHOD, Method::GET | Method::DELETE) && R::HAS_PAYLOAD { 63 | url.set_query(Some(&to_ustring(&req)?)); 64 | } 65 | 66 | let body = match R::METHOD { 67 | Method::PUT | Method::POST => to_jstring(&req)?, 68 | _ => "".to_string(), 69 | }; 70 | 71 | let mut builder = self.client.request(R::METHOD, url.clone()); 72 | 73 | if R::SIGNED { 74 | let cred = self.get_credential()?; 75 | let expires = (Utc::now() + Duration::seconds(EXPIRE_DURATION)).timestamp() as u64; 76 | let (key, signature) = cred.signature(R::METHOD, expires, &url, &body)?; 77 | 78 | builder = builder 79 | .header("api-expires", expires) 80 | .header("api-key", key) 81 | .header("api-signature", signature); 82 | } 83 | 84 | let resp = builder 85 | .header("content-type", "application/json") 86 | .header("user-agent", "bitmex-rs") 87 | .body(body) 88 | .send() 89 | .await?; 90 | 91 | self.handle_response(resp).await? 92 | } 93 | 94 | #[throws(failure::Error)] 95 | fn get_credential(&self) -> &Credential { 96 | match self.credential.as_ref() { 97 | None => throw!(BitMEXError::NoApiKeySet), 98 | Some(c) => c, 99 | } 100 | } 101 | 102 | #[throws(failure::Error)] 103 | async fn handle_response(&self, resp: Response) -> T { 104 | let status = resp.status(); 105 | let content = resp.text().await?; 106 | if status.is_success() { 107 | match from_str::(&content) { 108 | Ok(ret) => ret, 109 | Err(e) => { 110 | error!("Cannot deserialize '{}'", content); 111 | throw!(e); 112 | } 113 | } 114 | } else { 115 | match from_str::(&content) { 116 | Ok(ret) => throw!(BitMEXError::from(ret.error)), 117 | Err(e) => { 118 | error!("Cannot deserialize error '{}'", content); 119 | throw!(e); 120 | } 121 | } 122 | } 123 | } 124 | 125 | #[throws(failure::Error)] 126 | pub async fn get_swagger(&self) -> SwaggerApiDescription { 127 | let resp: Response = self 128 | .client 129 | .get(SWAGGER_URL) 130 | .header("user-agent", "bitmex-rs") 131 | .header("content-type", "application/json") 132 | .send() 133 | .await?; 134 | self.handle_response(resp).await? 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/websocket/mod.rs: -------------------------------------------------------------------------------- 1 | mod command; 2 | mod message; 3 | mod topic; 4 | 5 | pub use self::command::Command; 6 | pub use self::message::Message as BitMEXWsMessage; 7 | pub use self::message::{ 8 | Action, CancelAllAfterMessage, ErrorMessage, InfoMessage, Limit, SuccessMessage, TableFilter, 9 | TableMessage, 10 | }; 11 | pub use self::topic::Topic; 12 | use crate::consts::WS_URL; 13 | use crate::credential::Credential; 14 | use crate::error::BitMEXError; 15 | use failure::Fallible; 16 | use fehler::{throw, throws}; 17 | use futures::sink::Sink; 18 | use futures::stream::Stream; 19 | use futures::task::{Context, Poll}; 20 | use http::Method; 21 | use log::trace; 22 | pub use serde_json::Value; 23 | use serde_json::{from_str, json, to_string}; 24 | use std::pin::Pin; 25 | use tokio::net::TcpStream; 26 | use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; 27 | use tungstenite::protocol::Message as WSMessage; 28 | use url::Url; 29 | 30 | #[allow(dead_code)] 31 | type WSStream = WebSocketStream>; 32 | 33 | pub struct BitMEXWebsocket { 34 | credential: Option, 35 | inner: WSStream, 36 | } 37 | 38 | impl BitMEXWebsocket { 39 | #[throws(failure::Error)] 40 | pub async fn new() -> Self { 41 | let (stream, _) = connect_async(Url::parse(&WS_URL).unwrap()).await?; 42 | Self { 43 | credential: None, 44 | inner: stream, 45 | } 46 | } 47 | 48 | #[throws(failure::Error)] 49 | pub async fn with_credential(api_key: &str, api_secret: &str) -> Self { 50 | let mut c = Self::new().await?; 51 | c.credential = Some(Credential(api_key.into(), api_secret.into())); 52 | c 53 | } 54 | 55 | #[throws(failure::Error)] 56 | fn get_credential(&self) -> &Credential { 57 | match self.credential.as_ref() { 58 | None => throw!(BitMEXError::NoApiKeySet), 59 | Some(c) => c, 60 | } 61 | } 62 | } 63 | 64 | impl Sink for BitMEXWebsocket { 65 | type Error = failure::Error; 66 | 67 | fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 68 | let inner = Pin::new(&mut self.inner); 69 | inner.poll_ready(cx).map_err(|e| e.into()) 70 | } 71 | 72 | fn start_send(mut self: Pin<&mut Self>, item: Command) -> Result<(), Self::Error> { 73 | let command = match &item { 74 | &Command::Ping => "ping".to_string(), 75 | &Command::Authenticate(_, expires, _) => { 76 | let cred = self.get_credential()?; 77 | let (key, sig) = cred.signature(Method::GET, expires, &Url::parse(&WS_URL)?, "")?; 78 | to_string(&json!({"op": "authKeyExpires", "args": [key, expires, sig]}))? 79 | } 80 | command => to_string(command)?, 81 | }; 82 | trace!("Sending '{}' through websocket", command); 83 | let inner = Pin::new(&mut self.inner); 84 | Ok(inner.start_send(WSMessage::Text(command))?) 85 | } 86 | 87 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 88 | let inner = Pin::new(&mut self.inner); 89 | inner.poll_flush(cx).map_err(|e| e.into()) 90 | } 91 | 92 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 93 | let inner = Pin::new(&mut self.inner); 94 | inner.poll_close(cx).map_err(|e| e.into()) 95 | } 96 | } 97 | 98 | impl Stream for BitMEXWebsocket { 99 | type Item = Fallible; 100 | 101 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 102 | let inner = Pin::new(&mut self.inner); 103 | let poll = inner.poll_next(cx); 104 | match poll { 105 | Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e.into()))), 106 | Poll::Ready(Some(Ok(m))) => match parse_message(m) { 107 | Ok(m) => Poll::Ready(Some(Ok(m))), 108 | Err(e) => Poll::Ready(Some(Err(e))), 109 | }, 110 | Poll::Ready(None) => Poll::Ready(None), 111 | Poll::Pending => Poll::Pending, 112 | } 113 | } 114 | } 115 | 116 | #[throws(failure::Error)] 117 | fn parse_message(msg: WSMessage) -> BitMEXWsMessage { 118 | match msg { 119 | WSMessage::Text(message) => match message.as_str() { 120 | "pong" => BitMEXWsMessage::Pong, 121 | others => match from_str(others) { 122 | Ok(r) => r, 123 | Err(_) => unreachable!("Cannot deserialize message from BitMEX: '{}'", others), 124 | }, 125 | }, 126 | WSMessage::Close(_) => throw!(BitMEXError::WebsocketClosed), 127 | WSMessage::Binary(c) => throw!(BitMEXError::UnexpectedWebsocketBinaryContent(c)), 128 | WSMessage::Ping(_) => BitMEXWsMessage::Ping, 129 | WSMessage::Pong(_) => BitMEXWsMessage::Pong, 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/websocket/topic.rs: -------------------------------------------------------------------------------- 1 | use crate::BitMEXError; 2 | use fehler::throw; 3 | use serde::de::{Error, Unexpected}; 4 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 5 | 6 | #[derive(Debug, Clone, Hash, PartialEq, Eq)] 7 | pub enum Topic { 8 | Announcement, 9 | Chat, 10 | Connected, 11 | Funding, 12 | Instrument, 13 | Insurance, 14 | Liquidation, 15 | OrderBookL2_25(Option), // Optional filter 16 | OrderBookL2(Option), // Optional filter 17 | OrderBook10(Option), 18 | PublicNotifications, 19 | Quote(Option), 20 | QuoteBin1m(Option), 21 | QuoteBin5m(Option), 22 | QuoteBin1h(Option), 23 | QuoteBin1d(Option), 24 | Settlement, 25 | Trade(Option), 26 | TradeBin1m(Option), 27 | TradeBin5m(Option), 28 | TradeBin1h(Option), 29 | TradeBin1d(Option), 30 | 31 | // requires auth 32 | Affiliate, 33 | Execution, 34 | Order, 35 | Margin, 36 | Position, 37 | PrivateNotifications, 38 | Transact, 39 | Wallet, 40 | } 41 | 42 | impl std::fmt::Display for Topic { 43 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 44 | use self::Topic::*; 45 | let repr = match self { 46 | Announcement => "announcement".to_string(), 47 | Chat => "chat".to_string(), 48 | Connected => "connected".to_string(), 49 | Funding => "funding".to_string(), 50 | Instrument => "instrument".to_string(), 51 | Insurance => "insurance".to_string(), 52 | Liquidation => "liquidation".to_string(), 53 | 54 | OrderBook10(None) => "orderBook10".to_string(), 55 | OrderBook10(Some(filter)) => format!("orderBook10:{}", filter), 56 | OrderBookL2(None) => "orderBookL2".to_string(), 57 | OrderBookL2(Some(filter)) => format!("orderBookL2:{}", filter), 58 | OrderBookL2_25(None) => "orderBookL2_25".to_string(), 59 | OrderBookL2_25(Some(filter)) => format!("orderBookL2_25:{}", filter), 60 | 61 | PublicNotifications => "publicNotifications".to_string(), 62 | 63 | Quote(None) => "quote".to_string(), 64 | Quote(Some(filter)) => format!("quote:{}", filter), 65 | QuoteBin1m(None) => "quoteBin1m".to_string(), 66 | QuoteBin1m(Some(filter)) => format!("quoteBin1m:{}", filter), 67 | QuoteBin5m(None) => "quoteBin5m".to_string(), 68 | QuoteBin5m(Some(filter)) => format!("quoteBin5m:{}", filter), 69 | QuoteBin1h(None) => "quoteBin1h".to_string(), 70 | QuoteBin1h(Some(filter)) => format!("quoteBin1h:{}", filter), 71 | QuoteBin1d(None) => "quoteBin1d".to_string(), 72 | QuoteBin1d(Some(filter)) => format!("quoteBin1d:{}", filter), 73 | 74 | Settlement => "settlement".to_string(), 75 | 76 | Trade(None) => "trade".to_string(), 77 | Trade(Some(filter)) => format!("trade:{}", filter), 78 | TradeBin1m(None) => "tradeBin1m".to_string(), 79 | TradeBin1m(Some(filter)) => format!("tradeBin1m:{}", filter), 80 | TradeBin5m(None) => "tradeBin5m".to_string(), 81 | TradeBin5m(Some(filter)) => format!("tradeBin5m:{}", filter), 82 | TradeBin1h(None) => "tradeBin1h".to_string(), 83 | TradeBin1h(Some(filter)) => format!("tradeBin1h:{}", filter), 84 | TradeBin1d(None) => "tradeBin1d".to_string(), 85 | TradeBin1d(Some(filter)) => format!("tradeBin1d:{}", filter), 86 | 87 | // requires auth 88 | Affiliate => "affiliate".to_string(), 89 | Execution => "execution".to_string(), 90 | Order => "order".to_string(), 91 | Margin => "margin".to_string(), 92 | Position => "position".to_string(), 93 | PrivateNotifications => "privateNotifications".to_string(), 94 | Transact => "transact".to_string(), 95 | Wallet => "wallet".to_string(), 96 | }; 97 | 98 | write!(f, "{}", repr) 99 | } 100 | } 101 | 102 | impl std::str::FromStr for Topic { 103 | type Err = BitMEXError; 104 | fn from_str(s: &str) -> Result { 105 | use self::Topic::*; 106 | let reprs: Vec<_> = s.split(':').collect(); 107 | 108 | let topic = match reprs.as_slice() { 109 | ["announcement"] => Announcement, 110 | ["chat"] => Chat, 111 | ["connected"] => Connected, 112 | ["funding"] => Funding, 113 | ["instrument"] => Instrument, 114 | ["insurance"] => Insurance, 115 | ["liquidation"] => Liquidation, 116 | 117 | ["orderBook10"] => OrderBook10(None), 118 | ["orderBook10", filter] => OrderBook10(Some((*filter).to_string())), 119 | ["orderBookL2"] => OrderBookL2(None), 120 | ["orderBookL2", filter] => OrderBookL2(Some((*filter).to_string())), 121 | ["orderBookL2_25"] => OrderBookL2_25(None), 122 | ["orderBookL2_25", filter] => OrderBookL2_25(Some((*filter).to_string())), 123 | 124 | ["publicNotifications"] => PublicNotifications, 125 | 126 | ["quote"] => Quote(None), 127 | ["quote", filter] => Quote(Some((*filter).to_string())), 128 | ["quoteBin1m"] => QuoteBin1m(None), 129 | ["quoteBin1m", filter] => QuoteBin1m(Some((*filter).to_string())), 130 | ["quoteBin5m"] => QuoteBin5m(None), 131 | ["quoteBin5m", filter] => QuoteBin5m(Some((*filter).to_string())), 132 | ["quoteBin1h"] => QuoteBin1h(None), 133 | ["quoteBin1h", filter] => QuoteBin1h(Some((*filter).to_string())), 134 | ["quoteBin1d"] => QuoteBin1d(None), 135 | ["quoteBin1d", filter] => QuoteBin1d(Some((*filter).to_string())), 136 | 137 | ["settlement"] => Settlement, 138 | 139 | ["trade"] => Trade(None), 140 | ["trade", filter] => Trade(Some((*filter).to_string())), 141 | ["tradeBin1m"] => TradeBin1m(None), 142 | ["tradeBin1m", filter] => TradeBin1m(Some((*filter).to_string())), 143 | ["tradeBin5m"] => TradeBin5m(None), 144 | ["tradeBin5m", filter] => TradeBin5m(Some((*filter).to_string())), 145 | ["tradeBin1h"] => TradeBin1h(None), 146 | ["tradeBin1h", filter] => TradeBin1h(Some((*filter).to_string())), 147 | ["tradeBin1d"] => TradeBin1d(None), 148 | ["tradeBin1d", filter] => TradeBin1d(Some((*filter).to_string())), 149 | 150 | // requires auth 151 | ["affiliate"] => Affiliate, 152 | ["execution"] => Execution, 153 | ["order"] => Order, 154 | ["margin"] => Margin, 155 | ["position"] => Position, 156 | ["privateNotifications"] => PrivateNotifications, 157 | ["transact"] => Transact, 158 | ["wallet"] => Wallet, 159 | _ => throw!(BitMEXError::ParseTopicError(s.into())), 160 | }; 161 | 162 | Ok(topic) 163 | } 164 | } 165 | impl Serialize for Topic { 166 | fn serialize(&self, serializer: S) -> Result { 167 | serializer.serialize_str(&self.to_string()) 168 | } 169 | } 170 | 171 | impl<'de> Deserialize<'de> for Topic { 172 | fn deserialize(deserializer: D) -> Result 173 | where 174 | D: Deserializer<'de>, 175 | { 176 | let repr = String::deserialize(deserializer)?; 177 | let topic = repr 178 | .parse() 179 | .map_err(|_| D::Error::invalid_value(Unexpected::Str(&repr), &"A valid topic"))?; 180 | Ok(topic) 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /tests/order.rs: -------------------------------------------------------------------------------- 1 | use bitmex::rest::BitMEXRest; 2 | use bitmex::rest::{ 3 | DeleteOrderAllRequest, DeleteOrderRequest, OrdType, PostOrderBulkRequest, PostOrderRequest, 4 | PutOrderBulkRequest, PutOrderRequest, 5 | }; 6 | use failure::Fallible; 7 | use log::debug; 8 | use serde_json::Value; 9 | use std::env::var; 10 | use tokio::runtime::Runtime; 11 | 12 | // SKip order testings otherwise we will be marked as spammer 13 | #[test] 14 | fn create_order_market() -> Fallible<()> { 15 | let _ = dotenv::dotenv(); 16 | let _ = env_logger::try_init(); 17 | let rt = Runtime::new()?; 18 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 19 | 20 | let resp = rt.block_on(bm.request(post_market_order(100)))?; 21 | 22 | let _ = rt.block_on(bm.request(DeleteOrderRequest { 23 | order_id: Some(Value::String(resp.order_id.to_string())), 24 | ..Default::default() 25 | }))?; 26 | Ok(()) 27 | } 28 | 29 | #[test] 30 | fn create_order_limit_buy() -> Fallible<()> { 31 | let _ = dotenv::dotenv(); 32 | let _ = env_logger::try_init(); 33 | let rt = Runtime::new()?; 34 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 35 | 36 | let resp = rt.block_on(bm.request(post_limit_order(6000., 100)))?; 37 | 38 | let _ = rt.block_on(bm.request(DeleteOrderRequest { 39 | order_id: Some(Value::String(resp.order_id.to_string())), 40 | ..Default::default() 41 | }))?; 42 | 43 | Ok(()) 44 | } 45 | 46 | #[test] 47 | #[ignore] 48 | fn create_order_limit_sell() -> Fallible<()> { 49 | let _ = dotenv::dotenv(); 50 | let _ = env_logger::try_init(); 51 | let rt = Runtime::new()?; 52 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 53 | 54 | let resp = rt.block_on(bm.request(post_limit_order(6500., -100)))?; 55 | 56 | let _ = rt.block_on(bm.request(DeleteOrderRequest { 57 | order_id: Some(Value::String(resp.order_id.to_string())), 58 | ..Default::default() 59 | }))?; 60 | 61 | Ok(()) 62 | } 63 | 64 | #[test] 65 | fn create_order_stop() -> Fallible<()> { 66 | let _ = dotenv::dotenv(); 67 | let _ = env_logger::try_init(); 68 | let rt = Runtime::new()?; 69 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 70 | 71 | let resp = rt.block_on(bm.request(post_stop_order(-100, 7000.)))?; 72 | 73 | let _ = rt.block_on(bm.request(DeleteOrderRequest { 74 | order_id: Some(Value::String(resp.order_id.to_string())), 75 | ..Default::default() 76 | }))?; 77 | 78 | Ok(()) 79 | } 80 | 81 | #[test] 82 | fn create_order_stoplimit() -> Fallible<()> { 83 | let _ = dotenv::dotenv(); 84 | let _ = env_logger::try_init(); 85 | let rt = Runtime::new()?; 86 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 87 | 88 | let resp = rt.block_on(bm.request(post_stop_limit_order(7100., -100, 7000.)))?; 89 | 90 | let _ = rt.block_on(bm.request(DeleteOrderRequest { 91 | order_id: Some(Value::String(resp.order_id.to_string())), 92 | ..Default::default() 93 | }))?; 94 | 95 | Ok(()) 96 | } 97 | 98 | #[test] 99 | fn create_amend_delete_order() -> Fallible<()> { 100 | let _ = dotenv::dotenv(); 101 | let _ = env_logger::try_init(); 102 | let rt = Runtime::new()?; 103 | 104 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 105 | 106 | let cor = post_stop_limit_order(6000., 1000, 6000.); 107 | let fut = bm.request(cor); 108 | let resp = rt.block_on(fut)?; 109 | 110 | let fut = bm.request(PutOrderRequest { 111 | order_id: Some(resp.order_id.to_string()), 112 | order_qty: Some(100), 113 | ..Default::default() 114 | }); 115 | debug!("{:?}", rt.block_on(fut)?); 116 | 117 | let fut = bm.request(DeleteOrderRequest { 118 | order_id: Some(Value::String(resp.order_id.to_string())), 119 | ..Default::default() 120 | }); 121 | debug!("{:?}", rt.block_on(fut)?); 122 | 123 | Ok(()) 124 | } 125 | 126 | #[test] 127 | fn create_delete_all_order() -> Fallible<()> { 128 | let _ = dotenv::dotenv(); 129 | let _ = env_logger::try_init(); 130 | let rt = Runtime::new()?; 131 | 132 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 133 | 134 | let cor = post_stop_limit_order(6000., 200, 6000.); 135 | let fut = bm.request(cor); 136 | debug!("{:?}", rt.block_on(fut)?); 137 | let cor = post_stop_limit_order(6000., 200, 6000.); 138 | let fut = bm.request(cor); 139 | debug!("{:?}", rt.block_on(fut)?); 140 | 141 | let fut = bm.request(DeleteOrderAllRequest { 142 | symbol: Some("XBTUSD".to_string()), 143 | ..Default::default() 144 | }); 145 | debug!("{:?}", rt.block_on(fut)?); 146 | 147 | Ok(()) 148 | } 149 | 150 | #[test] 151 | fn create_amend_delete_order_bulk() -> Fallible<()> { 152 | let _ = dotenv::dotenv(); 153 | let _ = env_logger::try_init(); 154 | let rt = Runtime::new()?; 155 | 156 | let bm = BitMEXRest::with_credential(&var("BITMEX_KEY")?, &var("BITMEX_SECRET")?); 157 | 158 | let orders = vec![ 159 | post_stop_limit_order(6000., 100, 6000.), 160 | post_stop_limit_order(6000., 100, 6000.), 161 | ]; 162 | 163 | let fut = bm.request(PostOrderBulkRequest { 164 | orders: Some(orders), 165 | }); 166 | let orders = rt.block_on(fut)?; 167 | 168 | let req: Vec<_> = orders 169 | .into_iter() 170 | .map(|order| PutOrderRequest { 171 | order_id: Some(order.order_id.to_string()), 172 | order_qty: Some(110), 173 | ..Default::default() 174 | }) 175 | .collect(); 176 | 177 | let fut = bm.request(PutOrderBulkRequest { orders: Some(req) }); 178 | debug!("{:?}", rt.block_on(fut)); 179 | 180 | let fut = bm.request(DeleteOrderAllRequest { 181 | symbol: Some("XBTUSD".to_string()), 182 | filter: None, 183 | text: None, 184 | }); 185 | debug!("{:?}", rt.block_on(fut)?); 186 | 187 | Ok(()) 188 | } 189 | 190 | fn post_stop_limit_order(price: f64, qty: i32, stop: f64) -> PostOrderRequest { 191 | PostOrderRequest { 192 | symbol: "XBTUSD".to_string(), 193 | side: None, 194 | simple_order_qty: None, 195 | order_qty: Some(qty), 196 | price: Some(price), 197 | display_qty: None, 198 | stop_px: Some(stop), 199 | cl_ord_id: None, 200 | cl_ord_link_id: None, 201 | peg_offset_value: None, 202 | peg_price_type: None, 203 | ord_type: Some(OrdType::StopLimit), 204 | time_in_force: None, 205 | exec_inst: None, 206 | contingency_type: None, 207 | text: None, 208 | } 209 | } 210 | 211 | fn post_limit_order(price: f64, qty: i32) -> PostOrderRequest { 212 | PostOrderRequest { 213 | symbol: "XBTUSD".to_string(), 214 | side: None, 215 | simple_order_qty: None, 216 | order_qty: Some(qty), 217 | price: Some(price), 218 | display_qty: None, 219 | stop_px: None, 220 | cl_ord_id: None, 221 | cl_ord_link_id: None, 222 | peg_offset_value: None, 223 | peg_price_type: None, 224 | ord_type: Some(OrdType::Limit), 225 | time_in_force: None, 226 | exec_inst: None, 227 | contingency_type: None, 228 | text: Some("Shine".into()), 229 | } 230 | } 231 | 232 | fn post_stop_order(qty: i32, stop: f64) -> PostOrderRequest { 233 | PostOrderRequest { 234 | symbol: "XBTUSD".to_string(), 235 | side: None, 236 | simple_order_qty: None, 237 | order_qty: Some(qty), 238 | price: None, 239 | display_qty: None, 240 | stop_px: Some(stop), 241 | cl_ord_id: None, 242 | cl_ord_link_id: None, 243 | peg_offset_value: None, 244 | peg_price_type: None, 245 | ord_type: Some(OrdType::Stop), 246 | time_in_force: None, 247 | exec_inst: None, 248 | contingency_type: None, 249 | text: Some("Shine".into()), 250 | } 251 | } 252 | 253 | fn post_market_order(qty: i32) -> PostOrderRequest { 254 | PostOrderRequest { 255 | symbol: "XBTUSD".to_string(), 256 | side: None, 257 | simple_order_qty: None, 258 | order_qty: Some(qty), 259 | price: None, 260 | display_qty: None, 261 | stop_px: None, 262 | cl_ord_id: None, 263 | cl_ord_link_id: None, 264 | peg_offset_value: None, 265 | peg_price_type: None, 266 | ord_type: None, 267 | time_in_force: None, 268 | exec_inst: None, 269 | contingency_type: None, 270 | text: Some("Shine".into()), 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /utils/parse swagger.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 741, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from stringcase import pascalcase, snakecase, camelcase\n", 10 | "from json import loads, load\n", 11 | "from copy import deepcopy\n", 12 | "from dataclasses import dataclass\n", 13 | "import re" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 742, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "from enum import Enum\n", 23 | "from typing import NamedTuple, List, Dict, Optional, Tuple, Any, Set" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 743, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "with open(\"../swagger.json\") as f:\n", 33 | " swagger = load(f)" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 744, 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "data": { 43 | "text/plain": [ 44 | "dict_keys(['swagger', 'info', 'basePath', 'paths', 'tags', 'consumes', 'host', 'produces', 'definitions', 'securityDefinitions', 'security'])" 45 | ] 46 | }, 47 | "execution_count": 744, 48 | "metadata": {}, 49 | "output_type": "execute_result" 50 | } 51 | ], 52 | "source": [ 53 | "swagger.keys()" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 745, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "PROVIDED_ENUMS: Set[str] = {\n", 63 | " 'side', 'pegPriceType', \n", 64 | " 'ordType', 'timeInForce', \n", 65 | " 'execInst', 'contingencyType', \n", 66 | " 'binSize'\n", 67 | "}\n", 68 | "\n", 69 | "def type_postfix(defs_: List[StructDef]):\n", 70 | " STRING_TYPEFIX = {\n", 71 | " \"PutOrderBulkRequest\": {\n", 72 | " \"orders\": \"Vec\"\n", 73 | " },\n", 74 | " \"PostOrderBulkRequest\": {\n", 75 | " \"orders\": \"Vec\"\n", 76 | " }\n", 77 | " }\n", 78 | " \n", 79 | " for def_ in defs_:\n", 80 | " if def_.name in STRING_TYPEFIX:\n", 81 | " for field in def_.fields:\n", 82 | " if field.name[1] in STRING_TYPEFIX[def_.name]:\n", 83 | " toty = STRING_TYPEFIX[def_.name][field.name[1]]\n", 84 | " print(f\"Replacing {field.ty} to {toty} for {def_.name}.{field.name[1]}\")\n", 85 | " field.ty = toty\n", 86 | "\n", 87 | "SIGNED_ENDPOINTS = {\n", 88 | " \"/announcement/urgent\": [\"get\"],\n", 89 | " \"/apiKey\": [\"get\"],\n", 90 | " \"/chat\": [\"post\"],\n", 91 | " \"/execution\": [\"get\"],\n", 92 | " \"/execution/tradeHistory\": [\"get\"],\n", 93 | " \"/globalNotification\": [\"get\"],\n", 94 | " \"/leaderboard/name\": [\"get\"],\n", 95 | " \"/order\": [\"get\", \"put\", \"post\", \"delete\"],\n", 96 | " \"/order/bulk\": [\"put\", \"post\"],\n", 97 | " \"/order/closePosition\": [\"post\"],\n", 98 | " \"/order/all\": [\"delete\"],\n", 99 | " \"/order/cancelAllAfter\": [\"post\"],\n", 100 | " \"/position\": [\"get\"],\n", 101 | " \"/position/isolate\": [\"post\"],\n", 102 | " \"/position/riskLimit\": [\"post\"],\n", 103 | " \"/position/transferMargin\": [\"post\"],\n", 104 | " \"/position/leverage\": [\"post\"],\n", 105 | " \"/user\": [\"get\"],\n", 106 | " \"/user/affiliateStatus\": [\"get\"],\n", 107 | " \"/user/commission\": [\"get\"],\n", 108 | " \"/user/communicationToken\": [\"post\"],\n", 109 | " \"/user/executionHistory\": [\"get\"],\n", 110 | " \"/user/depositAddress\": [\"get\"],\n", 111 | " \"/user/margin\": [\"get\"],\n", 112 | " \"/user/preferences\": [\"post\"],\n", 113 | " \"/user/quoteFillRatio\": [\"get\"],\n", 114 | " \"/user/requestWithdrawal\": [\"post\"],\n", 115 | " \"/user/wallet\": [\"get\"],\n", 116 | " \"/user/walletHistory\": [\"get\"],\n", 117 | " \"/user/walletSummary\": [\"get\"],\n", 118 | " \"/userEvent\": [\"get\"],\n", 119 | "}\n", 120 | "\n", 121 | "string_formats = {\n", 122 | " \"date-time\": \"DateTime\",\n", 123 | " \"guid\": \"Uuid\",\n", 124 | " None: \"String\",\n", 125 | " \"JSON\": \"Value\",\n", 126 | "}\n", 127 | "\n", 128 | "number_formats = {\n", 129 | " \"int64\": \"i64\",\n", 130 | " \"int32\": \"i32\",\n", 131 | " \"double\": \"f64\"\n", 132 | "}\n", 133 | "\n", 134 | "def rustify(s: str) -> str:\n", 135 | " s = s.replace(\"ID\", \"Id\")\n", 136 | " s = snakecase(s)\n", 137 | " if s == \"type\":\n", 138 | " s = \"r#type\"\n", 139 | " return s" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "# Definitions" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 769, 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [ 155 | "@dataclass\n", 156 | "class FieldDef:\n", 157 | " name: Tuple[str, str]\n", 158 | " ty: str\n", 159 | " optional: Optional[bool]\n", 160 | " modifiers: Dict[str, str]\n", 161 | " desc: Optional[str] = None\n", 162 | "\n", 163 | " @classmethod\n", 164 | " def from_swagger(cls, parent_name: str, name: str, tydesc: Dict[str, Any]) -> Tuple[FieldDef, List[StructDef]]:\n", 165 | " common_keys = [\"required\", \"type\", \"default\", \"description\"]\n", 166 | " if \"type\" in tydesc:\n", 167 | " ty = tydesc[\"type\"] \n", 168 | " desc = tydesc.get(\"description\")\n", 169 | " \n", 170 | " optional = not tydesc.get(\"required\", False)\n", 171 | "\n", 172 | " if ty == \"string\":\n", 173 | " assert_keys(name, tydesc, *common_keys, \"enum\", \"maxLength\", \"format\")\n", 174 | "\n", 175 | " if name in PROVIDED_ENUMS:\n", 176 | " rty = f\"super::{pascalcase(name)}\"\n", 177 | " else:\n", 178 | " rty = string_formats[tydesc.get(\"format\")]\n", 179 | "\n", 180 | " modifiers = {}\n", 181 | " \n", 182 | " return FieldDef((rustify(name), name), rty, optional, modifiers, desc), []\n", 183 | "\n", 184 | " elif ty == \"number\":\n", 185 | " assert_keys(name, tydesc, *common_keys, \"format\", \"minimum\")\n", 186 | "\n", 187 | " modifiers = {}\n", 188 | " if \"defaulyt\" in tydesc and tydesc[\"default\"] == 0:\n", 189 | " modifiers[\"default\"] = None\n", 190 | " \n", 191 | " rty = number_formats[tydesc.get(\"format\")]\n", 192 | "\n", 193 | " return FieldDef((rustify(name), name), rty, optional, modifiers, desc), []\n", 194 | " \n", 195 | " elif ty == \"boolean\":\n", 196 | " assert_keys(name, tydesc, *common_keys)\n", 197 | "\n", 198 | " modifiers = {}\n", 199 | " if \"default\" in tydesc and not tydesc[\"default\"]:\n", 200 | " modifiers[\"default\"] = None\n", 201 | " \n", 202 | " return FieldDef((rustify(name), name), \"bool\", optional, modifiers, desc), []\n", 203 | " \n", 204 | " elif ty == \"object\":\n", 205 | " assert_keys(name, tydesc, *common_keys, \"properties\")\n", 206 | " sdfs = StructDef.from_swagger(parent_name, name, tydesc)\n", 207 | " \n", 208 | " modifiers = {}\n", 209 | " \n", 210 | " assert sdfs\n", 211 | " \n", 212 | " fdf = FieldDef((rustify(name), name), sdfs[0].name, optional, modifiers, desc)\n", 213 | " \n", 214 | " return fdf, sdfs\n", 215 | "\n", 216 | " elif ty == \"array\":\n", 217 | " assert_keys(name, tydesc, *common_keys, \"items\")\n", 218 | " \n", 219 | " items = tydesc[\"items\"]\n", 220 | " \n", 221 | " fdf, sdfs = FieldDef.from_swagger(parent_name, name, items)\n", 222 | " fdf.ty = f\"Vec<{fdf.ty}>\"\n", 223 | " if name == \"disableEmails\":\n", 224 | " print(fdf)\n", 225 | " \n", 226 | " if (\"default\" in tydesc and tydesc[\"default\"] == []) or \"default\" not in tydesc:\n", 227 | " fdf.modifiers[\"default\"] = None\n", 228 | " else:\n", 229 | " raise NotImplementedError(tydesc)\n", 230 | " \n", 231 | " return fdf, sdfs\n", 232 | " \n", 233 | " elif ty == \"null\":\n", 234 | " return FieldDef((rustify(name), name), \"()\", False, {}, None), []\n", 235 | " else:\n", 236 | " raise RuntimeError(f\"Unimplemented for {ty}\")\n", 237 | "\n", 238 | "\n", 239 | " elif \"$ref\" in tydesc:\n", 240 | " assert_keys(name, tydesc, \"$ref\", *common_keys)\n", 241 | " ref = tydesc[\"$ref\"]\n", 242 | "\n", 243 | " if ref.startswith(\"#/definitions/\"):\n", 244 | " ty = ref.lstrip(\"#/definitions/\")\n", 245 | " if ty == \"x-any\":\n", 246 | " ty = \"Value\"\n", 247 | " return FieldDef((rustify(name), name), ty, False, {}, None), []\n", 248 | " else:\n", 249 | " raise NotImplementedError\n", 250 | " else:\n", 251 | " raise NotImplementedError(f\"{name}, {tydesc}\")\n", 252 | " \n", 253 | " def can_default(self) -> bool:\n", 254 | " if \"default\" in self.modifiers or self.optional:\n", 255 | " return True\n", 256 | " return False\n", 257 | " \n", 258 | " def __str__(self) -> str:\n", 259 | " if self.optional:\n", 260 | " ty = f\"Option<{self.ty}>\"\n", 261 | " else:\n", 262 | " ty = self.ty\n", 263 | " \n", 264 | " mods = []\n", 265 | " if self.name[0] != self.name[1]:\n", 266 | " mods.append(f\"rename = \\\"{self.name[1]}\\\"\")\n", 267 | " \n", 268 | " for mod, modv in fdef.modifiers.items():\n", 269 | " if modv is None:\n", 270 | " mods.append(mod)\n", 271 | " else:\n", 272 | " mods.append(f\"{mod} = \\\"{modv}\\\"\")\n", 273 | " \n", 274 | " serde_header = \"\"\n", 275 | " if mods:\n", 276 | " mods = \", \".join(mods)\n", 277 | " serde_header = f\"#[serde({mods})]\\n\"\n", 278 | " field = serde_header + f\"\"\"pub {self.name[0]}: {ty}\"\"\"\n", 279 | " if self.desc:\n", 280 | " desc = self.desc.replace(\"\\n\", \" \")\n", 281 | " field = f\"\"\"/// {desc}\\n\"\"\" + field\n", 282 | " \n", 283 | " return field\n", 284 | " \n", 285 | "@dataclass\n", 286 | "class StructDef:\n", 287 | " name: str\n", 288 | " fields: List[FieldDef]\n", 289 | " derives: List[str]\n", 290 | " desc: Optional[str] = None\n", 291 | " value: bool = False\n", 292 | " \n", 293 | " @classmethod\n", 294 | " def from_swagger(cls, parent_name: str, name: str, defs: Dict[str, Any]) -> List[StructDef]:\n", 295 | " assert defs[\"type\"] == \"object\"\n", 296 | " derives = [\"Clone\", \"Debug\", \"Deserialize\", \"Serialize\"]\n", 297 | " \n", 298 | " desc = defs.get(\"description\")\n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " if \"properties\" in defs and not defs[\"properties\"]:\n", 303 | " return [StructDef(f\"{parent_name}{pascalcase(name)}\", [], derives + [\"Default\"], desc, True)]\n", 304 | " \n", 305 | " if name == \"x-any\":\n", 306 | " return [StructDef(f\"{parent_name}XAny\", [], derives + [\"Default\"], desc, True)]\n", 307 | " \n", 308 | " if \"properties\" not in defs:\n", 309 | " defs[\"properties\"] = {}\n", 310 | " \n", 311 | " required = set(defs.get(\"required\", []))\n", 312 | " fdfs, sdfs = [], []\n", 313 | " for subname, def_ in defs[\"properties\"].items():\n", 314 | " fdf, sdfs_ = FieldDef.from_swagger(f\"{parent_name}{pascalcase(subname)}\", subname, def_)\n", 315 | " \n", 316 | " sdfs.extend(sdfs_)\n", 317 | " fdfs.append(fdf)\n", 318 | " if fdf.name[1] == \"disableEmails\":\n", 319 | " print(fdf)\n", 320 | " print(fdf.optional, required, fdf.modifiers)\n", 321 | " \n", 322 | " fdf.optional &= fdf.name[1] not in required\n", 323 | " \n", 324 | " fields_can_default = all([fdf.can_default() for fdf in fdfs])\n", 325 | " if fields_can_default:\n", 326 | " derives.append(\"Default\")\n", 327 | " \n", 328 | " \n", 329 | " return [StructDef(f\"{parent_name}{pascalcase(name)}\", fdfs, derives, desc), *sdfs]\n", 330 | " \n", 331 | " def __str__(self) -> str:\n", 332 | " if self.desc:\n", 333 | " desc = self.desc.replace(\"\\n\", \" \")\n", 334 | " desc = f\"\\n/// {desc}\"\n", 335 | " else:\n", 336 | " desc = \"\"\n", 337 | " \n", 338 | " derives = \", \".join(self.derives)\n", 339 | " \n", 340 | " if self.value:\n", 341 | " code = f\"\"\"#[derive({derives})]{desc}\n", 342 | "pub struct {self.name}(serde_json::Value);\"\"\"\n", 343 | " return code\n", 344 | " elif not self.fields:\n", 345 | " code = f\"\"\"#[derive({derives})]{desc}\n", 346 | "pub struct {self.name};\"\"\"\n", 347 | " return code\n", 348 | " \n", 349 | " \n", 350 | " fields = [str(fdef).replace(\"\\n\", \"\\n \") for fdef in self.fields]\n", 351 | " fields = \",\\n \".join(fields)\n", 352 | " \n", 353 | " code = f\"\"\"#[derive({derives})]{desc}\n", 354 | "pub struct {self.name} {{\n", 355 | " {fields}\n", 356 | "}}\"\"\"\n", 357 | " return code" 358 | ] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": 770, 363 | "metadata": {}, 364 | "outputs": [ 365 | { 366 | "name": "stdout", 367 | "output_type": "stream", 368 | "text": [ 369 | "#[serde(rename = \"disableEmails\")]\n", 370 | "pub disable_emails: Option>\n", 371 | "#[serde(rename = \"disableEmails\")]\n", 372 | "pub disable_emails: Option>\n", 373 | "True set() {'default': None}\n" 374 | ] 375 | } 376 | ], 377 | "source": [ 378 | "defs_ = []\n", 379 | "\n", 380 | "for name, defs in swagger[\"definitions\"].items():\n", 381 | " defs_.extend(StructDef.from_swagger(\"\", name, defs))\n", 382 | "type_postfix(defs_)" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 771, 388 | "metadata": {}, 389 | "outputs": [], 390 | "source": [ 391 | "with open(\"../src/models/definitions.rs\", \"w\") as f:\n", 392 | " f.write(\"\"\"use chrono::{DateTime, Utc};\n", 393 | "use serde_json::Value;\n", 394 | "use uuid::Uuid;\n", 395 | "use serde::{Deserialize, Serialize};\n", 396 | "\"\"\")\n", 397 | " f.write(\"\\n\".join([str(d) for d in defs_]))\n" 398 | ] 399 | }, 400 | { 401 | "cell_type": "markdown", 402 | "metadata": {}, 403 | "source": [ 404 | "# Paths" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": 772, 410 | "metadata": {}, 411 | "outputs": [], 412 | "source": [ 413 | "@dataclass\n", 414 | "class RequestImpl:\n", 415 | " method: str\n", 416 | " endpoint: str\n", 417 | " \n", 418 | " reqty: str\n", 419 | " respty: str\n", 420 | " signed: bool\n", 421 | " has_payload: bool\n", 422 | "\n", 423 | " def __str__(self) -> str:\n", 424 | " signed = \"false\"\n", 425 | " if self.signed:\n", 426 | " signed = \"true\"\n", 427 | " \n", 428 | " has_payload = \"false\"\n", 429 | " if self.has_payload:\n", 430 | " has_payload = \"true\"\n", 431 | " \n", 432 | " return f\"\"\"impl Request for {self.reqty} {{\n", 433 | " const METHOD: Method = Method::{self.method.upper()};\n", 434 | " const SIGNED: bool = {signed};\n", 435 | " const ENDPOINT: &'static str = \"{self.endpoint}\";\n", 436 | " const HAS_PAYLOAD: bool = {has_payload};\n", 437 | " type Response = {self.respty};\n", 438 | "}}\"\"\"" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": 773, 444 | "metadata": {}, 445 | "outputs": [ 446 | { 447 | "name": "stdout", 448 | "output_type": "stream", 449 | "text": [ 450 | "Replacing Value to Vec for PostOrderBulkRequest.orders\n", 451 | "Replacing Value to Vec for PutOrderBulkRequest.orders\n" 452 | ] 453 | } 454 | ], 455 | "source": [ 456 | "defs_ = []\n", 457 | "impls = []\n", 458 | "\n", 459 | "for endpoint, defs in swagger[\"paths\"].items():\n", 460 | " for method, defs in defs.items():\n", 461 | " # Request\n", 462 | " cmethod = method.capitalize()\n", 463 | " \n", 464 | " reqname = pascalcase(endpoint.lstrip(\"/\").replace(\"/\", \"_\"))\n", 465 | " reqname = reqname.replace(\"_\", \"\")\n", 466 | " reqty = f\"{cmethod}{reqname}Request\"\n", 467 | " \n", 468 | " desc = defs.get(\"summary\", \"No description\")\n", 469 | " \n", 470 | " tydesc_ = {\"type\": \"object\", \"description\": desc}\n", 471 | " \n", 472 | " for tydesc in defs[\"parameters\"]:\n", 473 | " if \"properties\" not in tydesc_:\n", 474 | " tydesc_[\"properties\"] = {}\n", 475 | " \n", 476 | " tydesc = deepcopy(tydesc)\n", 477 | " tydesc.pop(\"in\")\n", 478 | " name = tydesc.pop(\"name\")\n", 479 | " tydesc_[\"properties\"][name] = tydesc\n", 480 | " \n", 481 | " reqdef, = StructDef.from_swagger(\"\", reqty, tydesc_)\n", 482 | " \n", 483 | " # Response\n", 484 | " respty = f\"{cmethod}{reqname}Response\"\n", 485 | " \n", 486 | " schema = defs[\"responses\"][\"200\"][\"schema\"]\n", 487 | " \n", 488 | " fdf, sdfs = FieldDef.from_swagger(\"\", respty, schema)\n", 489 | " \n", 490 | " respdefs = sdfs\n", 491 | "\n", 492 | " if not sdfs:\n", 493 | " # If no struct created, the type of the fdf is the response type\n", 494 | " respty = f\"{fdf.ty}\"\n", 495 | " \n", 496 | " \n", 497 | " # Impls\n", 498 | " signed = False\n", 499 | " if method in SIGNED_ENDPOINTS.get(endpoint, []):\n", 500 | " signed = True\n", 501 | " \n", 502 | " if len(defs[\"parameters\"]) == 0:\n", 503 | " has_payload = False\n", 504 | " else:\n", 505 | " has_payload = True\n", 506 | " \n", 507 | " impl = RequestImpl(method, endpoint, reqty, respty, signed, has_payload)\n", 508 | " \n", 509 | " defs_.extend([reqdef, *respdefs])\n", 510 | " impls.append(impl)\n", 511 | " \n", 512 | "type_postfix(defs_)" 513 | ] 514 | }, 515 | { 516 | "cell_type": "code", 517 | "execution_count": 774, 518 | "metadata": {}, 519 | "outputs": [], 520 | "source": [ 521 | "with open(\"../src/models/requests.rs\", \"w\") as f:\n", 522 | " f.write(\"\"\"use http::Method;\n", 523 | "use super::Request;\n", 524 | "use super::definitions::*;\n", 525 | "use serde_json::Value;\n", 526 | "use serde::{Deserialize, Serialize};\n", 527 | "use chrono::{DateTime, Utc};\n", 528 | "\"\"\")\n", 529 | " f.write(\"\\n\".join([str(d) for d in defs_]))\n", 530 | " f.write(\"\\n\")\n", 531 | " \n", 532 | " f.write(\"\\n\".join([str(d) for d in impls]))" 533 | ] 534 | }, 535 | { 536 | "cell_type": "code", 537 | "execution_count": null, 538 | "metadata": {}, 539 | "outputs": [], 540 | "source": [] 541 | } 542 | ], 543 | "metadata": { 544 | "kernelspec": { 545 | "display_name": "Python 3", 546 | "language": "python", 547 | "name": "python3" 548 | }, 549 | "language_info": { 550 | "codemirror_mode": { 551 | "name": "ipython", 552 | "version": 3 553 | }, 554 | "file_extension": ".py", 555 | "mimetype": "text/x-python", 556 | "name": "python", 557 | "nbconvert_exporter": "python", 558 | "pygments_lexer": "ipython3", 559 | "version": "3.7.5" 560 | } 561 | }, 562 | "nbformat": 4, 563 | "nbformat_minor": 4 564 | } 565 | -------------------------------------------------------------------------------- /src/rest/models/definitions.rs: -------------------------------------------------------------------------------- 1 | use chrono::{DateTime, Utc}; 2 | use serde_json::Value; 3 | use uuid::Uuid; 4 | use serde::{Deserialize, Serialize}; 5 | #[derive(Clone, Debug, Deserialize, Serialize)] 6 | /// Public Announcements 7 | pub struct Announcement { 8 | pub id: i32, 9 | pub link: Option, 10 | pub title: Option, 11 | pub content: Option, 12 | pub date: Option> 13 | } 14 | #[derive(Clone, Debug, Deserialize, Serialize)] 15 | pub struct Error { 16 | pub error: ErrorError 17 | } 18 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 19 | pub struct ErrorError { 20 | pub message: Option, 21 | pub name: Option 22 | } 23 | #[derive(Clone, Debug, Deserialize, Serialize)] 24 | /// Persistent API Keys for Developers 25 | pub struct APIKey { 26 | pub id: String, 27 | pub secret: Option, 28 | pub name: String, 29 | pub nonce: i64, 30 | pub cidr: Option, 31 | pub permissions: Vec, 32 | pub enabled: Option, 33 | #[serde(rename = "userId")] 34 | pub user_id: i32, 35 | pub created: Option> 36 | } 37 | #[derive(Clone, Debug, Deserialize, Serialize)] 38 | /// Trollbox Data 39 | pub struct Chat { 40 | pub id: Option, 41 | pub date: DateTime, 42 | pub user: String, 43 | pub message: String, 44 | pub html: String, 45 | #[serde(rename = "fromBot")] 46 | pub from_bot: Option, 47 | #[serde(rename = "channelID")] 48 | pub channel_id: Option 49 | } 50 | #[derive(Clone, Debug, Deserialize, Serialize)] 51 | pub struct ChatChannel { 52 | pub id: Option, 53 | pub name: String 54 | } 55 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 56 | pub struct ConnectedUsers { 57 | pub users: Option, 58 | pub bots: Option 59 | } 60 | #[derive(Clone, Debug, Deserialize, Serialize)] 61 | /// Raw Order and Balance Data 62 | pub struct Execution { 63 | #[serde(rename = "execID")] 64 | pub exec_id: Uuid, 65 | #[serde(rename = "orderID")] 66 | pub order_id: Option, 67 | #[serde(rename = "clOrdID")] 68 | pub cl_ord_id: Option, 69 | #[serde(rename = "clOrdLinkID")] 70 | pub cl_ord_link_id: Option, 71 | pub account: Option, 72 | pub symbol: Option, 73 | pub side: Option, 74 | #[serde(rename = "lastQty")] 75 | pub last_qty: Option, 76 | #[serde(rename = "lastPx")] 77 | pub last_px: Option, 78 | #[serde(rename = "underlyingLastPx")] 79 | pub underlying_last_px: Option, 80 | #[serde(rename = "lastMkt")] 81 | pub last_mkt: Option, 82 | #[serde(rename = "lastLiquidityInd")] 83 | pub last_liquidity_ind: Option, 84 | #[serde(rename = "simpleOrderQty")] 85 | pub simple_order_qty: Option, 86 | #[serde(rename = "orderQty")] 87 | pub order_qty: Option, 88 | pub price: Option, 89 | #[serde(rename = "displayQty")] 90 | pub display_qty: Option, 91 | #[serde(rename = "stopPx")] 92 | pub stop_px: Option, 93 | #[serde(rename = "pegOffsetValue")] 94 | pub peg_offset_value: Option, 95 | #[serde(rename = "pegPriceType")] 96 | pub peg_price_type: Option, 97 | pub currency: Option, 98 | #[serde(rename = "settlCurrency")] 99 | pub settl_currency: Option, 100 | #[serde(rename = "execType")] 101 | pub exec_type: Option, 102 | #[serde(rename = "ordType")] 103 | pub ord_type: Option, 104 | #[serde(rename = "timeInForce")] 105 | pub time_in_force: Option, 106 | #[serde(rename = "execInst")] 107 | pub exec_inst: Option, 108 | #[serde(rename = "contingencyType")] 109 | pub contingency_type: Option, 110 | #[serde(rename = "exDestination")] 111 | pub ex_destination: Option, 112 | #[serde(rename = "ordStatus")] 113 | pub ord_status: Option, 114 | pub triggered: Option, 115 | #[serde(rename = "workingIndicator")] 116 | pub working_indicator: Option, 117 | #[serde(rename = "ordRejReason")] 118 | pub ord_rej_reason: Option, 119 | #[serde(rename = "simpleLeavesQty")] 120 | pub simple_leaves_qty: Option, 121 | #[serde(rename = "leavesQty")] 122 | pub leaves_qty: Option, 123 | #[serde(rename = "simpleCumQty")] 124 | pub simple_cum_qty: Option, 125 | #[serde(rename = "cumQty")] 126 | pub cum_qty: Option, 127 | #[serde(rename = "avgPx")] 128 | pub avg_px: Option, 129 | pub commission: Option, 130 | #[serde(rename = "tradePublishIndicator")] 131 | pub trade_publish_indicator: Option, 132 | #[serde(rename = "multiLegReportingType")] 133 | pub multi_leg_reporting_type: Option, 134 | pub text: Option, 135 | #[serde(rename = "trdMatchID")] 136 | pub trd_match_id: Option, 137 | #[serde(rename = "execCost")] 138 | pub exec_cost: Option, 139 | #[serde(rename = "execComm")] 140 | pub exec_comm: Option, 141 | #[serde(rename = "homeNotional")] 142 | pub home_notional: Option, 143 | #[serde(rename = "foreignNotional")] 144 | pub foreign_notional: Option, 145 | #[serde(rename = "transactTime")] 146 | pub transact_time: Option>, 147 | pub timestamp: Option> 148 | } 149 | #[derive(Clone, Debug, Deserialize, Serialize)] 150 | /// Swap Funding History 151 | pub struct Funding { 152 | pub timestamp: DateTime, 153 | pub symbol: String, 154 | #[serde(rename = "fundingInterval")] 155 | pub funding_interval: Option>, 156 | #[serde(rename = "fundingRate")] 157 | pub funding_rate: Option, 158 | #[serde(rename = "fundingRateDaily")] 159 | pub funding_rate_daily: Option 160 | } 161 | #[derive(Clone, Debug, Deserialize, Serialize)] 162 | /// Tradeable Contracts, Indices, and History 163 | pub struct Instrument { 164 | pub symbol: String, 165 | #[serde(rename = "rootSymbol")] 166 | pub root_symbol: Option, 167 | pub state: Option, 168 | pub typ: Option, 169 | pub listing: Option>, 170 | pub front: Option>, 171 | pub expiry: Option>, 172 | pub settle: Option>, 173 | #[serde(rename = "relistInterval")] 174 | pub relist_interval: Option>, 175 | #[serde(rename = "inverseLeg")] 176 | pub inverse_leg: Option, 177 | #[serde(rename = "sellLeg")] 178 | pub sell_leg: Option, 179 | #[serde(rename = "buyLeg")] 180 | pub buy_leg: Option, 181 | #[serde(rename = "optionStrikePcnt")] 182 | pub option_strike_pcnt: Option, 183 | #[serde(rename = "optionStrikeRound")] 184 | pub option_strike_round: Option, 185 | #[serde(rename = "optionStrikePrice")] 186 | pub option_strike_price: Option, 187 | #[serde(rename = "optionMultiplier")] 188 | pub option_multiplier: Option, 189 | #[serde(rename = "positionCurrency")] 190 | pub position_currency: Option, 191 | pub underlying: Option, 192 | #[serde(rename = "quoteCurrency")] 193 | pub quote_currency: Option, 194 | #[serde(rename = "underlyingSymbol")] 195 | pub underlying_symbol: Option, 196 | pub reference: Option, 197 | #[serde(rename = "referenceSymbol")] 198 | pub reference_symbol: Option, 199 | #[serde(rename = "calcInterval")] 200 | pub calc_interval: Option>, 201 | #[serde(rename = "publishInterval")] 202 | pub publish_interval: Option>, 203 | #[serde(rename = "publishTime")] 204 | pub publish_time: Option>, 205 | #[serde(rename = "maxOrderQty")] 206 | pub max_order_qty: Option, 207 | #[serde(rename = "maxPrice")] 208 | pub max_price: Option, 209 | #[serde(rename = "lotSize")] 210 | pub lot_size: Option, 211 | #[serde(rename = "tickSize")] 212 | pub tick_size: Option, 213 | pub multiplier: Option, 214 | #[serde(rename = "settlCurrency")] 215 | pub settl_currency: Option, 216 | #[serde(rename = "underlyingToPositionMultiplier")] 217 | pub underlying_to_position_multiplier: Option, 218 | #[serde(rename = "underlyingToSettleMultiplier")] 219 | pub underlying_to_settle_multiplier: Option, 220 | #[serde(rename = "quoteToSettleMultiplier")] 221 | pub quote_to_settle_multiplier: Option, 222 | #[serde(rename = "isQuanto")] 223 | pub is_quanto: Option, 224 | #[serde(rename = "isInverse")] 225 | pub is_inverse: Option, 226 | #[serde(rename = "initMargin")] 227 | pub init_margin: Option, 228 | #[serde(rename = "maintMargin")] 229 | pub maint_margin: Option, 230 | #[serde(rename = "riskLimit")] 231 | pub risk_limit: Option, 232 | #[serde(rename = "riskStep")] 233 | pub risk_step: Option, 234 | pub limit: Option, 235 | pub capped: Option, 236 | pub taxed: Option, 237 | pub deleverage: Option, 238 | #[serde(rename = "makerFee")] 239 | pub maker_fee: Option, 240 | #[serde(rename = "takerFee")] 241 | pub taker_fee: Option, 242 | #[serde(rename = "settlementFee")] 243 | pub settlement_fee: Option, 244 | #[serde(rename = "insuranceFee")] 245 | pub insurance_fee: Option, 246 | #[serde(rename = "fundingBaseSymbol")] 247 | pub funding_base_symbol: Option, 248 | #[serde(rename = "fundingQuoteSymbol")] 249 | pub funding_quote_symbol: Option, 250 | #[serde(rename = "fundingPremiumSymbol")] 251 | pub funding_premium_symbol: Option, 252 | #[serde(rename = "fundingTimestamp")] 253 | pub funding_timestamp: Option>, 254 | #[serde(rename = "fundingInterval")] 255 | pub funding_interval: Option>, 256 | #[serde(rename = "fundingRate")] 257 | pub funding_rate: Option, 258 | #[serde(rename = "indicativeFundingRate")] 259 | pub indicative_funding_rate: Option, 260 | #[serde(rename = "rebalanceTimestamp")] 261 | pub rebalance_timestamp: Option>, 262 | #[serde(rename = "rebalanceInterval")] 263 | pub rebalance_interval: Option>, 264 | #[serde(rename = "openingTimestamp")] 265 | pub opening_timestamp: Option>, 266 | #[serde(rename = "closingTimestamp")] 267 | pub closing_timestamp: Option>, 268 | #[serde(rename = "sessionInterval")] 269 | pub session_interval: Option>, 270 | #[serde(rename = "prevClosePrice")] 271 | pub prev_close_price: Option, 272 | #[serde(rename = "limitDownPrice")] 273 | pub limit_down_price: Option, 274 | #[serde(rename = "limitUpPrice")] 275 | pub limit_up_price: Option, 276 | #[serde(rename = "bankruptLimitDownPrice")] 277 | pub bankrupt_limit_down_price: Option, 278 | #[serde(rename = "bankruptLimitUpPrice")] 279 | pub bankrupt_limit_up_price: Option, 280 | #[serde(rename = "prevTotalVolume")] 281 | pub prev_total_volume: Option, 282 | #[serde(rename = "totalVolume")] 283 | pub total_volume: Option, 284 | pub volume: Option, 285 | pub volume24h: Option, 286 | #[serde(rename = "prevTotalTurnover")] 287 | pub prev_total_turnover: Option, 288 | #[serde(rename = "totalTurnover")] 289 | pub total_turnover: Option, 290 | pub turnover: Option, 291 | pub turnover24h: Option, 292 | #[serde(rename = "homeNotional24h")] 293 | pub home_notional24h: Option, 294 | #[serde(rename = "foreignNotional24h")] 295 | pub foreign_notional24h: Option, 296 | #[serde(rename = "prevPrice24h")] 297 | pub prev_price24h: Option, 298 | pub vwap: Option, 299 | #[serde(rename = "highPrice")] 300 | pub high_price: Option, 301 | #[serde(rename = "lowPrice")] 302 | pub low_price: Option, 303 | #[serde(rename = "lastPrice")] 304 | pub last_price: Option, 305 | #[serde(rename = "lastPriceProtected")] 306 | pub last_price_protected: Option, 307 | #[serde(rename = "lastTickDirection")] 308 | pub last_tick_direction: Option, 309 | #[serde(rename = "lastChangePcnt")] 310 | pub last_change_pcnt: Option, 311 | #[serde(rename = "bidPrice")] 312 | pub bid_price: Option, 313 | #[serde(rename = "midPrice")] 314 | pub mid_price: Option, 315 | #[serde(rename = "askPrice")] 316 | pub ask_price: Option, 317 | #[serde(rename = "impactBidPrice")] 318 | pub impact_bid_price: Option, 319 | #[serde(rename = "impactMidPrice")] 320 | pub impact_mid_price: Option, 321 | #[serde(rename = "impactAskPrice")] 322 | pub impact_ask_price: Option, 323 | #[serde(rename = "hasLiquidity")] 324 | pub has_liquidity: Option, 325 | #[serde(rename = "openInterest")] 326 | pub open_interest: Option, 327 | #[serde(rename = "openValue")] 328 | pub open_value: Option, 329 | #[serde(rename = "fairMethod")] 330 | pub fair_method: Option, 331 | #[serde(rename = "fairBasisRate")] 332 | pub fair_basis_rate: Option, 333 | #[serde(rename = "fairBasis")] 334 | pub fair_basis: Option, 335 | #[serde(rename = "fairPrice")] 336 | pub fair_price: Option, 337 | #[serde(rename = "markMethod")] 338 | pub mark_method: Option, 339 | #[serde(rename = "markPrice")] 340 | pub mark_price: Option, 341 | #[serde(rename = "indicativeTaxRate")] 342 | pub indicative_tax_rate: Option, 343 | #[serde(rename = "indicativeSettlePrice")] 344 | pub indicative_settle_price: Option, 345 | #[serde(rename = "optionUnderlyingPrice")] 346 | pub option_underlying_price: Option, 347 | #[serde(rename = "settledPrice")] 348 | pub settled_price: Option, 349 | pub timestamp: Option> 350 | } 351 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 352 | pub struct InstrumentInterval { 353 | pub intervals: Vec, 354 | pub symbols: Vec 355 | } 356 | #[derive(Clone, Debug, Deserialize, Serialize)] 357 | pub struct IndexComposite { 358 | pub timestamp: DateTime, 359 | pub symbol: Option, 360 | #[serde(rename = "indexSymbol")] 361 | pub index_symbol: Option, 362 | pub reference: Option, 363 | #[serde(rename = "lastPrice")] 364 | pub last_price: Option, 365 | pub weight: Option, 366 | pub logged: Option> 367 | } 368 | #[derive(Clone, Debug, Deserialize, Serialize)] 369 | /// Insurance Fund Data 370 | pub struct Insurance { 371 | pub currency: String, 372 | pub timestamp: DateTime, 373 | #[serde(rename = "walletBalance")] 374 | pub wallet_balance: Option 375 | } 376 | #[derive(Clone, Debug, Deserialize, Serialize)] 377 | /// Information on Top Users 378 | pub struct Leaderboard { 379 | pub name: String, 380 | #[serde(rename = "isRealName")] 381 | pub is_real_name: Option, 382 | pub profit: Option 383 | } 384 | #[derive(Clone, Debug, Deserialize, Serialize)] 385 | /// Active Liquidations 386 | pub struct Liquidation { 387 | #[serde(rename = "orderID")] 388 | pub order_id: Uuid, 389 | pub symbol: Option, 390 | pub side: Option, 391 | pub price: Option, 392 | #[serde(rename = "leavesQty")] 393 | pub leaves_qty: Option 394 | } 395 | #[derive(Clone, Debug, Deserialize, Serialize)] 396 | /// Account Notifications 397 | pub struct GlobalNotification { 398 | pub id: Option, 399 | pub date: DateTime, 400 | pub title: String, 401 | pub body: String, 402 | pub ttl: i32, 403 | #[serde(rename = "type")] 404 | pub r#type: Option, 405 | pub closable: Option, 406 | pub persist: Option, 407 | #[serde(rename = "waitForVisibility")] 408 | pub wait_for_visibility: Option, 409 | pub sound: Option 410 | } 411 | #[derive(Clone, Debug, Deserialize, Serialize)] 412 | /// Placement, Cancellation, Amending, and History 413 | pub struct Order { 414 | #[serde(rename = "orderID")] 415 | pub order_id: Uuid, 416 | #[serde(rename = "clOrdID")] 417 | pub cl_ord_id: Option, 418 | #[serde(rename = "clOrdLinkID")] 419 | pub cl_ord_link_id: Option, 420 | pub account: Option, 421 | pub symbol: Option, 422 | pub side: Option, 423 | #[serde(rename = "simpleOrderQty")] 424 | pub simple_order_qty: Option, 425 | #[serde(rename = "orderQty")] 426 | pub order_qty: Option, 427 | pub price: Option, 428 | #[serde(rename = "displayQty")] 429 | pub display_qty: Option, 430 | #[serde(rename = "stopPx")] 431 | pub stop_px: Option, 432 | #[serde(rename = "pegOffsetValue")] 433 | pub peg_offset_value: Option, 434 | #[serde(rename = "pegPriceType")] 435 | pub peg_price_type: Option, 436 | pub currency: Option, 437 | #[serde(rename = "settlCurrency")] 438 | pub settl_currency: Option, 439 | #[serde(rename = "ordType")] 440 | pub ord_type: Option, 441 | #[serde(rename = "timeInForce")] 442 | pub time_in_force: Option, 443 | #[serde(rename = "execInst")] 444 | pub exec_inst: Option, 445 | #[serde(rename = "contingencyType")] 446 | pub contingency_type: Option, 447 | #[serde(rename = "exDestination")] 448 | pub ex_destination: Option, 449 | #[serde(rename = "ordStatus")] 450 | pub ord_status: Option, 451 | pub triggered: Option, 452 | #[serde(rename = "workingIndicator")] 453 | pub working_indicator: Option, 454 | #[serde(rename = "ordRejReason")] 455 | pub ord_rej_reason: Option, 456 | #[serde(rename = "simpleLeavesQty")] 457 | pub simple_leaves_qty: Option, 458 | #[serde(rename = "leavesQty")] 459 | pub leaves_qty: Option, 460 | #[serde(rename = "simpleCumQty")] 461 | pub simple_cum_qty: Option, 462 | #[serde(rename = "cumQty")] 463 | pub cum_qty: Option, 464 | #[serde(rename = "avgPx")] 465 | pub avg_px: Option, 466 | #[serde(rename = "multiLegReportingType")] 467 | pub multi_leg_reporting_type: Option, 468 | pub text: Option, 469 | #[serde(rename = "transactTime")] 470 | pub transact_time: Option>, 471 | pub timestamp: Option> 472 | } 473 | #[derive(Clone, Debug, Deserialize, Serialize)] 474 | pub struct OrderBookL2 { 475 | pub symbol: String, 476 | pub id: i64, 477 | pub side: super::Side, 478 | pub size: Option, 479 | pub price: Option 480 | } 481 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 482 | pub struct Ny(serde_json::Value); 483 | #[derive(Clone, Debug, Deserialize, Serialize)] 484 | /// Summary of Open and Closed Positions 485 | pub struct Position { 486 | pub account: i64, 487 | pub symbol: String, 488 | pub currency: String, 489 | pub underlying: Option, 490 | #[serde(rename = "quoteCurrency")] 491 | pub quote_currency: Option, 492 | pub commission: Option, 493 | #[serde(rename = "initMarginReq")] 494 | pub init_margin_req: Option, 495 | #[serde(rename = "maintMarginReq")] 496 | pub maint_margin_req: Option, 497 | #[serde(rename = "riskLimit")] 498 | pub risk_limit: Option, 499 | pub leverage: Option, 500 | #[serde(rename = "crossMargin")] 501 | pub cross_margin: Option, 502 | #[serde(rename = "deleveragePercentile")] 503 | pub deleverage_percentile: Option, 504 | #[serde(rename = "rebalancedPnl")] 505 | pub rebalanced_pnl: Option, 506 | #[serde(rename = "prevRealisedPnl")] 507 | pub prev_realised_pnl: Option, 508 | #[serde(rename = "prevUnrealisedPnl")] 509 | pub prev_unrealised_pnl: Option, 510 | #[serde(rename = "prevClosePrice")] 511 | pub prev_close_price: Option, 512 | #[serde(rename = "openingTimestamp")] 513 | pub opening_timestamp: Option>, 514 | #[serde(rename = "openingQty")] 515 | pub opening_qty: Option, 516 | #[serde(rename = "openingCost")] 517 | pub opening_cost: Option, 518 | #[serde(rename = "openingComm")] 519 | pub opening_comm: Option, 520 | #[serde(rename = "openOrderBuyQty")] 521 | pub open_order_buy_qty: Option, 522 | #[serde(rename = "openOrderBuyCost")] 523 | pub open_order_buy_cost: Option, 524 | #[serde(rename = "openOrderBuyPremium")] 525 | pub open_order_buy_premium: Option, 526 | #[serde(rename = "openOrderSellQty")] 527 | pub open_order_sell_qty: Option, 528 | #[serde(rename = "openOrderSellCost")] 529 | pub open_order_sell_cost: Option, 530 | #[serde(rename = "openOrderSellPremium")] 531 | pub open_order_sell_premium: Option, 532 | #[serde(rename = "execBuyQty")] 533 | pub exec_buy_qty: Option, 534 | #[serde(rename = "execBuyCost")] 535 | pub exec_buy_cost: Option, 536 | #[serde(rename = "execSellQty")] 537 | pub exec_sell_qty: Option, 538 | #[serde(rename = "execSellCost")] 539 | pub exec_sell_cost: Option, 540 | #[serde(rename = "execQty")] 541 | pub exec_qty: Option, 542 | #[serde(rename = "execCost")] 543 | pub exec_cost: Option, 544 | #[serde(rename = "execComm")] 545 | pub exec_comm: Option, 546 | #[serde(rename = "currentTimestamp")] 547 | pub current_timestamp: Option>, 548 | #[serde(rename = "currentQty")] 549 | pub current_qty: Option, 550 | #[serde(rename = "currentCost")] 551 | pub current_cost: Option, 552 | #[serde(rename = "currentComm")] 553 | pub current_comm: Option, 554 | #[serde(rename = "realisedCost")] 555 | pub realised_cost: Option, 556 | #[serde(rename = "unrealisedCost")] 557 | pub unrealised_cost: Option, 558 | #[serde(rename = "grossOpenCost")] 559 | pub gross_open_cost: Option, 560 | #[serde(rename = "grossOpenPremium")] 561 | pub gross_open_premium: Option, 562 | #[serde(rename = "grossExecCost")] 563 | pub gross_exec_cost: Option, 564 | #[serde(rename = "isOpen")] 565 | pub is_open: Option, 566 | #[serde(rename = "markPrice")] 567 | pub mark_price: Option, 568 | #[serde(rename = "markValue")] 569 | pub mark_value: Option, 570 | #[serde(rename = "riskValue")] 571 | pub risk_value: Option, 572 | #[serde(rename = "homeNotional")] 573 | pub home_notional: Option, 574 | #[serde(rename = "foreignNotional")] 575 | pub foreign_notional: Option, 576 | #[serde(rename = "posState")] 577 | pub pos_state: Option, 578 | #[serde(rename = "posCost")] 579 | pub pos_cost: Option, 580 | #[serde(rename = "posCost2")] 581 | pub pos_cost2: Option, 582 | #[serde(rename = "posCross")] 583 | pub pos_cross: Option, 584 | #[serde(rename = "posInit")] 585 | pub pos_init: Option, 586 | #[serde(rename = "posComm")] 587 | pub pos_comm: Option, 588 | #[serde(rename = "posLoss")] 589 | pub pos_loss: Option, 590 | #[serde(rename = "posMargin")] 591 | pub pos_margin: Option, 592 | #[serde(rename = "posMaint")] 593 | pub pos_maint: Option, 594 | #[serde(rename = "posAllowance")] 595 | pub pos_allowance: Option, 596 | #[serde(rename = "taxableMargin")] 597 | pub taxable_margin: Option, 598 | #[serde(rename = "initMargin")] 599 | pub init_margin: Option, 600 | #[serde(rename = "maintMargin")] 601 | pub maint_margin: Option, 602 | #[serde(rename = "sessionMargin")] 603 | pub session_margin: Option, 604 | #[serde(rename = "targetExcessMargin")] 605 | pub target_excess_margin: Option, 606 | #[serde(rename = "varMargin")] 607 | pub var_margin: Option, 608 | #[serde(rename = "realisedGrossPnl")] 609 | pub realised_gross_pnl: Option, 610 | #[serde(rename = "realisedTax")] 611 | pub realised_tax: Option, 612 | #[serde(rename = "realisedPnl")] 613 | pub realised_pnl: Option, 614 | #[serde(rename = "unrealisedGrossPnl")] 615 | pub unrealised_gross_pnl: Option, 616 | #[serde(rename = "longBankrupt")] 617 | pub long_bankrupt: Option, 618 | #[serde(rename = "shortBankrupt")] 619 | pub short_bankrupt: Option, 620 | #[serde(rename = "taxBase")] 621 | pub tax_base: Option, 622 | #[serde(rename = "indicativeTaxRate")] 623 | pub indicative_tax_rate: Option, 624 | #[serde(rename = "indicativeTax")] 625 | pub indicative_tax: Option, 626 | #[serde(rename = "unrealisedTax")] 627 | pub unrealised_tax: Option, 628 | #[serde(rename = "unrealisedPnl")] 629 | pub unrealised_pnl: Option, 630 | #[serde(rename = "unrealisedPnlPcnt")] 631 | pub unrealised_pnl_pcnt: Option, 632 | #[serde(rename = "unrealisedRoePcnt")] 633 | pub unrealised_roe_pcnt: Option, 634 | #[serde(rename = "simpleQty")] 635 | pub simple_qty: Option, 636 | #[serde(rename = "simpleCost")] 637 | pub simple_cost: Option, 638 | #[serde(rename = "simpleValue")] 639 | pub simple_value: Option, 640 | #[serde(rename = "simplePnl")] 641 | pub simple_pnl: Option, 642 | #[serde(rename = "simplePnlPcnt")] 643 | pub simple_pnl_pcnt: Option, 644 | #[serde(rename = "avgCostPrice")] 645 | pub avg_cost_price: Option, 646 | #[serde(rename = "avgEntryPrice")] 647 | pub avg_entry_price: Option, 648 | #[serde(rename = "breakEvenPrice")] 649 | pub break_even_price: Option, 650 | #[serde(rename = "marginCallPrice")] 651 | pub margin_call_price: Option, 652 | #[serde(rename = "liquidationPrice")] 653 | pub liquidation_price: Option, 654 | #[serde(rename = "bankruptPrice")] 655 | pub bankrupt_price: Option, 656 | pub timestamp: Option>, 657 | #[serde(rename = "lastPrice")] 658 | pub last_price: Option, 659 | #[serde(rename = "lastValue")] 660 | pub last_value: Option 661 | } 662 | #[derive(Clone, Debug, Deserialize, Serialize)] 663 | /// Best Bid/Offer Snapshots & Historical Bins 664 | pub struct Quote { 665 | pub timestamp: DateTime, 666 | pub symbol: String, 667 | #[serde(rename = "bidSize")] 668 | pub bid_size: Option, 669 | #[serde(rename = "bidPrice")] 670 | pub bid_price: Option, 671 | #[serde(rename = "askPrice")] 672 | pub ask_price: Option, 673 | #[serde(rename = "askSize")] 674 | pub ask_size: Option 675 | } 676 | #[derive(Clone, Debug, Deserialize, Serialize)] 677 | /// Historical Settlement Data 678 | pub struct Settlement { 679 | pub timestamp: DateTime, 680 | pub symbol: String, 681 | #[serde(rename = "settlementType")] 682 | pub settlement_type: Option, 683 | #[serde(rename = "settledPrice")] 684 | pub settled_price: Option, 685 | #[serde(rename = "optionStrikePrice")] 686 | pub option_strike_price: Option, 687 | #[serde(rename = "optionUnderlyingPrice")] 688 | pub option_underlying_price: Option, 689 | pub bankrupt: Option, 690 | #[serde(rename = "taxBase")] 691 | pub tax_base: Option, 692 | #[serde(rename = "taxRate")] 693 | pub tax_rate: Option 694 | } 695 | #[derive(Clone, Debug, Deserialize, Serialize)] 696 | /// Exchange Statistics 697 | pub struct Stats { 698 | #[serde(rename = "rootSymbol")] 699 | pub root_symbol: String, 700 | pub currency: Option, 701 | pub volume24h: Option, 702 | pub turnover24h: Option, 703 | #[serde(rename = "openInterest")] 704 | pub open_interest: Option, 705 | #[serde(rename = "openValue")] 706 | pub open_value: Option 707 | } 708 | #[derive(Clone, Debug, Deserialize, Serialize)] 709 | pub struct StatsHistory { 710 | pub date: DateTime, 711 | #[serde(rename = "rootSymbol")] 712 | pub root_symbol: String, 713 | pub currency: Option, 714 | pub volume: Option, 715 | pub turnover: Option 716 | } 717 | #[derive(Clone, Debug, Deserialize, Serialize)] 718 | pub struct StatsUSD { 719 | #[serde(rename = "rootSymbol")] 720 | pub root_symbol: String, 721 | pub currency: Option, 722 | pub turnover24h: Option, 723 | pub turnover30d: Option, 724 | pub turnover365d: Option, 725 | pub turnover: Option 726 | } 727 | #[derive(Clone, Debug, Deserialize, Serialize)] 728 | /// Individual & Bucketed Trades 729 | pub struct Trade { 730 | pub timestamp: DateTime, 731 | pub symbol: String, 732 | pub side: Option, 733 | pub size: Option, 734 | pub price: Option, 735 | #[serde(rename = "tickDirection")] 736 | pub tick_direction: Option, 737 | #[serde(rename = "trdMatchID")] 738 | pub trd_match_id: Option, 739 | #[serde(rename = "grossValue")] 740 | pub gross_value: Option, 741 | #[serde(rename = "homeNotional")] 742 | pub home_notional: Option, 743 | #[serde(rename = "foreignNotional")] 744 | pub foreign_notional: Option 745 | } 746 | #[derive(Clone, Debug, Deserialize, Serialize)] 747 | pub struct TradeBin { 748 | pub timestamp: DateTime, 749 | pub symbol: String, 750 | pub open: Option, 751 | pub high: Option, 752 | pub low: Option, 753 | pub close: Option, 754 | pub trades: Option, 755 | pub volume: Option, 756 | pub vwap: Option, 757 | #[serde(rename = "lastSize")] 758 | pub last_size: Option, 759 | pub turnover: Option, 760 | #[serde(rename = "homeNotional")] 761 | pub home_notional: Option, 762 | #[serde(rename = "foreignNotional")] 763 | pub foreign_notional: Option 764 | } 765 | #[derive(Clone, Debug, Deserialize, Serialize)] 766 | pub struct Wallet { 767 | pub account: i64, 768 | pub currency: String, 769 | #[serde(rename = "prevDeposited")] 770 | pub prev_deposited: Option, 771 | #[serde(rename = "prevWithdrawn")] 772 | pub prev_withdrawn: Option, 773 | #[serde(rename = "prevTransferIn")] 774 | pub prev_transfer_in: Option, 775 | #[serde(rename = "prevTransferOut")] 776 | pub prev_transfer_out: Option, 777 | #[serde(rename = "prevAmount")] 778 | pub prev_amount: Option, 779 | #[serde(rename = "prevTimestamp")] 780 | pub prev_timestamp: Option>, 781 | #[serde(rename = "deltaDeposited")] 782 | pub delta_deposited: Option, 783 | #[serde(rename = "deltaWithdrawn")] 784 | pub delta_withdrawn: Option, 785 | #[serde(rename = "deltaTransferIn")] 786 | pub delta_transfer_in: Option, 787 | #[serde(rename = "deltaTransferOut")] 788 | pub delta_transfer_out: Option, 789 | #[serde(rename = "deltaAmount")] 790 | pub delta_amount: Option, 791 | pub deposited: Option, 792 | pub withdrawn: Option, 793 | #[serde(rename = "transferIn")] 794 | pub transfer_in: Option, 795 | #[serde(rename = "transferOut")] 796 | pub transfer_out: Option, 797 | pub amount: Option, 798 | #[serde(rename = "pendingCredit")] 799 | pub pending_credit: Option, 800 | #[serde(rename = "pendingDebit")] 801 | pub pending_debit: Option, 802 | #[serde(rename = "confirmedDebit")] 803 | pub confirmed_debit: Option, 804 | pub timestamp: Option>, 805 | pub addr: Option, 806 | pub script: Option, 807 | #[serde(rename = "withdrawalLock")] 808 | pub withdrawal_lock: Option> 809 | } 810 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 811 | pub struct Transaction { 812 | #[serde(rename = "transactID")] 813 | pub transact_id: Option, 814 | pub account: Option, 815 | pub currency: Option, 816 | #[serde(rename = "transactType")] 817 | pub transact_type: Option, 818 | pub amount: Option, 819 | pub fee: Option, 820 | #[serde(rename = "transactStatus")] 821 | pub transact_status: Option, 822 | pub address: Option, 823 | pub tx: Option, 824 | pub text: Option, 825 | #[serde(rename = "transactTime")] 826 | pub transact_time: Option>, 827 | pub timestamp: Option> 828 | } 829 | #[derive(Clone, Debug, Deserialize, Serialize)] 830 | pub struct AccessToken { 831 | pub id: String, 832 | /// time to live in seconds (2 weeks by default) 833 | pub ttl: Option, 834 | pub created: Option>, 835 | #[serde(rename = "userId")] 836 | pub user_id: Option 837 | } 838 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 839 | pub struct Affiliate { 840 | pub account: Option, 841 | pub currency: Option, 842 | #[serde(rename = "prevPayout")] 843 | pub prev_payout: Option, 844 | #[serde(rename = "prevTurnover")] 845 | pub prev_turnover: Option, 846 | #[serde(rename = "prevComm")] 847 | pub prev_comm: Option, 848 | #[serde(rename = "prevTimestamp")] 849 | pub prev_timestamp: Option>, 850 | #[serde(rename = "execTurnover")] 851 | pub exec_turnover: Option, 852 | #[serde(rename = "execComm")] 853 | pub exec_comm: Option, 854 | #[serde(rename = "totalReferrals")] 855 | pub total_referrals: Option, 856 | #[serde(rename = "totalTurnover")] 857 | pub total_turnover: Option, 858 | #[serde(rename = "totalComm")] 859 | pub total_comm: Option, 860 | #[serde(rename = "payoutPcnt")] 861 | pub payout_pcnt: Option, 862 | #[serde(rename = "pendingPayout")] 863 | pub pending_payout: Option, 864 | pub timestamp: Option>, 865 | #[serde(rename = "referrerAccount")] 866 | pub referrer_account: Option, 867 | #[serde(rename = "referralDiscount")] 868 | pub referral_discount: Option, 869 | #[serde(rename = "affiliatePayout")] 870 | pub affiliate_payout: Option 871 | } 872 | #[derive(Clone, Debug, Deserialize, Serialize)] 873 | /// Daily Quote Fill Ratio Statistic 874 | pub struct QuoteFillRatio { 875 | pub date: DateTime, 876 | pub account: Option, 877 | #[serde(rename = "quoteCount")] 878 | pub quote_count: Option, 879 | #[serde(rename = "dealtCount")] 880 | pub dealt_count: Option, 881 | #[serde(rename = "quotesMavg7")] 882 | pub quotes_mavg7: Option, 883 | #[serde(rename = "dealtMavg7")] 884 | pub dealt_mavg7: Option, 885 | #[serde(rename = "quoteFillRatioMavg7")] 886 | pub quote_fill_ratio_mavg7: Option 887 | } 888 | #[derive(Clone, Debug, Deserialize, Serialize)] 889 | /// Account Operations 890 | pub struct User { 891 | pub id: Option, 892 | #[serde(rename = "ownerId")] 893 | pub owner_id: Option, 894 | pub firstname: Option, 895 | pub lastname: Option, 896 | pub username: String, 897 | pub email: String, 898 | pub phone: Option, 899 | pub created: Option>, 900 | #[serde(rename = "lastUpdated")] 901 | pub last_updated: Option>, 902 | pub preferences: UserPreferences, 903 | #[serde(rename = "TFAEnabled")] 904 | pub t_f_a_enabled: Option, 905 | #[serde(rename = "affiliateID")] 906 | pub affiliate_id: Option, 907 | #[serde(rename = "pgpPubKey")] 908 | pub pgp_pub_key: Option, 909 | pub country: Option, 910 | #[serde(rename = "geoipCountry")] 911 | pub geoip_country: Option, 912 | #[serde(rename = "geoipRegion")] 913 | pub geoip_region: Option, 914 | pub typ: Option 915 | } 916 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 917 | pub struct UserCommissionsBySymbol(serde_json::Value); 918 | #[derive(Clone, Debug, Deserialize, Serialize)] 919 | pub struct Margin { 920 | pub account: i64, 921 | pub currency: String, 922 | #[serde(rename = "riskLimit")] 923 | pub risk_limit: Option, 924 | #[serde(rename = "prevState")] 925 | pub prev_state: Option, 926 | pub state: Option, 927 | pub action: Option, 928 | pub amount: Option, 929 | #[serde(rename = "pendingCredit")] 930 | pub pending_credit: Option, 931 | #[serde(rename = "pendingDebit")] 932 | pub pending_debit: Option, 933 | #[serde(rename = "confirmedDebit")] 934 | pub confirmed_debit: Option, 935 | #[serde(rename = "prevRealisedPnl")] 936 | pub prev_realised_pnl: Option, 937 | #[serde(rename = "prevUnrealisedPnl")] 938 | pub prev_unrealised_pnl: Option, 939 | #[serde(rename = "grossComm")] 940 | pub gross_comm: Option, 941 | #[serde(rename = "grossOpenCost")] 942 | pub gross_open_cost: Option, 943 | #[serde(rename = "grossOpenPremium")] 944 | pub gross_open_premium: Option, 945 | #[serde(rename = "grossExecCost")] 946 | pub gross_exec_cost: Option, 947 | #[serde(rename = "grossMarkValue")] 948 | pub gross_mark_value: Option, 949 | #[serde(rename = "riskValue")] 950 | pub risk_value: Option, 951 | #[serde(rename = "taxableMargin")] 952 | pub taxable_margin: Option, 953 | #[serde(rename = "initMargin")] 954 | pub init_margin: Option, 955 | #[serde(rename = "maintMargin")] 956 | pub maint_margin: Option, 957 | #[serde(rename = "sessionMargin")] 958 | pub session_margin: Option, 959 | #[serde(rename = "targetExcessMargin")] 960 | pub target_excess_margin: Option, 961 | #[serde(rename = "varMargin")] 962 | pub var_margin: Option, 963 | #[serde(rename = "realisedPnl")] 964 | pub realised_pnl: Option, 965 | #[serde(rename = "unrealisedPnl")] 966 | pub unrealised_pnl: Option, 967 | #[serde(rename = "indicativeTax")] 968 | pub indicative_tax: Option, 969 | #[serde(rename = "unrealisedProfit")] 970 | pub unrealised_profit: Option, 971 | #[serde(rename = "syntheticMargin")] 972 | pub synthetic_margin: Option, 973 | #[serde(rename = "walletBalance")] 974 | pub wallet_balance: Option, 975 | #[serde(rename = "marginBalance")] 976 | pub margin_balance: Option, 977 | #[serde(rename = "marginBalancePcnt")] 978 | pub margin_balance_pcnt: Option, 979 | #[serde(rename = "marginLeverage")] 980 | pub margin_leverage: Option, 981 | #[serde(rename = "marginUsedPcnt")] 982 | pub margin_used_pcnt: Option, 983 | #[serde(rename = "excessMargin")] 984 | pub excess_margin: Option, 985 | #[serde(rename = "excessMarginPcnt")] 986 | pub excess_margin_pcnt: Option, 987 | #[serde(rename = "availableMargin")] 988 | pub available_margin: Option, 989 | #[serde(rename = "withdrawableMargin")] 990 | pub withdrawable_margin: Option, 991 | pub timestamp: Option>, 992 | #[serde(rename = "grossLastValue")] 993 | pub gross_last_value: Option, 994 | pub commission: Option 995 | } 996 | #[derive(Clone, Debug, Deserialize, Serialize)] 997 | /// User communication SNS token 998 | pub struct CommunicationToken { 999 | pub id: String, 1000 | #[serde(rename = "userId")] 1001 | pub user_id: i32, 1002 | #[serde(rename = "deviceToken")] 1003 | pub device_token: String, 1004 | pub channel: String 1005 | } 1006 | #[derive(Clone, Debug, Deserialize, Serialize)] 1007 | /// User Events for auditing 1008 | pub struct UserEvent { 1009 | pub id: Option, 1010 | #[serde(rename = "type")] 1011 | pub r#type: String, 1012 | pub status: String, 1013 | #[serde(rename = "userId")] 1014 | pub user_id: f64, 1015 | #[serde(rename = "createdById")] 1016 | pub created_by_id: Option, 1017 | pub ip: Option, 1018 | #[serde(rename = "geoipCountry")] 1019 | pub geoip_country: Option, 1020 | #[serde(rename = "geoipRegion")] 1021 | pub geoip_region: Option, 1022 | #[serde(rename = "geoipSubRegion")] 1023 | pub geoip_sub_region: Option, 1024 | #[serde(rename = "eventMeta")] 1025 | pub event_meta: Option, 1026 | pub created: DateTime 1027 | } 1028 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 1029 | pub struct EventMetaEventMeta(serde_json::Value); 1030 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 1031 | pub struct UserPreferences { 1032 | #[serde(rename = "alertOnLiquidations")] 1033 | pub alert_on_liquidations: Option, 1034 | #[serde(rename = "animationsEnabled")] 1035 | pub animations_enabled: Option, 1036 | #[serde(rename = "announcementsLastSeen")] 1037 | pub announcements_last_seen: Option>, 1038 | #[serde(rename = "chatChannelID")] 1039 | pub chat_channel_id: Option, 1040 | #[serde(rename = "colorTheme")] 1041 | pub color_theme: Option, 1042 | pub currency: Option, 1043 | pub debug: Option, 1044 | #[serde(rename = "disableEmails")] 1045 | pub disable_emails: Option>, 1046 | #[serde(rename = "disablePush")] 1047 | pub disable_push: Option>, 1048 | #[serde(rename = "hideConfirmDialogs")] 1049 | pub hide_confirm_dialogs: Option>, 1050 | #[serde(rename = "hideConnectionModal")] 1051 | pub hide_connection_modal: Option, 1052 | #[serde(rename = "hideFromLeaderboard")] 1053 | pub hide_from_leaderboard: Option, 1054 | #[serde(rename = "hideNameFromLeaderboard")] 1055 | pub hide_name_from_leaderboard: Option, 1056 | #[serde(rename = "hideNotifications")] 1057 | pub hide_notifications: Option>, 1058 | pub locale: Option, 1059 | #[serde(rename = "msgsSeen")] 1060 | pub msgs_seen: Option>, 1061 | #[serde(rename = "orderBookBinning")] 1062 | pub order_book_binning: Option, 1063 | #[serde(rename = "orderBookType")] 1064 | pub order_book_type: Option, 1065 | #[serde(rename = "orderClearImmediate")] 1066 | pub order_clear_immediate: Option, 1067 | #[serde(rename = "orderControlsPlusMinus")] 1068 | pub order_controls_plus_minus: Option, 1069 | #[serde(rename = "showLocaleNumbers")] 1070 | pub show_locale_numbers: Option, 1071 | pub sounds: Option>, 1072 | #[serde(rename = "strictIPCheck")] 1073 | pub strict_i_p_check: Option, 1074 | #[serde(rename = "strictTimeout")] 1075 | pub strict_timeout: Option, 1076 | #[serde(rename = "tickerGroup")] 1077 | pub ticker_group: Option, 1078 | #[serde(rename = "tickerPinned")] 1079 | pub ticker_pinned: Option, 1080 | #[serde(rename = "tradeLayout")] 1081 | pub trade_layout: Option 1082 | } 1083 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 1084 | pub struct OrderBookBinningOrderBookBinning(serde_json::Value); -------------------------------------------------------------------------------- /src/rest/models/requests.rs: -------------------------------------------------------------------------------- 1 | use http::Method; 2 | use super::Request; 3 | use super::definitions::*; 4 | use serde_json::Value; 5 | use serde::{Deserialize, Serialize}; 6 | use chrono::{DateTime, Utc}; 7 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 8 | /// Get site announcements. 9 | pub struct GetAnnouncementRequest { 10 | /// Array of column names to fetch. If omitted, will return all columns. 11 | pub columns: Option 12 | } 13 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 14 | /// Get urgent (banner) announcements. 15 | pub struct GetAnnouncementUrgentRequest; 16 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 17 | /// Get your API Keys. 18 | pub struct GetApiKeyRequest { 19 | /// If true, will sort results newest first. 20 | pub reverse: Option 21 | } 22 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 23 | /// Get chat messages. 24 | pub struct GetChatRequest { 25 | /// Number of results to fetch. 26 | pub count: Option, 27 | /// Starting ID for results. 28 | pub start: Option, 29 | /// If true, will sort results newest first. 30 | pub reverse: Option, 31 | /// Channel id. GET /chat/channels for ids. Leave blank for all. 32 | #[serde(rename = "channelID")] 33 | pub channel_id: Option 34 | } 35 | #[derive(Clone, Debug, Deserialize, Serialize)] 36 | /// Send a chat message. 37 | pub struct PostChatRequest { 38 | pub message: String, 39 | /// Channel to post to. Default 1 (English). 40 | #[serde(rename = "channelID")] 41 | pub channel_id: Option 42 | } 43 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 44 | /// Get available channels. 45 | pub struct GetChatChannelsRequest; 46 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 47 | /// Get connected users. 48 | pub struct GetChatConnectedRequest; 49 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 50 | /// Get all raw executions for your account. 51 | pub struct GetExecutionRequest { 52 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 53 | pub symbol: Option, 54 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 55 | pub filter: Option, 56 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 57 | pub columns: Option, 58 | /// Number of results to fetch. 59 | pub count: Option, 60 | /// Starting point for results. 61 | pub start: Option, 62 | /// If true, will sort results newest first. 63 | pub reverse: Option, 64 | /// Starting date filter for results. 65 | #[serde(rename = "startTime")] 66 | pub start_time: Option>, 67 | /// Ending date filter for results. 68 | #[serde(rename = "endTime")] 69 | pub end_time: Option> 70 | } 71 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 72 | /// Get all balance-affecting executions. This includes each trade, insurance charge, and settlement. 73 | pub struct GetExecutionTradeHistoryRequest { 74 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 75 | pub symbol: Option, 76 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 77 | pub filter: Option, 78 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 79 | pub columns: Option, 80 | /// Number of results to fetch. 81 | pub count: Option, 82 | /// Starting point for results. 83 | pub start: Option, 84 | /// If true, will sort results newest first. 85 | pub reverse: Option, 86 | /// Starting date filter for results. 87 | #[serde(rename = "startTime")] 88 | pub start_time: Option>, 89 | /// Ending date filter for results. 90 | #[serde(rename = "endTime")] 91 | pub end_time: Option> 92 | } 93 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 94 | /// Get funding history. 95 | pub struct GetFundingRequest { 96 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 97 | pub symbol: Option, 98 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 99 | pub filter: Option, 100 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 101 | pub columns: Option, 102 | /// Number of results to fetch. 103 | pub count: Option, 104 | /// Starting point for results. 105 | pub start: Option, 106 | /// If true, will sort results newest first. 107 | pub reverse: Option, 108 | /// Starting date filter for results. 109 | #[serde(rename = "startTime")] 110 | pub start_time: Option>, 111 | /// Ending date filter for results. 112 | #[serde(rename = "endTime")] 113 | pub end_time: Option> 114 | } 115 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 116 | /// Get instruments. 117 | pub struct GetInstrumentRequest { 118 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 119 | pub symbol: Option, 120 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 121 | pub filter: Option, 122 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 123 | pub columns: Option, 124 | /// Number of results to fetch. 125 | pub count: Option, 126 | /// Starting point for results. 127 | pub start: Option, 128 | /// If true, will sort results newest first. 129 | pub reverse: Option, 130 | /// Starting date filter for results. 131 | #[serde(rename = "startTime")] 132 | pub start_time: Option>, 133 | /// Ending date filter for results. 134 | #[serde(rename = "endTime")] 135 | pub end_time: Option> 136 | } 137 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 138 | /// Get all active instruments and instruments that have expired in <24hrs. 139 | pub struct GetInstrumentActiveRequest; 140 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 141 | /// Get all price indices. 142 | pub struct GetInstrumentIndicesRequest; 143 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 144 | /// Helper method. Gets all active instruments and all indices. This is a join of the result of /indices and /active. 145 | pub struct GetInstrumentActiveAndIndicesRequest; 146 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 147 | /// Return all active contract series and interval pairs. 148 | pub struct GetInstrumentActiveIntervalsRequest; 149 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 150 | /// Show constituent parts of an index. 151 | pub struct GetInstrumentCompositeIndexRequest { 152 | /// The composite index symbol. 153 | pub symbol: Option, 154 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 155 | pub filter: Option, 156 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 157 | pub columns: Option, 158 | /// Number of results to fetch. 159 | pub count: Option, 160 | /// Starting point for results. 161 | pub start: Option, 162 | /// If true, will sort results newest first. 163 | pub reverse: Option, 164 | /// Starting date filter for results. 165 | #[serde(rename = "startTime")] 166 | pub start_time: Option>, 167 | /// Ending date filter for results. 168 | #[serde(rename = "endTime")] 169 | pub end_time: Option> 170 | } 171 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 172 | /// Get insurance fund history. 173 | pub struct GetInsuranceRequest { 174 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 175 | pub symbol: Option, 176 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 177 | pub filter: Option, 178 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 179 | pub columns: Option, 180 | /// Number of results to fetch. 181 | pub count: Option, 182 | /// Starting point for results. 183 | pub start: Option, 184 | /// If true, will sort results newest first. 185 | pub reverse: Option, 186 | /// Starting date filter for results. 187 | #[serde(rename = "startTime")] 188 | pub start_time: Option>, 189 | /// Ending date filter for results. 190 | #[serde(rename = "endTime")] 191 | pub end_time: Option> 192 | } 193 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 194 | /// Get current leaderboard. 195 | pub struct GetLeaderboardRequest { 196 | /// Ranking type. Options: "notional", "ROE" 197 | pub method: Option 198 | } 199 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 200 | /// Get your alias on the leaderboard. 201 | pub struct GetLeaderboardNameRequest; 202 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 203 | pub struct GetLeaderboardNameResponse { 204 | pub name: Option 205 | } 206 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 207 | /// Get liquidation orders. 208 | pub struct GetLiquidationRequest { 209 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 210 | pub symbol: Option, 211 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 212 | pub filter: Option, 213 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 214 | pub columns: Option, 215 | /// Number of results to fetch. 216 | pub count: Option, 217 | /// Starting point for results. 218 | pub start: Option, 219 | /// If true, will sort results newest first. 220 | pub reverse: Option, 221 | /// Starting date filter for results. 222 | #[serde(rename = "startTime")] 223 | pub start_time: Option>, 224 | /// Ending date filter for results. 225 | #[serde(rename = "endTime")] 226 | pub end_time: Option> 227 | } 228 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 229 | /// Get your current GlobalNotifications. 230 | pub struct GetGlobalNotificationRequest; 231 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 232 | /// Get your orders. 233 | pub struct GetOrderRequest { 234 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 235 | pub symbol: Option, 236 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 237 | pub filter: Option, 238 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 239 | pub columns: Option, 240 | /// Number of results to fetch. 241 | pub count: Option, 242 | /// Starting point for results. 243 | pub start: Option, 244 | /// If true, will sort results newest first. 245 | pub reverse: Option, 246 | /// Starting date filter for results. 247 | #[serde(rename = "startTime")] 248 | pub start_time: Option>, 249 | /// Ending date filter for results. 250 | #[serde(rename = "endTime")] 251 | pub end_time: Option> 252 | } 253 | #[derive(Clone, Debug, Deserialize, Serialize)] 254 | /// Create a new order. 255 | pub struct PostOrderRequest { 256 | /// Instrument symbol. e.g. 'XBTUSD'. 257 | pub symbol: String, 258 | /// Order side. Valid options: Buy, Sell. Defaults to 'Buy' unless `orderQty` is negative. 259 | pub side: Option, 260 | /// Deprecated: simple orders are not supported after 2018/10/26 261 | #[serde(rename = "simpleOrderQty")] 262 | pub simple_order_qty: Option, 263 | /// Order quantity in units of the instrument (i.e. contracts). 264 | #[serde(rename = "orderQty")] 265 | pub order_qty: Option, 266 | /// Optional limit price for 'Limit', 'StopLimit', and 'LimitIfTouched' orders. 267 | pub price: Option, 268 | /// Optional quantity to display in the book. Use 0 for a fully hidden order. 269 | #[serde(rename = "displayQty")] 270 | pub display_qty: Option, 271 | /// Optional trigger price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders. Use a price below the current price for stop-sell orders and buy-if-touched orders. Use `execInst` of 'MarkPrice' or 'LastPrice' to define the current price used for triggering. 272 | #[serde(rename = "stopPx")] 273 | pub stop_px: Option, 274 | /// Optional Client Order ID. This clOrdID will come back on the order and any related executions. 275 | #[serde(rename = "clOrdID")] 276 | pub cl_ord_id: Option, 277 | /// Deprecated: linked orders are not supported after 2018/11/10. 278 | #[serde(rename = "clOrdLinkID")] 279 | pub cl_ord_link_id: Option, 280 | /// Optional trailing offset from the current price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders; use a negative offset for stop-sell orders and buy-if-touched orders. Optional offset from the peg price for 'Pegged' orders. 281 | #[serde(rename = "pegOffsetValue")] 282 | pub peg_offset_value: Option, 283 | /// Optional peg price type. Valid options: LastPeg, MidPricePeg, MarketPeg, PrimaryPeg, TrailingStopPeg. 284 | #[serde(rename = "pegPriceType")] 285 | pub peg_price_type: Option, 286 | /// Order type. Valid options: Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched, Pegged. Defaults to 'Limit' when `price` is specified. Defaults to 'Stop' when `stopPx` is specified. Defaults to 'StopLimit' when `price` and `stopPx` are specified. 287 | #[serde(rename = "ordType")] 288 | pub ord_type: Option, 289 | /// Time in force. Valid options: Day, GoodTillCancel, ImmediateOrCancel, FillOrKill. Defaults to 'GoodTillCancel' for 'Limit', 'StopLimit', and 'LimitIfTouched' orders. 290 | #[serde(rename = "timeInForce")] 291 | pub time_in_force: Option, 292 | /// Optional execution instructions. Valid options: ParticipateDoNotInitiate, AllOrNone, MarkPrice, IndexPrice, LastPrice, Close, ReduceOnly, Fixed. 'AllOrNone' instruction requires `displayQty` to be 0. 'MarkPrice', 'IndexPrice' or 'LastPrice' instruction valid for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders. 293 | #[serde(rename = "execInst")] 294 | pub exec_inst: Option, 295 | /// Deprecated: linked orders are not supported after 2018/11/10. 296 | #[serde(rename = "contingencyType")] 297 | pub contingency_type: Option, 298 | /// Optional order annotation. e.g. 'Take profit'. 299 | pub text: Option 300 | } 301 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 302 | /// Amend the quantity or price of an open order. 303 | pub struct PutOrderRequest { 304 | /// Order ID 305 | #[serde(rename = "orderID")] 306 | pub order_id: Option, 307 | /// Client Order ID. See POST /order. 308 | #[serde(rename = "origClOrdID")] 309 | pub orig_cl_ord_id: Option, 310 | /// Optional new Client Order ID, requires `origClOrdID`. 311 | #[serde(rename = "clOrdID")] 312 | pub cl_ord_id: Option, 313 | /// Deprecated: simple orders are not supported after 2018/10/26 314 | #[serde(rename = "simpleOrderQty")] 315 | pub simple_order_qty: Option, 316 | /// Optional order quantity in units of the instrument (i.e. contracts). 317 | #[serde(rename = "orderQty")] 318 | pub order_qty: Option, 319 | /// Deprecated: simple orders are not supported after 2018/10/26 320 | #[serde(rename = "simpleLeavesQty")] 321 | pub simple_leaves_qty: Option, 322 | /// Optional leaves quantity in units of the instrument (i.e. contracts). Useful for amending partially filled orders. 323 | #[serde(rename = "leavesQty")] 324 | pub leaves_qty: Option, 325 | /// Optional limit price for 'Limit', 'StopLimit', and 'LimitIfTouched' orders. 326 | pub price: Option, 327 | /// Optional trigger price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders. Use a price below the current price for stop-sell orders and buy-if-touched orders. 328 | #[serde(rename = "stopPx")] 329 | pub stop_px: Option, 330 | /// Optional trailing offset from the current price for 'Stop', 'StopLimit', 'MarketIfTouched', and 'LimitIfTouched' orders; use a negative offset for stop-sell orders and buy-if-touched orders. Optional offset from the peg price for 'Pegged' orders. 331 | #[serde(rename = "pegOffsetValue")] 332 | pub peg_offset_value: Option, 333 | /// Optional amend annotation. e.g. 'Adjust skew'. 334 | pub text: Option 335 | } 336 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 337 | /// Cancel order(s). Send multiple order IDs to cancel in bulk. 338 | pub struct DeleteOrderRequest { 339 | /// Order ID(s). 340 | #[serde(rename = "orderID")] 341 | pub order_id: Option, 342 | /// Client Order ID(s). See POST /order. 343 | #[serde(rename = "clOrdID")] 344 | pub cl_ord_id: Option, 345 | /// Optional cancellation annotation. e.g. 'Spread Exceeded'. 346 | pub text: Option 347 | } 348 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 349 | /// Create multiple new orders for the same symbol. 350 | pub struct PostOrderBulkRequest { 351 | /// An array of orders. 352 | pub orders: Option> 353 | } 354 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 355 | /// Amend multiple orders for the same symbol. 356 | pub struct PutOrderBulkRequest { 357 | /// An array of orders. 358 | pub orders: Option> 359 | } 360 | #[derive(Clone, Debug, Deserialize, Serialize)] 361 | /// Close a position. [Deprecated, use POST /order with execInst: 'Close'] 362 | pub struct PostOrderClosePositionRequest { 363 | /// Symbol of position to close. 364 | pub symbol: String, 365 | /// Optional limit price. 366 | pub price: Option 367 | } 368 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 369 | /// Cancels all of your orders. 370 | pub struct DeleteOrderAllRequest { 371 | /// Optional symbol. If provided, only cancels orders for that symbol. 372 | pub symbol: Option, 373 | /// Optional filter for cancellation. Use to only cancel some orders, e.g. `{"side": "Buy"}`. 374 | pub filter: Option, 375 | /// Optional cancellation annotation. e.g. 'Spread Exceeded' 376 | pub text: Option 377 | } 378 | #[derive(Clone, Debug, Deserialize, Serialize)] 379 | /// Automatically cancel all your orders after a specified timeout. 380 | pub struct PostOrderCancelAllAfterRequest { 381 | /// Timeout in ms. Set to 0 to cancel this timer. 382 | pub timeout: f64 383 | } 384 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 385 | pub struct PostOrderCancelAllAfterResponse(serde_json::Value); 386 | #[derive(Clone, Debug, Deserialize, Serialize)] 387 | /// Get current orderbook in vertical format. 388 | pub struct GetOrderBookL2Request { 389 | /// Instrument symbol. Send a series (e.g. XBT) to get data for the nearest contract in that series. 390 | pub symbol: String, 391 | /// Orderbook depth per side. Send 0 for full depth. 392 | pub depth: Option 393 | } 394 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 395 | /// Get your positions. 396 | pub struct GetPositionRequest { 397 | /// Table filter. For example, send {"symbol": "XBTUSD"}. 398 | pub filter: Option, 399 | /// Which columns to fetch. For example, send ["columnName"]. 400 | pub columns: Option, 401 | /// Number of rows to fetch. 402 | pub count: Option 403 | } 404 | #[derive(Clone, Debug, Deserialize, Serialize)] 405 | /// Enable isolated margin or cross margin per-position. 406 | pub struct PostPositionIsolateRequest { 407 | /// Position symbol to isolate. 408 | pub symbol: String, 409 | /// True for isolated margin, false for cross margin. 410 | pub enabled: Option 411 | } 412 | #[derive(Clone, Debug, Deserialize, Serialize)] 413 | /// Update your risk limit. 414 | pub struct PostPositionRiskLimitRequest { 415 | /// Symbol of position to update risk limit on. 416 | pub symbol: String, 417 | /// New Risk Limit, in Satoshis. 418 | #[serde(rename = "riskLimit")] 419 | pub risk_limit: i64 420 | } 421 | #[derive(Clone, Debug, Deserialize, Serialize)] 422 | /// Transfer equity in or out of a position. 423 | pub struct PostPositionTransferMarginRequest { 424 | /// Symbol of position to isolate. 425 | pub symbol: String, 426 | /// Amount to transfer, in Satoshis. May be negative. 427 | pub amount: i64 428 | } 429 | #[derive(Clone, Debug, Deserialize, Serialize)] 430 | /// Choose leverage for a position. 431 | pub struct PostPositionLeverageRequest { 432 | /// Symbol of position to adjust. 433 | pub symbol: String, 434 | /// Leverage value. Send a number between 0.01 and 100 to enable isolated margin with a fixed leverage. Send 0 to enable cross margin. 435 | pub leverage: f64 436 | } 437 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 438 | /// Get Quotes. 439 | pub struct GetQuoteRequest { 440 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 441 | pub symbol: Option, 442 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 443 | pub filter: Option, 444 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 445 | pub columns: Option, 446 | /// Number of results to fetch. 447 | pub count: Option, 448 | /// Starting point for results. 449 | pub start: Option, 450 | /// If true, will sort results newest first. 451 | pub reverse: Option, 452 | /// Starting date filter for results. 453 | #[serde(rename = "startTime")] 454 | pub start_time: Option>, 455 | /// Ending date filter for results. 456 | #[serde(rename = "endTime")] 457 | pub end_time: Option> 458 | } 459 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 460 | /// Get previous quotes in time buckets. 461 | pub struct GetQuoteBucketedRequest { 462 | /// Time interval to bucket by. Available options: [1m,5m,1h,1d]. 463 | #[serde(rename = "binSize")] 464 | pub bin_size: Option, 465 | /// If true, will send in-progress (incomplete) bins for the current time period. 466 | pub partial: Option, 467 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 468 | pub symbol: Option, 469 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 470 | pub filter: Option, 471 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 472 | pub columns: Option, 473 | /// Number of results to fetch. 474 | pub count: Option, 475 | /// Starting point for results. 476 | pub start: Option, 477 | /// If true, will sort results newest first. 478 | pub reverse: Option, 479 | /// Starting date filter for results. 480 | #[serde(rename = "startTime")] 481 | pub start_time: Option>, 482 | /// Ending date filter for results. 483 | #[serde(rename = "endTime")] 484 | pub end_time: Option> 485 | } 486 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 487 | /// Get model schemata for data objects returned by this API. 488 | pub struct GetSchemaRequest { 489 | /// Optional model filter. If omitted, will return all models. 490 | pub model: Option 491 | } 492 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 493 | pub struct GetSchemaResponse(serde_json::Value); 494 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 495 | /// Returns help text & subject list for websocket usage. 496 | pub struct GetSchemaWebsocketHelpRequest; 497 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 498 | pub struct GetSchemaWebsocketHelpResponse(serde_json::Value); 499 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 500 | /// Get settlement history. 501 | pub struct GetSettlementRequest { 502 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 503 | pub symbol: Option, 504 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 505 | pub filter: Option, 506 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 507 | pub columns: Option, 508 | /// Number of results to fetch. 509 | pub count: Option, 510 | /// Starting point for results. 511 | pub start: Option, 512 | /// If true, will sort results newest first. 513 | pub reverse: Option, 514 | /// Starting date filter for results. 515 | #[serde(rename = "startTime")] 516 | pub start_time: Option>, 517 | /// Ending date filter for results. 518 | #[serde(rename = "endTime")] 519 | pub end_time: Option> 520 | } 521 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 522 | /// Get exchange-wide and per-series turnover and volume statistics. 523 | pub struct GetStatsRequest; 524 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 525 | /// Get historical exchange-wide and per-series turnover and volume statistics. 526 | pub struct GetStatsHistoryRequest; 527 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 528 | /// Get a summary of exchange statistics in USD. 529 | pub struct GetStatsHistoryUSDRequest; 530 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 531 | /// Get Trades. 532 | pub struct GetTradeRequest { 533 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 534 | pub symbol: Option, 535 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 536 | pub filter: Option, 537 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 538 | pub columns: Option, 539 | /// Number of results to fetch. 540 | pub count: Option, 541 | /// Starting point for results. 542 | pub start: Option, 543 | /// If true, will sort results newest first. 544 | pub reverse: Option, 545 | /// Starting date filter for results. 546 | #[serde(rename = "startTime")] 547 | pub start_time: Option>, 548 | /// Ending date filter for results. 549 | #[serde(rename = "endTime")] 550 | pub end_time: Option> 551 | } 552 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 553 | /// Get previous trades in time buckets. 554 | pub struct GetTradeBucketedRequest { 555 | /// Time interval to bucket by. Available options: [1m,5m,1h,1d]. 556 | #[serde(rename = "binSize")] 557 | pub bin_size: Option, 558 | /// If true, will send in-progress (incomplete) bins for the current time period. 559 | pub partial: Option, 560 | /// Instrument symbol. Send a bare series (e.g. XBT) to get data for the nearest expiring contract in that series. You can also send a timeframe, e.g. `XBT:quarterly`. Timeframes are `nearest`, `daily`, `weekly`, `monthly`, `quarterly`, `biquarterly`, and `perpetual`. 561 | pub symbol: Option, 562 | /// Generic table filter. Send JSON key/value pairs, such as `{"key": "value"}`. You can key on individual fields, and do more advanced querying on timestamps. See the [Timestamp Docs](https://www.bitmex.com/app/restAPI#Timestamp-Filters) for more details. 563 | pub filter: Option, 564 | /// Array of column names to fetch. If omitted, will return all columns. Note that this method will always return item keys, even when not specified, so you may receive more columns that you expect. 565 | pub columns: Option, 566 | /// Number of results to fetch. 567 | pub count: Option, 568 | /// Starting point for results. 569 | pub start: Option, 570 | /// If true, will sort results newest first. 571 | pub reverse: Option, 572 | /// Starting date filter for results. 573 | #[serde(rename = "startTime")] 574 | pub start_time: Option>, 575 | /// Ending date filter for results. 576 | #[serde(rename = "endTime")] 577 | pub end_time: Option> 578 | } 579 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 580 | /// Get a deposit address. 581 | pub struct GetUserDepositAddressRequest { 582 | pub currency: Option 583 | } 584 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 585 | /// Get your current wallet information. 586 | pub struct GetUserWalletRequest { 587 | pub currency: Option 588 | } 589 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 590 | /// Get a history of all of your wallet transactions (deposits, withdrawals, PNL). 591 | pub struct GetUserWalletHistoryRequest { 592 | pub currency: Option, 593 | /// Number of results to fetch. 594 | pub count: Option, 595 | /// Starting point for results. 596 | pub start: Option 597 | } 598 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 599 | /// Get a summary of all of your wallet transactions (deposits, withdrawals, PNL). 600 | pub struct GetUserWalletSummaryRequest { 601 | pub currency: Option 602 | } 603 | #[derive(Clone, Debug, Deserialize, Serialize)] 604 | /// Get the execution history by day. 605 | pub struct GetUserExecutionHistoryRequest { 606 | pub symbol: String, 607 | pub timestamp: DateTime 608 | } 609 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 610 | pub struct GetUserExecutionHistoryResponse(serde_json::Value); 611 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 612 | /// Get the minimum withdrawal fee for a currency. 613 | pub struct GetUserMinWithdrawalFeeRequest { 614 | pub currency: Option 615 | } 616 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 617 | pub struct GetUserMinWithdrawalFeeResponse(serde_json::Value); 618 | #[derive(Clone, Debug, Deserialize, Serialize)] 619 | /// Request a withdrawal to an external wallet. 620 | pub struct PostUserRequestWithdrawalRequest { 621 | /// 2FA token. Required if 2FA is enabled on your account. 622 | #[serde(rename = "otpToken")] 623 | pub otp_token: Option, 624 | /// Currency you're withdrawing. Options: `XBt` 625 | pub currency: String, 626 | /// Amount of withdrawal currency. 627 | pub amount: i64, 628 | /// Destination Address. 629 | pub address: String, 630 | /// Network fee for Bitcoin withdrawals. If not specified, a default value will be calculated based on Bitcoin network conditions. You will have a chance to confirm this via email. 631 | pub fee: Option, 632 | /// Optional annotation, e.g. 'Transfer to home wallet'. 633 | pub text: Option 634 | } 635 | #[derive(Clone, Debug, Deserialize, Serialize)] 636 | /// Cancel a withdrawal. 637 | pub struct PostUserCancelWithdrawalRequest { 638 | pub token: String 639 | } 640 | #[derive(Clone, Debug, Deserialize, Serialize)] 641 | /// Confirm a withdrawal. 642 | pub struct PostUserConfirmWithdrawalRequest { 643 | pub token: String 644 | } 645 | #[derive(Clone, Debug, Deserialize, Serialize)] 646 | /// Confirm your email address with a token. 647 | pub struct PostUserConfirmEmailRequest { 648 | pub token: String 649 | } 650 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 651 | /// Get your current affiliate/referral status. 652 | pub struct GetUserAffiliateStatusRequest; 653 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 654 | /// Check if a referral code is valid. 655 | pub struct GetUserCheckReferralCodeRequest { 656 | #[serde(rename = "referralCode")] 657 | pub referral_code: Option 658 | } 659 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 660 | /// Get 7 days worth of Quote Fill Ratio statistics. 661 | pub struct GetUserQuoteFillRatioRequest; 662 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 663 | /// Log out of BitMEX. 664 | pub struct PostUserLogoutRequest; 665 | #[derive(Clone, Debug, Deserialize, Serialize)] 666 | /// Save user preferences. 667 | pub struct PostUserPreferencesRequest { 668 | pub prefs: Value, 669 | /// If true, will overwrite all existing preferences. 670 | pub overwrite: Option 671 | } 672 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 673 | /// Get your user model. 674 | pub struct GetUserRequest; 675 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 676 | /// Get your account's commission status. 677 | pub struct GetUserCommissionRequest; 678 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 679 | /// Get your account's margin status. Send a currency of "all" to receive an array of all supported currencies. 680 | pub struct GetUserMarginRequest { 681 | pub currency: Option 682 | } 683 | #[derive(Clone, Debug, Deserialize, Serialize)] 684 | /// Register your communication token for mobile clients 685 | pub struct PostUserCommunicationTokenRequest { 686 | pub token: String, 687 | #[serde(rename = "platformAgent")] 688 | pub platform_agent: String 689 | } 690 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 691 | /// Get your user events 692 | pub struct GetUserEventRequest { 693 | /// Number of results to fetch. 694 | pub count: Option, 695 | /// Cursor for pagination. 696 | #[serde(rename = "startId")] 697 | pub start_id: Option 698 | } 699 | #[derive(Clone, Debug, Deserialize, Serialize, Default)] 700 | pub struct GetUserEventResponse { 701 | #[serde(rename = "userEvents")] 702 | pub user_events: Vec 703 | } 704 | impl Request for GetAnnouncementRequest { 705 | const METHOD: Method = Method::GET; 706 | const SIGNED: bool = false; 707 | const ENDPOINT: &'static str = "/announcement"; 708 | const HAS_PAYLOAD: bool = true; 709 | type Response = Vec; 710 | } 711 | impl Request for GetAnnouncementUrgentRequest { 712 | const METHOD: Method = Method::GET; 713 | const SIGNED: bool = true; 714 | const ENDPOINT: &'static str = "/announcement/urgent"; 715 | const HAS_PAYLOAD: bool = false; 716 | type Response = Vec; 717 | } 718 | impl Request for GetApiKeyRequest { 719 | const METHOD: Method = Method::GET; 720 | const SIGNED: bool = true; 721 | const ENDPOINT: &'static str = "/apiKey"; 722 | const HAS_PAYLOAD: bool = true; 723 | type Response = Vec; 724 | } 725 | impl Request for GetChatRequest { 726 | const METHOD: Method = Method::GET; 727 | const SIGNED: bool = false; 728 | const ENDPOINT: &'static str = "/chat"; 729 | const HAS_PAYLOAD: bool = true; 730 | type Response = Vec; 731 | } 732 | impl Request for PostChatRequest { 733 | const METHOD: Method = Method::POST; 734 | const SIGNED: bool = true; 735 | const ENDPOINT: &'static str = "/chat"; 736 | const HAS_PAYLOAD: bool = true; 737 | type Response = Chat; 738 | } 739 | impl Request for GetChatChannelsRequest { 740 | const METHOD: Method = Method::GET; 741 | const SIGNED: bool = false; 742 | const ENDPOINT: &'static str = "/chat/channels"; 743 | const HAS_PAYLOAD: bool = false; 744 | type Response = Vec; 745 | } 746 | impl Request for GetChatConnectedRequest { 747 | const METHOD: Method = Method::GET; 748 | const SIGNED: bool = false; 749 | const ENDPOINT: &'static str = "/chat/connected"; 750 | const HAS_PAYLOAD: bool = false; 751 | type Response = ConnectedUsers; 752 | } 753 | impl Request for GetExecutionRequest { 754 | const METHOD: Method = Method::GET; 755 | const SIGNED: bool = true; 756 | const ENDPOINT: &'static str = "/execution"; 757 | const HAS_PAYLOAD: bool = true; 758 | type Response = Vec; 759 | } 760 | impl Request for GetExecutionTradeHistoryRequest { 761 | const METHOD: Method = Method::GET; 762 | const SIGNED: bool = true; 763 | const ENDPOINT: &'static str = "/execution/tradeHistory"; 764 | const HAS_PAYLOAD: bool = true; 765 | type Response = Vec; 766 | } 767 | impl Request for GetFundingRequest { 768 | const METHOD: Method = Method::GET; 769 | const SIGNED: bool = false; 770 | const ENDPOINT: &'static str = "/funding"; 771 | const HAS_PAYLOAD: bool = true; 772 | type Response = Vec; 773 | } 774 | impl Request for GetInstrumentRequest { 775 | const METHOD: Method = Method::GET; 776 | const SIGNED: bool = false; 777 | const ENDPOINT: &'static str = "/instrument"; 778 | const HAS_PAYLOAD: bool = true; 779 | type Response = Vec; 780 | } 781 | impl Request for GetInstrumentActiveRequest { 782 | const METHOD: Method = Method::GET; 783 | const SIGNED: bool = false; 784 | const ENDPOINT: &'static str = "/instrument/active"; 785 | const HAS_PAYLOAD: bool = false; 786 | type Response = Vec; 787 | } 788 | impl Request for GetInstrumentIndicesRequest { 789 | const METHOD: Method = Method::GET; 790 | const SIGNED: bool = false; 791 | const ENDPOINT: &'static str = "/instrument/indices"; 792 | const HAS_PAYLOAD: bool = false; 793 | type Response = Vec; 794 | } 795 | impl Request for GetInstrumentActiveAndIndicesRequest { 796 | const METHOD: Method = Method::GET; 797 | const SIGNED: bool = false; 798 | const ENDPOINT: &'static str = "/instrument/activeAndIndices"; 799 | const HAS_PAYLOAD: bool = false; 800 | type Response = Vec; 801 | } 802 | impl Request for GetInstrumentActiveIntervalsRequest { 803 | const METHOD: Method = Method::GET; 804 | const SIGNED: bool = false; 805 | const ENDPOINT: &'static str = "/instrument/activeIntervals"; 806 | const HAS_PAYLOAD: bool = false; 807 | type Response = InstrumentInterval; 808 | } 809 | impl Request for GetInstrumentCompositeIndexRequest { 810 | const METHOD: Method = Method::GET; 811 | const SIGNED: bool = false; 812 | const ENDPOINT: &'static str = "/instrument/compositeIndex"; 813 | const HAS_PAYLOAD: bool = true; 814 | type Response = Vec; 815 | } 816 | impl Request for GetInsuranceRequest { 817 | const METHOD: Method = Method::GET; 818 | const SIGNED: bool = false; 819 | const ENDPOINT: &'static str = "/insurance"; 820 | const HAS_PAYLOAD: bool = true; 821 | type Response = Vec; 822 | } 823 | impl Request for GetLeaderboardRequest { 824 | const METHOD: Method = Method::GET; 825 | const SIGNED: bool = false; 826 | const ENDPOINT: &'static str = "/leaderboard"; 827 | const HAS_PAYLOAD: bool = true; 828 | type Response = Vec; 829 | } 830 | impl Request for GetLeaderboardNameRequest { 831 | const METHOD: Method = Method::GET; 832 | const SIGNED: bool = true; 833 | const ENDPOINT: &'static str = "/leaderboard/name"; 834 | const HAS_PAYLOAD: bool = false; 835 | type Response = GetLeaderboardNameResponse; 836 | } 837 | impl Request for GetLiquidationRequest { 838 | const METHOD: Method = Method::GET; 839 | const SIGNED: bool = false; 840 | const ENDPOINT: &'static str = "/liquidation"; 841 | const HAS_PAYLOAD: bool = true; 842 | type Response = Vec; 843 | } 844 | impl Request for GetGlobalNotificationRequest { 845 | const METHOD: Method = Method::GET; 846 | const SIGNED: bool = true; 847 | const ENDPOINT: &'static str = "/globalNotification"; 848 | const HAS_PAYLOAD: bool = false; 849 | type Response = Vec; 850 | } 851 | impl Request for GetOrderRequest { 852 | const METHOD: Method = Method::GET; 853 | const SIGNED: bool = true; 854 | const ENDPOINT: &'static str = "/order"; 855 | const HAS_PAYLOAD: bool = true; 856 | type Response = Vec; 857 | } 858 | impl Request for PostOrderRequest { 859 | const METHOD: Method = Method::POST; 860 | const SIGNED: bool = true; 861 | const ENDPOINT: &'static str = "/order"; 862 | const HAS_PAYLOAD: bool = true; 863 | type Response = Order; 864 | } 865 | impl Request for PutOrderRequest { 866 | const METHOD: Method = Method::PUT; 867 | const SIGNED: bool = true; 868 | const ENDPOINT: &'static str = "/order"; 869 | const HAS_PAYLOAD: bool = true; 870 | type Response = Order; 871 | } 872 | impl Request for DeleteOrderRequest { 873 | const METHOD: Method = Method::DELETE; 874 | const SIGNED: bool = true; 875 | const ENDPOINT: &'static str = "/order"; 876 | const HAS_PAYLOAD: bool = true; 877 | type Response = Vec; 878 | } 879 | impl Request for PostOrderBulkRequest { 880 | const METHOD: Method = Method::POST; 881 | const SIGNED: bool = true; 882 | const ENDPOINT: &'static str = "/order/bulk"; 883 | const HAS_PAYLOAD: bool = true; 884 | type Response = Vec; 885 | } 886 | impl Request for PutOrderBulkRequest { 887 | const METHOD: Method = Method::PUT; 888 | const SIGNED: bool = true; 889 | const ENDPOINT: &'static str = "/order/bulk"; 890 | const HAS_PAYLOAD: bool = true; 891 | type Response = Vec; 892 | } 893 | impl Request for PostOrderClosePositionRequest { 894 | const METHOD: Method = Method::POST; 895 | const SIGNED: bool = true; 896 | const ENDPOINT: &'static str = "/order/closePosition"; 897 | const HAS_PAYLOAD: bool = true; 898 | type Response = Order; 899 | } 900 | impl Request for DeleteOrderAllRequest { 901 | const METHOD: Method = Method::DELETE; 902 | const SIGNED: bool = true; 903 | const ENDPOINT: &'static str = "/order/all"; 904 | const HAS_PAYLOAD: bool = true; 905 | type Response = Vec; 906 | } 907 | impl Request for PostOrderCancelAllAfterRequest { 908 | const METHOD: Method = Method::POST; 909 | const SIGNED: bool = true; 910 | const ENDPOINT: &'static str = "/order/cancelAllAfter"; 911 | const HAS_PAYLOAD: bool = true; 912 | type Response = PostOrderCancelAllAfterResponse; 913 | } 914 | impl Request for GetOrderBookL2Request { 915 | const METHOD: Method = Method::GET; 916 | const SIGNED: bool = false; 917 | const ENDPOINT: &'static str = "/orderBook/L2"; 918 | const HAS_PAYLOAD: bool = true; 919 | type Response = Vec; 920 | } 921 | impl Request for GetPositionRequest { 922 | const METHOD: Method = Method::GET; 923 | const SIGNED: bool = true; 924 | const ENDPOINT: &'static str = "/position"; 925 | const HAS_PAYLOAD: bool = true; 926 | type Response = Vec; 927 | } 928 | impl Request for PostPositionIsolateRequest { 929 | const METHOD: Method = Method::POST; 930 | const SIGNED: bool = true; 931 | const ENDPOINT: &'static str = "/position/isolate"; 932 | const HAS_PAYLOAD: bool = true; 933 | type Response = Position; 934 | } 935 | impl Request for PostPositionRiskLimitRequest { 936 | const METHOD: Method = Method::POST; 937 | const SIGNED: bool = true; 938 | const ENDPOINT: &'static str = "/position/riskLimit"; 939 | const HAS_PAYLOAD: bool = true; 940 | type Response = Position; 941 | } 942 | impl Request for PostPositionTransferMarginRequest { 943 | const METHOD: Method = Method::POST; 944 | const SIGNED: bool = true; 945 | const ENDPOINT: &'static str = "/position/transferMargin"; 946 | const HAS_PAYLOAD: bool = true; 947 | type Response = Position; 948 | } 949 | impl Request for PostPositionLeverageRequest { 950 | const METHOD: Method = Method::POST; 951 | const SIGNED: bool = true; 952 | const ENDPOINT: &'static str = "/position/leverage"; 953 | const HAS_PAYLOAD: bool = true; 954 | type Response = Position; 955 | } 956 | impl Request for GetQuoteRequest { 957 | const METHOD: Method = Method::GET; 958 | const SIGNED: bool = false; 959 | const ENDPOINT: &'static str = "/quote"; 960 | const HAS_PAYLOAD: bool = true; 961 | type Response = Vec; 962 | } 963 | impl Request for GetQuoteBucketedRequest { 964 | const METHOD: Method = Method::GET; 965 | const SIGNED: bool = false; 966 | const ENDPOINT: &'static str = "/quote/bucketed"; 967 | const HAS_PAYLOAD: bool = true; 968 | type Response = Vec; 969 | } 970 | impl Request for GetSchemaRequest { 971 | const METHOD: Method = Method::GET; 972 | const SIGNED: bool = false; 973 | const ENDPOINT: &'static str = "/schema"; 974 | const HAS_PAYLOAD: bool = true; 975 | type Response = GetSchemaResponse; 976 | } 977 | impl Request for GetSchemaWebsocketHelpRequest { 978 | const METHOD: Method = Method::GET; 979 | const SIGNED: bool = false; 980 | const ENDPOINT: &'static str = "/schema/websocketHelp"; 981 | const HAS_PAYLOAD: bool = false; 982 | type Response = GetSchemaWebsocketHelpResponse; 983 | } 984 | impl Request for GetSettlementRequest { 985 | const METHOD: Method = Method::GET; 986 | const SIGNED: bool = false; 987 | const ENDPOINT: &'static str = "/settlement"; 988 | const HAS_PAYLOAD: bool = true; 989 | type Response = Vec; 990 | } 991 | impl Request for GetStatsRequest { 992 | const METHOD: Method = Method::GET; 993 | const SIGNED: bool = false; 994 | const ENDPOINT: &'static str = "/stats"; 995 | const HAS_PAYLOAD: bool = false; 996 | type Response = Vec; 997 | } 998 | impl Request for GetStatsHistoryRequest { 999 | const METHOD: Method = Method::GET; 1000 | const SIGNED: bool = false; 1001 | const ENDPOINT: &'static str = "/stats/history"; 1002 | const HAS_PAYLOAD: bool = false; 1003 | type Response = Vec; 1004 | } 1005 | impl Request for GetStatsHistoryUSDRequest { 1006 | const METHOD: Method = Method::GET; 1007 | const SIGNED: bool = false; 1008 | const ENDPOINT: &'static str = "/stats/historyUSD"; 1009 | const HAS_PAYLOAD: bool = false; 1010 | type Response = Vec; 1011 | } 1012 | impl Request for GetTradeRequest { 1013 | const METHOD: Method = Method::GET; 1014 | const SIGNED: bool = false; 1015 | const ENDPOINT: &'static str = "/trade"; 1016 | const HAS_PAYLOAD: bool = true; 1017 | type Response = Vec; 1018 | } 1019 | impl Request for GetTradeBucketedRequest { 1020 | const METHOD: Method = Method::GET; 1021 | const SIGNED: bool = false; 1022 | const ENDPOINT: &'static str = "/trade/bucketed"; 1023 | const HAS_PAYLOAD: bool = true; 1024 | type Response = Vec; 1025 | } 1026 | impl Request for GetUserDepositAddressRequest { 1027 | const METHOD: Method = Method::GET; 1028 | const SIGNED: bool = true; 1029 | const ENDPOINT: &'static str = "/user/depositAddress"; 1030 | const HAS_PAYLOAD: bool = true; 1031 | type Response = String; 1032 | } 1033 | impl Request for GetUserWalletRequest { 1034 | const METHOD: Method = Method::GET; 1035 | const SIGNED: bool = true; 1036 | const ENDPOINT: &'static str = "/user/wallet"; 1037 | const HAS_PAYLOAD: bool = true; 1038 | type Response = Wallet; 1039 | } 1040 | impl Request for GetUserWalletHistoryRequest { 1041 | const METHOD: Method = Method::GET; 1042 | const SIGNED: bool = true; 1043 | const ENDPOINT: &'static str = "/user/walletHistory"; 1044 | const HAS_PAYLOAD: bool = true; 1045 | type Response = Vec; 1046 | } 1047 | impl Request for GetUserWalletSummaryRequest { 1048 | const METHOD: Method = Method::GET; 1049 | const SIGNED: bool = true; 1050 | const ENDPOINT: &'static str = "/user/walletSummary"; 1051 | const HAS_PAYLOAD: bool = true; 1052 | type Response = Vec; 1053 | } 1054 | impl Request for GetUserExecutionHistoryRequest { 1055 | const METHOD: Method = Method::GET; 1056 | const SIGNED: bool = true; 1057 | const ENDPOINT: &'static str = "/user/executionHistory"; 1058 | const HAS_PAYLOAD: bool = true; 1059 | type Response = GetUserExecutionHistoryResponse; 1060 | } 1061 | impl Request for GetUserMinWithdrawalFeeRequest { 1062 | const METHOD: Method = Method::GET; 1063 | const SIGNED: bool = false; 1064 | const ENDPOINT: &'static str = "/user/minWithdrawalFee"; 1065 | const HAS_PAYLOAD: bool = true; 1066 | type Response = GetUserMinWithdrawalFeeResponse; 1067 | } 1068 | impl Request for PostUserRequestWithdrawalRequest { 1069 | const METHOD: Method = Method::POST; 1070 | const SIGNED: bool = true; 1071 | const ENDPOINT: &'static str = "/user/requestWithdrawal"; 1072 | const HAS_PAYLOAD: bool = true; 1073 | type Response = Transaction; 1074 | } 1075 | impl Request for PostUserCancelWithdrawalRequest { 1076 | const METHOD: Method = Method::POST; 1077 | const SIGNED: bool = false; 1078 | const ENDPOINT: &'static str = "/user/cancelWithdrawal"; 1079 | const HAS_PAYLOAD: bool = true; 1080 | type Response = Transaction; 1081 | } 1082 | impl Request for PostUserConfirmWithdrawalRequest { 1083 | const METHOD: Method = Method::POST; 1084 | const SIGNED: bool = false; 1085 | const ENDPOINT: &'static str = "/user/confirmWithdrawal"; 1086 | const HAS_PAYLOAD: bool = true; 1087 | type Response = Transaction; 1088 | } 1089 | impl Request for PostUserConfirmEmailRequest { 1090 | const METHOD: Method = Method::POST; 1091 | const SIGNED: bool = false; 1092 | const ENDPOINT: &'static str = "/user/confirmEmail"; 1093 | const HAS_PAYLOAD: bool = true; 1094 | type Response = AccessToken; 1095 | } 1096 | impl Request for GetUserAffiliateStatusRequest { 1097 | const METHOD: Method = Method::GET; 1098 | const SIGNED: bool = true; 1099 | const ENDPOINT: &'static str = "/user/affiliateStatus"; 1100 | const HAS_PAYLOAD: bool = false; 1101 | type Response = Affiliate; 1102 | } 1103 | impl Request for GetUserCheckReferralCodeRequest { 1104 | const METHOD: Method = Method::GET; 1105 | const SIGNED: bool = false; 1106 | const ENDPOINT: &'static str = "/user/checkReferralCode"; 1107 | const HAS_PAYLOAD: bool = true; 1108 | type Response = f64; 1109 | } 1110 | impl Request for GetUserQuoteFillRatioRequest { 1111 | const METHOD: Method = Method::GET; 1112 | const SIGNED: bool = true; 1113 | const ENDPOINT: &'static str = "/user/quoteFillRatio"; 1114 | const HAS_PAYLOAD: bool = false; 1115 | type Response = QuoteFillRatio; 1116 | } 1117 | impl Request for PostUserLogoutRequest { 1118 | const METHOD: Method = Method::POST; 1119 | const SIGNED: bool = false; 1120 | const ENDPOINT: &'static str = "/user/logout"; 1121 | const HAS_PAYLOAD: bool = false; 1122 | type Response = (); 1123 | } 1124 | impl Request for PostUserPreferencesRequest { 1125 | const METHOD: Method = Method::POST; 1126 | const SIGNED: bool = true; 1127 | const ENDPOINT: &'static str = "/user/preferences"; 1128 | const HAS_PAYLOAD: bool = true; 1129 | type Response = User; 1130 | } 1131 | impl Request for GetUserRequest { 1132 | const METHOD: Method = Method::GET; 1133 | const SIGNED: bool = true; 1134 | const ENDPOINT: &'static str = "/user"; 1135 | const HAS_PAYLOAD: bool = false; 1136 | type Response = User; 1137 | } 1138 | impl Request for GetUserCommissionRequest { 1139 | const METHOD: Method = Method::GET; 1140 | const SIGNED: bool = true; 1141 | const ENDPOINT: &'static str = "/user/commission"; 1142 | const HAS_PAYLOAD: bool = false; 1143 | type Response = UserCommissionsBySymbol; 1144 | } 1145 | impl Request for GetUserMarginRequest { 1146 | const METHOD: Method = Method::GET; 1147 | const SIGNED: bool = true; 1148 | const ENDPOINT: &'static str = "/user/margin"; 1149 | const HAS_PAYLOAD: bool = true; 1150 | type Response = Margin; 1151 | } 1152 | impl Request for PostUserCommunicationTokenRequest { 1153 | const METHOD: Method = Method::POST; 1154 | const SIGNED: bool = true; 1155 | const ENDPOINT: &'static str = "/user/communicationToken"; 1156 | const HAS_PAYLOAD: bool = true; 1157 | type Response = Vec; 1158 | } 1159 | impl Request for GetUserEventRequest { 1160 | const METHOD: Method = Method::GET; 1161 | const SIGNED: bool = true; 1162 | const ENDPOINT: &'static str = "/userEvent"; 1163 | const HAS_PAYLOAD: bool = true; 1164 | type Response = GetUserEventResponse; 1165 | } --------------------------------------------------------------------------------