diff --git a/src/CoinMarketCap/Currencies.cs b/src/CoinMarketCap/Currencies.cs new file mode 100644 index 0000000..121134f --- /dev/null +++ b/src/CoinMarketCap/Currencies.cs @@ -0,0 +1,16 @@ +namespace Kalakoi.Crypto.CoinMarketCap +{ + /// + /// Fiat currencies available for price conversions. + /// + public enum Currencies + { + USD, AUD, BRL, CAD, CHF, + CLP, CNY, CZK, DKK, EUR, + GBP, HKD, HUF, IDR, ILS, + INR, JPY, KRW, MXN, MYR, + NOK, NZD, PHP, PKR, PLN, + RUB, SEK, SGD, THB, TRY, + TWD, ZAR + } +} diff --git a/src/CoinMarketCap/GlobalData.cs b/src/CoinMarketCap/GlobalData.cs new file mode 100644 index 0000000..373721f --- /dev/null +++ b/src/CoinMarketCap/GlobalData.cs @@ -0,0 +1,140 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace Kalakoi.Crypto.CoinMarketCap +{ + /// + /// Provides access to global data provided by CoinMarketCap + /// + public class GlobalData + { + /// + /// Market capitalization in USD. + /// + public double TotalMarketCapUSD { get; private set; } + /// + /// 24 Hour trade volume in USD. + /// + public double Total24HourVolumeUSD { get; private set; } + /// + /// Bitcoin percentage dominance. + /// + public double BitcoinPercentageOfMarketCap { get; private set; } + /// + /// Number of active currencies on CoinMarketCap. + /// + public int ActiveCurrencies { get; private set; } + /// + /// Number of active assets on CoinMarketCap. + /// + public int ActiveAssets { get; private set; } + /// + /// Number of active markets on CoinMarketCap. + /// + public int ActiveMarkets { get; private set; } + /// + /// Timestamp for when API was last updated. + /// + public int LastUpdated { get; private set; } + /// + /// Currency specified for value conversions. + /// + public Currencies Currency { get; private set; } + /// + /// Market capitalization in specified currency. + /// + public double TotalMarketCap { get; private set; } + /// + /// 24 hour trade volume in specified currency. + /// + public double Total24HourVolume { get; private set; } + + private GlobalData() { } + + internal static async Task GetDataAsync(Currencies currency = Currencies.USD) + { + Uri uri = GetUri(currency); + string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false); + return await ParseResponseAsync(response, currency).ConfigureAwait(false); + } + + private static Uri GetUri(Currencies currency) + { + string BaseUrl = @"https://api.coinmarketcap.com/v1/global/{0}"; + string AdditionFormat = "?convert={0}"; + string Addition = string.Empty; + if (currency != Currencies.USD) + Addition = string.Format(AdditionFormat, currency.ToString()); + return new Uri(string.Format(BaseUrl, Addition)); + } + + private static async Task ParseResponseAsync(string response, Currencies currency) + { + GlobalData data = new GlobalData(); + data.Currency = currency; + using (JsonTextReader jtr = new JsonTextReader(new StringReader(response))) + { + while (await jtr.ReadAsync().ConfigureAwait(false)) + { + if (jtr.Value != null) + { + if (jtr.Value.ToString() == "total_market_cap_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.TotalMarketCapUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "total_24h_volume_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.Total24HourVolumeUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "bitcoin_percentage_of_market_cap") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.BitcoinPercentageOfMarketCap = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "active_currencies") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.ActiveCurrencies = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "active_assets") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.ActiveAssets = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "active_markets") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.ActiveMarkets = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "last_updated") + { + await jtr.ReadAsync().ConfigureAwait(false); + data.LastUpdated = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("total_market_cap_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + data.TotalMarketCap = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("total_24h_volume_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + data.Total24HourVolume = Convert.ToDouble(jtr.Value.ToString()); + } + } + else continue; + } + } + if (currency == Currencies.USD) + { + data.TotalMarketCap = data.TotalMarketCapUSD; + data.Total24HourVolume = data.Total24HourVolumeUSD; + } + return data; + } + } +} diff --git a/src/CoinMarketCap/Ticker.cs b/src/CoinMarketCap/Ticker.cs new file mode 100644 index 0000000..3410050 --- /dev/null +++ b/src/CoinMarketCap/Ticker.cs @@ -0,0 +1,384 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace Kalakoi.Crypto.CoinMarketCap +{ + /// + /// Provides access to ticker data provided by CoinMarketCap + /// + public class Ticker + { + /// + /// ID specific to CoinMarketCap. + /// + public string ID { get; private set; } + /// + /// Currency name. + /// + public string Name { get; private set; } + /// + /// Ticker symbol. + /// + public string Symbol { get; private set; } + /// + /// Rank among all active assets by market capitalization. + /// + public int Rank { get; private set; } + /// + /// Price per unit in USD. + /// + public double PriceUSD { get; private set; } + /// + /// Price per unit in BTC. + /// + public double PriceBTC { get; private set; } + /// + /// 24 hour trade volume in USD. + /// + public double Volume24HourUSD { get; private set; } + /// + /// Market capitalization in USD. + /// + public double MarketCapUSD { get; private set; } + /// + /// Available coin supply. + /// + public double AvailableSupply { get; private set; } + /// + /// Total coin supply. + /// + public double TotalSupply { get; private set; } + /// + /// Maximum coin supply, if applicable. + /// + public double MaxSupply { get; private set; } + /// + /// Percentage price change in last hour. + /// + public double PercentChange1Hour { get; private set; } + /// + /// Percentage price change in last 24 hours. + /// + public double PercentChange24Hour { get; private set; } + /// + /// Percentage price change in last 7 days. + /// + public double PercentChange7Day { get; private set; } + /// + /// Timestamp of when API was last updated. + /// + public int LastUpdated { get; private set; } + /// + /// Fiat currency to convert values to. + /// + public Currencies Currency { get; private set; } + /// + /// Price per unit in specified currency. + /// + public double Price { get; private set; } + /// + /// 24 hour trade volume in specified currency. + /// + public double Volume24Hour { get; private set; } + /// + /// Market capitalization in specified currency. + /// + public double MarketCap { get; private set; } + + private Ticker() { } + + internal static async Task> GetTickersAsync(Currencies currency = Currencies.USD, int start = 0, int limit = 100) + { + Uri uri = GetListUri(currency, start, limit); + string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false); + return await ParseListResponseAsync(response, currency).ConfigureAwait(false); + } + + internal static async Task GetTickerAsync(string id, Currencies currency = Currencies.USD) + { + Uri uri = GetSingleUri(currency, id); + string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false); + return await ParseSingleResponseAsync(response, currency).ConfigureAwait(false); + } + + private static Uri GetListUri(Currencies currency, int start, int limit) + { + string BaseUrl = @"https://api.coinmarketcap.com/v1/ticker/"; + string AdditionFormat = "{0}{1}={2}"; + string UrlAddition = string.Empty; + bool HasFirstAddition = false; + if (currency != Currencies.USD) + { + UrlAddition += string.Format(AdditionFormat, HasFirstAddition ? "&" : "?", "convert", currency.ToString()); + HasFirstAddition = true; + } + if (start != 0) + { + UrlAddition += string.Format(AdditionFormat, HasFirstAddition ? "&" : "?", "start", start.ToString()); + HasFirstAddition = true; + } + if (limit != 100) + { + UrlAddition += string.Format(AdditionFormat, HasFirstAddition ? "&" : "?", "limit", limit.ToString()); + HasFirstAddition = true; + } + return new Uri(BaseUrl + UrlAddition); + } + + private static Uri GetSingleUri(Currencies currency, string id) + { + string BaseUrl = @"https://api.coinmarketcap.com/v1/ticker/{0}/{1}"; + string AdditionFormat = "?convert={0}"; + string Addition = string.Empty; + if (currency != Currencies.USD) + Addition = string.Format(AdditionFormat, currency.ToString()); + return new Uri(string.Format(BaseUrl, id, Addition)); + } + + private static async Task> ParseListResponseAsync(string response, Currencies currency) + { + List TickerList = new List(); + Ticker ToAdd = new Ticker(); + ToAdd.Currency = currency; + using (JsonTextReader jtr = new JsonTextReader(new StringReader(response))) + { + while (await jtr.ReadAsync().ConfigureAwait(false)) + { + if (jtr.TokenType.ToString() == "StartObject") + { + if (!string.IsNullOrEmpty(ToAdd.Name)) + { + if (currency == Currencies.USD) + { + ToAdd.Price = ToAdd.PriceUSD; + ToAdd.Volume24Hour = ToAdd.Volume24HourUSD; + ToAdd.MarketCap = ToAdd.MarketCapUSD; + } + TickerList.Add(ToAdd); + } + ToAdd = new Ticker(); + ToAdd.Currency = currency; + continue; + } + if (jtr.Value != null) + { + if (jtr.Value.ToString() == "id") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.ID = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "name") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Name = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "symbol") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Symbol = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "rank") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Rank = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "price_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PriceUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "price_btc") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PriceBTC = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "24h_volume_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Volume24HourUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "market_cap_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MarketCapUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "available_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.AvailableSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "total_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.TotalSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "max_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MaxSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_1h") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange1Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_24h") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange24Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_7d") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange7Day = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "last_updated") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.LastUpdated = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("price_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Price = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("24h_volume_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Volume24Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("market_cap_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MarketCap = Convert.ToDouble(jtr.Value.ToString()); + } + else continue; + } + else continue; + } + } + if (!string.IsNullOrEmpty(ToAdd.Name)) + { + if (currency == Currencies.USD) + { + ToAdd.Price = ToAdd.PriceUSD; + ToAdd.Volume24Hour = ToAdd.Volume24HourUSD; + ToAdd.MarketCap = ToAdd.MarketCapUSD; + } + TickerList.Add(ToAdd); + } + return TickerList; + } + + private static async Task ParseSingleResponseAsync(string response, Currencies currency) + { + Ticker ToAdd = new Ticker(); + ToAdd.Currency = currency; + using (JsonTextReader jtr = new JsonTextReader(new StringReader(response))) + { + while (await jtr.ReadAsync().ConfigureAwait(false)) + { + if (jtr.Value != null) + { + if (jtr.Value.ToString() == "id") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.ID = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "name") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Name = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "symbol") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Symbol = jtr.Value.ToString(); + } + else if (jtr.Value.ToString() == "rank") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Rank = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "price_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PriceUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "price_btc") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PriceBTC = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "24h_volume_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Volume24HourUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "market_cap_usd") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MarketCapUSD = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "available_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.AvailableSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "total_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.TotalSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "max_supply") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MaxSupply = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_1h") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange1Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_24h") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange24Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "percent_change_7d") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.PercentChange7Day = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == "last_updated") + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.LastUpdated = Convert.ToInt32(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("price_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Price = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("24h_volume_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.Volume24Hour = Convert.ToDouble(jtr.Value.ToString()); + } + else if (jtr.Value.ToString() == string.Format("market_cap_{0}", currency.ToString().ToLower())) + { + await jtr.ReadAsync().ConfigureAwait(false); + ToAdd.MarketCap = Convert.ToDouble(jtr.Value.ToString()); + } + else continue; + } + else continue; + } + } + return ToAdd; + } + } +}