public HistoricalExecutionSource(BitFlyerClient client, BfProductCode productCode, long before, long after, long readCount = ReadCountMax) { readCount = Math.Min(readCount, ReadCountMax); _source = Observable.Create <IBfExecution>(observer => { return(Task.Run(async() => { while (true) { var resp = client.GetExecutions(productCode, ReadCountMax, before, 0); if (resp.IsError) { switch (resp.StatusCode) { case HttpStatusCode.BadRequest: // no more records observer.OnCompleted(); return; case HttpStatusCode.InternalServerError: await Task.Delay(30 * 1000); // Probably server is in maintanace. wait 30 secs break; } continue; } var elements = resp.GetContent(); foreach (var element in elements) { if (_cancel.IsCancellationRequested) { observer.OnCompleted(); return; } if (element.ExecutionId <= after) { observer.OnCompleted(); return; } observer.OnNext(element); } before = elements.Last().ExecutionId; } })); }); }
public static async Task <IEnumerable <(BfProductCode ProductCode, string Symbol)> > GetAvailableMarketsAsync(this BitFlyerClient client, CancellationToken ct) { var result = new List <(BfProductCode ProductCode, string Symbol)>(); foreach (var task in client.GetMarketsAllAsync(ct)) { var markets = (await task).GetContent(); foreach (var market in markets) { if (market.ProductCode.StartsWith("BTCJPY")) { if (string.IsNullOrEmpty(market.Alias)) { continue; // ******** BTCJPY future somtimes missing alias, skip it ******** } result.Add(((BfProductCode)Enum.Parse(typeof(BfProductCode), market.Alias.Replace("_", "")), market.ProductCode)); } else { result.Add(((BfProductCode)Enum.Parse(typeof(BfProductCode), market.ProductCode.Replace("_", "")), market.ProductCode)); } } } return(result.Distinct(e => e.ProductCode)); }
public static IEnumerable <(BfProductCode ProductCode, string Symbol)> GetAvailableMarkets(this BitFlyerClient client) { var result = new List <(BfProductCode ProductCode, string Symbol)>(); foreach (var market in client.GetMarketsAll().SelectMany(e => e.GetContent())) { if (market.ProductCode.StartsWith("BTCJPY")) { if (string.IsNullOrEmpty(market.Alias)) { continue; // ******** BTCJPY future somtimes missing alias, skip it ******** } result.Add(((BfProductCode)Enum.Parse(typeof(BfProductCode), market.Alias.Replace("_", "")), market.ProductCode)); } else { result.Add(((BfProductCode)Enum.Parse(typeof(BfProductCode), market.ProductCode.Replace("_", "")), market.ProductCode)); } } return(result.Distinct(e => e.ProductCode)); }
public RealtimeSourceFactory(BitFlyerClient client = null) { _client = (client == null) ? new BitFlyerClient().AddTo(_disposables) : client; if (client != null) { GetAvailableMarkets(); } _webSocket = new WebSocket("wss://ws.lightstream.bitflyer.com/json-rpc"); _webSocket.Security.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12; _wsReconnectionTimer = new Timer((_) => { _wsReconnectionTimer.Change(Timeout.Infinite, Timeout.Infinite); // stop Debug.WriteLine("{0} WebSocket is reopening connection... state={1}", DateTime.Now, _webSocket.State); switch (_webSocket.State) { case WebSocketState.None: case WebSocketState.Closed: try { _webSocket.Open(); } catch (Exception ex) { Debug.WriteLine(ex.Message); _wsReconnectionTimer.Change(WebSocketReconnectionIntervalMs, Timeout.Infinite); // restart } break; case WebSocketState.Open: Debug.WriteLine("{0} Web socket is still opened.", DateTime.Now); break; default: _wsReconnectionTimer.Change(WebSocketReconnectionIntervalMs, Timeout.Infinite); // restart break; } }); _openedEvent.Reset(); _webSocket.Opened += (_, __) => { Debug.WriteLine("{0} WebSocket opened.", DateTime.Now); _wsReconnectionTimer.Change(Timeout.Infinite, Timeout.Infinite); // stop if (_webSocketSources.Count > 0) { Debug.WriteLine("{0} WebSocket recover subscriptions.", DateTime.Now); _webSocketSources.Values.ForEach(source => { source.Subscribe(); }); // resubscribe } OnWebSocketOpened(); _openedEvent.Set(); }; _webSocket.MessageReceived += (_, e) => { var subscriptionResult = JObject.Parse(e.Message)["params"]; var channel = subscriptionResult["channel"].Value <string>(); _webSocketSources[channel].OnSubscribe(subscriptionResult["message"]); }; _webSocket.Error += (_, e) => { // Classifies expected or unexpexted var error = new ErrorStatus(); switch (e.Exception) { case IOException ioex: error.Message = (ioex.InnerException != null) ? ioex.InnerException.Message : ioex.Message; break; case SocketException sockex: Debug.WriteLine("{0} WebSocket socket error({1})", DateTime.Now, sockex.SocketErrorCode); Debug.WriteLine("{0} WebSocket caused exception. Will be closed.", DateTime.Now, sockex.Message); error.SocketError = sockex.SocketErrorCode; error.Message = sockex.Message; break; default: switch ((uint)e.Exception.HResult) { case 0x80131500: // Bad gateway - probably terminated from host error.Message = e.Exception.Message; break; default: // Unexpected exception throw e.Exception; } break; } ErrorHandlers?.Invoke(error); }; _webSocket.Closed += (_, __) => { Debug.WriteLine("{0} WebSocket connection closed. Will be reopening...", DateTime.Now); _wsReconnectionTimer.Change(WebSocketReconnectionIntervalMs, Timeout.Infinite); }; }