Skip to content

Commit 7abe68e

Browse files
committed
Gemini enhance tickers
1 parent 2b8556f commit 7abe68e

File tree

1 file changed

+74
-51
lines changed

1 file changed

+74
-51
lines changed

src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs

Lines changed: 74 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)