A full-featured .NET Standard 2.0 Binance API facade designed for ease of use.
Using Nuget Package Manager:
PM> Install-Package Binance
- Complete implementation of Binance API including latest deposit/withdrawal features and WebSocket feeds.
- Simple API abstraction using domain/value objects that do not expose underlying (HTTP/REST) behavior.
- Unique dual-layer API design returning either raw JSON (low-level) or deserialized domain/value objects.
- API exceptions include the Binance server ERROR code and message with exceptions for easier troubleshooting.
- Implementation supports multiple users (authentication details passed via method injection).
- Web API interface includes automatic rate limiting and system-to-server time synchronization.
- Easy to use websocket endpoint clients and a ready-to-use order book cache (w/ event subscribing).
- Multiple .NET Core sample applications, including a 'minimal' live display of market depth for a symbol.
- Limited third-party dependencies with the extensible Microsoft dependency injection and logging frameworks.
- The JSON API is implemented as a singleton (using DI framework) with a cached HttpClient for performance.
- All IEnumerable<> data is returned in ascending order. Oldest first, newest last.
- All timestamp related fields are in milliseconds (Unix time).
The first example (recommended) uses dependency injection, while the second minimal example does not. NOTE: C# 7.1 is required for async Main (set language version in project advanced build properties).
using Binance;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static async Task Main(string[] args) // C# 7.1
{
var services = new ServiceCollection()
.AddBinance()
.BuildServiceProvider();
using (var api = services.GetService<IBinanceApi>())
{
if (await api.PingAsync())
Console.WriteLine("SUCCESSFUL!");
Console.ReadKey(true);
}
}
}
}
using Binance.Api;
using System;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static async Task Main(string[] args) // C# 7.1
{
using (var api = new BinanceApi())
{
if (await api.PingAsync())
Console.WriteLine("SUCCESSFUL!");
Console.ReadKey(true);
}
}
}
}
This example demonstrates how to handle exceptions from API methods.
NOTE: Handling exceptions with this level of precision is only applicable to actions that an application may retry should the first attempt fail (e.g. new order placement).
try
{
using (var api = new BinanceApi())
using (var user = new BinanceUser("api-key", "api-secret"))
{
var order = await api.PlaceAsync(user, new MarketOrder()
{
Symbol = Symbol.BTC_USDT,
Side = OrderSide.Sell,
Quantity = 1
});
}
}
catch (BinanceUnknownStatusException)
{
// Respond to HTTP 504 response errors:
// HTTP 504 return code is used when the API successfully sent the message but not get a response within the timeout period.
// It is important to NOT treat this as a failure; the execution status is UNKNOWN and could have been a success.
}
catch (BinanceHttpException)
{
// Respond to HTTP response errors/codes:
// HTTP 4XX return codes are used for malformed requests; client side issue.
// HTTP 5XX return codes are used for internal errors; server side issue.
}
catch (BinanceApiException)
{
// Respond to other Binance API exceptions (typically JSON deserialization failures).
}
catch (Exception)
{
// ...
}
If using the BinanceConsoleApp sample you may see this message when accessing non-public API methods:
To access some Binance endpoint features, your API Key and Secret may be required. You can either modify the 'ApiKey' and 'ApiSecret' configuration values in appsettings.json. Or use the following commands to configure the .NET user secrets for the project:
dotnet user-secrets set BinanceApiKey <your api key>
dotnet user-secrets set BinanceApiSecret <your api secret>
For more information: https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets
var successful = await api.PingAsync();
var time = await api.GetTimeAsync();
Get order book (depth of market) for a symbol with optional limit [1-100].
var book = await api.GetOrderBookAsync(Symbol.BTC_USDT);
Get compressed/aggregate trades for a symbol with optional limit [1-500].
var trades = await api.GetTradesAsync(Symbol.BTC_USDT);
Get candlesticks for a symbol with optional limit [1-500].
var candles = await api.GetCandlesticksAsync(Symbol.BTC_USDT, KlineInterval.Hour);
Get 24-hour statistics for a symbol.
var stats = await api.Get24hrStatsAsync(Symbol.BTC_USDT);
Get current prices for all symbols.
var prices = await api.GetPricesAsync();
Get best (top) price and quantity on the order book for all symbols.
var tops = await api.GetOrderBookTopsAsync();
Utilize the depth of market WebSocket client to create a real-time, synchronized order book for a symbol.
using (var book = serviceProvider.GetService<IOrderBookCache>()) // ...is IOrderBook too
{
book.Update += OnOrderBookUpdate; // subscribe to order book update events.
var task = Task.Run(() => book.SubscribeAsync(Symbol.BTC_USDT, cts.Token)); // start synchronization.
// ...
var bid = book.Top.Bid.Price; // access the live order book directly (thread-safe).
var copy = book.Clone(); // take a snapshot of the order book (for a consistent/complete state).
// ...
cts.Cancel(); // end the order book task.
await task; // wait for task to complete.
}
void OnOrderBookUpdate(object sender, OrderBookUpdateEventArgs e)
{
e.OrderBook.Top.Bid.Price; // safely use a snapshot of the updated order book.
}
Create a user authentication object using your Binance account API Key and Secret.
var user = new BinanceUser("<Your API Key>", <your API Secret>);
NOTE: User authentication is method injected so that a single Binance API instance can support multiple users.
Create and place a new Limit order. NOTE: Client (or pending) orders are created as a mutable order placeholder, only after the client order is placed does an Order (with status) exist.
using (var user = new BinanceUser("api-key", "api-secret"))
{
var order = await api.PlaceAsync(user, new LimitOrder()
{
Symbol = Symbol.BTC_USDT,
Side = OrderSide.Buy,
Quantity = 1,
Price = 5000
});
}
Create and place a new Market order. You do not set the price for Market orders. NOTE: Client (or pending) orders are created as a mutable order placeholder, only after the client order is placed does an Order (with status) exist.
using (var user = new BinanceUser("api-key", "api-secret"))
{
var order = await api.PlaceAsync(user, new MarketOrder()
{
Symbol = Symbol.BTC_USDT,
Side = OrderSide.Sell,
Quantity = 1
});
}
Create and place a new Test order. NOTE: To specify an order is for test-only, the IsTestOnly flag is set true (default: false).
using (var user = new BinanceUser("api-key", "api-secret"))
{
var order = await api.PlaceAsync(user, new MarketOrder()
{
Symbol = Symbol.BTC_USDT,
Side = OrderSide.Sell,
Quantity = 1,
IsTestOnly = true
});
}
Get an order to determine current status. Order lookup requires an order instance or the combination of a symbol and the order ID or client order ID. If an order instance is provided, it will be updated in place in addition to being returned.
var order = await api.GetOrderAsync(user, order); // use to update status in place.
// ...or...
var order = await api.GetOrderAsync(user, Symbol.BTC_USDT, orderId);
// ...or...
var order = await api.GetOrderAsync(user, Symbol.BTC_USDT, clientOrderId);
Cancel an order Order lookup requires an order instance or the combination of a symbol and the order ID or client order ID.
await api.CancelAsync(user, order);
// ...or...
await api.CancelOrderAsync(user, Symbol.BTC_USDT, orderId);
// ...or...
await api.CancelOrderAsync(user, Symbol.BTC_USDT, clientOrderId);
Get all open orders for a symbol with optional limit [1-500].
var orders = await api.GetOpenOrdersAsync(user, Symbol.BTC_USDT);
Get all orders; active, canceled, or filled with optional limit [1-500].
var orders = await api.GetOrdersAsync(user, Symbol.BTC_USDT);
Get current account information.
var account = await api.GetAccountAsync(user);
Get trades for a specific account and symbol with optional limit [1-500].
var account = await api.GetTradesAsync(user, Symbol.BTC_USDT);
Get deposit history.
var deposits = await api.GetDepositsAsync(user);
Get withdraw history.
var withdrawals = await api.GetWithdrawalsAsync(user);
Start a new user data stream.
var listenKey = await api.UserStreamStartAsync(user);
Ping a user data stream to prevent a timeout.
await api.UserStreamKeepAliveAsync(user, listenKey);
Close a user data stream.
await api.UserStreamCloseAsync(user, listenKey);
Get real-time depth update events.
using (var client = serviceProvider.GetService<IDepthWebSocketClient>())
{
client.DepthUpdate += OnDepthUpdateEvent;
var task = Task.Run(() => client.SubscribeAsync(Symbol.BTC_USDT, cts.Token));
// ...
cts.Cancel();
await task;
}
void OnDepthUpdateEvent(object sender, DepthUpdateEventArgs e)
{
// ...
}
Get real-time kline/candlestick events.
using (var client = serviceProvider.GetService<IKlineWebSocketClient>())
{
client.Kline += OnKlineEvent;
var task = Task.Run(() => client.SubscribeAsync(Symbol.BTC_USDT, KlineInterval.Hour, cts.Token));
// ...
cts.Cancel();
await task;
}
void OnKlineEvent(object sender, KlineEventArgs e)
{
// ...
}
Get real-time aggregate trade events.
using (var client = serviceProvider.GetService<ITradesWebSocketClient>())
{
client.AggregateTrade += OnAggregateTradeEvent;
var task = Task.Run(() => client.SubscribeAsync(Symbol.BTC_USDT, cts.Token));
// ...
cts.Cancel();
await task;
}
void OnAggregateTradeEvent(object sender, AggregateTradeEventArgs e)
{
// ...
}
Get real-time account update events.
using (var client = serviceProvider.GetService<IUserDataWebSocketClient>())
{
client.AccountUpdate += OnAccountUpdateEvent;
client.OrderUpdate += OnOrderUpdateEvent;
client.TradeUpdate += OnTradeUpdateEvent;
var task = Task.Run(() => client.SubscribeAsync(user, cts.Token));
// ...
cts.Cancel();
await task;
}
void OnAccountUpdateEvent(object sender, AccountUpdateEventArgs e)
{
// ...
}
void OnOrderUpdateEvent(object sender, OrderUpdateEventArgs e)
{
// ...
}
void OnTradeUpdateEvent(object sender, TradeUpdateEventArgs e)
{
// ...
}