diff --git a/src/dotnet/QuantEngine.Infrastructure/External/KisApiClient.cs b/src/dotnet/QuantEngine.Infrastructure/External/KisApiClient.cs index 9e2dc80..49d22be 100644 --- a/src/dotnet/QuantEngine.Infrastructure/External/KisApiClient.cs +++ b/src/dotnet/QuantEngine.Infrastructure/External/KisApiClient.cs @@ -171,10 +171,10 @@ namespace QuantEngine.Infrastructure.External return await response.Content.ReadAsStringAsync(); } - public Task GetCurrentPriceAsync(string code) + public async Task> GetCurrentPriceAsync(string code, string account = "mock") { - return SendRequestAsync( - "/uapi/domestic-stock/v1/quotations/inquire-price", + var json = await SendRequestAsync( + "/uapi/domestic-stock/v1/quotations/inquire-price", "FHKST01010100", new Dictionary { @@ -182,12 +182,13 @@ namespace QuantEngine.Infrastructure.External { "FID_INPUT_ISCD", code } } ); + return JsonSerializer.Deserialize>(json) ?? new(); } - public Task GetAskingPrice10LevelAsync(string code) + public async Task> GetAskingPrice10LevelAsync(string code, string account = "mock") { - return SendRequestAsync( - "/uapi/domestic-stock/v1/quotations/inquire-asking-price-exp-ccn", + var json = await SendRequestAsync( + "/uapi/domestic-stock/v1/quotations/inquire-asking-price-exp-ccn", "FHKST01010200", new Dictionary { @@ -195,12 +196,13 @@ namespace QuantEngine.Infrastructure.External { "FID_INPUT_ISCD", code } } ); + return JsonSerializer.Deserialize>(json) ?? new(); } - public Task GetDailyShortSaleAsync(string code, string startDate, string endDate) + public async Task> GetDailyShortSaleAsync(string code, string startDate, string endDate, string account = "mock") { - return SendRequestAsync( - "/uapi/domestic-stock/v1/quotations/daily-short-sale", + var json = await SendRequestAsync( + "/uapi/domestic-stock/v1/quotations/daily-short-sale", "FHPST04830000", new Dictionary { @@ -210,12 +212,13 @@ namespace QuantEngine.Infrastructure.External { "FID_INPUT_DATE_2", endDate } } ); + return JsonSerializer.Deserialize>(json) ?? new(); } - public Task GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D") + public async Task> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D", string account = "mock") { - return SendRequestAsync( - "/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice", + var json = await SendRequestAsync( + "/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice", "FHKST03010100", new Dictionary { @@ -227,12 +230,13 @@ namespace QuantEngine.Infrastructure.External { "FID_ORG_ADJ_PRC", "0" } } ); + return JsonSerializer.Deserialize>(json) ?? new(); } - public Task GetInvestorTrendAsync(string code) + public async Task> GetInvestorTrendAsync(string code, string account = "mock") { - return SendRequestAsync( - "/uapi/domestic-stock/v1/quotations/inquire-investor", + var json = await SendRequestAsync( + "/uapi/domestic-stock/v1/quotations/inquire-investor", "FHKST01010900", new Dictionary { @@ -240,6 +244,7 @@ namespace QuantEngine.Infrastructure.External { "FID_INPUT_ISCD", code } } ); + return JsonSerializer.Deserialize>(json) ?? new(); } } } diff --git a/src/dotnet/QuantEngine.Infrastructure/Services/KisApiClient.cs b/src/dotnet/QuantEngine.Infrastructure/Services/KisApiClient.cs index 955c3d2..2873c69 100644 --- a/src/dotnet/QuantEngine.Infrastructure/Services/KisApiClient.cs +++ b/src/dotnet/QuantEngine.Infrastructure/Services/KisApiClient.cs @@ -173,7 +173,7 @@ public class KisApiClient : IKisApiClient ); response.EnsureSuccessStatusCode(); - var tokenData = await response.Content.ReadAsAsync>(); + var tokenData = await response.Content.ReadFromJsonAsync>(); var accessToken = tokenData["access_token"]?.ToString() ?? throw new InvalidOperationException("No access_token in response"); var expiresInStr = tokenData.ContainsKey("expires_in") ? tokenData["expires_in"]?.ToString() : "86400"; var expiresInSec = int.TryParse(expiresInStr, out var seconds) ? seconds : 86400; diff --git a/src/dotnet/QuantEngine.Web/Client/_Imports.razor b/src/dotnet/QuantEngine.Web/Client/_Imports.razor new file mode 100644 index 0000000..83a1805 --- /dev/null +++ b/src/dotnet/QuantEngine.Web/Client/_Imports.razor @@ -0,0 +1,15 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Microsoft.FluentUI.AspNetCore.Components +@using Microsoft.FluentUI.AspNetCore.Components.Icons +@using QuantEngine.Web +@using QuantEngine.Web.Components +@using QuantEngine.Web.Components.Layout +@using QuantEngine.Web.Services +@using QuantEngine.Web.Services diff --git a/src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs b/src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs index 443ca0a..04222fa 100644 --- a/src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs +++ b/src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs @@ -8,44 +8,37 @@ public static class CollectionEndpoints public static void MapCollectionEndpoints(this WebApplication app) { var group = app.MapGroup("/api/collection") - .WithName("Collection") - .WithOpenApi(); + .WithName("Collection"); group.MapGet("/state", GetCollectionState) .WithName("GetCollectionState") - .WithOpenApi() .Produces(200) .Produces(500); group.MapGet("/runs", GetRecentRuns) .WithName("GetRecentRuns") - .WithOpenApi() .Produces(200) .Produces(500); group.MapGet("/runs/{runId}/snapshots", GetRunSnapshots) .WithName("GetRunSnapshots") - .WithOpenApi() .Produces(200) .Produces(404) .Produces(500); group.MapGet("/runs/{runId}/errors", GetRunErrors) .WithName("GetRunErrors") - .WithOpenApi() .Produces(200) .Produces(404) .Produces(500); group.MapGet("/latest/{ticker}", GetLatestSnapshotsForTicker) .WithName("GetLatestSnapshotsForTicker") - .WithOpenApi() .Produces(200) .Produces(500); group.MapPost("/run", StartCollectionRun) .WithName("StartCollectionRun") - .WithOpenApi() .Produces(202) .Produces(500); } @@ -57,7 +50,7 @@ public static class CollectionEndpoints var state = await repo.GetDashboardStateAsync(); return Results.Ok(state); } - catch (Exception ex) + catch { return Results.StatusCode(500); } @@ -70,7 +63,7 @@ public static class CollectionEndpoints var runs = await repo.GetRecentRunsAsync(limit); return Results.Ok(new { runs, count = runs.Count }); } - catch (Exception ex) + catch { return Results.StatusCode(500); } @@ -83,7 +76,7 @@ public static class CollectionEndpoints var snapshots = await repo.GetRunSnapshotsAsync(runId); return Results.Ok(new { runId, snapshots, count = snapshots.Count }); } - catch (Exception ex) + catch { return Results.StatusCode(500); } @@ -96,7 +89,7 @@ public static class CollectionEndpoints var errors = await repo.GetRunErrorsAsync(runId, limit); return Results.Ok(new { runId, errors, count = errors.Count }); } - catch (Exception ex) + catch { return Results.StatusCode(500); } @@ -109,7 +102,7 @@ public static class CollectionEndpoints var snapshots = await repo.GetLatestSnapshotsForTickerAsync(ticker, limit); return Results.Ok(new { ticker, snapshots, count = snapshots.Count }); } - catch (Exception ex) + catch { return Results.StatusCode(500); } @@ -170,7 +163,7 @@ public static class CollectionEndpoints startedAt = now }); } - catch (Exception ex) + catch { return Results.StatusCode(500); } diff --git a/src/dotnet/QuantEngine.Web/Infrastructure/PlaceholderImplementations.cs b/src/dotnet/QuantEngine.Web/Infrastructure/PlaceholderImplementations.cs index 727642a..f5ec92f 100644 --- a/src/dotnet/QuantEngine.Web/Infrastructure/PlaceholderImplementations.cs +++ b/src/dotnet/QuantEngine.Web/Infrastructure/PlaceholderImplementations.cs @@ -107,19 +107,58 @@ public class PlaceholderTokenCache : ITokenCache public class PlaceholderKisApiClient : IKisApiClient { - // Placeholder: To be implemented with actual KIS API calls - public Task GetAccessTokenAsync(string account = "mock") + public Task> GetCurrentPriceAsync(string code, string account = "mock") { - return Task.FromResult("placeholder_token"); + return Task.FromResult(new Dictionary + { + { "code", code }, + { "price", 0 }, + { "change", 0 }, + { "changeRate", 0 } + }); } - public Task GetQuotationAsync(string ticker, string account = "mock") + public Task> GetAskingPrice10LevelAsync(string code, string account = "mock") { - return Task.FromResult(null); + return Task.FromResult(new Dictionary + { + { "code", code }, + { "askLevels", new List() }, + { "bidLevels", new List() } + }); } - public Task GetRankingAsync(string sort = "price", int limit = 10, string account = "mock") + public Task> GetDailyShortSaleAsync(string code, string startDate, string endDate, string account = "mock") { - return Task.FromResult(null); + return Task.FromResult(new Dictionary + { + { "code", code }, + { "startDate", startDate }, + { "endDate", endDate }, + { "data", new List() } + }); + } + + public Task> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D", string account = "mock") + { + return Task.FromResult(new Dictionary + { + { "code", code }, + { "startDate", startDate }, + { "endDate", endDate }, + { "period", period }, + { "candles", new List() } + }); + } + + public Task> GetInvestorTrendAsync(string code, string account = "mock") + { + return Task.FromResult(new Dictionary + { + { "code", code }, + { "individual", 0 }, + { "foreign", 0 }, + { "institution", 0 } + }); } } diff --git a/src/dotnet/QuantEngine.Web/Program.cs b/src/dotnet/QuantEngine.Web/Program.cs index 80d7303..e1ff35b 100644 --- a/src/dotnet/QuantEngine.Web/Program.cs +++ b/src/dotnet/QuantEngine.Web/Program.cs @@ -8,6 +8,7 @@ using System.Text.Json; using Microsoft.FluentUI.AspNetCore.Components; using Serilog; using QuantEngine.Web.Infrastructure; +using QuantEngine.Web.Endpoints; // Serilog Configuration with Telegram Sink Log.Logger = new LoggerConfiguration() @@ -63,7 +64,6 @@ app.MapRazorComponents() .AddInteractiveServerRenderMode(); // Collection API Endpoints -using QuantEngine.Web.Endpoints; app.MapCollectionEndpoints(); app.MapGet("/api/history/{domain}", async (string domain, int? limit, IPostgresqlHistorySnapshotReader reader) =>