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); }
public async ValueTask OStart(CancellationToken cancelToken, string symbol) { BNLogger.SNG.WriteO(this, $"polling service start: symbol => {symbol}..."); if (__bnconfig.UsePollingTicker == false) { PollingTasks.Add(Task.Run(async() => { var _client = CreateJsonClient(publicApi.publicClient.ApiUrl); var _o_params = new Dictionary <string, object>(); { _o_params.Add("symbol", symbol.ToUpper()); _o_params.Add("limit", 20); } var _o_request = CreateJsonRequest($"/depth", _o_params); var _last_limit_milli_secs = 0L; while (true) { try { await Task.Delay(0); var _waiting_milli_secs = (CUnixTime.NowMilli - __bnconfig.PollingPrevTime) / __bnconfig.PollingTermTime; if (_waiting_milli_secs == _last_limit_milli_secs) { var _waiting = cancelToken.WaitHandle.WaitOne(0); if (_waiting == true) { break; } await Task.Delay(10); } else { _last_limit_milli_secs = _waiting_milli_secs; // orderbook var _o_json_value = await RestExecuteAsync(_client, _o_request); if (_o_json_value.IsSuccessful && _o_json_value.Content[0] == '{') { var _o_json_data = JsonConvert.DeserializeObject <BAOrderBookItem>(_o_json_value.Content); _o_json_data.symbol = symbol; _o_json_data.lastId = _last_limit_milli_secs; var _orderbook = new BAOrderBook { stream = "orderbook", data = _o_json_data }; var _o_json_content = JsonConvert.SerializeObject(_orderbook); Processing.SendReceiveQ(new QMessage { command = "AP", payload = _o_json_content }); } else { var _http_status = (int)_o_json_value.StatusCode; if (_http_status == 403 || _http_status == 418 || _http_status == 429) { BNLogger.SNG.WriteQ(this, $"request-limit: symbol => {symbol}, https_status => {_http_status}"); var _waiting = cancelToken.WaitHandle.WaitOne(0); if (_waiting == true) { break; } await Task.Delay(1000); // waiting 1 second } } } } catch (TaskCanceledException) { } catch (Exception ex) { BNLogger.SNG.WriteX(this, ex.ToString()); } //finally { //__semaphore.Release(); if (cancelToken.IsCancellationRequested == true) { break; } } var _cancelled = cancelToken.WaitHandle.WaitOne(0); if (_cancelled == true) { break; } } }, cancelToken )); } await Task.WhenAll(PollingTasks); BNLogger.SNG.WriteO(this, $"polling service stopped: symbol => {symbol}..."); }
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); }