示例#1
0
        private void AddAsk(List <MarketDepthLevel> levels, MarketDepthLevel newLevel)
        {// уровни продаж.  с индексом ноль меньшее значение
            for (int i = 0; i < levels.Count; i++)
            {
                if (levels[i].Price == newLevel.Price)
                {
                    levels[i] = newLevel;
                    return;
                }

                if (levels[i].Price > newLevel.Price)
                {
                    levels.Insert(i, newLevel);
                    return;
                }
            }

            levels.Add(newLevel);
        }
示例#2
0
        private void AddBid(List <MarketDepthLevel> levels, MarketDepthLevel newLevel)
        { // buy levels. with index zero greater value / уровни покупок.  с индексом ноль бОльшее значение
            for (int i = 0; i < levels.Count; i++)
            {
                if (levels[i].Price == newLevel.Price)
                {
                    levels[i] = newLevel;
                    return;
                }

                if (levels[i].Price < newLevel.Price)
                {
                    levels.Insert(i, newLevel);
                    return;
                }
            }

            levels.Add(newLevel);
        }
示例#3
0
        /// <summary>
        /// incoming depth
        /// входящий стакан
        /// </summary>
        /// <param name="namePaper">instrument name / название инструмента</param>
        /// <param name="message">depth / стакан</param>
        private void OrderBook_Income(string namePaper, string message)
        {
            if (_isDisposed)
            {
                return;
            }

            try
            {
                var resp = JsonConvert.DeserializeObject <OrderBookResponse>(message);

                MarketDepth depth = new MarketDepth();
                depth.SecurityNameCode = namePaper;

                for (int i = 0; i < 10; i++)
                {
                    MarketDepthLevel ask = new MarketDepthLevel();
                    ask.Price = resp.asks[i][0].ToDecimal();
                    ask.Ask   = resp.asks[i][1].ToDecimal();
                    depth.Asks.Add(ask);

                    MarketDepthLevel bid = new MarketDepthLevel();
                    bid.Price = resp.bids[i][0].ToDecimal();
                    bid.Bid   = resp.bids[i][1].ToDecimal();
                    depth.Bids.Add(bid);
                }

                if (UpdateMarketDepth != null)
                {
                    UpdateMarketDepth(depth);
                }
            }
            catch (Exception error)
            {
                if (LogMessageEvent != null)
                {
                    //   LogMessageEvent(error.ToString(), LogMessageType.Error);
                }
            }
        }
示例#4
0
        /// <summary>
        /// разбор входящих сообощений о стакане
        /// </summary>
        private void LoadMarketDepths(string message)
        {
            /* string marketDepthStr = marketDepthUpdate.Instrument.FullName + "#"; // бумага
             *
             * if (marketDepthUpdate.MarketDataType == MarketDataType.Ask)
             * {
             *   marketDepthStr += "Ask" + "#";
             * }
             * else
             * {
             *   marketDepthStr += "Bid" + "#";
             * }
             *
             * //Operation.Add //Operation.Remove //Operation.Update
             *
             * marketDepthStr += marketDepthUpdate.Operation + "#"; // операция
             *
             * marketDepthStr += marketDepthUpdate.Price + "#"; // цена
             * marketDepthStr += marketDepthUpdate.Volume + "#"; // объём на уровне
             *
             * marketDepthStr += marketDepthUpdate.Time + "$"; // время*/


            string[] messageInArray = message.Split('$');

            for (int i = 0; i < messageInArray.Length - 1; i++)
            {
                string[] str = messageInArray[i].Split('#');

                MarketDepthLevel level = new MarketDepthLevel();

                if (str[1] == "Ask")
                {
                    level.Ask = Convert.ToDecimal(str[4]);
                }
                else
                {
                    level.Bid = Convert.ToDecimal(str[4]);
                }
                level.Price = Convert.ToDecimal(str[3]);

                MarketDepth myDepth = _marketDepths.Find(m => m.SecurityNameCode == str[0]);

                if (myDepth == null)
                {
                    myDepth = new MarketDepth();
                    myDepth.SecurityNameCode = str[0];
                    _marketDepths.Add(myDepth);
                }

                myDepth.Time = Convert.ToDateTime(str[5]);

                if (myDepth.Bids == null)
                {
                    myDepth.Bids = new List <MarketDepthLevel>();
                }

                if (myDepth.Asks == null)
                {
                    myDepth.Asks = new List <MarketDepthLevel>();
                }

                //Operation.Add //Operation.Remove //Operation.Update
                if (str[1] == "Ask" && (str[2] == "Add" || str[2] == "Update"))
                {
                    AddAsk(myDepth.Asks, level);
                }
                if (str[1] == "Ask" && str[2] == "Remove")
                {
                    Remove(myDepth.Asks, level);
                }

                if (str[1] == "Bid" && (str[2] == "Add" || str[2] == "Update"))
                {
                    AddBid(myDepth.Bids, level);
                }
                if (str[1] == "Bid" && str[2] == "Remove")
                {
                    Remove(myDepth.Bids, level);
                }

                while (myDepth.Asks != null &&
                       myDepth.Asks.Count > 10)
                {
                    myDepth.Asks.RemoveAt(myDepth.Asks.Count - 1);
                }

                while (myDepth.Bids != null &&
                       myDepth.Bids.Count > 10)
                {
                    myDepth.Bids.RemoveAt(myDepth.Bids.Count - 1);
                }

                if (myDepth.Bids != null &&
                    myDepth.Bids.Count > 0 &&
                    myDepth.Asks != null &&
                    myDepth.Asks.Count > 0)

                {
                    if (str[1] == "Bid" &&
                        myDepth.Bids[0].Price >= myDepth.Asks[0].Price)
                    {
                        myDepth.Asks.RemoveAt(0);
                    }
                    if (str[1] == "Ask" &&
                        myDepth.Bids[0].Price >= myDepth.Asks[0].Price)
                    {
                        myDepth.Bids.RemoveAt(0);
                    }
                }

                if (UpdateMarketDepth != null)
                {
                    UpdateMarketDepth(myDepth.GetCopy());
                }
            }
        }
