From 8abf648b7bc1d6a93eed412e8fd56a5a518597d6 Mon Sep 17 00:00:00 2001 From: ridicoulous Date: Wed, 25 Mar 2020 15:19:42 +0200 Subject: [PATCH] error handlers --- Bitmex.Net.ClientExample/Program.cs | 45 +++++++++--- Bitmex.Net.sln | 2 +- Bitmex.Net/Bitmex.Net.Client.csproj | 2 +- Bitmex.Net/BitmexSocketClient.cs | 103 +++++++++++++++++++++++----- Bitmex.Net/BitmexSymbolOrderBook.cs | 53 ++++++++++---- 5 files changed, 161 insertions(+), 44 deletions(-) diff --git a/Bitmex.Net.ClientExample/Program.cs b/Bitmex.Net.ClientExample/Program.cs index 47adcce..6db3b78 100644 --- a/Bitmex.Net.ClientExample/Program.cs +++ b/Bitmex.Net.ClientExample/Program.cs @@ -23,7 +23,7 @@ static async Task Main(string[] args) Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US"); var builder = new ConfigurationBuilder() .AddJsonFile("appconfig.json", optional: true, reloadOnChange: true); - ob = new BitmexSymbolOrderBook("XBTUSD", new BitmexSocketOrderBookOptions("XBT")); + ob = new BitmexSymbolOrderBook("XBTUSD", new BitmexSocketOrderBookOptions("XBT") { LogVerbosity = CryptoExchange.Net.Logging.LogVerbosity.Info }); ob.OnBestOffersChanged += Ob_OnBestOffersChanged; @@ -36,20 +36,29 @@ static async Task Main(string[] args) var configuration = builder.Build(); + var socket = new BitmexSocketClient(new BitmexSocketClientOptions(false) { LogVerbosity = CryptoExchange.Net.Logging.LogVerbosity.Debug }); - var socket = new BitmexSocketClient(new BitmexSocketClientOptions(configuration["key"], configuration["secret"], bool.Parse(configuration["testnet"]))); + //var socket = new BitmexSocketClient(new BitmexSocketClientOptions(configuration["key"], configuration["secret"], bool.Parse(configuration["testnet"])) { LogVerbosity = CryptoExchange.Net.Logging.LogVerbosity.Debug }); socket.OnUserOrdersUpdate += OnBitmexOrderUpdate; socket.OnUserExecutionsUpdate += OnExecution; socket.OnUserPositionsUpdate += BitmexSocketClient_OnUserPositionsUpdate; socket.OnOrderBookL2_25Update += Socket_OnOrderBookL2_25Update; socket.OnTradeUpdate += Socket_OnTradeUpdate; + socket.OnSocketClose += Socket_OnSocketClose; + socket.OnSocketException += Socket_OnSocketException; + socket.OnChatMessageUpdate += Socket_OnChatMessageUpdate; socket.Subscribe(new BitmexSubscribeRequest() - .AddSubscription(BitmexSubscribtions.Order, "XBTUSD") - .AddSubscription(BitmexSubscribtions.Execution, "XBTUSD") - .AddSubscription(BitmexSubscribtions.Position, "XBTUSD") + //.AddSubscription(BitmexSubscribtions.Order, "XBTUSD") + //.AddSubscription(BitmexSubscribtions.Execution, "XBTUSD") + //.AddSubscription(BitmexSubscribtions.Position, "XBTUSD") .AddSubscription(BitmexSubscribtions.Trade, "XBTUSD") + .AddSubscription(BitmexSubscribtions.Chat) .AddSubscription(BitmexSubscribtions.OrderBookL2_25, "XBTUSD")); + //socket.Subscribe(new BitmexSubscribeRequest() + // .AddSubscription(BitmexSubscribtions.Trade, "XBTUSD")); + //socket.Subscribe(new BitmexSubscribeRequest() + // .AddSubscription(BitmexSubscribtions.OrderBookL2_25, "XBTUSD")); // var client = new BitmexClient(new BitmexClientOptions(configuration["key"], configuration["secret"], bool.Parse(configuration["testnet"]))); // var posit = client.GetExecutions(new BitmexRequestWithFilter().WithSymbolFilter("XBTUSD").WithOldestFirst().WithResultsCount(19)); //string id = posit.Data.FirstOrDefault().OrderID; @@ -62,31 +71,47 @@ static async Task Main(string[] args) Console.ReadLine(); } + private static void Socket_OnChatMessageUpdate(BitmexSocketEvent obj) + { + Console.WriteLine($"{obj.Data[0].Date}{obj.Data[0].Message}"); + } + + private static void Socket_OnSocketException(Exception obj) + { + Console.WriteLine($"{DateTime.UtcNow}:EXCEPTION: {obj}"); + } + + private static void Socket_OnSocketClose() + { + Console.WriteLine($"{DateTime.UtcNow}:CLOSED"); + + } + private static void Socket_OnTradeUpdate(BitmexSocketEvent obj) { - Console.WriteLine("trade"); + Console.WriteLine($"{DateTime.UtcNow}:trade"); } private static void Socket_OnOrderBookL2_25Update(BitmexSocketEvent obj) { - Console.WriteLine("ob"); + Console.WriteLine($"{DateTime.UtcNow}:ob"); } private static void BitmexSocketClient_OnUserPositionsUpdate(BitmexSocketEvent obj) { - Console.WriteLine($"Catched POSITION {JsonConvert.SerializeObject(obj.AsDictionary())}"); + Console.WriteLine($"{DateTime.UtcNow}:Catched POSITION {JsonConvert.SerializeObject(obj.AsDictionary())}"); Console.WriteLine(); } private static void OnExecution(BitmexSocketEvent obj) { - Console.WriteLine($"Catched EXEC {JsonConvert.SerializeObject(obj.AsDictionary())}"); + Console.WriteLine($"{DateTime.UtcNow}:Catched EXEC {JsonConvert.SerializeObject(obj.AsDictionary())}"); Console.WriteLine(); } private static void OnBitmexOrderUpdate(BitmexSocketEvent obj) { - Console.WriteLine($"Catched ORDER {JsonConvert.SerializeObject(obj.AsDictionary())}"); + Console.WriteLine($"{DateTime.UtcNow}:Catched ORDER {JsonConvert.SerializeObject(obj.AsDictionary())}"); Console.WriteLine(); } diff --git a/Bitmex.Net.sln b/Bitmex.Net.sln index 117ef6a..65de089 100644 --- a/Bitmex.Net.sln +++ b/Bitmex.Net.sln @@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitmex.Net.Client", "Bitmex EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitmex.Net.Tests", "Bitmex.Net.Tests\Bitmex.Net.Tests.csproj", "{E79E7122-28A2-427E-AD85-14988D241692}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bitmex.Net.ClientExample", "Bitmex.Net.ClientExample\Bitmex.Net.ClientExample.csproj", "{BC5277BC-080C-46E7-B7C3-D3C959E108C4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitmex.Net.ClientExample", "Bitmex.Net.ClientExample\Bitmex.Net.ClientExample.csproj", "{BC5277BC-080C-46E7-B7C3-D3C959E108C4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Bitmex.Net/Bitmex.Net.Client.csproj b/Bitmex.Net/Bitmex.Net.Client.csproj index 61b95b6..3a148e0 100644 --- a/Bitmex.Net/Bitmex.Net.Client.csproj +++ b/Bitmex.Net/Bitmex.Net.Client.csproj @@ -3,7 +3,7 @@ latest netstandard2.0 - 0.2.9 + 0.3.5 true Bitmex.Net.Client ridicoulous diff --git a/Bitmex.Net/BitmexSocketClient.cs b/Bitmex.Net/BitmexSocketClient.cs index 72ee125..f5b53dc 100644 --- a/Bitmex.Net/BitmexSocketClient.cs +++ b/Bitmex.Net/BitmexSocketClient.cs @@ -11,6 +11,7 @@ using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; using CryptoExchange.Net.Sockets; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -32,9 +33,8 @@ public BitmexSocketClient() : this(DefaultOptions) } public BitmexSocketClient(BitmexSocketClientOptions bitmexSocketClientOptions) : base(bitmexSocketClientOptions, bitmexSocketClientOptions.ApiCredentials == null ? null : new BitmexAuthenticationProvider(bitmexSocketClientOptions.ApiCredentials)) { - //var rest = Query("ping", false).Result; - - //SendPeriodic(TimeSpan.FromSeconds(10), conn => "ping"); + AddGenericHandler("ping", OnPong); + SendPeriodic(TimeSpan.FromSeconds(10), connection => "ping"); if (bitmexSocketClientOptions.LoadInstruments) { using (var bitmexClient = new BitmexClient(new BitmexClientOptions(bitmexSocketClientOptions.IsTestnet))) @@ -55,6 +55,15 @@ public BitmexSocketClient() : this(DefaultOptions) } } + + private void OnPong(SocketConnection arg1, JToken arg2) + { + if (arg2.Type == JTokenType.String && (string)arg2 == "pong") + { + OnPongReceived?.Invoke(); + } + } + public event Action OnPongReceived; public event Action> OnAnnouncementUpdate; public event Action> OnChatMessageUpdate; @@ -85,14 +94,72 @@ public BitmexSocketClient() : this(DefaultOptions) public event Action> OnUserPositionsUpdate; public event Action> OnUserTransactionsUpdate; public event Action> OnUserWalletUpdate; + public event Action OnSocketException; + public event Action OnSocketClose; + public event Action OnSocketOpened; + private bool isBrocked = false; + protected override IWebsocket CreateSocket(string address) { Dictionary empty = new Dictionary(); var s = SocketFactory.CreateWebsocket(this.log, address, empty, this.authProvider == null ? empty : this.authProvider.AddAuthenticationToHeaders("bitmex.com/realtime", HttpMethod.Get, null, true)); + s.OnClose += S_OnClose; + s.OnError += S_OnError; + s.OnOpen += S_OnOpen; + //s.SSLProtocols = System.Security.Authentication.SslProtocols.Tls + // | System.Security.Authentication.SslProtocols.Tls11 + // | System.Security.Authentication.SslProtocols.Tls12 + // | System.Security.Authentication.SslProtocols.Ssl2 + // | System.Security.Authentication.SslProtocols.Ssl3; + //s.vers return s; } + + private void S_OnOpen() + { + if (isBrocked) + { + foreach (var s in this.sockets) + { + s.Value.Send("ping"); + } + } + OnSocketOpened?.Invoke(); + } + + private void S_OnError(Exception obj) + { + OnSocketException?.Invoke(obj); + } + + private void S_OnClose() + { + isBrocked = true; + OnSocketClose?.Invoke(); + //try + //{ + // foreach (var s in this.sockets.Values) + // { + // if (!s.Connected || !s.Socket.IsOpen || s.Socket.IsClosed) + // { + // log.Write(LogVerbosity.Error, $"socket {s.Socket.Id} was closed, try to reconnect it and send ping"); // s.Socket.Reset(); + + // s.Socket.Connect(); + // s.Socket.Send("ping"); + + // } + // } + //} + //catch (Exception ex) + //{ + // log.Write(LogVerbosity.Error, $"On closing socket error catched: {ex.ToString()}"); + // OnSocketException?.Invoke(ex); + //} + + } + protected override async Task> AuthenticateSocket(SocketConnection s) { if (authProvider == null) @@ -103,12 +170,12 @@ protected override async Task> AuthenticateSocket(SocketConnect } protected override async Task Unsubscribe(SocketConnection connection, SocketSubscription s) - { - if(s.Request is BitmexSubscribeRequest) + { + if (s.Request is BitmexSubscribeRequest) { var unsub = s.Request as BitmexSubscribeRequest; unsub.Op = BitmexWebSocketOperation.Unsubscribe; - var handler = new Action(data=> + var handler = new Action(data => { log.Write(LogVerbosity.Debug, data); }); @@ -129,22 +196,12 @@ protected override bool HandleSubscriptionResponse(SocketConnection s, SocketSub if (message.Type == JTokenType.String && (string)message == "pong") { - //callResult = new CallResult(, null); return true; } - - // var greetings = message.ToObject(); var response = Deserialize(message, false); - var bRequest = (BitmexSubscribeRequest)request; if (response.Success && response.Data.Success) { - //if (response.Data.Request.Args.Contains(response.Data.Subscribe) || response.Data.Request.Args.Contains(response.Data.Unsubscribe)) - //{ - // callResult = new CallResult(response, response.Success ? null : new ServerError("Subscribtion was not success", response)); - - // return true; - //} if (bRequest.Args.Contains(response.Data.Subscribe)) { callResult = new CallResult(response, response.Success ? null : new ServerError("Subscribtion was not success", response)); @@ -199,8 +256,16 @@ public async Task> SubscribeAsync(BitmexSubscribe var table = (string)token["table"]; if (String.IsNullOrEmpty(table) || !Map.Mappings.ContainsKey(table)) { - log.Write(LogVerbosity.Warning, $"Unknown table [{table}] update catched at data {data}"); - return; + if (data.Contains("info") || data.StartsWith("{\r\n \"success\": true")) + { + return; + } + else + { + log.Write(LogVerbosity.Warning, $"Unknown table [{table}] update catched at data {data}"); + return; + } + } BitmexSubscribtions updatedTable = Map.Mappings[table]; @@ -501,7 +566,7 @@ private async Task> Subscribe(BitmexSubscribeR { request.Args.ValidateNotNull(nameof(request)); var url = BaseAddress + $"?{request.Op.ToString().ToLower()}={String.Join(",", request.Args)}"; - return await Subscribe(url, request, url + NextId(), authProvider != null, onData).ConfigureAwait(false); + return await Subscribe(url, null, url + NextId(), authProvider != null, onData).ConfigureAwait(false); } public void Ping() { diff --git a/Bitmex.Net/BitmexSymbolOrderBook.cs b/Bitmex.Net/BitmexSymbolOrderBook.cs index d80b186..8bd085b 100644 --- a/Bitmex.Net/BitmexSymbolOrderBook.cs +++ b/Bitmex.Net/BitmexSymbolOrderBook.cs @@ -20,10 +20,12 @@ public class BitmexSymbolOrderBook : SymbolOrderBook private readonly int InstrumentIndex; private readonly decimal InstrumentTickSize; private bool IsInititalBookSetted; - public BitmexSymbolOrderBook(string symbol, BitmexSocketOrderBookOptions options) : base(symbol, options) + private bool isTestnet; + public BitmexSymbolOrderBook(string symbol, BitmexSocketOrderBookOptions options, BitmexSocketClient? bitmexSocketClient = null) : base(symbol, options) { - _bitmexSocketClient = new BitmexSocketClient(new BitmexSocketClientOptions(options.IsTestnet)); - InstrumentIndex = _bitmexSocketClient.InstrumentsIndexesAndTicks[symbol].Index; + isTestnet = options.IsTestnet; + _bitmexSocketClient = bitmexSocketClient ?? new BitmexSocketClient(new BitmexSocketClientOptions(options.IsTestnet)); + InstrumentIndex = _bitmexSocketClient.InstrumentsIndexesAndTicks[symbol].Index; InstrumentTickSize = options.TickSize.HasValue ? options.TickSize.Value : _bitmexSocketClient.InstrumentsIndexesAndTicks[symbol].TickSize; } public void Ping() @@ -34,7 +36,7 @@ public override void Dispose() { processBuffer.Clear(); asks.Clear(); - bids.Clear(); + bids.Clear(); _bitmexSocketClient.Dispose(); } @@ -53,9 +55,11 @@ protected override async Task> DoStart() var setResult = await WaitForSetOrderBook(10000).ConfigureAwait(false); return setResult ? subscriptionResult : new CallResult(null, setResult.Error); } - + public DateTime LastOrderBookMessage; + public DateTime LastAction; private void OnUpdate(BitmexSocketEvent update) { + LastOrderBookMessage = DateTime.UtcNow; if (update.Action == Objects.Socket.BitmexAction.Partial) { Create(update.Data); @@ -63,6 +67,7 @@ private void OnUpdate(BitmexSocketEvent update) } Update(update.Data); } + /// /// You may receive other messages before the partial comes through. In that case, drop any messages received until you have received the partial. /// @@ -71,22 +76,44 @@ private void Create(List entries) { SetInitialOrderBook(DateTime.UtcNow.Ticks, entries.Where(e => e.Side == OrderBookEntryType.Bid), entries.Where(e => e.Side == OrderBookEntryType.Ask)); IsInititalBookSetted = true; + } private void Update(List entries) { - if (IsInititalBookSetted) + try { - if(entries==null||!entries.Any()) + if (IsInititalBookSetted) { - return; + if (entries == null || !entries.Any()) + { + return; + } + foreach (var e in entries) + { + e.SetPrice(InstrumentIndex, InstrumentTickSize); + } + UpdateOrderBook(DateTime.UtcNow.Ticks, entries.Where(e => e.Side == OrderBookEntryType.Bid), entries.Where(e => e.Side == OrderBookEntryType.Ask)); + LastAction = DateTime.UtcNow; } - foreach (var e in entries) + else { - e.SetPrice(InstrumentIndex, InstrumentTickSize); - // log.Write(CryptoExchange.Net.Logging.LogVerbosity.Warning, $"Price for orderboook level {e.Id} was not setted"); - } + log.Write(CryptoExchange.Net.Logging.LogVerbosity.Error, $"Orderbook was not updated cause not initiated"); + using (var client = new BitmexClient(new BitmexClientOptions(isTestnet))) + { + log.Write(CryptoExchange.Net.Logging.LogVerbosity.Debug, $"Setting orderdbook through api"); - UpdateOrderBook(DateTime.UtcNow.Ticks, entries.Where(e => e.Side == OrderBookEntryType.Bid), entries.Where(e => e.Side == OrderBookEntryType.Ask)); + var ob = client.GetOrderBook(Symbol); + if (ob) + { + SetInitialOrderBook(DateTime.UtcNow.Ticks, ob.Data.Where(x => x.Side == OrderBookEntryType.Bid), ob.Data.Where(x => x.Side == OrderBookEntryType.Ask)); + IsInititalBookSetted = true; + } + } + } + } + catch (Exception ex) + { + log.Write(CryptoExchange.Net.Logging.LogVerbosity.Error, $"Orderbook was not updated {ex.ToString()}"); } } }