add enum currency, add coin gecko implementation

This commit is contained in:
DavidGudEnough 2025-01-08 15:25:25 -05:00
parent 20ed8e38f7
commit caf6f3275c
Signed by: david.nguyen
GPG Key ID: 0B95DC36355BEB37
14 changed files with 113 additions and 47 deletions

View File

@ -16,6 +16,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\CH.Authority\CH.Authority.csproj" /> <ProjectReference Include="..\CH.Authority\CH.Authority.csproj" />
<ProjectReference Include="..\CH.CryptoStats.CoinGecko\CH.CryptoStats.CoinGecko.csproj" />
<ProjectReference Include="..\CH.CryptoStats.CoinMarketCap\CH.CryptoStats.CoinMarketCap.csproj" /> <ProjectReference Include="..\CH.CryptoStats.CoinMarketCap\CH.CryptoStats.CoinMarketCap.csproj" />
<ProjectReference Include="..\CH.CryptoStats\CH.CryptoStats.Abstractions.csproj" /> <ProjectReference Include="..\CH.CryptoStats\CH.CryptoStats.Abstractions.csproj" />
<ProjectReference Include="..\CH.Dal\CH.Dal.csproj" /> <ProjectReference Include="..\CH.Dal\CH.Dal.csproj" />

View File

@ -1,12 +1,13 @@
 
