diff --git a/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs b/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs new file mode 100644 index 0000000..1608d1c --- /dev/null +++ b/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs @@ -0,0 +1,105 @@ +using CertReports.Syncfusion.Models; +using Microsoft.Data.SqlClient; +using System.Data; + +namespace CertReports.Syncfusion.Services.Implementations; + +/// +/// Recupera i dati per il grafico V2 con solo 2 round-trip al DB. +/// +/// SP utilizzate: +/// - cedlab_Chart_UL1: Metadata sottostanti (1 query, N sottostanti) +/// - cedlab_Chart_AllSeriesV2: Tutte le serie CTF + UL in una query (TOP 350 per-serie) +/// +public interface IChartDataServiceV2 +{ + Task GetChartDataV2Async(string isin); +} + +public class ChartDataServiceV2 : IChartDataServiceV2 +{ + private readonly string _connectionString; + private readonly ILogger _logger; + + public ChartDataServiceV2(IConfiguration config, ILogger logger) + { + _connectionString = config.GetConnectionString("CertDb") + ?? throw new InvalidOperationException("ConnectionString 'CertDb' non configurata."); + _logger = logger; + } + + public async Task GetChartDataV2Async(string isin) + { + await using var conn = new SqlConnection(_connectionString); + await conn.OpenAsync(); + + // ── 1. Metadata sottostanti (cedlab_Chart_UL1) ───────────────── + var underlyings = new List(); + + await using (var cmd = new SqlCommand("cedlab_Chart_UL1", conn) + { CommandType = CommandType.StoredProcedure }) + { + cmd.Parameters.AddWithValue("@isin", isin); + await using var r = await cmd.ExecuteReaderAsync(); + while (await r.ReadAsync()) + { + underlyings.Add(new ChartUlMetadata + { + IDCertificates = r.GetInt32(r.GetOrdinal("IDCertificates")), + IDUnderlyings = r.GetInt32(r.GetOrdinal("IDUnderlyings")), + StartDate = r.GetDateTime(r.GetOrdinal("StartDate")), + Strike = r.GetDecimal(r.GetOrdinal("Strike")), + BarrieraCouponPerc = r.GetDecimal(r.GetOrdinal("BarrieraCouponPerc")), + BarrieraCoupon = r.GetDecimal(r.GetOrdinal("BarrieraCoupon")), + BarrieraCapitalePerc = r.GetDecimal(r.GetOrdinal("BarrieraCapitalePerc")), + BarrieraCapitale = r.GetDecimal(r.GetOrdinal("BarrieraCapitale")), + Sottostante = r.GetString(r.GetOrdinal("Sottostante")), + IsWorstOf = r.GetInt32(r.GetOrdinal("IsWorstOf")), + PriceWorst = r.GetDecimal(r.GetOrdinal("PriceWorst")), + PriceWorstPerc = r.GetDecimal(r.GetOrdinal("PriceWorstPerc")), + NumPrezziCFT = r.GetInt32(r.GetOrdinal("NumPrezziCFT")), + NomeCFT = r.GetString(r.GetOrdinal("NomeCFT")), + TriggerAutocallPerc = r.GetDecimal(r.GetOrdinal("TriggerAutocallPerc")), + AutocallValue = r.GetDecimal(r.GetOrdinal("AutocallValue")), + }); + } + } + + if (underlyings.Count == 0) + { + _logger.LogWarning( + "Nessun sottostante trovato per il grafico V2 di {Isin} (meno di 30 prezzi EOD?)", isin); + return null; + } + + var result = new ChartDataV2 + { + Isin = isin, + GlobalMeta = underlyings[0], // worst-of è il primo (SP ordina IsWorstOf DESC) + Underlyings = underlyings, + }; + + // ── 2. Tutte le serie (cedlab_Chart_AllSeriesV2) ──────────────── + await using (var cmd = new SqlCommand("cedlab_Chart_AllSeriesV2", conn) + { CommandType = CommandType.StoredProcedure }) + { + cmd.Parameters.AddWithValue("@isin", isin); + await using var r = await cmd.ExecuteReaderAsync(); + while (await r.ReadAsync()) + { + result.SeriesPoints.Add(new ChartSeriesPoint + { + IDUnderlyings = r.GetInt32(r.GetOrdinal("IDUnderlyings")), + Date = r.GetDateTime(r.GetOrdinal("Px_date")), + Performance = r.GetDecimal(r.GetOrdinal("Performance")), + }); + } + } + + _logger.LogInformation( + "Dati grafico V2 caricati per {Isin}: {UlCount} sottostanti, {Points} punti totali", + isin, underlyings.Count, result.SeriesPoints.Count); + + return result; + } +}