示例#5
0
        public void GetMarketDepth(Security security)
        {
            if (_securitiesSubscrible.Count == 0)
            {
                return;
            }

            //https://api-invest.tinkoff.ru/openapi/market/orderbook?figi=BBG001DJNR51&depth=10

            string url = _url + "market/orderbook?";

            url += "figi=" + security.NameId;
            url += "&depth=7";

            var jsonCurrency = ApiQuery(url, "GET", new Dictionary <string, string>());


            if (jsonCurrency == null)
            {
                return;
            }

            MarketDepth depth = new MarketDepth();

            depth.SecurityNameCode = security.Name;
            depth.Time             = DateTime.Now;
            //  var time = JToken.Parse(jsonCurrency).SelectToken("payload").SelectToken("time");

            var jBid = JToken.Parse(jsonCurrency).SelectToken("payload").SelectToken("bids");

            List <MarketDepthLevel> bids = new List <MarketDepthLevel>();

            foreach (var bid in jBid)
            {
                MarketDepthLevel newBid = new MarketDepthLevel();

                newBid.Bid   = bid.SelectToken("quantity").ToString().ToDecimal();
                newBid.Price = bid.SelectToken("price").ToString().ToDecimal();

                bids.Add(newBid);
            }

            depth.Bids = bids;


            var jAsk = JToken.Parse(jsonCurrency).SelectToken("payload").SelectToken("asks");

            List <MarketDepthLevel> asks = new List <MarketDepthLevel>();

            foreach (var ask in jAsk)
            {
                MarketDepthLevel newAsk = new MarketDepthLevel();

                newAsk.Ask   = ask.SelectToken("quantity").ToString().ToDecimal();
                newAsk.Price = ask.SelectToken("price").ToString().ToDecimal();

                asks.Add(newAsk);
            }

            depth.Asks = asks;

            if (depth.Asks == null ||
                depth.Asks.Count == 0 ||
                depth.Bids == null ||
                depth.Bids.Count == 0)
            {
                return;
            }

            if (UpdateMarketDepth != null)
            {
                UpdateMarketDepth(depth);
            }
        }
        void _ibClient_NewMarketDepth(int id, int position, int operation, int side, decimal price, int size)
        {
            try
            {
                // take all the necessary data / берём все нужные данные
                SecurityIb myContract = _secIB.Find(contract => contract.ConId == id);

                if (myContract == null)
                {
                    return;
                }

                if (position > 10)
                {
                    return;
                }

                string name = myContract.Symbol + "_" + myContract.SecType + "_" + myContract.Exchange;

                Security mySecurity = _securities.Find(security => security.Name == name);

                if (mySecurity == null)
                {
                    return;
                }

                if (_depths == null)
                {
                    _depths = new List <MarketDepth>();
                }

                MarketDepth myDepth = _depths.Find(depth => depth.SecurityNameCode == name);
                if (myDepth == null)
                {
                    myDepth = new MarketDepth();
                    myDepth.SecurityNameCode = name;
                    _depths.Add(myDepth);
                }

                myDepth.Time = DateTime.Now;

                Side sideLine;
                if (side == 1)
                { // ask/аск
                    sideLine = Side.Buy;
                }
                else
                { // bid/бид
                    sideLine = Side.Sell;
                }

                List <MarketDepthLevel> bids = myDepth.Bids;
                List <MarketDepthLevel> asks = myDepth.Asks;

                if (asks == null || asks.Count < 10)
                {
                    asks = new List <MarketDepthLevel>();
                    bids = new List <MarketDepthLevel>();

                    for (int i = 0; i < 10; i++)
                    {
                        asks.Add(new MarketDepthLevel());
                        bids.Add(new MarketDepthLevel());
                    }
                    myDepth.Bids = bids;
                    myDepth.Asks = asks;
                }

                if (operation == 2)
                {// if need to remove / если нужно удалить
                    if (sideLine == Side.Buy)
                    {
                        // asks.RemoveAt(position);
                        MarketDepthLevel level = bids[position];
                        level.Ask   = 0;
                        level.Bid   = 0;
                        level.Price = 0;
                    }
                    else if (sideLine == Side.Sell)
                    {
                        //bids.RemoveAt(position);
                        MarketDepthLevel level = asks[position];
                        level.Ask   = 0;
                        level.Bid   = 0;
                        level.Price = 0;
                    }
                }
                else if (operation == 0 || operation == 1)
                { // need to update / нужно обновить
                    if (sideLine == Side.Buy)
                    {
                        MarketDepthLevel level = bids[position];
                        level.Bid   = Convert.ToDecimal(size);
                        level.Ask   = 0;
                        level.Price = price;
                    }
                    else if (sideLine == Side.Sell)
                    {
                        MarketDepthLevel level = asks[position];
                        level.Bid   = 0;
                        level.Ask   = Convert.ToDecimal(size);
                        level.Price = price;
                    }
                }

                if (myDepth.Bids[0].Price != 0 &&
                    myDepth.Asks[0].Price != 0)
                {
                    MarketDepth copy = myDepth.GetCopy();

                    if (MarketDepthEvent != null)
                    {
                        MarketDepthEvent(copy);
                    }
                }
            }
            catch (Exception error)
            {
                SendLogMessage(error.ToString(), LogMessageType.Error);
            }
        }
