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); }
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); }
/// <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); } } }
/// <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()); } } }
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); } }
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); } }
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); }
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()); } }