9 个版本

0.1.8 2021 年 4 月 26 日
0.1.7 2021 年 4 月 19 日

#8 in #algorithmic-trading

每月 29 次下载

MIT 许可证

98KB
2K SLoC

Rust Binance API 异步/Await 库,配合 Tokio 使用

WebSocket

https://github.com/binance/binance-spot-api-docs/blob/master/web-socket-streams.md

单独交易 / 订单簿快照 / 汇总交易 / 部分订单簿深度流 / 24 小时快照 / 差异深度流

use binance_ws::websocket::*;
use binance_ws::futures::TryStreamExt;
use binance_ws::api::Binance;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {

    let symbols = vec!["ETHBTC".into(), "ADABTC".into()];

    let mut binance_ws: Websocket = Binance::new(None, None);
    
    // ** Change the variant wrapping the input symbols passed to the subscribe function to change the stream type!
    // For e.g., to do aggregated trades instead:
    // let sub_id = binance_ws.subscribe(WebsocketStreamType::AggregatedTrades(symbols)).await?;
    let sub_id = binance_ws.subscribe(WebsocketStreamType::IndividualTrade(symbols)).await?;
    
    while let Some(event) = binance_ws.try_next().await.expect("Didn't receive next transmit") {
        match event {
            WebsocketEvent::IndividualTrade(data) => {
                println!("{}, {}, {}", data.price, data.symbol, data.qty);
            },
            // Other events that use same format:
            
            // WebsocketEvent::BookTicker(data) => {
            //     println!("{}, {}, {}", data.best_bid, data.symbol, data.update_id);
            // },
            // WebsocketEvent::AggregatedTrades(data) => {
            //     println!("{}, {}, {}", data.price, data.symbol, data.qty);
            // },
            // WebsocketEvent::PartialBookDepthStream(data) => {
            //     println!("{}, {}, {}", data.asks.len(), data.bids.len(), data.last_update_id);
            // },
            // WebsocketEvent::TwentyFourHourTicker(data) => {
            //     println!("{}, {}, {}", data.prev_close, data.best_ask_qty, data.event_time);
            // },
            // WebsocketEvent::DiffDepthStream(data) => {
            //     println!("{}, {}, {}", data.bids.len(), data.symbol, data.event_time);
            // },
            _ => {}
        }
    }
    
    binance_ws.unsubscribe(sub_id);
    
    Ok(())
}

蜡烛图

use binance_ws::websocket::*;
use binance_ws::futures::TryStreamExt;
use binance_ws::api::Binance;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let symbols = vec!["ETHBTC".into(), "ADABTC".into()];

    let mut binance_ws: Websocket = Binance::new(None, None);
    let interval = KlineInterval::Minutes(5);
    // OR let interval = KlineInterval::None;
    let sub_id = binance_ws.subscribe(WebsocketStreamType::Kline { interval, symbols }).await?;
    
    while let Some(event) = binance_ws.try_next().await.expect("Didn't receive next transmit") {
        match event {
            WebsocketEvent::Kline(kline) => {
                println!("{}, {}, {}", kline.symbol, kline.event_time, kline.kline.high);
            },
            _ => {}
        }
    }

    binance_ws.unsubscribe(sub_id);
}

每日快照全部

use binance_ws::websocket::*;
use binance_ws::futures::TryStreamExt;
use binance_ws::api::Binance;
use binance_ws::userstream::{UserStream, UserStreamAsync};

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let mut binance_ws: Websocket = Binance::new(None, None);
    let sub_id = binance_ws.subscribe(WebsocketStreamType::DayTickerAll).await?;

    while let Some(event) = binance_ws.try_next().await.expect("Didn't receive next transmit") {
        match event {
            WebsocketEvent::DayTickerAll(many_ticker) => {
                for ticker in many_ticker {
                    println!("{}, {}, {}", ticker.best_ask_qty, ticker.high, ticker.close_time);
                }
            },
            _ => {}
        }
    }

    binance_ws.unsubscribe(sub_id);
}

用户流

https://github.com/binance/binance-spot-api-docs/blob/master/user-data-stream.md

