feat: add ?years= param to underlying-only chart endpoint
Endpoint standalone /api/chart/underlying/{id} caricava un TOP 350
fisso; ora accetta ?years= (default 5, clamp 1-20) e la SP filtra per
data invece che per numero di righe.
Il prezzo usato resta Px_close/Px_closeadj in base ad
AdjustedPrices, senza fallback incrociato tra i due campi: quando
Px_closeadj non è backfillato prima di uno split (es. Apple, valorizzato
solo da inizio 2019), un fallback avrebbe mischiato dati adjusted/raw
creando un gradino artificiale nel grafico. La SP ora taglia lo storico
dove il campo scelto non è popolato.
Fix collaterale: skip righe con prezzo NULL prima del cast a decimal,
evitava un InvalidCastException con storici lunghi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
||||
/// </summary>
|
||||
[HttpGet("underlying/{idUnderlyings:int}")]
|
||||
public async Task<IActionResult> 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)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace CertReports.Syncfusion.Services.Implementations;
|
||||
/// </summary>
|
||||
public interface IUnderlyingChartDataService
|
||||
{
|
||||
Task<UnderlyingChartData?> GetChartDataAsync(int idUnderlyings);
|
||||
Task<UnderlyingChartData?> GetChartDataAsync(int idUnderlyings, int years = 5);
|
||||
}
|
||||
|
||||
public class UnderlyingChartDataService : IUnderlyingChartDataService
|
||||
@@ -25,7 +25,7 @@ public class UnderlyingChartDataService : IUnderlyingChartDataService
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<UnderlyingChartData?> GetChartDataAsync(int idUnderlyings)
|
||||
public async Task<UnderlyingChartData?> 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)),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user