diff --git a/CertReports.Syncfusion/Controllers/ChartController.cs b/CertReports.Syncfusion/Controllers/ChartController.cs index fd104cf..b11df9c 100644 --- a/CertReports.Syncfusion/Controllers/ChartController.cs +++ b/CertReports.Syncfusion/Controllers/ChartController.cs @@ -184,23 +184,26 @@ public class ChartController : ControllerBase /// Richiede SP cedlab_Chart_UnderlyingOnly nel DB. /// Formati supportati: png (default), jpg/jpeg, pdf. Non supporta jpgEnc né ?save=true /// (nessun alias-certificato applicabile a un sottostante puro). + /// ?years= (default 5, clamp 1-20): ampiezza storico prezzi caricato dalla SP. /// [HttpGet("underlying/{idUnderlyings:int}")] public async Task GenerateChartUnderlying( int idUnderlyings, [FromQuery] int width = 1100, [FromQuery] int height = 700, - [FromQuery] string format = "png") + [FromQuery] string format = "png", + [FromQuery] int years = 5) { if (idUnderlyings <= 0) return BadRequest("IDUnderlyings non valido."); width = Math.Clamp(width, 400, 2000); height = Math.Clamp(height, 300, 1500); + years = Math.Clamp(years, 1, 20); try { - var chartData = await _underlyingChartDataService.GetChartDataAsync(idUnderlyings); + var chartData = await _underlyingChartDataService.GetChartDataAsync(idUnderlyings, years); if (chartData == null || chartData.Points.Count == 0) { diff --git a/CertReports.Syncfusion/Services/Implementations/UnderlyingChartDataService.cs b/CertReports.Syncfusion/Services/Implementations/UnderlyingChartDataService.cs index 7a3c8b1..0bce83e 100644 --- a/CertReports.Syncfusion/Services/Implementations/UnderlyingChartDataService.cs +++ b/CertReports.Syncfusion/Services/Implementations/UnderlyingChartDataService.cs @@ -10,7 +10,7 @@ namespace CertReports.Syncfusion.Services.Implementations; /// public interface IUnderlyingChartDataService { - Task GetChartDataAsync(int idUnderlyings); + Task GetChartDataAsync(int idUnderlyings, int years = 5); } public class UnderlyingChartDataService : IUnderlyingChartDataService @@ -25,7 +25,7 @@ public class UnderlyingChartDataService : IUnderlyingChartDataService _logger = logger; } - public async Task GetChartDataAsync(int idUnderlyings) + public async Task GetChartDataAsync(int idUnderlyings, int years = 5) { await using var conn = new SqlConnection(_connectionString); await conn.OpenAsync(); @@ -33,6 +33,7 @@ public class UnderlyingChartDataService : IUnderlyingChartDataService await using var cmd = new SqlCommand("cedlab_Chart_UnderlyingOnly", conn) { CommandType = CommandType.StoredProcedure }; cmd.Parameters.AddWithValue("@IDUnderlyings", idUnderlyings); + cmd.Parameters.AddWithValue("@Years", years); var result = new UnderlyingChartData { IDUnderlyings = idUnderlyings }; @@ -42,10 +43,14 @@ public class UnderlyingChartDataService : IUnderlyingChartDataService if (result.Points.Count == 0) result.Nome = ToStr(r, "Nome"); + int pxOrd = r.GetOrdinal("Px"); + if (r.IsDBNull(pxOrd)) + continue; // riga storica con solo Px_low/high/open valorizzati, no close + result.Points.Add(new UnderlyingChartPoint { Date = r.GetDateTime(r.GetOrdinal("Px_date")), - Px = Convert.ToDecimal(r.GetValue(r.GetOrdinal("Px"))), + Px = Convert.ToDecimal(r.GetValue(pxOrd)), }); } diff --git a/README.md b/README.md index b73d150..4bed1dc 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ GET /api/chart/v2/{isin}[?format=png|jpg|jpeg|jpgEnc|pdf&width=&height=&save=tru ### Grafico Sottostante standalone — parametri ``` -GET /api/chart/underlying/{idUnderlyings}[?format=png|jpg|jpeg|pdf&width=&height=] +GET /api/chart/underlying/{idUnderlyings}[?format=png|jpg|jpeg|pdf&width=&height=&years=] ``` Mostra solo l'andamento storico prezzo di **un singolo sottostante** (`dbo.Underlyings`), identificato da `IDUnderlyings` — nessun ISIN certificato, nessuna barriera/strike/trigger, nessuna legenda. Titolo del grafico: `{Name} ({Ticker_bbg})`. SP: `cedlab_Chart_UnderlyingOnly`. @@ -135,6 +135,9 @@ Mostra solo l'andamento storico prezzo di **un singolo sottostante** (`dbo.Under | Parametro | Valori | Effetto | |-----------|--------|---------| | `?format=` | `png` (default), `jpg`/`jpeg`, `pdf` | Formato output | +| `?years=` | intero, default `5`, clamp `1`-`20` | Ampiezza storico prezzi caricato dalla SP | + +**Prezzo usato**: `Px_close` se `Underlyings.AdjustedPrices=0`, altrimenti `Px_closeadj`. Nessun fallback incrociato tra i due campi — se `Px_closeadj` non è backfillato prima di uno split/rettifica (es. Apple: valorizzato solo da gennaio 2019), lo storico restituito si ferma lì invece di mostrare un gradino artificiale mischiando dati adjusted/non-adjusted. Non supporta `jpgEnc` né `?save=true` (nessun alias-certificato applicabile a un sottostante puro). diff --git a/docs/sql/cedlab_Chart_UnderlyingOnly.sql b/docs/sql/cedlab_Chart_UnderlyingOnly.sql index fd28474..a2019b6 100644 --- a/docs/sql/cedlab_Chart_UnderlyingOnly.sql +++ b/docs/sql/cedlab_Chart_UnderlyingOnly.sql @@ -8,14 +8,20 @@ GO -- Usata da UnderlyingChartDataService per il grafico standalone -- sottostante. -- --- Output (Px_date ASC, TOP 350 più recenti): +-- @Years: ampiezza storico in anni (default 5). +-- +-- Output (Px_date ASC, ultimi @Years anni): -- Nome VARCHAR -- "{Name} ({Ticker_bbg})", uguale su ogni riga -- Px_date DATE --- Px DECIMAL -- Px_close o Px_closeadj in base ad AdjustedPrices +-- Px DECIMAL -- Px_closeadj se AdjustedPrices=1, altrimenti +-- Px_close. Nessun fallback incrociato tra i due +-- campi: evita il gradino artificiale quando +-- Px_closeadj non è backfillato prima di uno split -- ============================================================ CREATE OR ALTER PROCEDURE [dbo].[cedlab_Chart_UnderlyingOnly] - @IDUnderlyings INT + @IDUnderlyings INT, + @Years INT = 5 AS BEGIN SET NOCOUNT ON; @@ -29,24 +35,17 @@ BEGIN IF @AdjustedPrices IS NULL RETURN; -- non trovato / cancellato / sospeso - ;WITH Ranked AS - ( - SELECT - p.Px_date, - CASE WHEN @AdjustedPrices = 0 THEN p.Px_close ELSE p.Px_closeadj END AS Px, - ROW_NUMBER() OVER (ORDER BY p.Px_date DESC) AS rn - FROM dbo.Prices p - WHERE p.UnderlyingsID = @IDUnderlyings - AND (p.Px_low IS NOT NULL OR p.Px_high IS NOT NULL OR - p.Px_open IS NOT NULL OR p.Px_close IS NOT NULL) - ) + DECLARE @FromDate DATE = DATEADD(YEAR, -@Years, CAST(GETDATE() AS DATE)); + SELECT CONCAT(u.Name, ' (', u.Ticker_bbg, ')') AS Nome, - r.Px_date, - r.Px - FROM Ranked r + p.Px_date, + CASE WHEN @AdjustedPrices = 0 THEN p.Px_close ELSE p.Px_closeadj END AS Px + FROM dbo.Prices p CROSS JOIN (SELECT TOP 1 * FROM dbo.Underlyings WHERE IDUnderlyings = @IDUnderlyings) u - WHERE r.rn <= 350 - ORDER BY r.Px_date ASC; + WHERE p.UnderlyingsID = @IDUnderlyings + AND p.Px_date >= @FromDate + AND (CASE WHEN @AdjustedPrices = 0 THEN p.Px_close ELSE p.Px_closeadj END) IS NOT NULL + ORDER BY p.Px_date ASC; END GO