@@ -355,93 +355,116 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy
355355 await MakeJsonRequestAsync < JToken > ( "/order/cancel" , null , new Dictionary < string , object > { { "nonce" , nonce } , { "order_id" , orderId } } ) ;
356356 }
357357
358- protected override async Task < IWebSocket > OnGetTickersWebSocketAsync ( Action < IReadOnlyCollection < KeyValuePair < string , ExchangeTicker > > > tickers , params string [ ] marketSymbols )
358+ protected override async Task < IWebSocket > OnGetTickersWebSocketAsync ( Action < IReadOnlyCollection < KeyValuePair < string , ExchangeTicker > > > tickerCallback , params string [ ] marketSymbols )
359359 {
360360 if ( marketSymbols == null || marketSymbols . Length == 0 )
361361 {
362362 marketSymbols = ( await GetMarketSymbolsAsync ( ) ) . ToArray ( ) ;
363363 }
364364 ConcurrentDictionary < string , decimal > volumeDict = new ConcurrentDictionary < string , decimal > ( ) ;
365365 ConcurrentDictionary < string , ExchangeTicker > tickerDict = new ConcurrentDictionary < string , ExchangeTicker > ( ) ;
366- return await ConnectWebSocketAsync ( null , messageCallback : async ( _socket , msg ) =>
366+ static ExchangeTicker GetTicker ( ConcurrentDictionary < string , ExchangeTicker > tickerDict , ExchangeGeminiAPI api , string marketSymbol )
367+ {
368+ return tickerDict . GetOrAdd ( marketSymbol , ( _marketSymbol ) =>
369+ {
370+ ( string baseCurrency , string quoteCurrency ) = api . ExchangeMarketSymbolToCurrenciesAsync ( _marketSymbol ) . Sync ( ) ;
371+ return new ExchangeTicker
372+ {
373+ MarketSymbol = _marketSymbol ,
374+ Volume = new ExchangeVolume
375+ {
376+ BaseCurrency = baseCurrency ,
377+ QuoteCurrency = quoteCurrency
378+ }
379+ } ;
380+ } ) ;
381+ }
382+
383+ static void PublishTicker ( ExchangeTicker ticker , string marketSymbol , ConcurrentDictionary < string , decimal > _volumeDict ,
384+ Action < IReadOnlyCollection < KeyValuePair < string , ExchangeTicker > > > callback )
385+ {
386+ // if we are fully populated...
387+ if ( ticker . Bid > 0m && ticker . Ask > 0m &&
388+ _volumeDict . TryGetValue ( marketSymbol , out decimal tickerVolume ) )
389+ {
390+ ticker . Volume . BaseCurrencyVolume = tickerVolume ;
391+ ticker . Volume . QuoteCurrencyVolume = tickerVolume * ticker . Last ;
392+ var kv = new KeyValuePair < string , ExchangeTicker > ( marketSymbol , ticker ) ;
393+ callback ( new KeyValuePair < string , ExchangeTicker > [ ] { kv } ) ;
394+ }
395+ }
396+
397+ return await ConnectWebSocketAsync ( null , messageCallback : ( _socket , msg ) =>
367398 {
368399 JToken token = JToken . Parse ( msg . ToStringFromUTF8 ( ) ) ;
369400 if ( token [ "result" ] . ToStringInvariant ( ) == "error" )
370401 {
371402 // {{ "result": "error", "reason": "InvalidJson"}}
372403 Logger . Info ( token [ "reason" ] . ToStringInvariant ( ) ) ;
404+ return Task . CompletedTask ;
373405 }
374- else if ( token [ "type" ] . ToStringInvariant ( ) == "candles_1d_updates" )
375- {
376- JToken changesToken = token [ "changes" ] ;
377- string marketSymbol = token [ "symbol" ] . ToStringInvariant ( ) ;
378- if ( changesToken != null )
379- {
380- if ( changesToken . FirstOrDefault ( ) is JArray candleArray )
381- {
382- decimal volume = candleArray [ 5 ] . ConvertInvariant < decimal > ( ) ;
383- volumeDict [ marketSymbol ] = volume ;
384- }
385- }
386- }
387- else if ( token [ "type" ] . ToStringInvariant ( ) == "l2_updates" )
406+ string type = token [ "type" ] . ToStringInvariant ( ) ;
407+ switch ( type )
388408 {
389- // fetch the active ticker metadata for this symbol
390- string marketSymbol = token [ "symbol" ] . ToStringInvariant ( ) ;
391- ExchangeTicker ticker = tickerDict . GetOrAdd ( marketSymbol , ( _marketSymbol ) =>
409+ case "candles_1d_updates" :
392410 {
393- ( string baseCurrency , string quoteCurrency ) = ExchangeMarketSymbolToCurrenciesAsync ( marketSymbol ) . Sync ( ) ;
394- return new ExchangeTicker
411+ JToken changesToken = token [ "changes" ] ;
412+ if ( changesToken != null )
395413 {
396- MarketSymbol = _marketSymbol ,
397- Volume = new ExchangeVolume
414+ string marketSymbol = token [ "symbol" ] . ToStringInvariant ( ) ;
415+ if ( changesToken . FirstOrDefault ( ) is JArray candleArray )
398416 {
399- BaseCurrency = baseCurrency ,
400- QuoteCurrency = quoteCurrency
417+ decimal volume = candleArray [ 5 ] . ConvertInvariant < decimal > ( ) ;
418+ volumeDict [ marketSymbol ] = volume ;
419+ ExchangeTicker ticker = GetTicker ( tickerDict , this , marketSymbol ) ;
420+ PublishTicker ( ticker , marketSymbol , volumeDict , tickerCallback ) ;
401421 }
402- } ;
403- } ) ;
404-
405- // fetch the last bid/ask/last prices
406- if ( token [ "changes" ] is JArray changesToken )
422+ }
423+ } break ;
424+ case "l2_updates" :
407425 {
426+ // fetch the last bid/ask/last prices
408427 if ( token [ "trades" ] is JArray tradesToken )
409428 {
429+ string marketSymbol = token [ "symbol" ] . ToStringInvariant ( ) ;
430+ ExchangeTicker ticker = GetTicker ( tickerDict , this , marketSymbol ) ;
410431 JToken lastSell = tradesToken . FirstOrDefault ( t => t [ "side" ] . ToStringInvariant ( ) . Equals ( "sell" , StringComparison . OrdinalIgnoreCase ) ) ;
411432 if ( lastSell != null )
412433 {
413434 decimal lastTradePrice = lastSell [ "price" ] . ConvertInvariant < decimal > ( ) ;
414- ticker . Last = ticker . Bid = lastTradePrice ;
415- if ( ticker . Bid > ticker . Ask )
416- {
417- // out of sync, reset ask
418- ticker . Ask = 0m ;
419- }
435+ ticker . Bid = ticker . Last = lastTradePrice ;
420436 }
421437 JToken lastBuy = tradesToken . FirstOrDefault ( t => t [ "side" ] . ToStringInvariant ( ) . Equals ( "buy" , StringComparison . OrdinalIgnoreCase ) ) ;
422438 if ( lastBuy != null )
423439 {
424440 decimal lastTradePrice = lastBuy [ "price" ] . ConvertInvariant < decimal > ( ) ;
425- ticker . Ask = lastTradePrice ;
426- if ( ticker . Ask < ticker . Bid )
427- {
428- // out of sync, reset bid
429- ticker . Bid = 0m ;
430- }
441+ ticker . Ask = ticker . Last = lastTradePrice ;
431442 }
432- }
433443
434- // if we are fully populated...
435- if ( ticker . Bid > 0m && ticker . Ask > 0m &&
436- volumeDict . TryGetValue ( marketSymbol , out decimal tickerVolume ) )
444+ PublishTicker ( ticker , marketSymbol , volumeDict , tickerCallback ) ;
445+ }
446+ } break ;
447+ case "trade" :
448+ {
449+ //{ "type":"trade","symbol":"ETHUSD","event_id":35899433249,"timestamp":1619191314701,"price":"2261.65","quantity":"0.010343","side":"buy"}
450+
451+ // fetch the active ticker metadata for this symbol
452+ string marketSymbol = token [ "symbol" ] . ToStringInvariant ( ) ;
453+ ExchangeTicker ticker = GetTicker ( tickerDict , this , marketSymbol ) ;
454+ string side = token [ "side" ] . ToStringInvariant ( ) ;
455+ decimal price = token [ "price" ] . ConvertInvariant < decimal > ( ) ;
456+ if ( side == "sell" )
437457 {
438- ticker . Volume . BaseCurrencyVolume = tickerVolume ;
439- ticker . Volume . QuoteCurrencyVolume = tickerVolume * ticker . Last ;
440- var kv = new KeyValuePair < string , ExchangeTicker > ( marketSymbol , ticker ) ;
441- tickers ( new KeyValuePair < string , ExchangeTicker > [ ] { kv } ) ;
458+ ticker . Bid = ticker . Last = price ;
442459 }
443- }
460+ else
461+ {
462+ ticker . Ask = ticker . Last = price ;
463+ }
464+ PublishTicker ( ticker , marketSymbol , volumeDict , tickerCallback ) ;
465+ } break ;
444466 }
467+ return Task . CompletedTask ;
445468 } , connectCallback : async ( _socket ) =>
446469 {
447470 await _socket . SendMessageAsync ( new
0 commit comments