Sono stati aggiunti tutti i file principali di Bootstrap 5.3.3, inclusi CSS, JavaScript (bundle, ESM, UMD, minificati), versioni RTL, utility, reboot, griglia e relative mappe delle sorgenti. Questi file abilitano un sistema di design moderno, responsive e accessibile, con supporto per layout LTR e RTL, debugging avanzato tramite source map e tutte le funzionalità di Bootstrap per lo sviluppo dell’interfaccia utente. Nessuna modifica ai file esistenti.
102 lines
3.6 KiB
C#
102 lines
3.6 KiB
C#
using System.Text.Json;
|
|
using TradingBot.Models;
|
|
|
|
namespace TradingBot.Services;
|
|
|
|
public class CoinGeckoMarketDataService : IMarketDataService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly Dictionary<string, string> _symbolToId = new()
|
|
{
|
|
{ "BTC", "bitcoin" },
|
|
{ "ETH", "ethereum" },
|
|
{ "BNB", "binancecoin" },
|
|
{ "XRP", "ripple" },
|
|
{ "ADA", "cardano" },
|
|
{ "SOL", "solana" },
|
|
{ "DOT", "polkadot" }
|
|
};
|
|
|
|
public CoinGeckoMarketDataService(HttpClient httpClient)
|
|
{
|
|
_httpClient = httpClient;
|
|
_httpClient.BaseAddress = new Uri("https://api.coingecko.com/api/v3/");
|
|
_httpClient.DefaultRequestHeaders.Add("User-Agent", "NovaTrader-Bot");
|
|
}
|
|
|
|
public async Task<List<MarketPrice>> GetMarketPricesAsync(List<string> symbols)
|
|
{
|
|
var prices = new List<MarketPrice>();
|
|
|
|
// Convert symbols to CoinGecko IDs
|
|
var ids = string.Join(",", symbols.Select(s => _symbolToId.GetValueOrDefault(s.ToUpper(), s.ToLower())));
|
|
|
|
try
|
|
{
|
|
// CoinGecko API: /simple/price endpoint
|
|
var response = await _httpClient.GetAsync(
|
|
$"simple/price?ids={ids}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var data = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json);
|
|
|
|
if (data != null)
|
|
{
|
|
foreach (var symbol in symbols)
|
|
{
|
|
var coinId = _symbolToId.GetValueOrDefault(symbol.ToUpper(), symbol.ToLower());
|
|
if (data.TryGetValue(coinId, out var coinData))
|
|
{
|
|
var price = new MarketPrice
|
|
{
|
|
Symbol = symbol.ToUpper(),
|
|
Price = coinData.GetProperty("usd").GetDecimal(),
|
|
Timestamp = DateTime.UtcNow
|
|
};
|
|
|
|
// Safely get optional properties
|
|
if (coinData.TryGetProperty("usd_24h_change", out var changeElement))
|
|
{
|
|
price.Change24h = changeElement.GetDecimal();
|
|
}
|
|
|
|
if (coinData.TryGetProperty("usd_24h_vol", out var volumeElement))
|
|
{
|
|
price.Volume24h = volumeElement.GetDecimal();
|
|
}
|
|
|
|
prices.Add(price);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"CoinGecko API error: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}");
|
|
}
|
|
}
|
|
catch (HttpRequestException ex)
|
|
{
|
|
Console.WriteLine($"Network error fetching market data: {ex.Message}");
|
|
}
|
|
catch (JsonException ex)
|
|
{
|
|
Console.WriteLine($"JSON parsing error: {ex.Message}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Unexpected error fetching market data: {ex.Message}");
|
|
}
|
|
|
|
return prices;
|
|
}
|
|
|
|
public async Task<MarketPrice?> GetPriceAsync(string symbol)
|
|
{
|
|
var prices = await GetMarketPricesAsync(new List<string> { symbol });
|
|
return prices.FirstOrDefault();
|
|
}
|
|
}
|