示例#7
0
        public void GetMarketDepth(string securities)
        {
            if (securities == "")
            {
                return;
            }

            // var jsonCurrency = ApiQuery("order_book", null, securities);

            // ask_quantity - объем всех ордеров на продажу
            // ask_amount - сумма всех ордеров на продажу
            // ask_top - минимальная цена продажи
            // bid_quantity - объем всех ордеров на покупку
            // bid_amount - сумма всех ордеров на покупку
            // bid_top - максимальная цена покупки
            // bid - список ордеров на покупку, где каждая строка это цена, количество и сумма
            // ask - список ордеров на продажу, где каждая строка это цена, количество и сумма

            var jsonCurrency = ApiQuery("order_book", new Dictionary <string, string>(), securities, 20);

            string[] secs = securities.Split(',');

            for (int i = 0; i < secs.Length; i++)
            {
                var jProperties = JToken.Parse(jsonCurrency)[secs[i]]; //.Children<JProperty>();

                MarketDepth depth = new MarketDepth();
                depth.SecurityNameCode = secs[i];

                var jBid =
                    JToken.Parse(jProperties.SelectToken("bid").ToString());

                List <MarketDepthLevel> Bids = new List <MarketDepthLevel>();

                foreach (var bid in jBid)
                {
                    MarketDepthLevel newBid = new MarketDepthLevel();

                    var str = bid.ToArray();
                    newBid.Price = str[0].ToString()
                                   .Replace("{", "")
                                   .Replace("}", "")
                                   .ToDecimal();

                    newBid.Bid = str[1].ToString()
                                 .Replace("{", "")
                                 .Replace("}", "")
                                 .ToDecimal();
                    //newBid.Bid = bid..SelectToken("price").ToString().ToDecimal();
                    Bids.Add(newBid);
                }

                depth.Bids = Bids;


                var jAsk =
                    JToken.Parse(jProperties.SelectToken("ask").ToString());

                List <MarketDepthLevel> Ask = new List <MarketDepthLevel>();

                foreach (var ask in jAsk)
                {
                    MarketDepthLevel newAsk = new MarketDepthLevel();

                    var str = ask.ToArray();
                    newAsk.Price = str[0].ToString()
                                   .Replace("{", "")
                                   .Replace("}", "")
                                   .ToDecimal();

                    newAsk.Ask = str[1].ToString()
                                 .Replace("{", "")
                                 .Replace("}", "")
                                 .ToDecimal();
                    //newBid.Bid = bid..SelectToken("price").ToString().ToDecimal();
                    Ask.Add(newAsk);
                }

                depth.Asks = Ask;

                if (UpdateMarketDepth != null)
                {
                    UpdateMarketDepth(depth);
                }
            }
        }
        public List <MarketDepth> Update(JToken data)
        {
            if (all_depths.Count() == 0)
            {
                return(all_depths);
            }

            lock (locker)
            {
                JToken[] jt_delete = data.SelectToken("delete").ToArray();

                JToken[] jt_update = data.SelectToken("update").ToArray();

                JToken[] jt_insert = data.SelectToken("insert").ToArray();

                if (jt_delete != null && jt_delete.Count() > 0)
                {
                    foreach (var jt_item in jt_delete)
                    {
                        if (jt_item.SelectToken("side").Value <string>() == "Sell")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var price_to_del = jt_item.SelectToken("price").Value <decimal>();

                                all_depths.Find(x => x.SecurityNameCode == security_name).Asks.Remove(all_depths.Find(x => x.SecurityNameCode == security_name).Asks.Find(x => x.Price == price_to_del));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }

                        if (jt_item.SelectToken("side").Value <string>() == "Buy")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var price_to_del = jt_item.SelectToken("price").Value <decimal>();

                                all_depths.Find(x => x.SecurityNameCode == security_name).Bids.Remove(all_depths.Find(x => x.SecurityNameCode == security_name).Bids.Find(x => x.Price == price_to_del));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }
                    }
                }

                if (jt_update != null && jt_update.Count() > 0)
                {
                    foreach (var jt_item in jt_update)
                    {
                        if (jt_item.SelectToken("side").Value <string>() == "Sell")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var new_ask_level = new MarketDepthLevel()
                                {
                                    Ask   = jt_item.SelectToken("size").Value <decimal>(),
                                    Bid   = 0,
                                    Price = jt_item.SelectToken("price").Value <decimal>(),
                                };

                                all_depths.Find(x => x.SecurityNameCode == security_name).Asks.Find(x => x.Price == new_ask_level.Price).Ask = new_ask_level.Ask;
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }

                        if (jt_item.SelectToken("side").Value <string>() == "Buy")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var new_bid_level = new MarketDepthLevel()
                                {
                                    Ask   = 0,
                                    Bid   = jt_item.SelectToken("size").Value <decimal>(),
                                    Price = jt_item.SelectToken("price").Value <decimal>(),
                                };

                                all_depths.Find(x => x.SecurityNameCode == security_name).Bids.Find(x => x.Price == new_bid_level.Price).Bid = new_bid_level.Bid;
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }
                    }
                }

                if (jt_insert != null && jt_insert.Count() > 0)
                {
                    foreach (var jt_item in jt_insert)
                    {
                        if (jt_item.SelectToken("side").Value <string>() == "Sell")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var new_ask_level = new MarketDepthLevel()
                                {
                                    Ask   = jt_item.SelectToken("size").Value <decimal>(),
                                    Bid   = 0,
                                    Price = jt_item.SelectToken("price").Value <decimal>(),
                                };

                                InsertLevel(new_ask_level.Price, new_ask_level.Ask, Side.Sell, all_depths.Find(x => x.SecurityNameCode == security_name));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }

                        if (jt_item.SelectToken("side").Value <string>() == "Buy")
                        {
                            try
                            {
                                string security_name = jt_item.SelectToken("symbol").Value <string>();

                                var new_bid_level = new MarketDepthLevel()
                                {
                                    Ask   = 0,
                                    Bid   = jt_item.SelectToken("size").Value <decimal>(),
                                    Price = jt_item.SelectToken("price").Value <decimal>(),
                                };

                                InsertLevel(new_bid_level.Price, new_bid_level.Bid, Side.Buy, all_depths.Find(x => x.SecurityNameCode == security_name));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }
                        }
                    }
                }

                return(all_depths);
            }
        }
