private void OnReceived(RealtimeReceived receivedMessage) { var order = new BidAskOrder(); order.Id = receivedMessage.OrderId; order.Price = receivedMessage.Price; order.Size = receivedMessage.Size; lock (_spreadLock) { if (receivedMessage.Side == "buy") { lock (_bidLock) { _buys.Add(order); Buys = _buys.ToList(); } } else if (receivedMessage.Side == "sell") { lock (_askLock) { _sells.Add(order); Sells = _sells.ToList(); } } } }
private static async void Subscribe(string product, Action <RealtimeMessage> onMessageReceived) { if (String.IsNullOrWhiteSpace(product)) { throw new ArgumentNullException("product"); } if (onMessageReceived == null) { throw new ArgumentNullException("onMessageReceived", "Message received callback must not be null."); } var uri = new Uri("wss://ws-feed.exchange.coinbase.com"); var webSocketClient = new ClientWebSocket(); var cancellationToken = new CancellationToken(); var requestString = String.Format(@"{{""type"": ""subscribe"",""product_id"": ""{0}""}}", product); var requestBytes = UTF8Encoding.UTF8.GetBytes(requestString); await webSocketClient.ConnectAsync(uri, cancellationToken); if (webSocketClient.State == WebSocketState.Open) { var subscribeRequest = new ArraySegment <byte>(requestBytes); var sendCancellationToken = new CancellationToken(); await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, sendCancellationToken); while (webSocketClient.State == WebSocketState.Open) { var receiveCancellationToken = new CancellationToken(); var receiveBuffer = new ArraySegment <byte>(new byte[1024 * 1024 * 5]); // 5MB buffer var webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, receiveCancellationToken); if (webSocketReceiveResult.Count == 0) { continue; } var jsonResponse = Encoding.UTF8.GetString(receiveBuffer.Array, 0, webSocketReceiveResult.Count); var jToken = JToken.Parse(jsonResponse); var typeToken = jToken["type"]; if (typeToken == null) { continue; } var type = typeToken.Value <string>(); RealtimeMessage realtimeMessage = null; switch (type) { case "received": realtimeMessage = new RealtimeReceived(jToken); break; case "open": realtimeMessage = new RealtimeOpen(jToken); break; case "done": realtimeMessage = new RealtimeDone(jToken); break; case "match": realtimeMessage = new RealtimeMatch(jToken); break; case "change": realtimeMessage = new RealtimeChange(jToken); break; default: break; } if (realtimeMessage == null) { continue; } onMessageReceived(realtimeMessage); } } }
private static async void Subscribe(string product, Action <RealtimeMessage> onMessageReceived) { if (String.IsNullOrWhiteSpace(product)) { throw new ArgumentNullException("product"); } if (onMessageReceived == null) { throw new ArgumentNullException("onMessageReceived", "Message received callback must not be null."); } JArray aj = new JArray(); var uri = new Uri("wss://ws-feed.gdax.com"); var webSocketClient = new ClientWebSocket(); var cancellationToken = new CancellationToken(); //jStr.Append() var requestString = string.Format(""); //String.Format(@"{{""type"": ""subscribe"",""product_id"": ""{0}""}}", product); //JObject jObj = new JObject( // new JProperty( // "type", "subscribe"), // new JProperty( // "product_ids", new JArray( // "BTC-USD")), // new JProperty( // "channels", new JArray( // "level2", "heartbeat", new JObject( // new JProperty( // "name", "ticker"), new JProperty( // "product_ids", new JArray( // "BTC-USD")))))); //JObject jObj = new JObject( // new JProperty( // "type", "subscribe"), // new JProperty( // "product_ids", new JArray( // "BTC-USD")), // new JProperty( // "channels", new JArray( // "heartbeat", new JObject( // new JProperty( // "name", "ticker"), new JProperty( // "product_ids", new JArray( // "BTC-USD")))))); //JObject jObj = new JObject( // new JProperty( // "type", "subscribe"), // new JProperty( // "product_ids", new JArray( // "BTC-USD")), // new JProperty( // "channels", new JArray( // "matches", "heartbeat", new JObject( // new JProperty( // "name", "ticker"), new JProperty( // "product_ids", new JArray( // "BTC-USD")))))); JObject jObj = new JObject( new JProperty( "type", "subscribe"), new JProperty( "product_ids", new JArray( "BTC-USD", product)), new JProperty( "channels", new JArray( "matches"))); //Console.WriteLine(jObj.ToString()); var requestBytes = UTF8Encoding.UTF8.GetBytes(jObj.ToString()); await webSocketClient.ConnectAsync(uri, cancellationToken); if (webSocketClient.State == WebSocketState.Open) { var subscribeRequest = new ArraySegment <byte>(requestBytes); var sendCancellationToken = new CancellationToken(); await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, sendCancellationToken); while (webSocketClient.State == WebSocketState.Open) { var receiveCancellationToken = new CancellationToken(); var receiveBuffer = new ArraySegment <byte>(new byte[1024 * 1024 * 1]); // 5MB buffer 1024 * 1024 * 5 var webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, receiveCancellationToken); if (webSocketReceiveResult.Count == 0) { continue; } var jsonResponse = Encoding.UTF8.GetString(receiveBuffer.Array, 0, webSocketReceiveResult.Count); //var jToken = JToken.Parse(jsonResponse); var jToken = JObject.Parse(jsonResponse); var typeToken = jToken["type"]; if (typeToken == null) { continue; } var type = typeToken.Value <string>(); RealtimeMessage realtimeMessage = null; //Console.WriteLine("MSG TYPE: {0}", type); switch (type) { case "received": realtimeMessage = new RealtimeReceived(jToken); break; case "open": realtimeMessage = new RealtimeOpen(jToken); break; case "done": realtimeMessage = new RealtimeDone(jToken); break; case "match": realtimeMessage = new RealtimeMatch(jToken); break; case "change": realtimeMessage = new RealtimeChange(jToken); break; default: break; } if (realtimeMessage == null) { continue; } onMessageReceived(realtimeMessage); } } }
public async Task SubscribeAsync(bool reConnectOnDisconnect) { var uri = ExchangeClientBase.IsSandbox ? WSS_SANDBOX_ENDPOINT_URL : WSS_ENDPOINT_URL; if (_authContainer != null) // authenticated feed { uri = new Uri(uri, "/users/self/verify"); } cancellationTokenSource = new CancellationTokenSource(); while (!cancellationTokenSource.IsCancellationRequested) { string disconnectReason = ""; try { webSocketClient = new ClientWebSocket(); await webSocketClient.ConnectAsync(uri, cancellationTokenSource.Token); if (webSocketClient.State == System.Net.WebSockets.WebSocketState.Open && !cancellationTokenSource.IsCancellationRequested) { await rateGateRealtime.WaitToProceedAsync(); // don't subscribe at too high of a rate await sendSubscriptionMsgAsync(Products : Products, gdax_Channel : gdax_Channel); // key is product name, value is whether connection was just opened if (webSocketClient.State == System.Net.WebSockets.WebSocketState.Open && !cancellationTokenSource.IsCancellationRequested) { // checking again bc maybe the server disconnected after the subscribe msg was sent // + move to processing subscriptions section below later foreach (var product in Products) { ConnectionOpened?.Invoke(product, gdax_Channel); } } while (webSocketClient.State == System.Net.WebSockets.WebSocketState.Open && !cancellationTokenSource.IsCancellationRequested) { using (var timeoutCTS = new CancellationTokenSource(6500)) // heartbeat every 1000 ms, so give it 5 hearbeat chances using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutCTS.Token, cancellationTokenSource.Token)) using (var stream = new MemoryStream(1024)) { var receiveBuffer = new ArraySegment <byte>(new byte[1024 * 8]); bool timedOut = false; WebSocketReceiveResult webSocketReceiveResult; do { try { webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, linkedTokenSource.Token); } catch (OperationCanceledException) { timedOut = true; disconnectReason = " - stream timed out"; break; } await stream.WriteAsync(receiveBuffer.Array, receiveBuffer.Offset, webSocketReceiveResult.Count, cancellationTokenSource.Token); } while (!webSocketReceiveResult.EndOfMessage && !cancellationTokenSource.IsCancellationRequested); if (!timedOut && !cancellationTokenSource.IsCancellationRequested) { var message = stream.ToArray().Where(b => b != 0).ToArray(); var messageString = Encoding.ASCII.GetString(message, 0, message.Length); if (!String.IsNullOrEmpty(messageString)) { try { var jToken = JToken.Parse(messageString); var typeToken = jToken["type"]; if (typeToken == null) { RealtimeDataError?.Invoke(this, new RealtimeError("null typeToken: + " + Encoding.ASCII.GetString(message, 0, message.Length))); return; // go to next msg } var type = typeToken.Value <string>(); switch (type) { case "subscriptions": // + process initial subscription confirmation // + also for unsubscribe confirmation break; case "received": var rr = new RealtimeReceived(jToken); if (rr.Message != null) { RealtimeDataError?.Invoke(this, rr); } RealtimeReceived?.Invoke(this, rr); break; case "open": var ro = new RealtimeOpen(jToken); if (ro.Message != null) { RealtimeDataError?.Invoke(this, ro); } RealtimeOpen?.Invoke(this, ro); break; case "done": var rd = new RealtimeDone(jToken); if (rd.Message != null) { RealtimeDataError?.Invoke(this, rd); } RealtimeDone?.Invoke(this, rd); break; case "match": var rm = new RealtimeMatch(jToken); if (rm.Message != null) { RealtimeDataError?.Invoke(this, rm); } RealtimeMatch?.Invoke(this, rm); break; case "last_match": var rlm = new RealtimeMatch(jToken); if (rlm.Message != null) { RealtimeDataError?.Invoke(this, rlm); } RealtimeLastMatch?.Invoke(this, rlm); break; case "change": var rc = new RealtimeChange(jToken); if (rc.Message != null) { RealtimeDataError?.Invoke(this, rc); } RealtimeChange?.Invoke(this, rc); break; case "heartbeat": // + should implement this (checking LastTraderId) var hb = new Heartbeat(jToken); Heartbeat?.Invoke(this, hb); break; case "error": RealtimeDataError?.Invoke(this, new RealtimeError(jToken)); break; default: RealtimeDataError?.Invoke(this, new RealtimeError("Unexpected type: " + jToken)); break; } } catch (JsonReaderException e) { RealtimeDataError?.Invoke(this, new RealtimeError( "JsonReaderException: " + e.Message + ":" + messageString)); } } else { RealtimeDataError?.Invoke(this, new RealtimeError("empty message received. Connection state: " + webSocketClient.State + ", linkedToken: " + linkedTokenSource.Token.IsCancellationRequested)); } } } } } } catch (Exception e) { if (e.Message == "The remote party closed the WebSocket connection without completing the close handshake.") // System.Net.WebSockets.WebSocketException { disconnectReason = " - remote closed the WebSocket w/o completing the close handshake"; } else if (e.Message == "Unable to connect to the remote server") // System.Net.WebSockets.WebSocketException { disconnectReason = " - unable to connect to server"; // shorten it a bit await Task.Delay(10000); // if unable to connect, then wait 10 seconds before trying to connect again } else { RealtimeStreamError?.Invoke(this, new RealtimeError("other exception caught: " + e.GetType() + " : " + e.Message)); } } if (!reConnectOnDisconnect) { UnSubscribe(); } foreach (var product in Products) { RealtimeStreamError?.Invoke(this, new RealtimeError("disconnected" + disconnectReason)); ConnectionClosed?.Invoke(product, gdax_Channel); } if (!reConnectOnDisconnect) { break; } } }
private static async void Subscribe(string product, Action<RealtimeMessage> onMessageReceived) { if (String.IsNullOrWhiteSpace(product)) throw new ArgumentNullException("product"); if (onMessageReceived == null) throw new ArgumentNullException("onMessageReceived", "Message received callback must not be null."); var uri = new Uri("wss://ws-feed.exchange.coinbase.com"); var webSocketClient = new ClientWebSocket(); var cancellationToken = new CancellationToken(); var requestString = String.Format(@"{{""type"": ""subscribe"",""product_id"": ""{0}""}}", product); var requestBytes = UTF8Encoding.UTF8.GetBytes(requestString); await webSocketClient.ConnectAsync(uri, cancellationToken); if (webSocketClient.State == WebSocketState.Open) { var subscribeRequest = new ArraySegment<byte>(requestBytes); var sendCancellationToken = new CancellationToken(); await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, sendCancellationToken); while (webSocketClient.State == WebSocketState.Open) { var receiveCancellationToken = new CancellationToken(); var receiveBuffer = new ArraySegment<byte>(new byte[1024 * 1024 * 5]); // 5MB buffer var webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, receiveCancellationToken); if (webSocketReceiveResult.Count == 0) continue; var jsonResponse = Encoding.UTF8.GetString(receiveBuffer.Array, 0, webSocketReceiveResult.Count); var jToken = JToken.Parse(jsonResponse); var typeToken = jToken["type"]; if (typeToken == null) continue; var type = typeToken.Value<string>(); RealtimeMessage realtimeMessage = null; switch (type) { case "received": realtimeMessage = new RealtimeReceived(jToken); break; case "open": realtimeMessage = new RealtimeOpen(jToken); break; case "done": realtimeMessage = new RealtimeDone(jToken); break; case "match": realtimeMessage = new RealtimeMatch(jToken); break; case "change": realtimeMessage = new RealtimeChange(jToken); break; default: break; } if (realtimeMessage == null) continue; onMessageReceived(realtimeMessage); } } }
private async void OnReceived(object sender, RealtimeReceived received) { await checkSequenceNumber(received.Sequence); }