private async ValueTask <SOrderBooks> createOrderbook(SOrderBooks cob) { cob.result.asks.ForEach(a => a.action = "insert"); cob.result.bids.ForEach(a => a.action = "insert"); return(await Task.FromResult(cob)); }
/// <summary> /// /// </summary> /// <param name="cob"></param> /// <returns></returns> private async ValueTask <bool> mergeOrderbooks(SOrderBooks cob) { var _result = false; SOrderBooks _qob; { if (__qOrderBooks.TryGetValue(cob.symbol, out _qob) == true) { _qob.stream = cob.stream; var _settings = GetSettings(cob.symbol); if (cob.action == "polling") { _result = await cleanOrderbooks(_qob, cob, _settings); } else { _result = await updateOrderbooks(_qob, cob, _settings); } } else { if (cob.action == "snapshot") { _result = await insertOrderbooks(cob); } } } return(_result); }
private async ValueTask publishOrderbook(SOrderBooks sob) { await Task.Delay(0); var _json_data = JsonConvert.SerializeObject(sob); __orderbook.Write(this, GMConfig.DealerName, _json_data); }
private async ValueTask publishOrderbook(SOrderBooks sob) { await Task.Delay(0); if (sob.result.asks.Count + sob.result.bids.Count > 0) { var _json_data = JsonConvert.SerializeObject(sob); __orderbook.Write(this, BNConfig.DealerName, _json_data); } }
private async ValueTask <bool> modifyOrderbook(SOrderBooks qob, SOrderBooks cob, Settings settings) { var _result = false; if (settings.last_orderbook_time < cob.result.timestamp) { settings.last_orderbook_time = cob.result.timestamp; var _current_ask_size = cob.result.askSumQty; var _current_bid_size = cob.result.bidSumQty; if (settings.last_order_ask_size != _current_ask_size || settings.last_order_bid_size != _current_bid_size) { if (settings.before_trade_ask_size != _current_ask_size || settings.before_trade_bid_size != _current_bid_size) { if (settings.trades_flag == true) { var _t_ask = qob.result.asks.OrderByDescending(o => o.price).LastOrDefault(); var _t_bid = qob.result.bids.OrderByDescending(o => o.price).FirstOrDefault(); if (_t_ask != null && _t_bid != null) { cob.result.asks.RemoveAll(o => o.price < _t_ask.price); cob.result.bids.RemoveAll(o => o.price > _t_bid.price); var _c_ask = cob.result.asks.Where(o => o.price == _t_ask.price).SingleOrDefault(); var _c_bid = cob.result.bids.Where(o => o.price == _t_bid.price).SingleOrDefault(); if (_c_ask != null && _c_bid != null) { if (_t_ask.quantity != _c_ask.quantity || _t_bid.quantity != _c_bid.quantity) { _t_ask.quantity = _c_ask.quantity; _t_bid.quantity = _c_bid.quantity; } } } settings.trades_flag = false; } _result = await updateOrderbook(qob, cob, settings); settings.last_order_ask_size = qob.result.asks.Sum(o => o.quantity); settings.last_order_bid_size = qob.result.bids.Sum(o => o.quantity); } } } return(_result); }
private async ValueTask <bool> cleanOrderbooks(SOrderBooks qob, SOrderBooks cob, Settings settings) { qob.result.asks.Clear(); qob.result.bids.Clear(); cob.result.asks.ForEach(a => a.action = "insert"); cob.result.bids.ForEach(a => a.action = "insert"); qob.result.asks.AddRange(cob.result.asks); qob.result.bids.AddRange(cob.result.bids); settings.orderbook_count = 0; await snapshotOrderbook(qob); return(true); }
private void cleanOrderbook(SOrderBooks qob, SOrderBooks nob, decimal price) { var _asks = qob.result.asks.Where(o => o.price < price); { foreach (var _ask in _asks) { nob.result.asks.Add(new SOrderBookItem { action = "delete", id = _ask.id, price = _ask.price, quantity = _ask.quantity, amount = _ask.price * _ask.quantity, count = 1 }); nob.result.askSumQty -= _ask.quantity; _ask.quantity = 0; _ask.amount = 0; } } var _bids = qob.result.bids.Where(o => o.price > price); { foreach (var _bid in _bids) { nob.result.bids.Add(new SOrderBookItem { action = "delete", id = _bid.id, price = _bid.price, quantity = _bid.quantity, amount = _bid.price * _bid.quantity, count = 1 }); nob.result.bidSumQty -= _bid.quantity; _bid.quantity = 0; _bid.amount = 0; } } }
private async ValueTask snapshotOrderbook(string exchange, string symbol) { if (exchange == BNLogger.SNG.exchange_name) { SOrderBooks _sob = null; lock (__qOrderBooks) { if (__qOrderBooks.ContainsKey(symbol) == true) { _sob = __qOrderBooks[symbol]; _sob.stream = "snapshot"; } } if (_sob != null) { await publishOrderbook(_sob); } } }
private async ValueTask <bool> insertOrderbook(SOrderBooks cob) { var _result = false; var _sqo = await createOrderbook(cob); if (__qOrderBooks.TryAdd(cob.symbol, _sqo) == true) { var _settings = GetSettings(cob.symbol); { _settings.last_orderbook_time = cob.result.timestamp; _settings.orderbook_count = 0; } await snapshotOrderbook(cob.symbol); _result = true; } return(_result); }
/// <summary> /// /// </summary> /// <param name="cob"></param> /// <returns></returns> private async ValueTask <bool> mergeOrderbook(SOrderBooks cob) { var _result = false; SOrderBooks _qob; { if (__qOrderBooks.TryGetValue(cob.symbol, out _qob) == true) { _qob.stream = cob.stream; var _settings = GetSettings(cob.symbol); _result = await modifyOrderbook(_qob, cob, _settings); } else { _result = await insertOrderbook(cob); } } return(_result); }
private async ValueTask <bool> insertOrderbooks(SOrderBooks cob) { var _result = false; cob.result.asks.ForEach(a => a.action = "insert"); cob.result.bids.ForEach(a => a.action = "insert"); if (__qOrderBooks.TryAdd(cob.symbol, cob) == true) { var _settings = GetSettings(cob.symbol); { _settings.last_orderbook_time = cob.result.timestamp; _settings.orderbook_count = 0; } await snapshotOrderbook(cob); _result = true; } return(_result); }
/// <summary> /// Fetch pending or registered order details /// </summary> /// <param name="base_name">The type of trading base-currency of which information you want to query for.</param> /// <param name="quote_name">The type of trading quote-currency of which information you want to query for.</param> /// <returns></returns> public async ValueTask <SOrderBooks> GetOrderBooks(string base_name, string quote_name) { var _result = new SOrderBooks(); var _params = new Dictionary <string, object>(); { _params.Add("market", $"{quote_name}-{base_name}"); } var _response = await publicClient.CallApiGet2Async("/orderbook", _params); if (_response != null) { #if RAWJSON _result.rawJson = _response.Content; #endif if (_response.IsSuccessful == true) { var _orderbooks = publicClient.DeserializeObject <List <UOrderBook> >(_response.Content); { var _orderbook = _orderbooks.FirstOrDefault(); if (_orderbook != null) { _result.result = _orderbook; _result.SetSuccess(); } } } else { var _message = publicClient.GetResponseMessage(_response); _result.SetFailure(_message.message); } } return(_result); }
public async ValueTask Start(CancellationTokenSource cancelTokenSource) { DRLogger.SNG.WriteO(this, $"processing service start..."); var _processing = Task.Run(async() => { var _last_polling_trade = 0L; var _orderbook_size = 25; while (true) { try { await Task.Delay(0); var _message = (QMessage)null; if (ReceiveQ.TryDequeue(out _message) == false) { var _cancelled = cancelTokenSource.Token.WaitHandle.WaitOne(0); if (_cancelled == true) { break; } await Task.Delay(10); continue; } if (_message.command == "WS") { if (_message.stream == "trade") { var _w_trades = JsonConvert.DeserializeObject <List <DCompleteOrderItem> >(_message.payload ?? ""); var _s_trades = new SCompleteOrders { exchange = _message.exchange, // deribit stream = _message.stream, // trade symbol = _message.symbol, // BTC-PERPETUAL action = _message.action, // pushing sequentialId = _w_trades.Max(t => t.timestamp), result = _w_trades.Select(t => { return(new SCompleteOrderItem { timestamp = t.timestamp, sideType = t.sideType, price = t.price, quantity = t.quantity }); }) .ToList() }; if (_s_trades.result.Count() > 0) { _last_polling_trade = _s_trades.sequentialId; await mergeTrades(_s_trades); } } else if (_message.stream == "orderbook") { var _w_orderbooks = JsonConvert.DeserializeObject <DWsOrderBook>(_message.payload ?? ""); if (_w_orderbooks.asks.Count() > 0 || _w_orderbooks.bids.Count() > 0) { var _timestamp = _w_orderbooks.timestamp; var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, // deribit symbol = _message.symbol, // BTC-PERPETUAL stream = _message.stream, // orderbook action = _w_orderbooks.type, // snapshot, change sequentialId = _timestamp, result = new SOrderBook { timestamp = _timestamp, askSumQty = 0, bidSumQty = 0, asks = new List <SOrderBookItem>(), bids = new List <SOrderBookItem>() } }; foreach (var _a in _w_orderbooks.asks.OrderBy(a => a[1]).Take(_orderbook_size)) { _s_orderbooks.result.asks.Add(new SOrderBookItem { action = _a[0].ToString(), quantity = Convert.ToDecimal(_a[2]), price = Convert.ToDecimal(_a[1]), amount = 0, id = 0, count = 1 }); } foreach (var _b in _w_orderbooks.bids.OrderByDescending(b => b[1]).Take(_orderbook_size)) { _s_orderbooks.result.bids.Add(new SOrderBookItem { action = _b[0].ToString(), quantity = Convert.ToDecimal(_b[2]), price = Convert.ToDecimal(_b[1]), amount = 0, id = 0, count = 1 }); } await mergeOrderbooks(_s_orderbooks); } } } else if (_message.command == "AP") { if (_message.stream == "trade") { var _a_trades = JsonConvert.DeserializeObject <DRResults <DCompleteOrders> >(_message.payload ?? ""); if (_a_trades.result.trades.Count > 0) { var _s_trades = new SCompleteOrders { exchange = _message.exchange, // deribit symbol = _message.symbol, // BTC-PERPETUAL stream = _message.stream, // trade action = _message.action, // polling sequentialId = _a_trades.result.trades.Max(t => t.timestamp), result = _a_trades.result.trades.Where(t => t.timestamp > _last_polling_trade).Select(t => { return(new SCompleteOrderItem { timestamp = t.timestamp, sideType = t.sideType, price = t.price, quantity = t.quantity }); }) .ToList() }; if (_s_trades.result.Count() > 0) { _last_polling_trade = _s_trades.sequentialId; await mergeTrades(_s_trades); } } } else if (_message.stream == "orderbook") { var _a_orderbooks = JsonConvert.DeserializeObject <DRResults <DOrderBook> >(_message.payload ?? ""); if (_a_orderbooks.result.asks.Count > 0 || _a_orderbooks.result.bids.Count > 0) { var _timestamp = _a_orderbooks.result.timestamp; var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, // deribit symbol = _message.symbol, // BTC-PERPETUAL stream = _message.stream, // orderbook action = _message.action, // polling sequentialId = _timestamp, result = new SOrderBook { timestamp = _timestamp, askSumQty = 0, bidSumQty = 0, asks = _a_orderbooks.result.asks.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = 0, id = 0, count = 1 }); }) .ToList(), bids = _a_orderbooks.result.bids.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = 0, id = 0, count = 1 }); }) .ToList() } }; await mergeOrderbooks(_s_orderbooks); } } } else if (_message.command == "SS") { await snapshotOrderbook(_message.exchange); } #if DEBUG else { DRLogger.SNG.WriteO(this, _message.payload); } #endif if (cancelTokenSource.Token.IsCancellationRequested == true) { break; } } catch (TaskCanceledException) { } catch (Exception ex) { DRLogger.SNG.WriteX(this, ex.ToString()); } } }, cancelTokenSource.Token ); await Task.WhenAll(_processing); DRLogger.SNG.WriteO(this, $"processing service stop..."); }
private async ValueTask <bool> updateOrderbook(SOrderBooks qob, BAOrderBook orderbook, Settings settings) { var _dqo = new SOrderBooks { exchange = BNLogger.SNG.exchange_name, stream = "diffbooks", symbol = orderbook.data.symbol, sequentialId = orderbook.data.lastId, result = new SOrderBook() }; lock (__qOrderBooks) { foreach (var _oi in orderbook.data.asks) { var _ask = qob.result.asks.Where(o => o.price == _oi[0]).SingleOrDefault(); if (_ask == null) { var _aoi = new SOrderBookItem { action = "insert", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }; _dqo.result.asks.Add(_aoi); qob.result.asks.Add(_aoi); } else if (_ask.quantity != _oi[1]) { var _aoi = new SOrderBookItem { action = "update", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }; _dqo.result.asks.Add(_aoi); _ask.quantity = _oi[1]; } } foreach (var _oi in orderbook.data.bids) { var _bid = qob.result.bids.Where(o => o.price == _oi[0]).SingleOrDefault(); if (_bid == null) { var _boi = new SOrderBookItem { action = "insert", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }; _dqo.result.bids.Add(_boi); qob.result.bids.Add(_boi); } else if (_bid.quantity != _oi[1]) { var _boi = new SOrderBookItem { action = "update", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }; _dqo.result.bids.Add(_boi); _bid.quantity = _oi[1]; } } foreach (var _qi in qob.result.asks) { var _ask = orderbook.data.asks.Where(o => o[0] == _qi.price).SingleOrDefault(); if (_ask == null) { _dqo.result.asks.Add(new SOrderBookItem { action = "delete", price = _qi.price, quantity = _qi.quantity, amount = _qi.price * _qi.quantity, count = 1 }); _qi.quantity = 0; } } foreach (var _qi in qob.result.bids) { var _bid = orderbook.data.bids.Where(o => o[0] == _qi.price).SingleOrDefault(); if (_bid == null) { _dqo.result.bids.Add(new SOrderBookItem { action = "delete", price = _qi.price, quantity = _qi.quantity, amount = _qi.price * _qi.quantity, count = 1 }); _qi.quantity = 0; } } qob.result.asks.RemoveAll(o => o.quantity == 0); qob.result.bids.RemoveAll(o => o.quantity == 0); } if (++settings.orderbook_count == __bnconfig.OrderBookCounter) { settings.orderbook_count = 0; qob.sequentialId = orderbook.data.lastId; await snapshotOrderbook(_dqo.exchange, _dqo.symbol); } else { await publishOrderbook(_dqo); } return(true); }
private async ValueTask <bool> updateCompleteOrder(SOrderBooks qob, SCompleteOrders cco, Settings settings) { var _nob = new SOrderBooks { exchange = cco.exchange, stream = "difftrade", symbol = cco.symbol, action = cco.action, sequentialId = cco.sequentialId, result = new SOrderBook { timestamp = cco.result.Max(o => o.timestamp), askSumQty = 0, bidSumQty = 0 } }; lock (__qOrderBooks) { settings.before_trade_ask_size = qob.result.asks.Sum(o => o.quantity); settings.before_trade_bid_size = qob.result.bids.Sum(o => o.quantity); foreach (var _t in cco.result.OrderBy(t => t.timestamp)) { if (settings.last_trade_id >= _t.timestamp) { continue; } settings.last_trade_id = _t.timestamp; var _ask = qob.result.asks.Where(o => o.price == _t.price).SingleOrDefault(); if (_ask != null) { if (_ask.quantity <= _t.quantity) { _nob.result.asks.Add(new SOrderBookItem { action = "delete", id = _ask.id, price = _ask.price, quantity = _ask.quantity, amount = _ask.price * _ask.quantity, count = 1 }); _nob.result.askSumQty -= _ask.quantity; _ask.quantity = 0; _ask.amount = 0; } else { _ask.quantity -= _t.quantity; _ask.amount = _ask.price * _ask.quantity; _nob.result.asks.Add(new SOrderBookItem { action = "update", id = _ask.id, price = _ask.price, quantity = _ask.quantity, amount = _ask.price * _ask.quantity, count = 1 }); _nob.result.askSumQty += _ask.quantity; } } var _bid = qob.result.bids.Where(o => o.price == _t.price).SingleOrDefault(); if (_bid != null) { if (_bid.quantity <= _t.quantity) { _nob.result.bids.Add(new SOrderBookItem { action = "delete", id = _bid.id, price = _bid.price, quantity = _bid.quantity, amount = _bid.price * _bid.quantity, count = 1 }); _nob.result.bidSumQty -= _bid.quantity; _bid.quantity = 0; _bid.amount = 0; } else { _bid.quantity -= _t.quantity; _bid.amount = _bid.price * _bid.quantity; _nob.result.bids.Add(new SOrderBookItem { action = "update", id = _bid.id, price = _bid.price, quantity = _bid.quantity, amount = _bid.price * _bid.quantity, count = 1 }); _nob.result.bidSumQty += _bid.quantity; } } //cleanOrderbook(qob, _nob, _t.price); } qob.sequentialId = _nob.sequentialId; qob.result.asks.RemoveAll(o => o.quantity == 0); qob.result.bids.RemoveAll(o => o.quantity == 0); } _nob.result.asks.RemoveAll(o => o.quantity == 0); _nob.result.bids.RemoveAll(o => o.quantity == 0); if (_nob.result.asks.Count + _nob.result.bids.Count > 0) { await publishOrderbook(_nob); settings.orderbook_count = 0; settings.trades_flag = true; } return(true); }
private async ValueTask <bool> updateOrderbook(SOrderBooks qob, SOrderBooks cob, Settings settings) { var _nob = new SOrderBooks { exchange = cob.exchange, stream = "diffbooks", symbol = cob.symbol, action = cob.action, sequentialId = cob.sequentialId, result = new SOrderBook { timestamp = cob.result.timestamp, askSumQty = 0, bidSumQty = 0 } }; lock (__qOrderBooks) { foreach (var _ci in cob.result.asks) { var _qi = qob.result.asks.Where(o => o.price == _ci.price).SingleOrDefault(); if (_qi == null) { var _ici = new SOrderBookItem { action = "insert", id = _ci.id, price = _ci.price, quantity = _ci.quantity, amount = _ci.price * _ci.quantity, count = 1 }; _nob.result.asks.Add(_ici); qob.result.asks.Add(_ici); _nob.result.askSumQty += _ci.quantity; } else if (_qi.quantity != _ci.quantity) { _nob.result.asks.Add(new SOrderBookItem { action = "update", id = _qi.id, price = _qi.price, quantity = _ci.quantity, amount = _qi.price * _ci.quantity, count = 1 }); _qi.quantity = _ci.quantity; _qi.amount = _qi.price * _qi.quantity; _nob.result.askSumQty += _ci.quantity; } } foreach (var _ci in cob.result.bids) { var _qi = qob.result.bids.Where(o => o.price == _ci.price).SingleOrDefault(); if (_qi == null) { var _ici = new SOrderBookItem { action = "insert", id = _ci.id, price = _ci.price, quantity = _ci.quantity, amount = _ci.price * _ci.quantity, count = 1 }; _nob.result.bids.Add(_ici); qob.result.bids.Add(_ici); _nob.result.bidSumQty += _ci.quantity; } else if (_qi.quantity != _ci.quantity) { _nob.result.bids.Add(new SOrderBookItem { action = "update", id = _qi.id, price = _qi.price, quantity = _ci.quantity, amount = _qi.price * _ci.quantity, count = 1 }); _qi.quantity = _ci.quantity; _qi.amount = _qi.quantity * _qi.price; _nob.result.bidSumQty += _ci.quantity; } } foreach (var _qi in qob.result.asks) { var _ci = cob.result.asks.Where(o => o.price == _qi.price).SingleOrDefault(); if (_ci == null) { _nob.result.asks.Add(new SOrderBookItem { action = "delete", id = _qi.id, price = _qi.price, quantity = _qi.quantity, amount = _qi.price * _qi.quantity, count = 1 }); _nob.result.askSumQty -= _qi.quantity; _qi.quantity = 0; _qi.amount = 0; } } foreach (var _qi in qob.result.bids) { var _ci = cob.result.bids.Where(o => o.price == _qi.price).SingleOrDefault(); if (_ci == null) { _nob.result.bids.Add(new SOrderBookItem { action = "delete", id = _qi.id, price = _qi.price, quantity = _qi.quantity, amount = _qi.price * _qi.quantity, count = 1 }); _nob.result.bidSumQty -= _qi.quantity; _qi.quantity = 0; _qi.amount = 0; } } qob.result.asks.RemoveAll(o => o.quantity == 0); qob.result.bids.RemoveAll(o => o.quantity == 0); } if (++settings.orderbook_count == __gmconfig.SnapshotSkipCounter) { qob.sequentialId = cob.sequentialId; await snapshotOrderbook(_nob.symbol); } else { _nob.result.asks.RemoveAll(o => o.quantity == 0); _nob.result.bids.RemoveAll(o => o.quantity == 0); if (_nob.result.asks.Count > 0 || _nob.result.bids.Count > 0) { await publishOrderbook(_nob); } } return(true); }
public async ValueTask Start(CancellationToken cancelToken) { BTLogger.SNG.WriteO(this, $"processing service start..."); var _processing = Task.Run(async() => { var _last_polling_trade = 0L; while (true) { try { await Task.Delay(0); var _message = (QMessage)null; if (ReceiveQ.TryDequeue(out _message) == false) { var _cancelled = cancelToken.WaitHandle.WaitOne(0); if (_cancelled == true) { break; } await Task.Delay(10); continue; } if (_message.command == "WS") { if (_message.stream == "trade") { var _w_trade = JsonConvert.DeserializeObject <UWCompleteOrderItem>(_message.payload ?? ""); var _s_trade = new SCompleteOrders { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _w_trade.timestamp, result = new List <SCompleteOrderItem> { new SCompleteOrderItem { timestamp = _w_trade.timestamp, sideType = _w_trade.sideType, price = _w_trade.price, quantity = _w_trade.quantity } } }; if (_s_trade.result.Count() > 0) { _last_polling_trade = _s_trade.sequentialId; await mergeCompleteOrder(_s_trade); } } else if (_message.stream == "orderbook") { var _w_orderbook = JsonConvert.DeserializeObject <UWOrderBook>(_message.payload ?? ""); var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _w_orderbook.timestamp, result = new SOrderBook { timestamp = _w_orderbook.timestamp, askSumQty = _w_orderbook.askSumQty, bidSumQty = _w_orderbook.bidSumQty, asks = _w_orderbook.asks, bids = _w_orderbook.bids } }; await mergeOrderbook(_s_orderbooks); } } else if (_message.command == "AP") { if (_message.stream == "trade") { var _a_trades = JsonConvert.DeserializeObject <List <UACompleteOrderItem> >(_message.payload ?? ""); var _s_trade = new SCompleteOrders { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _a_trades.Max(t => t.timestamp), result = _a_trades.Where(t => t.timestamp > _last_polling_trade).Select(t => { return(new SCompleteOrderItem { timestamp = t.timestamp, sideType = t.sideType, price = t.price, quantity = t.quantity }); }) .ToList() }; if (_s_trade.result.Count() > 0) { _last_polling_trade = _s_trade.sequentialId; await mergeCompleteOrder(_s_trade); } } else if (_message.stream == "orderbook") { var _a_orderbooks = JsonConvert.DeserializeObject <List <UAOrderBook> >(_message.payload ?? ""); var _timestamp = _a_orderbooks.Max(o => o.timestamp); var _asks = _a_orderbooks[0].asks; var _bids = _a_orderbooks[0].bids; var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _a_orderbooks.Max(t => t.timestamp), result = new SOrderBook { timestamp = _timestamp, askSumQty = _asks.Sum(o => o.quantity), bidSumQty = _bids.Sum(o => o.quantity), asks = _asks, bids = _bids } }; await mergeOrderbook(_s_orderbooks); } else if (_message.stream == "ticker") { var _a_ticker_data = JsonConvert.DeserializeObject <List <UAOrderBook> >(_message.payload ?? ""); await publishTicker(new STickers { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _message.sequentialId, timestamp = _a_ticker_data.Max(o => o.timestamp), totalAskSize = _a_ticker_data.Sum(o => o.askSumQty), totalBidSize = _a_ticker_data.Sum(o => o.bidSumQty), result = _a_ticker_data.Select(o => { var _ask = o.asks.OrderBy(a => a.price).First(); var _bid = o.bids.OrderBy(a => a.price).Last(); return(new STickerItem { askPrice = _ask.price, askSize = _ask.quantity, bidPrice = _bid.price, bidSize = _bid.quantity }); }) .ToList() }); } } else if (_message.command == "SS") { await snapshotOrderbook(_message.symbol); } #if DEBUG else { BTLogger.SNG.WriteO(this, _message.payload); } #endif if (cancelToken.IsCancellationRequested == true) { break; } } catch (TaskCanceledException) { } catch (Exception ex) { BTLogger.SNG.WriteX(this, ex.ToString()); } } }, cancelToken ); await Task.WhenAll(_processing); BTLogger.SNG.WriteO(this, $"processing service stop..."); }
private async ValueTask <bool> mergeOrderbook(BAOrderBook orderbook) { var _result = false; var _settings = __qSettings.ContainsKey(orderbook.data.symbol) ? __qSettings[orderbook.data.symbol] : __qSettings[orderbook.data.symbol] = new Settings(); if (__qOrderBooks.ContainsKey(orderbook.data.symbol) == false) { _settings.last_orderbook_id = orderbook.data.lastId; var _sqo = new SOrderBooks { exchange = BNLogger.SNG.exchange_name, stream = "snapshot", symbol = orderbook.data.symbol, sequentialId = orderbook.data.lastId, result = new SOrderBook() }; foreach (var _oi in orderbook.data.asks) { _sqo.result.asks.Add(new SOrderBookItem { action = "insert", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }); } foreach (var _oi in orderbook.data.bids) { _sqo.result.bids.Add(new SOrderBookItem { action = "insert", price = _oi[0], quantity = _oi[1], amount = _oi[0] * _oi[1], count = 1 }); } __qOrderBooks[_sqo.symbol] = _sqo; await publishOrderbook(_sqo); _settings.orderbook_count = 0; _result = true; } else if (_settings.last_orderbook_id < orderbook.data.lastId) { _settings.last_orderbook_id = orderbook.data.lastId; var _qob = __qOrderBooks[orderbook.data.symbol]; var _current_ask_size = orderbook.data.asks.Sum(o => o[1]); var _current_bid_size = orderbook.data.bids.Sum(o => o[1]); if (_settings.last_order_ask_size != _current_ask_size || _settings.last_order_bid_size != _current_bid_size) { if (_settings.before_trade_ask_size != _current_ask_size || _settings.before_trade_bid_size != _current_bid_size) { _result = await updateOrderbook(_qob, orderbook, _settings); _settings.last_order_ask_size = _qob.result.asks.Sum(o => o.quantity); _settings.last_order_bid_size = _qob.result.bids.Sum(o => o.quantity); #if DEBUG // modified check if (_current_ask_size != _settings.last_order_ask_size || _current_bid_size != _settings.last_order_bid_size) { BNLogger.SNG.WriteQ(this, $"diffb-{orderbook.stream}: timestamp => {_settings.last_orderbook_id}, symbol => {orderbook.data.symbol}, ask_size => {_current_ask_size}, {_settings.last_order_ask_size}, bid_size => {_current_bid_size}, {_settings.last_order_bid_size}"); } if (_qob.result.asks.Count + _qob.result.bids.Count != 40) { var _ask_count = _qob.result.asks.Count(); var _bid_count = _qob.result.bids.Count(); BNLogger.SNG.WriteQ(this, $"diffb-{orderbook.stream}: timestamp => {_settings.last_orderbook_id}, symbol => {orderbook.data.symbol}, ask_count => {_ask_count}, bid_count => {_bid_count}"); } #endif } else { BNLogger.SNG.WriteQ(this, $"trade-{orderbook.stream}: timestamp => {_settings.last_orderbook_id}, symbol => {orderbook.data.symbol}, ask_size => {_current_ask_size}, bid_size => {_current_bid_size}"); } } else { BNLogger.SNG.WriteQ(this, $"equal-{orderbook.stream}: timestamp => {_settings.last_orderbook_id}, symbol => {orderbook.data.symbol}, ask_size => {_current_ask_size}, bid_size => {_current_bid_size}"); } } return(_result); }
private async ValueTask snapshotOrderbook(SOrderBooks qob) { qob.stream = "snapshot"; await publishOrderbook(qob); }
private async ValueTask <bool> updateTradeItem(SOrderBooks qob, List <BTradeItem> tradeItems, string stream) { var _rqo = new SOrderBooks { exchange = BNLogger.SNG.exchange_name, stream = stream, symbol = qob.symbol, sequentialId = tradeItems.Max(t => t.timestamp), result = new SOrderBook() }; var _settings = __qSettings.ContainsKey(qob.symbol) ? __qSettings[qob.symbol] : __qSettings[qob.symbol] = new Settings(); lock (__qOrderBooks) { _settings.before_trade_ask_size = qob.result.asks.Sum(o => o.quantity); _settings.before_trade_bid_size = qob.result.bids.Sum(o => o.quantity); foreach (var _t in tradeItems.OrderBy(t => t.timestamp)) { if (_settings.last_trade_time >= _t.timestamp) { continue; } _settings.last_trade_time = _t.timestamp; var _ask = qob.result.asks.Where(o => o.price == _t.price).SingleOrDefault(); if (_ask != null) { if (_ask.quantity <= _t.quantity) { var _aoi = new SOrderBookItem { action = "delete", price = _ask.price, quantity = _ask.quantity, amount = _ask.price * _ask.quantity, count = 1 }; _rqo.result.asks.Add(_aoi); _ask.quantity = 0; } else { _ask.quantity -= _t.quantity; var _aoi = new SOrderBookItem { action = "update", price = _ask.price, quantity = _ask.quantity, amount = _ask.price * _ask.quantity, count = 1 }; _rqo.result.asks.Add(_aoi); } } var _bid = qob.result.bids.Where(o => o.price == _t.price).SingleOrDefault(); if (_bid != null) { if (_bid.quantity <= _t.quantity) { var _aoi = new SOrderBookItem { action = "delete", price = _bid.price, quantity = _bid.quantity, amount = _bid.price * _bid.quantity, count = 1 }; _rqo.result.bids.Add(_aoi); _bid.quantity = 0; } else { _bid.quantity -= _t.quantity; var _aoi = new SOrderBookItem { action = "update", price = _bid.price, quantity = _bid.quantity, amount = _bid.price * _bid.quantity, count = 1 }; _rqo.result.bids.Add(_aoi); } } // orderbook에 해당 하는 price-level 보다 안쪽에 위치한 level들은 삭제 해야 한다. var _strange_asks = qob.result.asks.Where(o => o.price < _t.price); if (_strange_asks.Count() > 0) { foreach (var _qox in _strange_asks) { var _aoi = new SOrderBookItem { action = "delete", price = _qox.price, quantity = _qox.quantity, amount = _qox.price * _qox.quantity, count = 1 }; _rqo.result.asks.Add(_aoi); _qox.quantity = 0; } } var _strange_bids = qob.result.bids.Where(o => o.price > _t.price); if (_strange_bids.Count() > 0) { foreach (var _qox in _strange_bids) { var _aoi = new SOrderBookItem { action = "delete", price = _qox.price, quantity = _qox.quantity, amount = _qox.price * _qox.quantity, count = 1 }; _rqo.result.bids.Add(_aoi); _qox.quantity = 0; } } } qob.sequentialId = _rqo.sequentialId; qob.result.asks.RemoveAll(o => o.quantity == 0); qob.result.bids.RemoveAll(o => o.quantity == 0); } if (_rqo.result.asks.Count + _rqo.result.bids.Count > 0) { await publishOrderbook(_rqo); //_settings.orderbook_count = 0; } return(true); }
public async ValueTask Start(CancellationToken cancelToken) { BMLogger.SNG.WriteO(this, $"processing service start..."); var _processing = Task.Run(async() => { var _last_polling_trade = 0L; while (true) { try { await Task.Delay(0); var _message = (QMessage)null; if (ReceiveQ.TryDequeue(out _message) == false) { var _cancelled = cancelToken.WaitHandle.WaitOne(0); if (_cancelled == true) { break; } await Task.Delay(10); continue; } if (_message.command == "WS") { if (_message.stream == "order") { var _w_orders = JsonConvert.DeserializeObject <List <BMyOrderItem> >(_message.payload ?? ""); var _s_order = new SMyOrders { exchange = _message.exchange, stream = _message.stream, symbol = _message.symbol, action = _message.action, sequentialId = _w_orders.Max(t => t.timestamp), result = _w_orders.Select(o => { return(new SMyOrderItem { orderId = o.orderId ?? "", symbol = o.symbol ?? "", sideType = o.sideType, timestamp = o.timestamp, makerType = MakerType.Maker, orderStatus = o.orderStatus, orderType = o.orderType, quantity = o.quantity, price = o.price, amount = o.amount, filled = o.filled, remaining = o.remaining, workingIndicator = o.workingIndicator, avgPx = o.avgPx.HasValue ? o.avgPx.Value : 0, fee = o.fee, cost = o.cost, count = o.count }); }) .ToList <ISMyOrderItem>() }; await mergeMyOrder(_s_order); } else if (_message.stream == "trade") { var _w_trades = JsonConvert.DeserializeObject <List <BCompleteOrderItem> >(_message.payload ?? ""); var _s_trade = new SCompleteOrders { exchange = _message.exchange, stream = _message.stream, symbol = _message.symbol, action = _message.action, sequentialId = _w_trades.Max(t => t.timestamp), result = _w_trades.Select(t => { return(new SCompleteOrderItem { timestamp = t.timestamp, sideType = t.sideType, price = t.price, quantity = t.quantity }); }) .ToList() }; if (_s_trade.result.Count() > 0) { _last_polling_trade = _s_trade.sequentialId; await mergeCompleteOrder(_s_trade); } } else if (_message.stream == "orderbook") { var _w_orderbooks = JsonConvert.DeserializeObject <List <BOrderBookItem> >(_message.payload ?? ""); var _timestamp = CUnixTime.NowMilli; var _asks = _w_orderbooks.Where(o => o.sideType == SideType.Ask); var _bids = _w_orderbooks.Where(o => o.sideType == SideType.Bid); var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _timestamp, result = new SOrderBook { timestamp = _timestamp, askSumQty = _asks.Sum(o => o.quantity), bidSumQty = _bids.Sum(o => o.quantity), asks = _asks.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = o.quantity * o.price, id = o.id, count = 1 }); }).ToList(), bids = _bids.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = o.quantity * o.price, id = o.id, count = 1 }); }).ToList() } }; await mergeOrderbook(_s_orderbooks); } } else if (_message.command == "AP") { if (_message.stream == "order") { var _w_orders = JsonConvert.DeserializeObject <List <BMyOrderItem> >(_message.payload ?? ""); var _s_order = new SMyOrders { exchange = _message.exchange, stream = _message.stream, symbol = _message.symbol, action = _message.action, sequentialId = _w_orders.Max(t => t.timestamp), result = _w_orders.Select(o => { return(new SMyOrderItem { orderId = o.orderId ?? "", symbol = o.symbol ?? "", sideType = o.sideType, timestamp = o.timestamp, makerType = o.makerType, orderStatus = o.orderStatus, orderType = o.orderType, quantity = o.quantity, price = o.price, amount = o.amount, filled = o.filled, remaining = o.remaining, workingIndicator = o.workingIndicator, avgPx = o.avgPx.HasValue ? o.avgPx.Value : 0, fee = o.fee, cost = o.cost, count = o.count }); }) .ToList <ISMyOrderItem>() }; await mergeMyOrder(_s_order); } else if (_message.stream == "trade") { var _a_trades = JsonConvert.DeserializeObject <List <BCompleteOrderItem> >(_message.payload ?? ""); var _s_trade = new SCompleteOrders { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _a_trades.Max(t => t.timestamp), result = _a_trades.Where(t => t.timestamp > _last_polling_trade).Select(t => { return(new SCompleteOrderItem { timestamp = t.timestamp, sideType = t.sideType, price = t.price, quantity = t.quantity }); }) .ToList() }; if (_s_trade.result.Count() > 0) { _last_polling_trade = _s_trade.sequentialId; await mergeCompleteOrder(_s_trade); } } else if (_message.stream == "orderbook") { var _a_orderbooks = JsonConvert.DeserializeObject <List <BOrderBookItem> >(_message.payload ?? ""); var _timestamp = CUnixTime.NowMilli; var _asks = _a_orderbooks.Where(o => o.sideType == SideType.Ask); var _bids = _a_orderbooks.Where(o => o.sideType == SideType.Bid); var _s_orderbooks = new SOrderBooks { exchange = _message.exchange, symbol = _message.symbol, stream = _message.stream, action = _message.action, sequentialId = _timestamp, result = new SOrderBook { timestamp = _timestamp, askSumQty = _asks.Sum(o => o.quantity), bidSumQty = _bids.Sum(o => o.quantity), asks = _asks.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = o.quantity * o.price, id = o.id, count = 1 }); }).ToList(), bids = _bids.Select(o => { return(new SOrderBookItem { quantity = o.quantity, price = o.price, amount = o.quantity * o.price, id = o.id, count = 1 }); }).ToList() } }; await mergeOrderbook(_s_orderbooks); } } else if (_message.command == "SS") { await snapshotOrderbook(_message.exchange); } #if DEBUG else { BMLogger.SNG.WriteO(this, _message.payload); } #endif if (cancelToken.IsCancellationRequested == true) { break; } } catch (TaskCanceledException) { } catch (Exception ex) { BMLogger.SNG.WriteX(this, ex.ToString()); } } }, cancelToken ); await Task.WhenAll(_processing); BMLogger.SNG.WriteO(this, $"processing service stop..."); }