示例#9
0
        public MarketDepth Insert(StreamDataMessage replmsg, Security security)
        {
            // обрабатываем ревизию

            // создаём новую
            RevisionInfo revision = new RevisionInfo();

            revision.Price         = Convert.ToDecimal(replmsg["price"].asDecimal());
            revision.TableRevision = replmsg["replRev"].asLong();
            revision.ReplId        = replmsg["replID"].asLong();
            revision.Security      = security.Name;

            if (_marketDepthsRevisions == null)
            {
                _marketDepthsRevisions = new List <RevisionInfo>();
            }

            // удаляем по этой же цене, если такая есть
            RevisionInfo revisionInArray =
                _marketDepthsRevisions.Find(info => info.Security == revision.Security && info.ReplId == revision.ReplId);

            if (revisionInArray != null)
            {
                _marketDepthsRevisions.Remove(revisionInArray);
            }

            // добавляем новую
            _marketDepthsRevisions.Add(revision);


            // создаём строку для стакана

            MarketDepthLevel depthLevel = new MarketDepthLevel();

            int direction = replmsg["dir"].asInt(); // 1 покупка 2 продажа

            if (direction == 1)
            {
                depthLevel.Ask = replmsg["volume"].asInt();
            }
            else
            {
                depthLevel.Bid = replmsg["volume"].asInt();
            }

            depthLevel.Price = Convert.ToDecimal(replmsg["price"].asDecimal());
            // берём наш стакан
            if (_marketDepths == null)
            {
                _marketDepths = new List <MarketDepth>();
            }

            MarketDepth myDepth = _marketDepths.Find(depth => depth.SecurityNameCode == security.Name);

            if (myDepth == null)
            {
                myDepth = new MarketDepth();
                myDepth.SecurityNameCode = security.Name;
                _marketDepths.Add(myDepth);
            }

            // добавляем строку в наш стакан

            List <MarketDepthLevel> asks = null;

            if (myDepth.Asks != null)
            {
                asks = myDepth.Asks.ToList();
            }

            List <MarketDepthLevel> bids = null;

            if (myDepth.Bids != null)
            {
                bids = myDepth.Bids.ToList();
            }

            if (direction == 1)
            {
                // уровни покупок
                if (asks == null || asks.Count == 0)
                {
                    asks = new List <MarketDepthLevel>();
                    asks.Add(depthLevel);
                }
                else
                {
                    bool isInArray = false;
                    for (int i = 0; i < asks.Count; i++)
                    {
                        // обрабатываем ситуацию когда такой уровень уже есть
                        if (asks[i].Price == depthLevel.Price)
                        {
                            asks[i]   = depthLevel;
                            isInArray = true;
                            break;
                        }
                    }

                    if (isInArray == false)
                    {
                        // обрабатываем ситуацию когда такого уровня нет
                        List <MarketDepthLevel> asksNew = new List <MarketDepthLevel>();
                        bool isIn = false;

                        for (int i = 0, i2 = 0; i2 < asks.Count + 1; i2++)
                        {
                            if (i == asks.Count && isIn == false ||
                                (isIn == false &&
                                 depthLevel.Price > asks[i].Price))
                            {
                                isIn = true;
                                asksNew.Add(depthLevel);
                            }
                            else
                            {
                                asksNew.Add(asks[i]);
                                i++;
                            }
                        }


                        while (asksNew.Count > 20)
                        {
                            asksNew.Remove(asksNew[asksNew.Count - 1]);
                        }

                        asks = asksNew;
                    }

                    if (bids != null && bids.Count != 0 &&
                        bids[0].Price <= asks[0].Price)
                    {
                        while (bids.Count != 0 &&
                               bids[0].Price <= asks[0].Price)
                        {
                            bids.Remove(bids[0]);
                        }

                        myDepth.Bids = bids;
                    }
                }

                myDepth.Asks = asks;
            }

            if (direction == 2)
            {
                // уровни продажи
                if (bids == null || bids.Count == 0)
                {
                    bids = new List <MarketDepthLevel>();
                    bids.Add(depthLevel);
                }
                else
                {
                    bool isInArray = false;
                    for (int i = 0; i < bids.Count; i++)
                    {
                        // обрабатываем ситуацию когда такой уровень уже есть
                        if (bids[i].Price == depthLevel.Price)
                        {
                            bids[i]   = depthLevel;
                            isInArray = true;
                            break;
                        }
                    }
                    if (isInArray == false)
                    {
                        // обрабатываем ситуацию когда такого уровня нет
                        List <MarketDepthLevel> bidsNew = new List <MarketDepthLevel>();
                        bool isIn = false;
                        for (int i = 0, i2 = 0; i2 < bids.Count + 1; i2++)
                        {
                            if (i == bids.Count && isIn == false ||
                                (isIn == false &&
                                 depthLevel.Price < bids[i].Price))
                            {
                                isIn = true;
                                bidsNew.Add(depthLevel);
                            }
                            else
                            {
                                bidsNew.Add(bids[i]);
                                i++;
                            }
                        }

                        while (bidsNew.Count > 20)
                        {
                            bidsNew.Remove(bidsNew[bidsNew.Count - 1]);
                        }

                        bids = bidsNew;
                    }

                    if (asks != null && asks.Count != 0 &&
                        bids[0].Price <= asks[0].Price)
                    {
                        while (asks.Count != 0 && bids[0].Price <= asks[0].Price)
                        {
                            asks.Remove(asks[0]);
                        }

                        myDepth.Asks = asks;
                    }
                }

                myDepth.Bids = bids;
            }


            return(myDepth);
        }
