2018-05-04 15:35:39 +09:00
|
|
|
|
using System;
|
2018-08-21 15:59:57 +09:00
|
|
|
|
using System.Collections.Concurrent;
|
2018-05-04 15:35:39 +09:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
2019-03-05 17:09:17 +09:00
|
|
|
|
using System.Threading;
|
2018-05-04 15:35:39 +09:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using BTCPayServer.Rating;
|
|
|
|
|
using ExchangeSharp;
|
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Services.Rates
|
|
|
|
|
{
|
2018-08-25 15:09:42 +09:00
|
|
|
|
public class ExchangeSharpRateProvider : IRateProvider, IHasExchangeName
|
2018-05-04 15:35:39 +09:00
|
|
|
|
{
|
|
|
|
|
readonly ExchangeAPI _ExchangeAPI;
|
|
|
|
|
readonly string _ExchangeName;
|
|
|
|
|
public ExchangeSharpRateProvider(string exchangeName, ExchangeAPI exchangeAPI, bool reverseCurrencyPair = false)
|
|
|
|
|
{
|
|
|
|
|
if (exchangeAPI == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(exchangeAPI));
|
|
|
|
|
exchangeAPI.RequestTimeout = TimeSpan.FromSeconds(5.0);
|
|
|
|
|
_ExchangeAPI = exchangeAPI;
|
|
|
|
|
_ExchangeName = exchangeName;
|
|
|
|
|
ReverseCurrencyPair = reverseCurrencyPair;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool ReverseCurrencyPair
|
|
|
|
|
{
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-25 15:09:42 +09:00
|
|
|
|
public string ExchangeName => _ExchangeName;
|
|
|
|
|
|
2019-03-05 17:09:17 +09:00
|
|
|
|
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
2018-05-04 15:35:39 +09:00
|
|
|
|
{
|
|
|
|
|
await new SynchronizationContextRemover();
|
|
|
|
|
var rates = await _ExchangeAPI.GetTickersAsync();
|
|
|
|
|
lock (notFoundSymbols)
|
|
|
|
|
{
|
|
|
|
|
var exchangeRates =
|
2019-04-04 19:39:37 +09:00
|
|
|
|
rates
|
|
|
|
|
.Where(t => t.Value.Ask != 0m && t.Value.Bid != 0m)
|
|
|
|
|
.Select(t => CreateExchangeRate(t))
|
2018-05-04 15:35:39 +09:00
|
|
|
|
.Where(t => t != null)
|
|
|
|
|
.ToArray();
|
|
|
|
|
return new ExchangeRates(exchangeRates);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ExchangeSymbolToGlobalSymbol throws exception which would kill perf
|
2018-08-21 15:59:57 +09:00
|
|
|
|
ConcurrentDictionary<string, string> notFoundSymbols = new ConcurrentDictionary<string, string>();
|
2018-05-04 15:35:39 +09:00
|
|
|
|
private ExchangeRate CreateExchangeRate(KeyValuePair<string, ExchangeTicker> ticker)
|
|
|
|
|
{
|
2018-08-21 15:59:57 +09:00
|
|
|
|
if (notFoundSymbols.ContainsKey(ticker.Key))
|
2018-05-04 15:35:39 +09:00
|
|
|
|
return null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var tickerName = _ExchangeAPI.ExchangeSymbolToGlobalSymbol(ticker.Key);
|
|
|
|
|
if (!CurrencyPair.TryParse(tickerName, out var pair))
|
|
|
|
|
{
|
2018-08-21 15:59:57 +09:00
|
|
|
|
notFoundSymbols.TryAdd(ticker.Key, ticker.Key);
|
2018-05-04 15:35:39 +09:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if(ReverseCurrencyPair)
|
|
|
|
|
pair = new CurrencyPair(pair.Right, pair.Left);
|
|
|
|
|
var rate = new ExchangeRate();
|
|
|
|
|
rate.CurrencyPair = pair;
|
|
|
|
|
rate.Exchange = _ExchangeName;
|
2018-05-23 02:18:38 +09:00
|
|
|
|
rate.BidAsk = new BidAsk(ticker.Value.Bid, ticker.Value.Ask);
|
2018-05-04 15:35:39 +09:00
|
|
|
|
return rate;
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentException)
|
|
|
|
|
{
|
2018-08-21 15:59:57 +09:00
|
|
|
|
notFoundSymbols.TryAdd(ticker.Key, ticker.Key);
|
2018-05-04 15:35:39 +09:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|