// ^(\[187,.*) to only see order book for Gnosis
        // [187,10615808,[["o",1,"0.04490263","23.55422232"],["t","625586",0,"0.04490263","0.03820551",1503964002]]]
        async void BeginReceiveMessages()
        {
            isReceiving = true;

            while (isReceiving)
            {
                WebSocketReceiveResult receiveResult = null;

                using (var ms = new MemoryStream())
                {
                    do
                    {
                        receiveResult = await client.ReceiveAsync(clientBuffer, CancellationToken.None);

                        ms.Write(clientBuffer.Array, clientBuffer.Offset, receiveResult.Count);
                    }while (!receiveResult.EndOfMessage);

                    if (receiveResult.MessageType == WebSocketMessageType.Text)
                    {
                        JArray    data           = null;
                        Exception parseException = null;

                        ms.Seek(0, SeekOrigin.Begin);

                        try
                        {
                            using (var sr = new StreamReader(ms, readEncoding, false))
                                using (var reader = new JsonTextReader(sr))
                                {
                                    data = JArray.Load(reader);
                                }
                        }
                        catch (Exception ex)
                        {
                            parseException = ex;
                        }

                        if (parseException != null)
                        {
                            var receivedString = readEncoding.GetString(clientBuffer.Array);
                            Console.WriteLine($"Exception parsing {receivedString}:\r\n{parseException.ToString()}");
                            continue;
                        }

                        ProcessDataArray(data);
                    }
                }
            }

            void ProcessDataArray(JToken data)
            {
                int messageType = data[0].ToObject <int>();

                switch (messageType)
                {
                case 1010:
                    OnHeartBeat();
                    return;

                case 1002:
                    if (data[1].ToObject <int?>() != 1)
                    {
                        OnTicker(data[2]);
                    }
                    return;

                default:
                    break;
                }

                if (Markets.CurrencyPairs.TryGetValue(messageType, out var matchingCurrency))
                {
                    // [187,10615808,[["o",1,"0.04490263","23.55422232"],["t","625586",0,"0.04490263","0.03820551",1503964002]]]
                    int orderId    = data[1].ToObject <int>();
                    var orderArray = data[2].ToArray();
                    foreach (var orderEntryArray in orderArray)
                    {
                        var orderType = orderEntryArray[0].ToObject <string>();
                        if (orderType == "t")
                        {
                            //["t","625586",0,"0.04490263","0.03820551",1503964002]
                            var trade = new Trade
                            {
                                CurrencyPair  = matchingCurrency,
                                TradeId       = orderEntryArray[1].ToObject <string>(),
                                TradeType     = (TradeType)orderEntryArray[2].ToObject <int>(), // buy or sell
                                Price         = orderEntryArray[3].ToObject <string>(),
                                Quantity      = orderEntryArray[4].ToObject <string>(),
                                UnixEpochTime = orderEntryArray[5].ToObject <long>(),
                            };
                            OnTradeAction?.OnTradeEvent(trade);
                        }
                        else if (orderType == "o")
                        {
                            //["o",1,"0.04490263","23.55422232"]  1 = buy order, 0 = sell order
                            var order = new Order
                            {
                                CurrencyPair = matchingCurrency,
                                OrderType    = (OrderType)orderEntryArray[1].ToObject <int>(), // bid or ask
                                Rate         = orderEntryArray[2].ToObject <string>(),
                                Amount       = orderEntryArray[3].ToObject <string>(),
                            };
                            OnOrderAction?.OnOrderEvent(order);
                        }
                    }
                }
            }
        }
        // ^(\[187,.*) to only see order book for Gnosis
        // [187,10615808,[["o",1,"0.04490263","23.55422232"],["t","625586",0,"0.04490263","0.03820551",1503964002]]]
        public void OnMessageReceived(MemoryStream ms)
        {
            JArray    data           = null;
            Exception parseException = null;
            var       readEncoding   = client.Encoding;

            try
            {
                using (var sr = new StreamReader(ms, readEncoding, false))
                    using (var reader = new JsonTextReader(sr))
                    {
                        data = JArray.Load(reader);
                    }
            }
            catch (Exception ex)
            {
                parseException = ex;
            }

            if (parseException != null)
            {
                var receivedString = readEncoding.GetString(ms.GetBuffer());
                Console.WriteLine($"Exception parsing {receivedString}:\r\n{parseException.ToString()}");
                return;
            }

            ProcessDataArray();

            void ProcessDataArray()
            {
                int messageType = data[0].ToObject <int>();

                switch (messageType)
                {
                case 1010:
                    OnHeartBeat();
                    return;

                case 1002:
                    if (data[1].ToObject <int?>() != 1)
                    {
                        OnTicker(data[2]);
                    }
                    return;

                default:
                    break;
                }

                if (Markets.CurrencyPairs.TryGetValue(messageType, out var matchingCurrency))
                {
                    // [187,10615808,[["o",1,"0.04490263","23.55422232"],["t","625586",0,"0.04490263","0.03820551",1503964002]]]
                    int orderId    = data[1].ToObject <int>();
                    var orderArray = data[2].ToArray();
                    foreach (var orderEntryArray in orderArray)
                    {
                        var orderType = orderEntryArray[0].ToObject <string>();
                        if (orderType == "t")
                        {
                            //["t","625586",0,"0.04490263","0.03820551",1503964002]
                            var trade = new Trade
                            {
                                CurrencyPair  = matchingCurrency,
                                TradeId       = orderEntryArray[1].ToObject <string>(),
                                TradeType     = (TradeType)orderEntryArray[2].ToObject <int>(), // buy or sell
                                Price         = orderEntryArray[3].ToObject <string>(),
                                Quantity      = orderEntryArray[4].ToObject <string>(),
                                UnixEpochTime = orderEntryArray[5].ToObject <long>(),
                            };
                            OnTradeAction?.OnTradeEvent(trade);
                        }
                        else if (orderType == "o")
                        {
                            //["o",1,"0.04490263","23.55422232"]  1 = buy order, 0 = sell order
                            var order = new Order
                            {
                                CurrencyPair = matchingCurrency,
                                OrderType    = (OrderType)orderEntryArray[1].ToObject <int>(), // bid or ask
                                Rate         = orderEntryArray[2].ToObject <string>(),
                                Amount       = orderEntryArray[3].ToObject <string>(),
                            };
                            OnOrderAction?.OnOrderEvent(order);
                        }
                    }
                }
            }
        }