示例#10
0
        private static void Client_BookSnapshotReceived(object sender, Events.KrakenDataEventArgs<BookSnapshotMessage> e)
        {
            string pair = e.Pair.ToString();

            Sec security = Securities.Find(sec => sec.NameInSocket == pair);

            MarketDepth depth = _marketDepths.Find(d => d.SecurityNameCode == security.NameInRest);

            if (depth == null)
            {
                depth = new MarketDepth();
                depth.SecurityNameCode = security.NameInRest;
                _marketDepths.Add(depth);
            }

            for (int i = 0; e.DataMessage.Asks != null && i < e.DataMessage.Asks.Length; i++)
            {
                OsEngine.Entity.MarketDepthLevel ask = new OsEngine.Entity.MarketDepthLevel();
                ask.Price = e.DataMessage.Asks[i].Price;
                ask.Ask = e.DataMessage.Asks[i].Volume;

                for (int i2 = 0; i2 < depth.Asks.Count; i2++)
                {
                    if (depth.Asks[i2].Price == ask.Price)
                    {
                        depth.Asks.RemoveAt(i2);
                        break;
                    }
                }

                if (ask.Ask != 0)
                {
                    depth.Asks.Add(ask);
                }

                depth.Time = new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(e.DataMessage.Asks[i].Timestamp));
            }

            for (int i = 0; e.DataMessage.Bids != null && i < e.DataMessage.Bids.Length; i++)
            {
                OsEngine.Entity.MarketDepthLevel bid = new OsEngine.Entity.MarketDepthLevel();
                bid.Price = e.DataMessage.Bids[i].Price;
                bid.Bid = e.DataMessage.Bids[i].Volume;

                for (int i2 = 0; i2 < depth.Bids.Count; i2++)
                {
                    if (depth.Bids[i2].Price == bid.Price)
                    {
                        depth.Bids.RemoveAt(i2);
                        break;
                    }
                }

                if (bid.Bid != 0)
                {
                    depth.Bids.Add(bid);
                }

                depth.Time = new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(e.DataMessage.Bids[i].Timestamp));
            }

            // 1 Теперь сортируем биды и аски

            for (int i = 0; i < depth.Asks.Count; i++)
            {
                for (int i2 = 0; i2 < depth.Asks.Count - 1; i2++)
                {
                    if (depth.Asks[i2].Price > depth.Asks[i2 + 1].Price)
                    {
                        MarketDepthLevel level = depth.Asks[i2];
                        depth.Asks[i2] = depth.Asks[i2 + 1];
                        depth.Asks[i2 + 1] = level;
                    }
                }
            }


            for (int i = 0; i < depth.Bids.Count; i++)
            {
                for (int i2 = 0; i2 < depth.Bids.Count - 1; i2++)
                {
                    if (depth.Bids[i2].Price < depth.Bids[i2 + 1].Price)
                    {
                        MarketDepthLevel level = depth.Bids[i2];
                        depth.Bids[i2] = depth.Bids[i2 + 1];
                        depth.Bids[i2 + 1] = level;
                    }
                }
            }

            // 2 Теперь удаляем перехлёсты


            while (depth.Bids.Count > 0 &&
                depth.Asks.Count > 0 &&
                depth.Bids[0].Price > depth.Asks[0].Price)
            {
                depth.Asks.RemoveAt(0);
            }

            // !!!!!!!!!!!!!!!!!!!!!!


            // высылаем копию

            if (MarketDepthUpdateEvent != null)
            {
                MarketDepthUpdateEvent(depth.GetCopy());
            }
        }