title: GDAX/Coinbase API Level3 orderbook - skipping messages
body: <p>I'm using the GDAX API <a href="https://docs.gdax.com/#the-code-classprettyprintfullcode-channel" rel="nofollow noreferrer">Websocket Stream</a> to try and create a copy of the full LEVEL3 orderbook. </p>
  
  <p>I've got a very simple implementation using WebSocketSharp and Im basically doing something like this.</p>
  
  <pre><code>private readonly WebSocket _webSocket = new WebSocket("wss://ws-feed.gdax.com");
  
  _webSocket.OnMessage += WebSocket_OnMessage;
  _webSocket.Connect();
  _webSocket.Send(JsonConvert.SerializeObject(new BeginSubscriptionMessage()));
  
  private void WebSocket_OnMessage(object sender, MessageEventArgs e)
  {
      var message = JsonConvert.DeserializeObject&lt;BaseMessage&gt;(e.Data);
      switch (message.Type)
      {   
          case "match": //A trade occurred between two orders. 
              MatchMessage matchMessage = JsonConvert.DeserializeObject&lt;MatchMessage&gt;(e.Data);
              _receivedMatchQueue.Enqueue(matchMessage);
              break;
          case "received": //A valid order has been received and is now active. This message is emitted for every single valid order as soon as the matching engine receives it whether it fills immediately or not.
              ReceivedMessage receivedMessage = JsonConvert.DeserializeObject&lt;ReceivedMessage&gt;(e.Data);
              _receivedMessageQueue.Enqueue(receivedMessage);
              break;
          case "open": //The order is now open on the order book. This message will only be sent for orders which are not fully filled immediately. remaining_size will indicate how much of the order is unfilled and going on the book.
              OpenMessage openMessage = JsonConvert.DeserializeObject&lt;OpenMessage&gt;(e.Data);
              _receivedOpenQueue.Enqueue(openMessage);
              break;
          case "done": //The order is no longer on the order book. Sent for all orders for which there was a received message. This message can result from an order being canceled or filled. 
              DoneMessage doneMessage = JsonConvert.DeserializeObject&lt;DoneMessage&gt;(e.Data);
              _receivedDoneQueue.Enqueue(doneMessage);
              break;
          case "change": //Existing order has been changed
              ChangeMessage changeMessage = JsonConvert.DeserializeObject&lt;ChangeMessage&gt;(e.Data);
              _receivedChangeQueue.Enqueue(changeMessage);
              break;
          case "activate": //Stop order placed
              //Console.WriteLine("Stop Order Placed");
              //ActivateMessage activateMessage = JsonConvert.DeserializeObject&lt;ActivateMessage&gt;(e.Data);
  
              break;
          case "subscriptions":
              break;
          case "ticker":
              TickerMessage tickerMessage = JsonConvert.DeserializeObject&lt;TickerMessage&gt;(e.Data);
              _receivedTickerQueue.Enqueue(tickerMessage);
              break;
          case "l2update":
  
              break;
      }
  }
  </code></pre>
  
  <p>The problem I am running into is that when I look at the sequence numbers as received through both the RECEIVED and OPEN messages I can see they are not sequential which (<a href="https://docs.gdax.com/#sequence-numbers" rel="nofollow noreferrer">based on the following information</a>) suggests that messages are being skipped.</p>
  
  <p>Basically you end up with something like this </p>
  
  <pre><code>Open Message SequenceId: 5359746354
  Open Message SequenceId: 5359746358
  Open Message SequenceId: 5359746361
  Open Message SequenceId: 5359746363
  Open Message SequenceId: 5359746365
  Open Message SequenceId: 5359746370
  Open Message SequenceId: 5359746372
  </code></pre>
  
  <p>I have tried testing this on Azure, just to make sure that it wasn't a bandwidth limitation on my end and the results were largely similar.</p>
  
  <p>So given this, how is it possible to build a complete 'real-time' orderbook using the 'full' websocket stream if messages are dropped? Can I just safely ignore them? Or do I just somehow clear orphaned values?</p>
  
  <p>Any advice from anyone having done something similar would be extremely appreciated.</p>