A .NET Standard Binance API library.
Available on NuGet.
Initial Beta Release
Changes:
IBinanceApi.GetWithdrawFeeAsync()
.BinanceUnknownStatusException
message (for #77).GetTradesAsync()
extension to GetAccountTradesAsync()
.ClientOrder.Time
(refer to Order.Time
instead).
IsNotPlaced()
extension method (an order will exist or query API for status).ClientOrder.Side
nullable (must be explicitly set before placing order).IRateLimiterProvider
and IApiRateLimiterProvider
.
recvWindow
parameter to GetDepositAddressAsync()
and GetAccountStatusAsync()
.IBinanceApi.CancelAllOrdersAsync()
.Available on NuGet.
Changes:
Unsubscribe()
not triggering automatic stream control (#76 - thanks @rakewell).SubscribedStreams
returned client SubscribedStreams
instead of cache-related subscriptions.BinanceHttpClient
message event subject was not AbsoluteUri
.GetStreamName(...)
public static
on clients (AggregateTradeClient
, etc.)Available on NuGet.
This release includes significant refactoring including removal of the web socket client and cache managers (functionality relocated) and removal of several namespaces (to simplify usage). The automatic streaming start/stop feature has been moved from the managers to a lower-level and is now a built-in part of the I...WebSocketClient
implementations (the IUserDataWebSocketManager
and composite managers remain). For those not wanting the automatic stream control, look to the IBinanceWebSocketStream
and I...Client
'advanced' implementations. Examples and sample applications have been updated.
The fundamental change in this release is the separation of IJsonStream
into a simpler IJsonStream
and the new IJsonPublisher
(both are JSON producers). The publisher handles subscriptions for the combined stream functionality where the web socket stream URI is automatically modified and changes to the URI trigger the automatic web socket abort and re-connect.
The architecture diagram has been updated.
Changes:
SymbolStatisticCache
link to client and unsubscribe for #75. (thanks @tompetko)....ClientManager
and ...CacheManager
classes moving functionality to existing ...WebSocketClient
and new ...WebSocketCache
.
IWatchdogTimer
to IJsonStreamController
(monitors JSON producer/stream rather than client data).IJsonStreamController
to new IAutoJsonStreamPublisher
.IJsonProvider
to IJsonProducer
, IJsonObserver
to IJsonSubscriber
, ObservedStreams
property to SubscribedStreams
, and ProvidesStreams
property to PublishedStreams
.Utility
namespace.IWatchdogTimer.IsEnabled
control.Available on NuGet.
Changes:
IAggregateTradeWebSocketCacheManager
) and update sample apps.IBinanceHttpClient.Options
(for #24).
IBinanceHttpClient.Options.RecvWindowDefault
with IBinanceHttpClient.DefaultRecvWindow
.IBinanceHttpClient.Options.TimestampOffsetRefreshPeriodMinutes
with IBinanceHttpClient.TimestampProvider.TimestampOffsetRefreshPeriod
.ClientOrder
validation.Available on NuGet.
Changes:
IWebSocketClient
extension to wait until web socket is open (for #71).
IWebSocketClient.IsOpen
flag.IJsonStream
on subscribe/unsubscribe to allow chaining.Available on NuGet.
Changes:
TaskController
and RetryTaskController
:
Pausing
and Resuming
events to IRetryTaskController
(for issue #50).Error
event instead).OrderExecutionEventArgs.OrderRejectedReason
type from enum to string.Available on NuGet.
Changes:
DateTime
(use long.ToDateTime()
for easy conversion).
IBinanceApi
and IBinanceHttpClient
GetDepositsAsync()
and GetWithdrawalsAsync()
timestamp parameters to DateTime
.IBinanceApi.GetCandlesticksAsync()
timestamps to DateTime
.IBinanceApi.GetAggregateTradesIn()
.Available on NuGet.
This release includes a redesign of the automatic web socket manager IBinanceWebSocketManager
, which allowed applications to use client interfaces (subscribe/unsubscribe) without needing to handle the required stream cancellation and restart. That functionality has been moved to a lower level but the usability remains in the new IBinanceWebSocketClientManager
. Also, there are new discrete automatic web socket managers for each of the Binance endpoints (e.g. ITradeWebSocketClientManager
, etc.).
Changes (significant refactoring of web sockets and caches with new managers):
IJsonClientManager
and implementations (provide automatic stream controller management).IJsonStream
, IJsonStreamObserver
, IJsonClient
, and IJsonStreamClient
.
BinanceWebSocketStream
subscribe/unsubscribe can be done while streaming.IUserDataClient
allows callbacks to be defined for specific event types.IJsonProvider
and JsonMessageEventArgs
(provides low-level access to JSON data).
BinanceHttpClient
and DefaultWebSocketClient
.IJsonClientCache
(caches no longer have reference to stream).
StreamAsync()
and SubscribeAndStream()
.LinkTo()
and Unlink()
(set IJsonClientCache.Client
instead).IBinanceWebSocketManager
is now IBinanceWebSocketClientManager
.Binance.WebSocket.Events
to Binance.Client.Events
namespace.IWebSocketClient
property WebSocket.Client
is now Stream.WebSocket
.ISymbolStatisticsClient
subscribe/unsubscribe method parameters rearranged.HttpClientTimeoutDefaultSeconds
configuration option (for #64).The purpose of this document is to describe the core separation of JSON producers and consumers and how they form the layered architecture of this library as well as to explain the is-a and has-a relationships of the interfaces and implementations of this library.
This is not intended to be a 'how-to' guide. Currently, the sample applications still offer the best demonstrations and example use of this library. For those looking for the simplest application-level development, consider using the new web socket client managers or the composite IBinanceWebSocketClientManager
.
IJsonProvider
This fundamental interface defines a JSON message provider. This can be anything that produces JSON messages (in Binance format or otherwise) such as a Web Socket, HTTP client, or database API (for back-testing/simulation).
public interface IJsonProvider
{
event EventHandler<JsonMessageEventArgs> Message;
}
NOTE: Application-level development will typically not use this 'low-level' event for anything other than logging or troubleshooting. Also, since some JSON data can contain sensitive information, this is no longer logged automatically as of this release (but, can still be logged at the application-level using this event).
JsonMessageEventArgs
The JSON message event arguments include the message data as a JSON object or array and the message Subject
, which defines the context of the message. For instance, the IBinanceHttpClient
and IWebSocketClient
implementations use their respective URI.AbsolutePath
as the message subject, while IJsonStream
implementations use the stream name.
public sealed class JsonMessageEventArgs
{
public string Subject { get; }
public string Json { get; }
}
NOTE: When using combined streams, the IWebSocketClient
message is the raw
JSON before being separated into stream name and data.
IBinanceHttpClient
This is the IJsonProvider
interface to the Binance REST API using a single HttpClient
that returns 'raw' JSON. The specific methods are implemented as extensions in BinanceHttpClientExtensions
. New capabilities can be added as extensions of IBinanceHttpClient
in a similar fashion (at the application level) utilizing the shared, singleton, BinanceHttpClient
.
The top-level IBinanceAPI
interface deserializes the JSON data from IBinanceHttpClient
into convenient domain value-objects. All of the deserializers used in BinanceApi
are available in the Binance.Serialization
namespace for application-level deserialization of 'raw' Binance JSON data (for instance, if stored for back-testing/simulation).
IJsonStream
This defines an abstract, streaming, JSON provider. New message notification is sent to subscribed observers or Message
event handlers, where the message subject is the stream name. When subscribing to a stream, the observer is optional (if using an event handler instead). The ProvidedStreams
property lists the unique stream names that are currently subscribed.
Streaming is controlled by calling the StreamAsync
method and by providing a required CancellationToken
to abort the streaming operation. The stream is 'closed' when the Task
has completed (and IsStreaming
is false
). There is no Error
event because exceptions can and should be caught with try/catch (when using async
) or with the AggregateException
via the returned Task
.
NOTE: Users of this library are expected to be familiar with TAP.
NOTE: The IJsonStream
implementations handle subscribe/unsubscribe of streams whether streaming is active or not. However (depending on the implementation), if changes are made while streaming, the flow of data may be interrupted (this is the case with BinanceWebSocketStream
since the web socket client must be aborted and another connection established with a new URI).
public interface IJsonStream : IJsonProvider
{
bool IsStreaming { get; }
IEnumerable<string> ProvidedStreams { get; }
void Subscribe(IJsonStreamObserver observer, params string[] streamNames);
void Unsubscribe(IJsonStreamObserver observer, params string[] streamNames);
Task StreamAsync(CancellationToken token);
IBufferedJsonProvicer
This IJsonProvider
decorator buffers data from another JSON provider.
public interface IBufferedJsonProvider<TProvider> : IJsonProvider
where TProvider : IJsonProvider
{
TProvider JsonProvider { get; }
}
IWebSocketStream
This interface defines a specific implementation of IJsonStream
that uses a 'low-level' IWebSocketClient
to provide JSON data, which can be accessed via the WebSocket
property. The extending IBinanceWebSocketStream
interface provides an additional IsCombined
property.
NOTE: An IWebSocketStream
is not an IWebSocketClient
. The IWebSocketStream
is a specific form of IJsonStream
that uses an IWebSocketClient
. The IWebSocketClient.StreamAsync()
method combines connect with receive operations and returns a Task
, in-part, controlled by the IJsonStream
. The Open
event is raised after a connection is established. The Close
event is raised just before the Task
completes. Stream controllers need only manage the StreamAsync()
returned Task
and not concern themselves with the implementation details of the IJsonStream
(i.e. the Open
and Close
events).
public interface IWebSocketClient : IJsonProvider
{
event EventHandler<EventArgs> Open;
event EventHandler<EventArgs> Close;
bool IsStreaming { get; }
Task StreamAsync(Uri uri, CancellationToken token);
}
public interface IWebSocketStream : IJsonStream
{
IWebSocketClient WebSocket { get; }
}
public interface IBinanceWebSocketStream : IWebSocketStream
{
bool IsCombined { get; }
}
IJsonStreamObserver
This interface provides a means of identifying classes as observers of a IJsonStream
as passed to the subscribe/unsubscribe methods as well as providing the ability to handle message events asynchronously. Any class can make use the IJsonProvider.Message
event, but that event handler will receive all 'raw' JSON messages (depending on context of the event).
public interface IJsonStreamObserver
{
Task HandleMessageAsync(string stream, string json, CancellationToken token = default);
}
IJsonClient
These JSON stream observers have the capability of deserializing JSON into higher-level objects and providing notification via subscribed callbacks and/or non-specific events. Each Binance implementation is responsible for interpreting JSON from one or more of the official web socket endpoints.
public interface IJsonClient : IJsonStreamObserver
{
IEnumerable<string> ObservedStreams { get; }
void Unsubscribe();
}
NOTE: As JSON observers, the clients, can be used to process JSON from any compatible IJsonProvider
implementation.
IAggregateTradeClient
Processes JSON data from Aggregate Trade streams. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface IAggregateTradeClient : IBinanceJsonClient
{
event EventHandler<AggregateTradeEventArgs> AggregateTrade;
void Subscribe(string symbol, Action<AggregateTradeEventArgs> callback);
void Unsubscribe(string symbol, Action<AggregateTradeEventArgs> callback);
}
ITradeClient
Processes JSON data from Trade streams. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface ITradeClient : IBinanceJsonClient
{
event EventHandler<TradeEventArgs> Trade;
void Subscribe(string symbol, Action<TradeEventArgs> callback);
void Unsubscribe(string symbol, Action<TradeEventArgs> callback);
}
ICandlestickClient
Processes JSON data from Candlestick streams. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface ICandlestickClient : IBinanceJsonClient
{
event EventHandler<CandlestickEventArgs> Candlestick;
void Subscribe(string symbol, CandlestickInterval interval, Action<CandlestickEventArgs> callback);
void Unsubscribe(string symbol, CandlestickInterval interval, Action<CandlestickEventArgs> callback);
}
ISymbolStatisticsClient
Processes JSON data from Symbol Ticker streams and All Market Tickers stream. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface ISymbolStatisticsClient : IBinanceJsonClient
{
event EventHandler<SymbolStatisticsEventArgs> StatisticsUpdate;
void Subscribe(Action<SymbolStatisticsEventArgs> callback, params string[] symbols);
void Unsubscribe(Action<SymbolStatisticsEventArgs> callback, params string[] symbols);
}
IDepthClient
Processes JSON data from Partial Book streams and Diff. Depth streams. The partial depth stream is used if a limit is specified. Currently, the only valid values for the partial book depth stream are: 5, 10, or 20. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface IDepthClient : IBinanceJsonClient
{
event EventHandler<DepthUpdateEventArgs> DepthUpdate;
void Subscribe(string symbol, int limit, Action<DepthUpdateEventArgs> callback);
void Unsubscribe(string symbol, int limit, Action<DepthUpdateEventArgs> callback);
}
IUserDataClient
Processes JSON data from User Data streams. When subscribing or unsubscribing, the callback is optional (extension methods are available).
public interface IUserDataClient : IBinanceJsonClient
{
event EventHandler<AccountUpdateEventArgs> AccountUpdate;
event EventHandler<OrderUpdateEventArgs> OrderUpdate;
event EventHandler<AccountTradeUpdateEventArgs> TradeUpdate;`
void Subscribe<TEventArgs>(string listenKey, IBinanceApiUser user, Action<TEventArgs> callback)
where TEventArgs : UserDataEventArgs;
void Unsubscribe<TEventArgs>(string listenKey, Action<TEventArgs> callback)
where TEventArgs : UserDataEventArgs;
void HandleListenKeyChange(string oldListenKey, string newListenKey);
IJsonClientCache
These classes add an in-memory, thread-safe, cache extending the IJsonClient
interface. After an event is received from the IJsonClient
the cache is updated and a translated Update
event is fired (and callbacks are notified).
NOTE: IJsonClientCache
has an IJsonClient
and is an IJsonClient
. The Client
can be set and, if previously subscribed, the cache will automatically unsubscribe (its context) from the existing client and subscribe (the cache context) to the new client.
NOTE: These classes do not include a JSON stream or stream controller.
public interface IJsonClientCache<TClient, TEventArgs>
: IJsonClient
where TClient : IJsonClient
where TEventArgs : CacheEventArgs
{
event EventHandler<TEventArgs> Update;
TClient Client { get; set; }
}
public abstract class CacheEventArgs : EventArgs
{ }
IAccountInfoCache
An IJsonClientCache
that keeps an in-memory copy of the latest account info updated by an IUserDataClient
.
public interface IAccountInfoCache
: IJsonClientCache<IUserDataWebSocketManager, AccountInfoCacheEventArgs>
{
AccountInfo AccountInfo { get; }
void Subscribe(string listenKey, IBinanceApiUser user, Action<AccountInfoCacheEventArgs> callback);
}
IAggregateTradeCache
An IJsonClientCache
that loads the latest IBinanceApi
and keeps an in-memory list of the latest aggregate trades updated by an IAggregateTradeClient
. When a new aggregate trade is received the oldest is removed from the in-memory list.
public interface IAggregateTradeCache
: IJsonClientCache<IAggregateTradeClient, AggregateTradeCacheEventArgs>
{
event EventHandler<EventArgs> OutOfSync;
IEnumerable<AggregateTrade> Trades { get; }
void Subscribe(string symbol, int limit, Action<AggregateTradeCacheEventArgs> callback);
ICandlestickCache
An IJsonClientCache
that loads the latest IBinanceApi
and keeps an in-memory list of the latest candlesticks updated by an ICandlestickClient
. When the latest candlestick is closed and a new candlestick is received the oldest candlestick is removed from the in-memory list.
public interface ICandlestickCache
: IJsonClientCache<ICandlestickClient, CandlestickCacheEventArgs>
{
IEnumerable<Candlestick> Candlesticks { get; }
void Subscribe(
string symbol, CandlestickInterval interval, int limit,
Action<CandlestickCacheEventArgs> callback);
}
IOrderBookCache
An IJsonClientCache
that loads the latest order book using IBinanceApi
and keeps an in-memory OrderBook
updated by an IDepthClient
.
public interface IOrderBookCache
: IJsonClientCache<IDepthClient, OrderBookCacheEventArgs>
{
event EventHandler<EventArgs> OutOfSync;
OrderBook OrderBook { get; }
void Subscribe(string symbol, int limit, Action<OrderBookCacheEventArgs> callback);
}
ISymbolStatisticsCache
An IJsonClientCache
that loads the latest 24-hour statistics using IBinanceApi
for a symbol or symbols and keeps an in-memory array updated by an ISymbolStatisticsClient
.
public interface ISymbolStatisticsCache
: IJsonClientCache<ISymbolStatisticsClient, SymbolStatisticsCacheEventArgs>
{
IEnumerable<SymbolStatistics> Statistics { get; }
SymbolStatistics GetStatistics(string symbol);
IEnumerable<SymbolStatistics> GetStatistics(params string[] symbols);
void Subscribe(Action<SymbolStatisticsCacheEventArgs> callback);
void Subscribe(Action<SymbolStatisticsCacheEventArgs> callback, params string[] symbols);
}
ITradeCache
An IJsonClientCache
that loads the latest IBinanceApi
and keeps an in-memory list of the latest trades updated by an ITradeClient
. When a new trade is received the oldest is removed from the in-memory list.
public interface ITradeCache
: IJsonClientCache<ITradeClient, TradeCacheEventArgs>
{
event EventHandler<EventArgs> OutOfSync;
IEnumerable<Trade> Trades { get; }
void Subscribe(string symbol, int limit, Action<TradeCacheEventArgs> callback);
}
IJsonStreamClient
This is the first interface to combine the behavior of a JSON producer and consumer. However, as with IJsonClient
, these classes do not provide a stream controller; an external controller is required to call Stream.StreamAsync()
and manage the returned Task
. The TaskController
and RetryTaskController
utility classes are available for this purpose, but are not required.
public interface IJsonStreamClient<out TStream> : IJsonClient
where TStream : IJsonStream
{
TStream Stream { get; }
}
IBinanceWebSocketClient
This interface extends IJsonStreamClient
and uses a web socket stream to provide JSON data. Implementations are responsible for translating application-level arguments into a Binance stream name and coordinating the subscribing of that stream name between the JSON stream (producer) and client (consumer).
public interface IBinanceWebSocketClient : IJsonStreamClient<IBinanceWebSocketStream>
{ }
IAggregateTradeWebSocketClient
An IAggregateTradeClient
that uses a IBinanceWebSocketStream
.
public interface IAggregateTradeWebSocketClient
: IAggregateTradeClient, IBinanceWebSocketClient
{ }
ITradeWebSocketClient
An ITradeClient
that uses a IBinanceWebSocketStream
.
public interface ITradeWebSocketClient
: ITradeClient, IBinanceWebSocketClient
{ }
ICandlestickWebSocketClient
An ICandlestickWebSocketClient
that uses a IBinanceWebSocketStream
.
public interface ICandlestickWebSocketClient
: ICandlestickClient, IBinanceWebSocketClient
{ }
ISymbolStatisticsWebSocketClient
An ISymbolStatisticsWebSocketClient
that uses a IBinanceWebSocketStream
.
public interface ISymbolStatisticsWebSocketClient
: ISymbolStatisticsClient, IBinanceWebSocketClient
{ }
IDepthWebSocketClient
An IDepthClient
that uses a IBinanceWebSocketStream
.
public interface IDepthWebSocketClient
: IDepthClient, IBinanceWebSocketClient
{ }
IUserDataWebSocketClient
An IUserDataClient
that uses a IBinanceWebSocketStream
.
public interface IUserDataWebSocketClient
: IUserDataClient, IBinanceWebSocketClient
{ }
IControllerManager
An IDisposable
facade for automatic management of a JSON stream controller. The specific implementations are used like their JSON client counterparts, but include automatic stream/controller/task management. A watchdog timer is added to abort streaming if data has not been received for a configurable time interval (default 1 hour). If a timeout occurs and streaming is aborted, streaming will be restarted by the IRetryTaskController
after a configurable delay. Internal exceptions are accessible from the ITaskController.Error
event.
NOTE: Cache implementations can be used with managers by setting the manager as the cache Client
(except with IUserDataWebSocketClientManager
and IAccountInfoCache
).
public interface IControllerManager<out TStream> : IDisposable
where TStream : IJsonStream
{
IJsonStreamController<TStream> Controller { get; }
IWatchdogTimer Watchdog { get; }
}
public interface IJsonStreamController<out TStream> : IRetryTaskController
where TStream : IJsonStream
{
TStream Stream { get; }
}
IAggregateTradeWebSocketClientManager
An IAggregateTradeClient
and IControllerManager
that uses a IBinanceWebSocketStream
.
public interface IAggregateTradeWebSocketClientManager
: IAggregateTradeClientManager<IWebSocketStream>
{ }
public interface IAggregateTradeClientManager<out TStream>
: IAggregateTradeClient, IControllerManager<TStream>
where TStream : IJsonStream
{ }
ITradeWebSocketClientManager
An ITradeClient
and IControllerManager
that uses a IBinanceWebSocketStream
.
public interface ITradeWebSocketClientManager
: ITradeClientManager<IWebSocketStream>
{ }
public interface ITradeClientManager<out TStream>
: ITradeClient, IControllerManager<TStream>
where TStream : IJsonStream
{ }
ICandlestickWebSocketClientManager
An ICandlestickWebSocketClient
and IControllerManager
that uses a IBinanceWebSocketStream
.
public interface ICandlestickWebSocketClientManager
: ICandlestickClientManager<IWebSocketStream>
{ }
public interface ICandlestickClientManager<out TStream>
: ICandlestickClient, IControllerManager<TStream>
where TStream : IJsonStream
{ }
ISymbolStatisticsWebSocketClientManager
An ISymbolStatisticsWebSocketClient
and IControllerManager
that uses a IBinanceWebSocketStream
.
public interface ISymbolStatisticsWebSocketClientManager
: ISymbolStatisticsClientManager<IWebSocketStream>
{ }
public interface ISymbolStatisticsClientManager<out TStream>
: ISymbolStatisticsClient, IControllerManager<TStream>
where TStream : IJsonStream
{ }
IDepthWebSocketClientManager
An IDepthClient
and IControllerManager
that uses a IBinanceWebSocketStream
.
public interface IDepthWebSocketClientManager
: IDepthClientManager<IWebSocketStream>
{ }
public interface IDepthClientManager<out TStream>
: IDepthClient, IControllerManager<TStream>
where TStream : IJsonStream
{ }
IUserDataWebSocketManager
A IControllerManager
that uses a IBinanceWebSocketStream
. Unlike the other managers, this interface does not extend IUserDataClient
(future implementations might). The implementation also encapsulates user listen key management with an IUserDataWebSocketStreamControl
.
public interface IUserDataWebSocketManager : IControllerManager<IWebSocketStream>
{
event EventHandler<AccountUpdateEventArgs> AccountUpdate;
event EventHandler<OrderUpdateEventArgs> OrderUpdate;
event EventHandler<AccountTradeUpdateEventArgs> TradeUpdate;
Task SubscribeAsync<TEventArgs>(IBinanceApiUser user, Action<TEventArgs> callback,
CancellationToken token = default)
where TEventArgs : UserDataEventArgs;
Task UnsubscribeAsync<TEventArgs>(IBinanceApiUser user, Action<TEventArgs> callback,
CancellationToken token = default)
where TEventArgs : UserDataEventArgs;
Task UnsubscribeAllAsync(CancellationToken token = default);
IUserDataWebSocketStreamControl
This interface handles user data web socket open, keep-alive, and close API calls and management of user listen keys. When a user is added, a listen key is queried and returned. An internal timer is used to keep-alive each user data stream with a ping every 30 minutes (default). If the ping fails, a new key is queried and listeners are notified via the ListenKeyUpdate
event.
public interface IUserDataWebSocketStreamControl : IDisposable
{
event EventHandler<UserDataListenKeyUpdateEventArgs> ListenKeyUpdate;
IEnumerable<IBinanceApiUser> Users { get; }
TimeSpan KeepAliveTimerPeriod { get; set; }
Task<string> GetStreamNameAsync(IBinanceApiUser user, CancellationToken token = default);
Task<string> OpenStreamAsync(IBinanceApiUser user, CancellationToken token = default);
Task CloseStreamAsync(IBinanceApiUser user, CancellationToken token = default);
Task CloseAllStreamsAsync(CancellationToken token = default);
}
Available on NuGet.
Changes (same as 0.2.0-alpha32):
UNLISTED on NuGet.
For Testing Only
Changes (same as 0.2.0-alpha31 and alpha32):