using CH.CryptoStats.CoinGecko;
using CH.CryptoStats.CoinMarketCap; using CH.CryptoStats.CoinMarketCap;
namespace CH.CQRS.Service.CryptoStats; namespace CH.CQRS.Service.CryptoStats;
public class CryptoService(CoinMarketCapService coinMarketCap) public class CryptoService(CoinGeckoService coinGecko)
{ {
public async Task GetCryptoStatsAsync(CancellationToken cancellationToken) public async Task GetCryptoStatsAsync(CancellationToken cancellationToken)
{ {
var crypto = await coinMarketCap.GetCryptoStatsAsync("bitcoin", "cad", cancellationToken); var crypto = await coinGecko.GetCryptoStatsAsync("bitcoin", "cad", cancellationToken);
} }
} }

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using CH.CryptoStats.Abstractions;
namespace CH.CryptoStats.CoinGecko;
public class CoinGecko : ICryptoStats
{
//https://docs.coingecko.com/reference/coins-id
public Task<Abstractions.CryptoStats> GetCryptoStatsAsync(string cryptoName, string currency, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<Abstractions.CryptoStats> ParseCryptoStats(JsonDocument jsonDocument, string currency, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,24 @@
using System.Text.Json.Serialization;
namespace CH.CryptoStats.CoinGecko;
public class CoinGeckoEntity
{
[JsonPropertyName("symbol")]
public required string Symbol { get; set; }
[JsonPropertyName("name")]
public required string Name { get; set; }
[JsonPropertyName("current_price")]
public decimal Price { get; set; }
[JsonPropertyName("market_cap")]
public decimal MarketCap { get; set; }
[JsonPropertyName("fully_diluted_valuation")]
public decimal FullyDilutedValuation { get; set; }
[JsonPropertyName("circulating_supply")]
public decimal CirculatingSupply { get; set; }
[JsonPropertyName("total_supply")]
public decimal TotalSupply { get; set; }
[JsonPropertyName("max_supply")]
public decimal MaxSupply { get; set; }
[JsonPropertyName("last_updated")]
public DateTime LastUpdated { get; set; }
}

View File

@ -9,7 +9,7 @@ public class CoinGeckoModule : IModule
{ {
public IServiceCollection ConfigureServices(IServiceCollection services) public IServiceCollection ConfigureServices(IServiceCollection services)
{ {
services.AddScoped<CoinGecko>(); services.AddScoped<CoinGeckoService>();
return services; return services;
} }
} }

View File

@ -0,0 +1,38 @@
using CH.CryptoStats.Abstractions;
using Microsoft.Extensions.Configuration;
using System.Net.Http.Json;
using System.Text.Json;
using CH.Energy.Abstractions.Enum;
namespace CH.CryptoStats.CoinGecko;
public class CoinGeckoService(IConfiguration configuration, HttpClient httpClient) : ICryptoStats
{
public async Task<Abstractions.CryptoStats> GetCryptoStatsAsync(string cryptoName, string currency, CancellationToken cancellationToken)
{
var apiKey = configuration.GetValue<string>("CoinGecko:ApiKey");
var apiUrl = configuration.GetValue<string>("CoinGecko:ApiUrl");
var response = await httpClient.GetAsync($"{apiUrl}?ids={cryptoName}&vs_currency={currency}&x_cg_demo_api_key={apiKey}",cancellationToken);
var jsonResponse = await response.Content.ReadFromJsonAsync<List<CoinGeckoEntity>>(cancellationToken);
return ParseCryptoStats(jsonResponse.FirstOrDefault(), currency, cancellationToken).Result;
}
private Task<Abstractions.CryptoStats> ParseCryptoStats(CoinGeckoEntity coinGeckoEntity, string currency, CancellationToken cancellationToken)
{
var cryptoStats = new Abstractions.CryptoStats
{
Name = coinGeckoEntity.Name,
Symbol = coinGeckoEntity.Symbol,
MaxSupply = coinGeckoEntity.MaxSupply,
CirculatingSupply = coinGeckoEntity.CirculatingSupply,
TotalSupply = coinGeckoEntity.TotalSupply,
Currency = (Currency)System.Enum.Parse(typeof(Currency), currency.ToUpper()),
UpdatedAt = coinGeckoEntity.LastUpdated,
Price = coinGeckoEntity.Price,
MarketCap = coinGeckoEntity.MarketCap,
FullyDilutedMarketCap = coinGeckoEntity.FullyDilutedValuation
};
return Task.FromResult(cryptoStats);
}
}

View File

@ -14,5 +14,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\CH.CryptoStats\CH.CryptoStats.Abstractions.csproj" /> <ProjectReference Include="..\CH.CryptoStats\CH.CryptoStats.Abstractions.csproj" />
<ProjectReference Include="..\CH.Enum\CH.Enum.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,9 +11,9 @@ public class CoinMarketCapEntity
[JsonPropertyName("id")] [JsonPropertyName("id")]
public int Id { get; set; } public int Id { get; set; }
[JsonPropertyName("name")] [JsonPropertyName("name")]
public string Name { get; set; } public required string Name { get; set; }
[JsonPropertyName("symbol")] [JsonPropertyName("symbol")]
public string Symbol { get; set; } public required string Symbol { get; set; }
[JsonPropertyName("max_supply")] [JsonPropertyName("max_supply")]
public int MaxSupply { get; set; } public int MaxSupply { get; set; }
[JsonPropertyName("circulating_supply")] [JsonPropertyName("circulating_supply")]
@ -27,6 +27,7 @@ public class CoinMarketCapEntity
} }
public class ApiResponse public class ApiResponse
{ {
[JsonPropertyName("data")]
public required Dictionary<string, CoinMarketCapEntity> Data { get; set; } public required Dictionary<string, CoinMarketCapEntity> Data { get; set; }
} }
@ -43,9 +44,9 @@ public class CurrencyValue
[JsonPropertyName("price")] [JsonPropertyName("price")]
public decimal Price { get; set; } public decimal Price { get; set; }
[JsonPropertyName("volume_24h")] [JsonPropertyName("volume_24h")]
public decimal Volume24h { get; set; } public decimal Volume24H { get; set; }
[JsonPropertyName("volume_change_24h")] [JsonPropertyName("volume_change_24h")]
public decimal VolumeChange24h { get; set; } public decimal VolumeChange24H { get; set; }
[JsonPropertyName("market_cap")] [JsonPropertyName("market_cap")]
public decimal MarketCap { get; set; } public decimal MarketCap { get; set; }
[JsonPropertyName("market_cap_dominance")] [JsonPropertyName("market_cap_dominance")]

View File

@ -2,6 +2,8 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json; using System.Text.Json;
using CH.Energy.Abstractions.Enum;
namespace CH.CryptoStats.CoinMarketCap; namespace CH.CryptoStats.CoinMarketCap;
public class CoinMarketCapService(HttpClient httpClient, IConfiguration configuration) : ICryptoStats public class CoinMarketCapService(HttpClient httpClient, IConfiguration configuration) : ICryptoStats
@ -18,6 +20,7 @@ public class CoinMarketCapService(HttpClient httpClient, IConfiguration configur
private Task<Abstractions.CryptoStats> ParseCryptoStats(CoinMarketCapEntity coinMarketCapEntity, string currency, CancellationToken cancellationToken) private Task<Abstractions.CryptoStats> ParseCryptoStats(CoinMarketCapEntity coinMarketCapEntity, string currency, CancellationToken cancellationToken)
{ {
var quoteData = coinMarketCapEntity.Quote.CAD ?? coinMarketCapEntity.Quote.USD;
var cryptoStats = new Abstractions.CryptoStats var cryptoStats = new Abstractions.CryptoStats
{ {
Name = coinMarketCapEntity.Name, Name = coinMarketCapEntity.Name,
@ -25,20 +28,14 @@ public class CoinMarketCapService(HttpClient httpClient, IConfiguration configur
MaxSupply = coinMarketCapEntity.MaxSupply, MaxSupply = coinMarketCapEntity.MaxSupply,
CirculatingSupply = coinMarketCapEntity.CirculatingSupply, CirculatingSupply = coinMarketCapEntity.CirculatingSupply,
TotalSupply = coinMarketCapEntity.TotalSupply, TotalSupply = coinMarketCapEntity.TotalSupply,
Currency = currency.ToUpper(), Currency = (Currency)System.Enum.Parse(typeof(Currency), currency.ToUpper()),
UpdatedAt = DateTime.Parse(coinMarketCapEntity.LastUpdated), UpdatedAt = DateTime.Parse(coinMarketCapEntity.LastUpdated),
Price = coinMarketCapEntity.Quote.CAD == null ? Price = quoteData.Price,
coinMarketCapEntity.Quote.USD.Price : coinMarketCapEntity.Quote.CAD.Price, Volume24H = quoteData.Volume24H,
Volume24H = coinMarketCapEntity.Quote.CAD == null ? VolumeChange24H = quoteData.VolumeChange24H,
coinMarketCapEntity.Quote.USD.Volume24h : coinMarketCapEntity.Quote.CAD.Volume24h, MarketCap = quoteData.MarketCap,
VolumeChange24H = coinMarketCapEntity.Quote.CAD == null ? MarketCapDominance = quoteData.MarketCapDominance,
coinMarketCapEntity.Quote.USD.VolumeChange24h : coinMarketCapEntity.Quote.CAD.VolumeChange24h, FullyDilutedMarketCap = quoteData.FullyDilutedMarketCap
MarketCap = coinMarketCapEntity.Quote.CAD == null ?
coinMarketCapEntity.Quote.USD.MarketCap : coinMarketCapEntity.Quote.CAD.MarketCap,
MarketCapDominance = coinMarketCapEntity.Quote.CAD == null ?
coinMarketCapEntity.Quote.USD.MarketCapDominance : coinMarketCapEntity.Quote.CAD.MarketCapDominance,
FullyDilutedMarketCap = coinMarketCapEntity.Quote.CAD == null ?
coinMarketCapEntity.Quote.USD.FullyDilutedMarketCap : coinMarketCapEntity.Quote.CAD.FullyDilutedMarketCap
}; };
return Task.FromResult(cryptoStats); return Task.FromResult(cryptoStats);
} }

View File

@ -12,4 +12,7 @@
<PackageReference Include="PoweredSoft.Data.Core" Version="3.0.0" /> <PackageReference Include="PoweredSoft.Data.Core" Version="3.0.0" />
<PackageReference Include="PoweredSoft.Module.Abstractions" Version="2.0.0" /> <PackageReference Include="PoweredSoft.Module.Abstractions" Version="2.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CH.Enum\CH.Enum.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using CH.Energy.Abstractions.Enum;
namespace CH.CryptoStats.Abstractions; namespace CH.CryptoStats.Abstractions;
@ -10,10 +11,10 @@ public class CryptoStats
{ {
public required string Name { get; set; } public required string Name { get; set; }
public required string Symbol { get; set; } public required string Symbol { get; set; }
public long MaxSupply { get; set; } public decimal MaxSupply { get; set; }
public long CirculatingSupply { get; set; } public decimal CirculatingSupply { get; set; }
public long TotalSupply { get; set; } public decimal TotalSupply { get; set; }
public required string Currency { get; set; } public required Currency Currency { get; set; }
public DateTime UpdatedAt { get; set; } public DateTime UpdatedAt { get; set; }
public decimal Price { get; set; } public decimal Price { get; set; }
public decimal Volume24H { get; set; } public decimal Volume24H { get; set; }

9
CH.Enum/CH.Enum.csproj Normal file
View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

7
CH.Enum/Currency.cs Normal file
View File

@ -0,0 +1,7 @@
namespace CH.Energy.Abstractions.Enum;
public enum Currency
{
USD,
CAD,
}

View File

@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.Abstractions", "C
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.HydroQuebec", "CH.Energy.HydroQuebec\CH.Energy.HydroQuebec.csproj", "{91BB50CF-87B6-40A0-BB70-B42B7208167A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.HydroQuebec", "CH.Energy.HydroQuebec\CH.Energy.HydroQuebec.csproj", "{91BB50CF-87B6-40A0-BB70-B42B7208167A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Enum", "CH.Enum\CH.Enum.csproj", "{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -63,6 +65,10 @@ Global
{91BB50CF-87B6-40A0-BB70-B42B7208167A}.Debug|Any CPU.Build.0 = Debug|Any CPU {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.ActiveCfg = Release|Any CPU {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.Build.0 = Release|Any CPU {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.Build.0 = Release|Any CPU
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE