mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 22:25:28 +01:00
107 lines
23 KiB
C#
107 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Rating;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace BTCPayServer.Services.Rates
|
|
{
|
|
public class CoinGeckoRateProvider : IRateProvider
|
|
{
|
|
public const string CoinGeckoName = "coingecko";
|
|
// https://api.coingecko.com/api/v3/exchanges/list
|
|
internal static readonly string SupportedExchanges = "[{\"id\":\"aave\",\"name\":\"Aave\"},{\"id\":\"aax\",\"name\":\"AAX\"},{\"id\":\"aax_futures\",\"name\":\"AAX Futures\"},{\"id\":\"abcc\",\"name\":\"ABCC\"},{\"id\":\"abit\",\"name\":\"Abit\"},{\"id\":\"acdx\",\"name\":\"ACDX\"},{\"id\":\"acdx_futures\",\"name\":\"ACDX Futures\"},{\"id\":\"aex\",\"name\":\"AEX\"},{\"id\":\"allbit\",\"name\":\"Allbit\"},{\"id\":\"allcoin\",\"name\":\"Allcoin\"},{\"id\":\"alpha_five\",\"name\":\"Alpha5\"},{\"id\":\"alterdice\",\"name\":\"AlterDice\"},{\"id\":\"altilly\",\"name\":\"Altilly\"},{\"id\":\"altmarkets\",\"name\":\"Altmarkets\"},{\"id\":\"anyswap\",\"name\":\"Anyswap\"},{\"id\":\"aprobit\",\"name\":\"Aprobit\"},{\"id\":\"artisturba\",\"name\":\"Artis Turba\"},{\"id\":\"atomars\",\"name\":\"Atomars\"},{\"id\":\"b2bx\",\"name\":\"B2BX\"},{\"id\":\"bakeryswap\",\"name\":\"Bakeryswap\"},{\"id\":\"bakkt\",\"name\":\"Bakkt\"},{\"id\":\"balancer\",\"name\":\"Balancer\"},{\"id\":\"bamboo_relay\",\"name\":\"Bamboo Relay\"},{\"id\":\"bancor\",\"name\":\"Bancor Network\"},{\"id\":\"bankera\",\"name\":\"Bankera\"},{\"id\":\"basefex\",\"name\":\"BaseFEX\"},{\"id\":\"bcex\",\"name\":\"BCEX\"},{\"id\":\"beaxy\",\"name\":\"Beaxy\"},{\"id\":\"bepswap\",\"name\":\"BepSwap\"},{\"id\":\"bgogo\",\"name\":\"Bgogo\"},{\"id\":\"bibo\",\"name\":\"Bibo\"},{\"id\":\"bibox\",\"name\":\"Bibox\"},{\"id\":\"bibox_futures\",\"name\":\"Bibox (Futures)\"},{\"id\":\"biconomy\",\"name\":\"Biconomy\"},{\"id\":\"bidesk\",\"name\":\"Bidesk\"},{\"id\":\"bigone\",\"name\":\"BigONE\"},{\"id\":\"bigone_futures\",\"name\":\"BigONE Futures\"},{\"id\":\"biki\",\"name\":\"BiKi\"},{\"id\":\"biki_futures\",\"name\":\"Biki (Futures)\"},{\"id\":\"bilaxy\",\"name\":\"Bilaxy\"},{\"id\":\"binance\",\"name\":\"Binance\"},{\"id\":\"binance_dex\",\"name\":\"Binance DEX\"},{\"id\":\"binance_dex_mini\",\"name\":\"Binance DEX (Mini)\"},{\"id\":\"binance_futures\",\"name\":\"Binance (Futures)\"},{\"id\":\"binance_jersey\",\"name\":\"Binance Jersey\"},{\"id\":\"binance_us\",\"name\":\"Binance US\"},{\"id\":\"bione\",\"name\":\"BiONE\"},{\"id\":\"birake\",\"name\":\"Birake\"},{\"id\":\"bisq\",\"name\":\"Bisq\"},{\"id\":\"bit2c\",\"name\":\"Bit2c\"},{\"id\":\"bitalong\",\"name\":\"Bitalong\"},{\"id\":\"bitbank\",\"name\":\"Bitbank\"},{\"id\":\"bitbay\",\"name\":\"BitBay\"},{\"id\":\"bitbns\",\"name\":\"BitBNS\"},{\"id\":\"bitbox\",\"name\":\"BITFRONT\"},{\"id\":\"bitci\",\"name\":\"Bitci\"},{\"id\":\"bitcoin_com\",\"name\":\"Bitcoin.com Exchange\"},{\"id\":\"bit_com_futures\",\"name\":\"Bit.com\"},{\"id\":\"bitcratic\",\"name\":\"Bitcratic\"},{\"id\":\"bitex\",\"name\":\"Bitex.la\"},{\"id\":\"bitexbook\",\"name\":\"BITEXBOOK\"},{\"id\":\"bitexlive\",\"name\":\"Bitexlive\"},{\"id\":\"bitfex\",\"name\":\"Bitfex\"},{\"id\":\"bitfinex\",\"name\":\"Bitfinex\"},{\"id\":\"bitfinex_futures\",\"name\":\"Bitfinex (Futures)\"},{\"id\":\"bitflyer\",\"name\":\"bitFlyer\"},{\"id\":\"bitflyer_futures\",\"name\":\"Bitflyer (Futures)\"},{\"id\":\"bitforex\",\"name\":\"Bitforex\"},{\"id\":\"bitforex_futures\",\"name\":\"Bitforex (Futures)\"},{\"id\":\"bitget\",\"name\":\"Bitget\"},{\"id\":\"bitget_futures\",\"name\":\"Bitget Futures\"},{\"id\":\"bithash\",\"name\":\"BitHash\"},{\"id\":\"bitholic\",\"name\":\"Bithumb Singapore\"},{\"id\":\"bithumb\",\"name\":\"Bithumb\"},{\"id\":\"bithumb_futures\",\"name\":\"Bithumb (Futures)\"},{\"id\":\"bithumb_global\",\"name\":\"Bithumb Global\"},{\"id\":\"bitinfi\",\"name\":\"Bitinfi\"},{\"id\":\"bitkonan\",\"name\":\"BitKonan\"},{\"id\":\"bitkub\",\"name\":\"Bitkub\"},{\"id\":\"bitmart\",\"name\":\"BitMart\"},{\"id\":\"bitmax\",\"name\":\"BitMax\"},{\"id\":\"bitmax_futures\",\"name\":\"BitMax (Futures)\"},{\"id\":\"bitmesh\",\"name\":\"Bitmesh\"},{\"id\":\"bitmex\",\"name\":\"BitMEX\"},{\"id\":\"bitoffer\",\"name\":\"Bitoffer\"},{\"id\":\"bitonbay\",\"name\":\"BitOnBay\"},{\"id\":\"bitopro\",\"name\":\"BitoPro\"},{\"id\":\"bitpanda\",\"name\":\"Bitpanda Pro\"},{\"id\":\"bitrabbit\",\"name\":\"BitRabbit\"},{\"id\":\"bitrue\",\"name\":\"Bitrue\"},{\"id\":\"bits_blockchain\",\"name\":\"Bits Blockchain\"},{\"id\":\"bitsdaq\",\"name\":\"Bitsdaq\"},{\"id\":\"bitso\",\"name\":\"Bitso\"},{\"id\":\"bitsonic\",\"name\":\"Bitsonic\"},{\"id\":\"bitstamp\",\"name\":\"Bitstamp\"},{\"id\":\"bitsten\",\"name\":\"Bitsten\"},{\"id\":\"bitstorage\",\"name\":\"BitStorage\"},{\"id\":\"bittrex\",\"name\":\"Bittrex\"},{\"id\":\"bitubu\",\"name\":\"Bitubu Exchange\"},{\"id\":\"bit_z\",\"name\":\"BitZ\"},{\"id\":\"bitz_futures\",\"name\":\"BitZ (Futures)\"},{\"id\":\"bkex\",\"name\":\"BKEX\"},{\"id\":\"bleutrade\",\"name\":\"bleutrade\"},{\"id\":\"blockchain_com\",\"name\":\"Blockchain.com\"},{\"id\":\"blockonix\",\"name\":\"Blockonix\"},{\"id\":\"boa\",\"name\":\"BOA Exchange\"},{\"id\":\"braziliex\",\"name\":\"Braziliex\"},{\"id\":\"bscswap\",\"name\":\"BSCswap\"},{\"id\":\"btc_alpha\",\"name\":\"BTC-Alpha\"},{\"id\":\"btcbox\",\"name\":\"BTCBOX\"},{\"id\":\"btcc\",\"name\":\"BTCC\"},{\"id\":\"btc_exchange\",\"name\":\"Btc Exchange\"},{\"id\":\"btcmarkets\",\"name\":\"BTCMarkets\"},{\"id\":\"btcmex\",\"name\":\"BTCMEX\"},{\"id\":\"btcnext\",\"name\":\"BTCNEXT\"},{\"id\":\"btcsquare\",\"name\":\"BTCSquare\"},{\"id\":\"btc_trade_ua\",\"name\":\"BTC Trade UA\"},{\"id\":\"btcturk\",\"name\":\"BtcTurk PRO\"},{\"id\":\"btse\",\"name\":\"BTSE\"},{\"id\":\"btse_futures\",\"name\":\"BTSE (Futures)\"},{\"id\":\"burgerswap\",\"name\":\"BurgerSwap\"},{\"id\":\"buyucoin\",\"name\":\"BuyUcoin\"},{\"id\":\"bvnex\",\"name\":\"Bvnex\"},{\"id\":\"bw\",\"name\":\"BW.com\"},{\"id\":\"bybit\",\"name\":\"Bybit\"},{\"id\":\"c2cx\",\"name\":\"C2CX\"},{\"id\":\"catex\",\"name\":\"Catex\"},{\"id\":\"cbx\",\"name\":\"CBX\"},{\"id\":\"ccex\",\"name\":\"C-CEX\"},{\"id\":\"cex\",\"name\":\"CEX.IO\"},{\"id\":\"chainex\",\"name\":\"ChainEX\"},{\"id\":\"changelly\",\"name\":\"Changelly PRO\"},{\"id\":\"chiliz\",\"name\":\"Chiliz\"},{\"id\":\"citex\",\"name\":\"CITEX\"},{\"id\":\"cme_futures\",\"name\":\"CME Bitcoin Futures\"},{\"id\":\"coinall\",\"name\":\"CoinAll\"},{\"id\":\"coinasset\",\"name\":\"CoinAsset\"},{\"id\":\"coinbene\",\"name\":\"CoinBene\"},{\"id\":\"coinbig\",\"name\":\"COINBIG\"},{\"id\":\"coinbit\",\"name\":\"Coinbit\"},{\"id\":\"coincheck\",\"name\":\"Coincheck\"},{\"id\":\"coindcx\",\"name\":\"CoinDCX\"},{\"id\":\"coindeal\",\"name\":\"Coindeal\"},{\"id\":\"coindirect\",\"name\":\"CoinDirect\"},{\"id\":\"coineal\",\"name\":\"Coineal\"},{\"id\":\"coin_egg\",\"name\":\"CoinEgg\"},{\"id\":\"coinex\",\"name\":\"CoinEx\"},{\"id\":\"coinfalcon\",\"name\":\"Coinfalcon\"},{\"id\":\"coinfield\",\"name\":\"Coinfield\"},{\"id\":\"coinflex\",\"name\":\"CoinFLEX\"},{\"id\":\"coinflex_futures\",\"name\":\"CoinFLEX (Futures)\"},{\"id\":\"coinfloor\",\"name\":\"Coinfloor\"},{\"id\":\"coingi\",\"name\":\"Coingi\"},{\"id\":\"coinhe\",\"name\":\"CoinHe\"},{\"id\":\"coinhub\",\"name\":\"Coinhub\"},{\"id\":\"coinjar\",\"name\":\"CoinJar Exchange\"},{\"id\":\"coinlim\",\"name\":\"Coinlim\"},{\"id\":\"coinlist\",\"name\":\"Coinlist\"},{\"id\":\"coinmargin\",\"name\":\"CoinMargin\"},{\"id\":\"coin_metro\",\"name\":\"Coinmetro\"},{\"id\":\"coinone\",\"name\":\"Coinone\"},{\"id\":\"coinpark\",\"name\":\"Coinpark\"},{\"id\":\"coinplace\",\"name\":\"Coinplace\"},{\"id\":\"coinsbank\",\"name\":\"Coinsbank\"},{\"id\":\"coinsbit\",\"name\":\"Coinsbit\"},{\"id\":\"coinsuper\",\"name\":\"Coinsuper\"},{\"id\":\"cointiger\",\"name\":\"CoinTiger\"},{\"id\":\"cointiger_futures\",\"name\":\"CoinTiger (Futures)\"},{\"id\":\"coinxpro\",\"name\":\"COINX.PRO\"},{\"id\":\"coinzo\",\"name\":\"Coinzo\"},{\"id\":\"compound_finance\",\"name\":\"Compound Finance\"},{\"id\":\"c_patex\",\"name\":\"C-Patex\"},{\"id\":\"cpdax\",\"name\":\"CPDAX\"},{\"id\":\"cream_swap\",\"name\":\"Cream Swap (v2)\"},{\"id\":\"cream_swap_v1\",\"name\":\"Cream Swap (v1)\"},{\"id\":\"crex24\",\"name\":\"CREX24\"},{\"id\":\"crxzone\",\"name\":\"CRXzone\"},{\"id\":\"cryptaldash\",\"name\":\"CryptalDash\"},{\"id\":\"cryptex\",\"name\":\"Cryptex\"},{\"id\":\"cryptlocex\",\"name\":\"Cryptlocex\"},{\"id\":\"crypto_com\",\"name\":\"Crypto.com\"},{\"id\":\"cryptology\",\"name\":\"Cryptology\"},{\"id\":\"crytrex\",\"name\":\"CryTrEx\"},{\"id\":\"c_trade\",\"name\":\"C-Trade\"},{\"id\":\"currency\",\"name\":\"Currency.com\"},{\"id\":\"curve\",\"name\":\"Curve Finance\"},{\"id\":\"cybex\",\"name\":\"Cybex DEX\"},{\"id\":\"darb_finance\",\"name\":\"Darb Finance\"},{\"id\":\"daybit\",\"name\":\"Daybit\"},{\"id\":\"dcoin\",\"name\":\"Dcoin\"},{\"id\":\"ddex\",\"name\":\"DDEX\"},{\"id\":\"decoin\",\"name\":\"Decoin\"},{\"id\":\"delta_futures\",\"name\":\"Delta Exchange\"},{\"id\":\"dem_exchange\",\"name\":\"Demex\"},{\"id\":\"deribit\",\"name\":\"Deribit\"},{\"id\":\"deversifi\",\"name\":\"Deversifi \"},{\"id\":\"dex_blue\",\"name\":\"dex.blue\"},{\"id\":\"dextrade\",\"name\":\"Dex-Trade\"},{\"id\":\"digifinex\",\"name\":\"Digifinex\"},{\"id\":\"dobitrade\",\"name\":\"Dobitrade\"},{\"id\":\"dodo\",\"name\":\"DODO\"},{\"id\":\"dolomite\",\"name\":\"Dolomite\"},{\"id\":\"dove_wallet\",\"name\":\"Dove Wallet\"},{\"id\":\"dragonex\",\"name\":\"DragonEx\"},{\"id\":\"dsx\",\"name\":\"DSX Global\"},{\"id\":\"duedex\",\"name\":\"DueDEX\"},{\"id\":\"dydx\",\"name\":\"dYdX\"},{\"id\":\"dydx_perpetual_l1\",\"name\":\"dYdX Perpetual (L1)\"},{\"id\":\"ecxx\",\"name\":\"Ecxx\"},{\"id\":\"elitex\",\"name\":\"Elitex\"},{\"id\":\"emirex\",\"name\":\"Emirex\"},{\"id\":\"eterbase\",\"name\":\"Eterbase\"},{\"id\":\"etherflyer\",\"name\":\"EtherFlyer\"},{\"id\":\"ethex\",\"name\":\"Ethex\"},{\"id\":\"etorox\",\"name\":\"eToroX\"},{\"id\":\"everbloom\",\"name\":\"Everbloom\"},{\"id\":\"exmarkets\",\"name\":\"ExMarkets\"},{\"id\":\"exmo\",\"name\":\"EXMO\"},{\"id\":\"exnce\",\"name\":\"EXNCE\"},{\"id\":\"exrates\",\"name\":\"Exrates\"},{\"id\":\"exx\",\"name\":\"EXX\"},{\"id\":\"fatbtc\",\"name\":\"FatBTC\"},{\"id\":\"fex\",\"name\":\"FEX\"},{\"id\":\"financex\",\"name\":\"FinanceX\"},{\"id\":\"finexbox\",\"name\":\"FinexBox\"},{\"id\":\"floatsv\",\"name\":\"Float SV\"},{\"id\":\"forkdelta\",\"name\":\"ForkDelta\"},{\"id\":\"freiexchange\",\"name\":\"Freiexchange\"},{\"id\":\"ftx\",\"name\":\"FTX (Derivatives)\"},{\"id\":\"ftx_spot\",\"name\":\"FTX\"},{\"id\":\"ftx_us\",\"name\":\"FTX.US\"},{\"id\":\"futureswap\",\"name\":\"Futureswap\"},{\"id\":\"gate\",\"name\":\"Gate.io\"},{\"id\":\"gate_futures\",\"name\":\"Gate.io (Futures)\"},{\"id\":\"gbx\",\"name\":\"Global Blockchain Exchange\"},{\"id\":\"gdac\",\"name\":\"GDAC\"},{\"id\":\"gdax\",\"name\":\"Coinbase Pro\"},{\"id\":\"gemini\",\"name\":\"Gemini\"},{\"id\":\"getbtc\",\"name\":\"GetBTC\"},{\"id\":\"gmo_japan\",\"name\":\"GMO Japan\"},{\"id\":\"gmo_japan_futures\",\"name\":\"GMO Japan (Futures)\"},{\"id\":\"gobaba\",\"name\":\"Gobaba\"},{\"id\":\"goku\",\"name\":\"GokuMarket\"},{\"id\":\"gopax\",\"name\":\"GoPax\"},{\"id\":\"graviex\",\"name\":\"Graviex\"},{\"id\":\"hanbitco\",\"name\":\"Hanbitco\"},{\"id\":\"hbtc\",\"name\":\"HBTC\"},{\"id\":\"hbtc_futures\",\"name\":\"HBTC (Futures)\"},{\"id\":\"hb_top\",\"name\":\"Hb.top\"},{\"id\":\"hitbtc\",\"name\":\"HitBTC\"},{\"id\":\"honeyswap\",\"name\":\"Honeyswap\"},{\"id\":\"hoo\",\"name\":\"Hoo.com\"},{\"id\":\"hopex\",\"name\":\"Hopex\"},{\"id\":\"hotbit\",\"name\":\"Hotbit\"},{\"id\":\"hpx\",\"name\":\"HPX\"},{\"id\":\"hubi\",\"name\":\"Hubi\"},{\"id\":\"huobi\",\"name\":\"Huobi Global\"},{\"id\":\"huobi_dm\",\"name\":\"Huobi Futures\"},{\"id\":\"huobi_id\",\"name\":\"Huobi Indonesia\"},{\"id\":\"huobi_japan\",\"name\":\"Huobi Japan\"},{\"id\":\"huobi_korea\",\"name\":\"Huobi Korea\"},{\"id\":\"huobi_thailand\",\"name\":\"Huobi Thailand\"},{\"id\":\"ice3x\",\"name\":\"Ice3x\"},{\"id\":\"idcm\",\"name\":\"IDCM\"},{\"id\":\"idex\",\"name\":\"Idex\"},{\"id\":\"incorex\",\"name\":\"IncoreX\"},{\"id\":\"independent_reserve\",\"name\":\"Independent Reserve\"},{\"id\":\"indodax\",\"name\":\"Indodax\"},{\"id\":\"infinity_coin\",\"name\":\"Infinity Coin\"},{\"id\":\"instantbitex\",\"name\":\"Instant Bitex\"},{\"id\":\"iqfinex\",\"name\":\"IQFinex\"},{\"id\":\"itbit\",\"name\":\"itBit\"},{\"id\":\"jex\",\"name\":\"Binance JEX\"},{\"id\":\"jex_futures\",\"name\":\"Binance JEX (Futures)\"},{\"id\":\"joyso\",\"name\":\"Joyso\"},{\"id\":\"julswap\",\"name\":\"Julswap\"},{\"id\":\"justswap\",\"name\":\"JustSwap\"},{\"id\":\"kkcoin\",\"name\":\"KKCoin\"},{\"id\":\"k_kex\",\"name\":\"KKEX\"},{\"id\":\"korbit\",\"name\":\"Korbit\"},{\"id\":\"kraken\",\"name\":\"Kraken\"},{\"id\":\"kraken_futures\",\"name\":\"Kraken (Futures)\"},{\"id\":\"kucoin\",\"name\":\"KuCoin\"},{\"id\":\"kumex\",\"name\":\"KuCoin Futures\"},{\"id\":\"kuna\",\"name\":\"Kuna Exchange\"},{\"id\":\"kyber_network\",\"name\":\"Kyber Network\"},{\"id\":\"lakebtc\",\"name\":\"LakeBTC\"},{\"id\":\"latoken\",\"name\":\"LATOKEN\"},{\"id\":\"lbank\",\"name\":\"LBank\"},{\"id\":\"leverj\",\"name\":\"Leverj\"},{\"id\":\"linkswap\",\"name\":\"Linkswap\"},{\"id\":\"liquid_derivatives\",\"name\":\"Liquid Perpetuals\"},{\"id\":\"localtrade\",\"name\":\"LocalTrade\"},{\"id\":\"loopring\",\"name\":\"Loopring\"},{\"id\":\"loopring_amm\",\"name\":\"Loopring AMM\"},{\"id\":\"luaswap\",\"name\":\"Luaswap\"},{\"id\":\"lucent\",\"name\":\"Lucent\"},{\"id\":\"lukki\",\"name\":\"Lukki\"},{\"id\":\"luno\",\"name\":\"Luno\"},{\"id\":\"lykke\",\"name\":\"Lykke\"},{\"id\":\"max_maicoin\",\"name\":\"Max Maicoin\"},{\"id\":\"mcdex\",\"name\":\"MCDEX\"},{\"id\":\"mdex\",\"name\":\"Mdex\"},{\"id\":\"mercado_bitcoin\",\"name\":\"Mercado Bitcoin\"},{\"id\":\"mercatox\",\"name\":\"Mercatox\"},{\"id\":\"mercuriex\",\"name\":\"MercuriEx\"},{\"id\":\"mesa\",\"name\":\" Gnosis Protocol\"},{\"id\":\"mirror\",\"name\":\"Mirror\"},{\"id\":\"mooniswap\",\"name\":\"Mooniswap\"},{\"id\":\"multi\",\"name\":\"Multi.io\"},{\"id\":\"mxc\",\"name\":\"MXC\"},{\"id\":\"mxc_futures\",\"name\":\"MXC (Futures)\"},{\"id\":\"mycoinstory\",\"name\":\"MyCoinStory\"},{\"id\":\"namebase\",\"name\":\"Namebase\"},{\"id\":\"nami_exchange\",\"name\":\"Nami.Exchange\"},{\"id\":\"nanu_exchange\",\"name\":\"Nanu Exchange\"},{\"id\":\"narkasa\",\"name\":\"Narkasa\"},{\"id\":\"nash\",\"name\":\"Nash\"},{\"id\":\"neblidex\",\"name\":\"Neblidex\"},{\"id\":\"negociecoins\",\"name\":\"Negociecoins\"},{\"id\":\"neraex\",\"name\":\"Neraex\"},{\"id\":\"newdex\",\"name\":\"Newdex\"},{\"id\":\"nexus_mutual\",\"name\":\"Nexus Mutual\"},{\"id\":\"nice_hash\",\"name\":\"NiceHash\"},{\"id\":\"nlexch\",\"name\":\"NLexch\"},{\"id\":\"nominex\",\"name\":\"Nominex\"},{\"id\":\"novadax\",\"name\":\"NovaDAX\"},{\"id\":\"oasis_trade\",\"name\":\"OasisDEX\"},{\"id\":\"oceanex\",\"name\":\"Oceanex\"},{\"id\":\"okcoin\",\"name\":\"OKCoin\"},{\"id\":\"okex\",\"name\":\"OKEx\"},{\"id\":\"okex_korea\",\"name\":\"OKEx Korea\"},{\"id\":\"okex_swap\",\"name\":\"OKEx (Futures)\"},{\"id\":\"omgfin\",\"name\":\"Omgfin\"},{\"id\":\"omnitrade\",\"name\":\"OmniTrade\"},{\"id\":\"one_inch\",\"name\":\"1inch\"},{\"id\":\"one_inch_liquidity_protocol\",\"name\":\"1inch Liquidity Protocol\"},{\"id\":\"orderbook\",\"name\":\"Orderbook.io\"},{\"id\":\"otcbtc\",\"name\":\"OTCBTC\"},{\"id\":\"ovex\",\"name\":\"Ovex\"},{\"id\":\"p2pb2b\",\"name\":\"P2PB2B\"},{\"id\":\"pancakeswap\",\"name\":\"PancakeSwap\"},{\"id\":\"pangolin\",\"name\":\"Pangolin\"},{\"id\":\"paraswap\",\"name\":\"Paraswap\"},{\"id\":\"paribu\",\"name\":\"Paribu\"},{\"id\":\"paroexchange\",\"name\":\"Paro Exchange\"},{\"id\":\"paymium\",\"name\":\"Paymium\"},{\"id\":\"perpetual_protocol\",\"name\":\"Perpetual protocol\"},{\"id\":\"phemex\",\"name\":\"Phemex\"},{\"id\":\"phemex_futures\",\"name\":\"Phemex (Futures)\"},{\"id\":\"poloniex\",\"name\":\"Poloniex\"},{\"id\":\"poloniex_futures\",\"name\":\"Poloniex Futures\"},{\"id\":\"polyient_dex\",\"name\":\"Polyient Dex\"},{\"id\":\"prime_xbt\",\"name\":\"Prime XBT\"},{\"id\":\"probit\",\"name\":\"ProBit\"},{\"id\":\"qtrade\",\"name\":\"qTrade\"},{\"id\":\"quickswap\",\"name\":\"Quickswap\"},{\"id\":\"quoine\",\"name\":\"Liquid\"},{\"id\":\"radar_relay\",\"name\":\"Radar Relay\"},{\"id\":\"resfinex\",\"name\":\"Resfinex\"},{\"id\":\"rfinex\",\"name\":\"Rfinex\"},{\"id\":\"safe_trade\",\"name\":\"SafeTrade\"},{\"id\":\"sakeswap\",\"name\":\"SakeSwap\"},{\"id\":\"sashimiswap\",\"name\":\"Sashimiswap\"},{\"id\":\"satoexchange\",\"name\":\"SatoExchange\"},{\"id\":\"saturn_network\",\"name\":\"Saturn Network\"},{\"id\":\"secondbtc\",\"name\":\"SecondBTC\"},{\"id\":\"serum_dex\",\"name\":\"Serum DEX\"},{\"id\":\"serumswap\",\"name\":\"SerumSwap\"},{\"id\":\"shortex\",\"name\":\"Shortex\"},{\"id\":\"simex\",\"name\":\"Simex\"},{\"id\":\"sinegy\",\"name\":\"SINEGY\"},{\"id\":\"sistemkoin\",\"name\":\"Sistemkoin\"},{\"id\":\"six_x\",\"name\":\"6x\"},{\"id\":\"south_xchange\",\"name\":\"SouthXchange\"},{\"id\":\"stake_cube\",\"name\":\"StakeCube Exchange\"},{\"id\":\"stellar_term\",\"name\":\"StellarTerm\"},{\"id\":\"stocks_exchange\",\"name\":\"STEX\"},{\"id\":\"stormgain\",\"name\":\"Stormgain\"},{\"id\":\"stormgain_futures\",\"name\":\"Stormgain Futures\"},{\"id\":\"sushiswap\",\"name\":\"Sushiswap\"},{\"id\":\"swiftex\",\"name\":\"Swiftex\"},{\"id\":\"switcheo\",\"name\":\"Switcheo\"},{\"id\":\"synthetix\",\"name\":\"Synthetix Exchange\"},{\"id\":\"tdax\",\"name\":\"Satang Pro\"},{\"id\":\"therocktrading\",\"name\":\"TheRockTrading\"},{\"id\":\"thodex\",\"name\":\"Thodex\"},{\"id\":\"tidebit\",\"name\":\"Tidebit\"},{\"id\":\"tidex\",\"name\":\"Tidex\"},{\"id\":\"tokenize\",\"name\":\"Tokenize\"},{\"id\":\"tokenlon\",\"name\":\"Tokenlon\"},{\"id\":\"tokenomy\",\"name\":\"Tokenomy\"},{\"id\":\"token_sets\",\"name\":\"TokenSets\"},{\"id\":\"tokens_net\",\"name\":\"TokensNet\"},{\"id\":\"toko_crypto\",\"name\":\"TokoCrypto\"},{\"id\":\"tokok\",\"name\":\"TOKOK\"},{\"id\":\"tokpie\",\"name\":\"Tokpie\"},{\"id\":\"tomodex\",\"name\":\"TomoDEX\"},{\"id\":\"topbtc\",\"name\":\"TopBTC\"},{\"id\":\"trade_ogre\",\"name\":\"TradeOgre\"},{\"id\":\"tron_trade\",\"name\":\"TronTrade\"},{\"id\":\"trx_market\",\"name\":\"PoloniDEX\"},{\"id\":\"txbit\",\"name\":\"Txbit\"},{\"id\":\"uniswap\",\"name\":\"Uniswap (v2)\"},{\"id\":\"uniswap_v1\",\"name\":\"Uniswap (v1)\"},{\"id\":\"unnamed\",\"name\":\"Unnamed\"},{\"id\":\"upbit\",\"name\":\"Upbit\"},{\"id\":\"upbit_indonesia\",\"name\":\"Upbit Indonesia \"},{\"id\":\"value_liquid\",\"name\":\"Value Liquid\"},{\"id\":\"vb\",\"name\":\"VB\"},{\"id\":\"vcc\",\"name\":\"VCC Exchange\"},{\"id\":\"vebitcoin\",\"name\":\"Vebitcoin\"},{\"id\":\"velic\",\"name\":\"Velic\"},{\"id\":\"vindax\",\"name\":\"Vindax\"},{\"id\":\"vinex\",\"name\":\"Vinex\"},{\"id\":\"virgox\",\"name\":\"Virgox\"},{\"id\":\"vitex\",\"name\":\"ViteX\"},{\"id\":\"waves\",\"name\":\"Waves.Exchange\"},{\"id\":\"wazirx\",\"name\":\"WazirX\"},{\"id\":\"whale_ex\",\"name\":\"WhaleEx\"},{\"id\":\"whitebit\",\"name\":\"WhiteBIT\"},{\"id\":\"xcoex\",\"name\":\"XCOEX\"},{\"id\":\"xfutures\",\"name\":\"xFutures\"},{\"id\":\"xt\",\"name\":\"XT\"},{\"id\":\"yobit\",\"name\":\"YoBit\"},{\"id\":\"yunex\",\"name\":\"Yunex.io\"},{\"id\":\"zaif\",\"name\":\"Zaif\"},{\"id\":\"zb\",\"name\":\"ZB\"},{\"id\":\"zbg\",\"name\":\"ZBG\"},{\"id\":\"zbg_futures\",\"name\":\"ZBG Futures\"},{\"id\":\"zebitex\",\"name\":\"Zebitex\"},{\"id\":\"zebpay\",\"name\":\"ZebPay\"},{\"id\":\"zero_ex\",\"name\":\"0x Protocol\"},{\"id\":\"zg\",\"name\":\"ZG.com\"},{\"id\":\"zgtop\",\"name\":\"ZG.TOP\"},{\"id\":\"zipmex\",\"name\":\"Zipmex\"}]";
|
|
private readonly HttpClient Client;
|
|
|
|
|
|
public string UnderlyingExchange
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public CoinGeckoRateProvider(IHttpClientFactory httpClientFactory)
|
|
{
|
|
if (httpClientFactory == null)
|
|
{
|
|
return;
|
|
;
|
|
}
|
|
Client = httpClientFactory.CreateClient();
|
|
Client.BaseAddress = new Uri("https://api.coingecko.com/api/v3/");
|
|
Client.DefaultRequestHeaders.Add("Accept", "application/json");
|
|
}
|
|
|
|
public virtual Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
|
{
|
|
return UnderlyingExchange is null ? GetCoinGeckoRates(cancellationToken) : GetCoinGeckoExchangeSpecificRates(1, cancellationToken);
|
|
}
|
|
|
|
private async Task<PairRate[]> GetCoinGeckoRates(CancellationToken cancellationToken)
|
|
{
|
|
using var resp = await GetWithBackoffAsync("exchange_rates", cancellationToken);
|
|
resp.EnsureSuccessStatusCode();
|
|
return JObject.Parse(await resp.Content.ReadAsStringAsync()).GetValue("rates").Children()
|
|
.Where(token => ((JProperty)token).Name != "btc")
|
|
.Select(token => new PairRate(new CurrencyPair("BTC", ((JProperty)token).Name.ToString()),
|
|
new BidAsk(((JProperty)token).Value["value"].Value<decimal>()))).ToArray();
|
|
}
|
|
|
|
private async Task<HttpResponseMessage> GetWithBackoffAsync(string request, CancellationToken cancellationToken)
|
|
{
|
|
TimeSpan retryWait = TimeSpan.FromSeconds(1);
|
|
retry:
|
|
var resp = await Client.GetAsync(request, cancellationToken);
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
|
|
{
|
|
resp.Dispose();
|
|
if (retryWait < TimeSpan.FromSeconds(60))
|
|
{
|
|
await Task.Delay(retryWait, cancellationToken);
|
|
retryWait = TimeSpan.FromSeconds(retryWait.TotalSeconds * 2);
|
|
goto retry;
|
|
}
|
|
resp.EnsureSuccessStatusCode();
|
|
}
|
|
return resp;
|
|
}
|
|
|
|
private async Task<PairRate[]> GetCoinGeckoExchangeSpecificRates(int page, CancellationToken cancellationToken)
|
|
{
|
|
using var resp = await GetWithBackoffAsync($"exchanges/{UnderlyingExchange}/tickers?page={page}", cancellationToken);
|
|
|
|
resp.EnsureSuccessStatusCode();
|
|
List<PairRate> result = JObject.Parse(await resp.Content.ReadAsStringAsync()).GetValue("tickers")
|
|
.Select(token => new PairRate(new CurrencyPair(token.Value<string>("base"), token.Value<string>("target")),
|
|
new BidAsk(token.Value<decimal>("last")))).ToList();
|
|
if (page == 1 && resp.Headers.TryGetValues("total", out var total) &&
|
|
resp.Headers.TryGetValues("per-page", out var perPage))
|
|
{
|
|
var totalItems = int.Parse(total.First());
|
|
var perPageItems = int.Parse(perPage.First());
|
|
|
|
var totalPages = totalItems / perPageItems;
|
|
if (totalItems % perPageItems != 0)
|
|
{
|
|
totalPages++;
|
|
}
|
|
|
|
var tasks = new List<Task<PairRate[]>>();
|
|
for (int i = 2; i <= totalPages; i++)
|
|
{
|
|
tasks.Add(GetCoinGeckoExchangeSpecificRates(i, cancellationToken));
|
|
}
|
|
|
|
foreach (var t in (await Task.WhenAll(tasks)))
|
|
{
|
|
result.AddRange(t);
|
|
}
|
|
}
|
|
|
|
return result.ToArray();
|
|
}
|
|
}
|
|
}
|