use binance_api_async::userstream::{UserStream, UserStreamAsync};
use binance_api_async::api::Binance;
use binance_api_async::futures::TryStreamExt;
use binance_api_async::websocket::WebsocketEvent;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let mut user_stream: UserStream = Binance::new(Some("<api-key>".into()), Some("<api-secret>".into()));
    let sub_id = user_stream.subscribe().await?;
    let mut binance_ws = user_stream.ws.as_mut().expect("You didn't subscribe!");
    while let Some(event) = binance_ws.try_next().await.expect("Didn't receive next transmit") {
        match event {
            WebsocketEvent::OrderUpdate(data) => {
                println!("{}, {}, {}", data.accumulated_qty_filled_trades, data.commission, data.qty_last_filled_trade)
            },
            WebsocketEvent::AccountUpdate(data) => {
                println!("{}", data.balance.first().unwrap().free)
            },
            WebsocketEvent::BalanceUpdate(data) => {
                println!("{}, {}, {}", data.asset, data.balance_delta, data.clear_time)
            }
            _ => {}
        }
    }

    user_stream.unsubscribe(sub_id);
    Ok(())
}

HTTP 请求

https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md

(这几乎是对 https://docs.rs/crate/binance/0.12.3 的分支进行修改并使其异步的)

市场

use binance::api::*;
use binance::market::*;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let market: Market = Binance::new(None, None);

    // Order book at default depth
    let depth = market.get_depth("BNBETH").await?;

    // Latest price for ALL symbols
    let all_prices = market.get_all_prices().await?;
    
    // Latest price for ONE symbol
    let price = market.get_price("BNBETH").await?;

    // Current average price for ONE symbol
    let avg_price = market.get_average_price("BNBETH").await?;

    // Best price/qty on the order book for ALL symbols
    let all_book_tickers = market.get_all_book_tickers().await?;

    // Best price/qty on the order book for ONE symbol
    let book_ticker = market.get_book_ticker("BNBETH").await?;

    // 24hr ticker price change statistics
    let twenty_four_hour_price = market.get_24h_price_stats("BNBETH").await?;

    // last 10 5min klines (candlesticks) for a symbol:
    let klines = market.get_klines("BNBETH", "5m", 10, None, None).await?;
    
    Ok(())
}

账户

use binance_api_async::account::Account;
use binance_api_async::api::Binance;
use binance_api_async::error::BinanceErr;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let api_key = Some("YOUR_API_KEY".into());
    let secret_key = Some("YOUR_SECRET_KEY".into());

    let account: Account = Binance::new(api_key, secret_key);

    let account = account.get_account().await?;

    let open_orders = account.get_open_orders("WTCETH").await?;

    let limit_buy = account.limit_buy("WTCETH", 10, 0.014000).await?;

    let market_buy = account.market_buy("WTCETH", 5).await?;

    let limit_sell = account.limit_sell("WTCETH", 10, 0.035000).await?;

    let market_sell = account.market_sell("WTCETH", 5).await?;

    let custom_order = account.custom_order("WTCETH", 9999, 0.0123, "SELL", "LIMIT", "IOC").await?;

    let order_id = 1_957_528;
    let order_status = account.order_status("WTCETH", order_id).await?;

    let cancelled_order = account.cancel_order("WTCETH", order_id).await?;

    let all_cancelled_orders = account.cancel_all_open_orders("WTCETH").await?;

    let balances = account.get_balance("KNC").await?;

    let trade_history = account.trade_history("WTCETH").await?;
    
    Ok(())
}

错误

"get_fmt_error" 是由本库 "BinanceErr" 暴露的泛型错误类型上的一个方法,该方法返回格式化的错误消息。

此方法是不必要的,仅存在于绕过 IntelliJ IDEs 无法理解 std::fmt::Display 实际已实现的问题。

use binance_api_async::api::Binance;
use binance_api_async::account::Account;

#[tokio::main]
async fn main() -> Result<(), BinanceErr> {
    let account: Account = Binance::new(Some(format!("<api-key>")), Some(format!("<API-SECRET>")));
    match account.market_buy(format!("DOGEBTC"), 101).await {
        Err(e) => {
            println!("{}", e);
        },
        _ => {}
    }
    // If you are getting "std::fmt::Display not implemented for BinanceErr"
    match account.market_buy(format!("DOGEBTC"), 101).await {
        Err(mut e) => {
            println!("{}", e.get_fmt_error());
        },
        _ => {}
    }
    Ok(())
}

依赖

~8–21MB
~340K SLoC