feat(derivatives): fix Trade Republic derivative pagination streaming and picker modal
This commit is contained in:
@@ -268,6 +268,101 @@ public class AssetsController : ControllerBase
|
||||
return NotFound(new { message = $"Keine technische Analyse für Asset '{normalizedSymbol}' verfügbar." });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Liest verfügbare Derivate (Knock-Outs, Optionsscheine etc.) für ein Basiswert-Asset via FinlyticAssets MQTT RPC.
|
||||
/// </summary>
|
||||
[HttpGet("{isin}/derivatives")]
|
||||
public async Task<IActionResult> GetDerivatives(
|
||||
[FromRoute] string isin,
|
||||
[FromQuery] string optionType = "long",
|
||||
[FromQuery] decimal? targetLeverage = null,
|
||||
[FromQuery] decimal? minLeverage = null,
|
||||
[FromQuery] decimal? maxLeverage = null,
|
||||
[FromQuery] string? search = null,
|
||||
[FromQuery] string? after = null,
|
||||
[FromQuery] int? page = null,
|
||||
[FromQuery] int? pageSize = null,
|
||||
[FromQuery] bool forceRefresh = false,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
string cleanIsin = isin.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(cleanIsin))
|
||||
{
|
||||
return BadRequest(new { message = "Eine gültige ISIN ist erforderlich." });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_mqttClient.IsConnected)
|
||||
{
|
||||
var req = new GetDerivativesRequest(
|
||||
UnderlyingIsin: cleanIsin,
|
||||
OptionType: optionType.ToLowerInvariant(),
|
||||
TargetLeverage: targetLeverage,
|
||||
After: after,
|
||||
Page: page,
|
||||
ForceRefresh: forceRefresh
|
||||
);
|
||||
|
||||
var rpcResult = await _mqttClient.SendRpcRequestAsync<List<AssetDto>, GetDerivativesRequest>(
|
||||
"assets_GetDerivatives",
|
||||
req,
|
||||
TimeSpan.FromSeconds(30)
|
||||
);
|
||||
|
||||
if (rpcResult != null)
|
||||
{
|
||||
var derivatives = rpcResult.OfType<DerivativeDto>().ToList();
|
||||
|
||||
if (minLeverage.HasValue)
|
||||
{
|
||||
derivatives = derivatives.Where(d => d.Leverage >= minLeverage.Value).ToList();
|
||||
}
|
||||
|
||||
if (maxLeverage.HasValue)
|
||||
{
|
||||
derivatives = derivatives.Where(d => d.Leverage <= maxLeverage.Value).ToList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
string q = search.Trim();
|
||||
derivatives = derivatives.Where(d =>
|
||||
(d.Isin != null && d.Isin.Contains(q, StringComparison.OrdinalIgnoreCase)) ||
|
||||
(d.Issuer != null && d.Issuer.Contains(q, StringComparison.OrdinalIgnoreCase)) ||
|
||||
(d.IssuerDisplayName != null && d.IssuerDisplayName.Contains(q, StringComparison.OrdinalIgnoreCase)) ||
|
||||
(d.ProductCategoryName != null && d.ProductCategoryName.Contains(q, StringComparison.OrdinalIgnoreCase))
|
||||
).ToList();
|
||||
}
|
||||
|
||||
derivatives = derivatives.OrderBy(d => d.Leverage).ToList();
|
||||
|
||||
int totalCount = derivatives.Count;
|
||||
if (page.HasValue && pageSize.HasValue && page.Value > 0 && pageSize.Value > 0)
|
||||
{
|
||||
int pSize = Math.Clamp(pageSize.Value, 1, 200);
|
||||
int pIndex = Math.Max(1, page.Value);
|
||||
int totalPages = (int)Math.Ceiling((double)totalCount / pSize);
|
||||
|
||||
Response.Headers["X-Total-Count"] = totalCount.ToString();
|
||||
Response.Headers["X-Total-Pages"] = totalPages.ToString();
|
||||
Response.Headers["X-Current-Page"] = pIndex.ToString();
|
||||
|
||||
derivatives = derivatives.Skip((pIndex - 1) * pSize).Take(pSize).ToList();
|
||||
}
|
||||
|
||||
return Ok(derivatives);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[AssetsController] Fehler beim Abrufen der Derivate für {Isin}", cleanIsin);
|
||||
}
|
||||
|
||||
return Ok(new List<DerivativeDto>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serviert das SVG-Logo direkt aus dem gemounteten Docker Volume (Volumes.LogosRelativePath).
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user