diff --git a/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs b/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs index 1608d1c..4fdc6bc 100644 --- a/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs +++ b/CertReports.Syncfusion/Services/Implementations/ChartDataServiceV2.cs @@ -33,10 +33,10 @@ public class ChartDataServiceV2 : IChartDataServiceV2 await using var conn = new SqlConnection(_connectionString); await conn.OpenAsync(); - // ── 1. Metadata sottostanti (cedlab_Chart_UL1) ───────────────── + // ── 1. Metadata sottostanti (cedlab_Chart_UL2) ───────────────── var underlyings = new List(); - await using (var cmd = new SqlCommand("cedlab_Chart_UL1", conn) + await using (var cmd = new SqlCommand("cedlab_Chart_UL2", conn) { CommandType = CommandType.StoredProcedure }) { cmd.Parameters.AddWithValue("@isin", isin); diff --git a/docs/sql/cedlab_Chart_AllSeriesV2.sql b/docs/sql/cedlab_Chart_AllSeriesV2.sql new file mode 100644 index 0000000..a94c9af --- /dev/null +++ b/docs/sql/cedlab_Chart_AllSeriesV2.sql @@ -0,0 +1,103 @@ +USE [FirstSolutionDB] +GO + +-- ============================================================ +-- SP: cedlab_Chart_AllSeriesV2 +-- Restituisce tutte le serie (CTF + UL) in un unico round-trip. +-- Usata da ChartDataServiceV2 per il grafico V2. +-- +-- Logica UL: identica a cedlab_Chart_DailyUL1, estesa a tutti i +-- sottostanti del certificato in un unico UNION ALL. +-- +-- Output (ordinato IDUnderlyings ASC, Px_date ASC): +-- IDUnderlyings INT -- 0 = CTF, altrimenti UnderlyingsID +-- Px_date DATE +-- Performance DECIMAL -- % su strike/nominal +-- +-- Colonne con <<< verify: adatta al tuo schema reale. +-- ============================================================ + +CREATE OR ALTER PROCEDURE [dbo].[cedlab_Chart_AllSeriesV2] + @isin NVARCHAR(12) +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @IDCertificates INT; + DECLARE @Nominal DECIMAL(18, 6); + + SELECT TOP 1 + @IDCertificates = c.IDCertificates, -- <<< verify + @Nominal = c.Nominal_amount -- <<< verify: valore nominale per CTF % + FROM [dbo].[Certificates] c -- <<< verify: nome tabella certificati + WHERE c.ISIN = @isin; + + IF @IDCertificates IS NULL RETURN; + + -- ── CTE: calcola performance per ogni serie, TOP 350 per-serie ───── + WITH AllSeriesRaw AS + ( + -- ── Serie CTF (IDUnderlyings = 0) ──────────────────────────────── + -- Performance = PX_LAST_EOD / Nominal * 100 + SELECT + 0 AS IDUnderlyings, + pc.Px_date, + CONVERT(DECIMAL(18, 4), + pc.PX_LAST_EOD / NULLIF(@Nominal, 0) * 100 + ) AS Performance, + ROW_NUMBER() OVER ( + PARTITION BY 0 + ORDER BY pc.Px_date DESC + ) AS rn + FROM dbo.Prices pc + WHERE pc.CertificatesID = @IDCertificates + AND pc.PX_LAST_EOD IS NOT NULL + AND pc.PX_LAST_EOD <> 0 + + UNION ALL + + -- ── Serie UL (una per ogni sottostante) ────────────────────────── + -- Stessa logica di cedlab_Chart_DailyUL1, estesa a tutti gli UL. + -- Date allineate al CTF (INNER JOIN su Px_date). + SELECT + pu.UnderlyingsID AS IDUnderlyings, + pu.Px_date, + CONVERT(DECIMAL(18, 4), + CASE + WHEN ISNULL(u.AdjustedPrices, 0) = 0 THEN pu.Px_close + ELSE pu.Px_closeadj + END + / NULLIF(u.Strike, 0) * 100 + ) AS Performance, + ROW_NUMBER() OVER ( + PARTITION BY pu.UnderlyingsID + ORDER BY pu.Px_date DESC + ) AS rn + FROM dbo.Prices pu + LEFT JOIN dbo.Underlyings u + ON u.IDUnderlyings = pu.UnderlyingsID + -- Allinea date UL al CTF (solo date presenti nel certificato) + INNER JOIN dbo.Prices pc + ON pu.Px_date = pc.Px_date + AND pc.CertificatesID = @IDCertificates + AND pc.PX_LAST_EOD IS NOT NULL + AND pc.PX_LAST_EOD <> 0 + WHERE u.IDCertificates = @IDCertificates -- <<< verify: colonna FK in Underlyings + AND ( + pu.px_low IS NOT NULL OR pu.Px_high IS NOT NULL OR + pu.Px_open IS NOT NULL OR pu.Px_close IS NOT NULL + ) + AND pu.px_date >= u.StartDate -- <<< verify: colonna StartDate in Underlyings + ) + + -- ── Filtra TOP 350 per serie e reinverte in ordine ASC ─────────────── + SELECT + IDUnderlyings, + Px_date, + Performance + FROM AllSeriesRaw + WHERE rn <= 350 + ORDER BY IDUnderlyings ASC, Px_date ASC; + +END +GO diff --git a/docs/sql/cedlab_Chart_UL1.sql b/docs/sql/cedlab_Chart_UL1.sql new file mode 100644 index 0000000..64cfd7d --- /dev/null +++ b/docs/sql/cedlab_Chart_UL1.sql @@ -0,0 +1,90 @@ +-- ============================================================ +-- SP: cedlab_Chart_UL1 +-- Metadata dei sottostanti per il grafico V2. +-- Estende FSWeb_Chart_UL con: +-- IsWorstOf, PriceWorst, PriceWorstPerc, +-- NumPrezziCFT, NomeCFT, +-- BarrieraCouponPerc, BarrieraCapitalePerc, +-- TriggerAutocallPerc, AutocallValue +-- +-- Ordinato: IsWorstOf DESC (worst-of nella prima riga) +-- +-- NOTA: se questa SP esiste già nel DB con questo nome e restituisce +-- già tutte queste colonne, questo file è solo documentazione. +-- Eseguilo solo se la SP non esiste o mancano le colonne. +-- +-- ADATTAMENTO RICHIESTO: stessi nomi tabella del file cedlab_Chart_AllSeriesV2.sql +-- ============================================================ + +USE [FirstSolutionDB] +GO + +CREATE OR ALTER PROCEDURE [dbo].[cedlab_Chart_UL1] + @isin NVARCHAR(12) +AS +BEGIN + SET NOCOUNT ON; + + -- Numero prezzi CTF disponibili (usato per il sub-titolo) + DECLARE @NumPrezziCFT INT; + DECLARE @IDCertificates INT; + DECLARE @Nominal DECIMAL(18,6); + DECLARE @NomeCFT NVARCHAR(200); + + SELECT TOP 1 + @IDCertificates = c.IDCertificates, -- <<< adatta + @Nominal = c.Nominal_amount, -- <<< adatta + @NomeCFT = c.Descrizione + ' - ' + c.ISIN -- <<< adatta + FROM [dbo].[Certificates] c -- <<< adatta + WHERE c.ISIN = @isin; + + SELECT @NumPrezziCFT = COUNT(*) + FROM [dbo].[CFT_PriceHistory] -- <<< adatta + WHERE IDCertificates = @IDCertificates; + + -- Prezzo attuale worst-of (prezzo corrente / strike * 100) + -- La logica di IsWorstOf dipende dalla tua definizione (es: peggior performer) + SELECT + u.IDCertificates, + u.IDUnderlyings, + u.StartDate, -- <<< adatta + u.Strike, -- <<< adatta + -- Percentuali barriere (es: BarrieraCoupon / Nominal * 100) + u.BarrieraCouponPerc, -- <<< adatta o calcola + u.BarrieraCoupon, -- <<< adatta (valore assoluto) + u.BarrieraCapitalePerc, -- <<< adatta o calcola + u.BarrieraCapitale, -- <<< adatta (valore assoluto) + u.Name AS Sottostante, -- <<< adatta nome colonna + u.IsWorstOf, -- <<< adatta: 1=worst-of, 0=altri + -- Prezzo attuale worst-of: 0 per non-worst-of + CASE WHEN u.IsWorstOf = 1 + THEN ISNULL(last_px.Px_close, 0) -- <<< adatta: ultimo prezzo disponibile + ELSE 0 + END AS PriceWorst, + CASE WHEN u.IsWorstOf = 1 AND u.Strike > 0 + THEN ISNULL(last_px.Px_close, 0) / u.Strike * 100 + ELSE 0 + END AS PriceWorstPerc, + @NumPrezziCFT AS NumPrezziCFT, + @NomeCFT AS NomeCFT, + ISNULL(u.TriggerAutocallPerc, 0) AS TriggerAutocallPerc, -- <<< adatta + ISNULL(u.AutocallValue, 0) AS AutocallValue -- <<< adatta + FROM [dbo].[Underlyings] u -- <<< adatta nome tabella + -- Join per ottenere l'ultimo prezzo disponibile + LEFT JOIN ( + SELECT ul.IDCertificates, ul.IDUnderlyings, + ul.Px_close, + ROW_NUMBER() OVER ( + PARTITION BY ul.IDCertificates, ul.IDUnderlyings + ORDER BY ul.Px_date DESC + ) AS rn + FROM [dbo].[UL_PriceHistory] ul -- <<< adatta nome tabella + ) last_px + ON last_px.IDCertificates = u.IDCertificates + AND last_px.IDUnderlyings = u.IDUnderlyings + AND last_px.rn = 1 + WHERE u.IDCertificates = @IDCertificates + ORDER BY u.IsWorstOf DESC; -- worst-of prima + +END +GO diff --git a/docs/sql/cedlab_Chart_UL2.sql b/docs/sql/cedlab_Chart_UL2.sql new file mode 100644 index 0000000..a55c185 --- /dev/null +++ b/docs/sql/cedlab_Chart_UL2.sql @@ -0,0 +1,102 @@ +USE [FirstSolutionDB] +GO + +-- ============================================================ +-- SP: cedlab_Chart_UL2 +-- Metadata dei sottostanti per il grafico V2. +-- NON modifica cedlab_Chart_UL1 (esistente, usata altrove). +-- +-- Restituisce (ordinato IsWorstOf DESC, worst-of nella prima riga): +-- IDCertificates, IDUnderlyings, StartDate, Strike, +-- BarrieraCouponPerc, BarrieraCoupon, +-- BarrieraCapitalePerc, BarrieraCapitale, +-- Sottostante, IsWorstOf, +-- PriceWorst, PriceWorstPerc, +-- NumPrezziCFT, NomeCFT, +-- TriggerAutocallPerc, AutocallValue +-- +-- Colonne con <<< verify: adatta al tuo schema reale. +-- ============================================================ + +CREATE OR ALTER PROCEDURE [dbo].[cedlab_Chart_UL2] + @isin NVARCHAR(12) +AS +BEGIN + SET NOCOUNT ON; + + -- Recupera IDCertificates + DECLARE @IDCertificates INT; + + SELECT TOP 1 + @IDCertificates = c.IDCertificates -- <<< verify: colonna ID nel tuo Certificates + FROM [dbo].[Certificates] c -- <<< verify: nome tabella certificati + WHERE c.ISIN = @isin; + + IF @IDCertificates IS NULL RETURN; + + -- Conta prezzi EOD disponibili del certificato (usato per il sub-titolo "< 30 gg") + DECLARE @NumPrezziCFT INT; + SELECT @NumPrezziCFT = COUNT(*) + FROM dbo.Prices + WHERE CertificatesID = @IDCertificates + AND PX_LAST_EOD IS NOT NULL + AND PX_LAST_EOD <> 0; + + SELECT + u.IDCertificates, + u.IDUnderlyings, + u.StartDate, -- <<< verify: colonna StartDate in Underlyings + u.Strike, -- <<< verify: colonna Strike in Underlyings + + -- Barriere (% e assolute) + u.BarrieraCouponPerc, -- <<< verify: colonna % barriera coupon + u.BarrieraCoupon, -- <<< verify: colonna assoluta barriera coupon + u.BarrieraCapitalePerc, -- <<< verify: colonna % barriera capitale + u.BarrieraCapitale, -- <<< verify: colonna assoluta barriera capitale + + u.Name AS Sottostante, -- <<< verify: colonna nome sottostante + + u.IsWorstOf, -- <<< verify: colonna 1/0 worst-of in Underlyings + + -- PriceWorst: ultimo Px_close per il worst-of (0 per gli altri) + CASE + WHEN u.IsWorstOf = 1 THEN ISNULL(lp.Px_close, 0) + ELSE 0 + END AS PriceWorst, + + -- PriceWorstPerc: PriceWorst / Strike * 100 + CASE + WHEN u.IsWorstOf = 1 AND ISNULL(u.Strike, 0) > 0 + THEN ISNULL(lp.Px_close, 0) / u.Strike * 100 + ELSE 0 + END AS PriceWorstPerc, + + @NumPrezziCFT AS NumPrezziCFT, + + -- NomeCFT: Descrizione + ' - ' + ISIN (adatta nomi colonne) + c.Descrizione + ' - ' + c.ISIN AS NomeCFT, -- <<< verify: colonne Descrizione e ISIN + + ISNULL(u.TriggerAutocallPerc, 0) AS TriggerAutocallPerc, -- <<< verify + ISNULL(u.AutocallValue, 0) AS AutocallValue -- <<< verify + + FROM dbo.Underlyings u + JOIN [dbo].[Certificates] c -- <<< verify + ON c.IDCertificates = u.IDCertificates + -- Ultimo prezzo disponibile per ogni sottostante (per PriceWorst) + LEFT JOIN ( + SELECT + UnderlyingsID, + Px_close, + ROW_NUMBER() OVER ( + PARTITION BY UnderlyingsID + ORDER BY Px_date DESC + ) AS rn + FROM dbo.Prices + WHERE Px_close IS NOT NULL + ) lp ON lp.UnderlyingsID = u.IDUnderlyings AND lp.rn = 1 + + WHERE u.IDCertificates = @IDCertificates + ORDER BY u.IsWorstOf DESC; -- worst-of nella prima riga + +END +GO