#![deny(
unstable_features,
unused_must_use,
unused_mut,
unused_imports,
unused_import_braces
)]
pub mod api;
pub mod client;
pub mod config;
pub mod credentials;
pub mod error;
pub mod models;
pub mod types;
pub mod websocket;
pub use client::Client;
pub use config::{Config, ConfigBuilder};
pub use credentials::{Credentials, SignatureType};
pub use error::{Error, Result};
pub use websocket::{
ConnectionHealthMonitor, ConnectionState, DepthCache, DepthCacheConfig, DepthCacheManager,
DepthCacheState, ReconnectConfig, ReconnectingWebSocket, UserDataStreamManager,
WebSocketClient, WebSocketConnection, WebSocketEventStream,
};
pub use types::{
AccountType, CancelReplaceMode, CancelReplaceResult, CancelRestrictions, ContingencyType,
ExecutionType, KlineInterval, OcoOrderStatus, OcoStatus, OrderRateLimitExceededMode,
OrderResponseType, OrderSide, OrderStatus, OrderType, RateLimitInterval, RateLimitType,
SymbolPermission, SymbolStatus, TickerType, TimeInForce,
};
pub use models::{
AccountCommission,
AccountInfo,
AccountSnapshot,
AccountSnapshotType,
AccountStatus,
AggTrade,
Allocation,
AmendListStatus,
AmendOrderResponse,
AmendedOrderInfo,
ApiKeyPermissions,
ApiTradingStatus,
AssetDetail,
AveragePrice,
Balance,
BnbBurnStatus,
BookTicker,
CancelOrderResponse,
CancelReplaceErrorData,
CancelReplaceErrorInfo,
CancelReplaceErrorResponse,
CancelReplaceResponse,
CancelReplaceSideResponse,
CoinInfo,
CoinNetwork,
DepositAddress,
DepositRecord,
DepositStatus,
ExchangeInfo,
Fill,
FundingAsset,
InterestHistoryRecord,
InterestRateRecord,
IsolatedAccountLimit,
IsolatedAssetDetails,
IsolatedMarginAccountAsset,
IsolatedMarginAccountDetails,
IsolatedMarginTransferType,
Kline,
ListenKey,
LoanRecord,
MarginAccountDetails,
MarginAsset,
MarginAssetInfo,
MarginOrderCancellation,
MarginOrderResult,
MarginOrderState,
MarginPairDetails,
MarginPriceIndex,
MarginTrade,
MarginTransferType,
MaxBorrowableAmount,
MaxTransferableAmount,
OcoOrder,
OcoOrderDetail,
OcoOrderReport,
Order,
OrderAck,
OrderAmendment,
OrderBook,
OrderBookEntry,
OrderFull,
OrderResponse,
OrderResult,
PreventedMatch,
RateLimit,
RecordsQueryResult,
RepayRecord,
RollingWindowTicker,
RollingWindowTickerMini,
ServerTime,
SideEffectType,
SorOrderCommissionRates,
SorOrderTestResponse,
Symbol,
SymbolFilter,
SystemStatus,
Ticker24h,
TickerPrice,
Trade,
TradeFee,
TradingDayTicker,
TradingDayTickerMini,
TransactionId,
TransferHistory,
TransferRecord,
TransferResponse,
UnfilledOrderCount,
UniversalTransferType,
UserTrade,
WalletBalance,
WithdrawRecord,
WithdrawResponse,
WithdrawStatus,
websocket::{
AccountBalance, AccountPositionEvent, AggTradeEvent, BalanceUpdateEvent, BookTickerEvent,
DepthEvent, DepthLevel, ExecutionReportEvent, KlineData, KlineEvent, ListStatusEvent,
ListStatusOrder, MiniTickerEvent, TickerEvent, TradeEvent, WebSocketEvent,
},
};
pub use api::{
CancelReplaceOrder, CancelReplaceOrderBuilder, NewOcoOrder, NewOpoOrder, NewOpocoOrder,
NewOrder, NewOtoOrder, NewOtocoOrder, OcoOrderBuilder, OpoOrderBuilder, OpocoOrderBuilder,
OrderBuilder, OtoOrderBuilder, OtocoOrderBuilder,
};
#[derive(Clone)]
pub struct Binance {
client: Client,
}
impl Binance {
pub fn new(api_key: impl Into<String>, secret_key: impl Into<String>) -> Result<Self> {
let config = Config::default();
let credentials = Credentials::new(api_key, secret_key);
let client = Client::new(config, credentials)?;
Ok(Self { client })
}
pub fn new_unauthenticated() -> Result<Self> {
let config = Config::default();
let client = Client::new_unauthenticated(config)?;
Ok(Self { client })
}
pub fn with_config<S: Into<String>>(
config: Config,
credentials: Option<(S, S)>,
) -> Result<Self> {
let client = match credentials {
Some((api_key, secret_key)) => {
let creds = Credentials::new(api_key, secret_key);
Client::new(config, creds)?
}
None => Client::new_unauthenticated(config)?,
};
Ok(Self { client })
}
pub fn from_env() -> Result<Self> {
let config = Config::default();
let credentials = Credentials::from_env()?;
let client = Client::new(config, credentials)?;
Ok(Self { client })
}
pub fn testnet(api_key: impl Into<String>, secret_key: impl Into<String>) -> Result<Self> {
let config = Config::testnet();
let credentials = Credentials::new(api_key, secret_key);
let client = Client::new(config, credentials)?;
Ok(Self { client })
}
pub fn testnet_unauthenticated() -> Result<Self> {
let config = Config::testnet();
let client = Client::new_unauthenticated(config)?;
Ok(Self { client })
}
pub fn binance_us(api_key: impl Into<String>, secret_key: impl Into<String>) -> Result<Self> {
let config = Config::binance_us();
let credentials = Credentials::new(api_key, secret_key);
let client = Client::new(config, credentials)?;
Ok(Self { client })
}
pub fn client(&self) -> &Client {
&self.client
}
pub fn config(&self) -> &Config {
self.client.config()
}
pub fn has_credentials(&self) -> bool {
self.client.has_credentials()
}
pub fn market(&self) -> api::Market {
api::Market::new(self.client.clone())
}
pub fn user_stream(&self) -> api::UserStream {
api::UserStream::new(self.client.clone())
}
pub fn account(&self) -> api::Account {
api::Account::new(self.client.clone())
}
pub fn wallet(&self) -> api::Wallet {
api::Wallet::new(self.client.clone())
}
pub fn margin(&self) -> api::Margin {
api::Margin::new(self.client.clone())
}
pub fn websocket(&self) -> websocket::WebSocketClient {
websocket::WebSocketClient::new(self.client.config().clone())
}
}
impl std::fmt::Debug for Binance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Binance")
.field("config", self.config())
.field("has_credentials", &self.has_credentials())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_unauthenticated() {
let client = Binance::new_unauthenticated().unwrap();
assert!(!client.has_credentials());
assert_eq!(client.config().rest_api_endpoint, "https://api.binance.com");
}
#[test]
fn test_new_authenticated() {
let client = Binance::new("api_key", "secret_key").unwrap();
assert!(client.has_credentials());
}
#[test]
fn test_testnet() {
let client = Binance::testnet("api_key", "secret_key").unwrap();
assert!(client.has_credentials());
assert_eq!(
client.config().rest_api_endpoint,
"https://testnet.binance.vision"
);
}
#[test]
fn test_testnet_unauthenticated() {
let client = Binance::testnet_unauthenticated().unwrap();
assert!(!client.has_credentials());
assert_eq!(
client.config().rest_api_endpoint,
"https://testnet.binance.vision"
);
}
#[test]
fn test_binance_us() {
let client = Binance::binance_us("api_key", "secret_key").unwrap();
assert!(client.has_credentials());
assert_eq!(client.config().rest_api_endpoint, "https://api.binance.us");
}
#[test]
fn test_with_config() {
let config = Config::builder()
.rest_api_endpoint("https://custom.api.com")
.build();
let client = Binance::with_config(config, Some(("api_key", "secret_key"))).unwrap();
assert!(client.has_credentials());
assert_eq!(client.config().rest_api_endpoint, "https://custom.api.com");
}
#[test]
fn test_with_config_no_credentials() {
let config = Config::default();
let client = Binance::with_config(config, None::<(&str, &str)>).unwrap();
assert!(!client.has_credentials());
}
#[test]
fn test_debug_output() {
let client = Binance::new("api_key", "secret_key").unwrap();
let debug_output = format!("{:?}", client);
assert!(debug_output.contains("Binance"));
assert!(debug_output.contains("has_credentials: true"));
assert!(!debug_output.contains("secret_key"));
}
}