build(infra): KIS API 클라이언트 시그니처 일원화 및 빌드 수정

- 수정: KisApiClient 메서드 반환 타입 Task<string> → Task<Dictionary<string, object>>로 통일
- 수정: GetOrRefreshTokenAsync ReadAsAsync → ReadFromJsonAsync로 변경
- 수정: PlaceholderKisApiClient IKisApiClient 인터페이스 완전 구현
- 수정: CollectionEndpoints 모든 WithOpenApi() 호출 제거
- 수정: Program.cs using 지시문 순서 재정렬
- 추가: Client/_Imports.razor Fluent UI 컴포넌트 네임스페이스 정의

이제 빌드 성공: QuantEngine.Web 프로젝트 컴파일 완료 (경고 0, 에러 0)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 23:19:35 +09:00
parent c56c9cc903
commit e7e7d1470d
6 changed files with 90 additions and 38 deletions
@@ -171,10 +171,10 @@ namespace QuantEngine.Infrastructure.External
return await response.Content.ReadAsStringAsync();
}
public Task<string> GetCurrentPriceAsync(string code)
public async Task<Dictionary<string, object>> 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<string, string>
{
@@ -182,12 +182,13 @@ namespace QuantEngine.Infrastructure.External
{ "FID_INPUT_ISCD", code }
}
);
return JsonSerializer.Deserialize<Dictionary<string, object>>(json) ?? new();
}
public Task<string> GetAskingPrice10LevelAsync(string code)
public async Task<Dictionary<string, object>> 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<string, string>
{
@@ -195,12 +196,13 @@ namespace QuantEngine.Infrastructure.External
{ "FID_INPUT_ISCD", code }
}
);
return JsonSerializer.Deserialize<Dictionary<string, object>>(json) ?? new();
}
public Task<string> GetDailyShortSaleAsync(string code, string startDate, string endDate)
public async Task<Dictionary<string, object>> 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<string, string>
{
@@ -210,12 +212,13 @@ namespace QuantEngine.Infrastructure.External
{ "FID_INPUT_DATE_2", endDate }
}
);
return JsonSerializer.Deserialize<Dictionary<string, object>>(json) ?? new();
}
public Task<string> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D")
public async Task<Dictionary<string, object>> 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<string, string>
{
@@ -227,12 +230,13 @@ namespace QuantEngine.Infrastructure.External
{ "FID_ORG_ADJ_PRC", "0" }
}
);
return JsonSerializer.Deserialize<Dictionary<string, object>>(json) ?? new();
}
public Task<string> GetInvestorTrendAsync(string code)
public async Task<Dictionary<string, object>> 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<string, string>
{
@@ -240,6 +244,7 @@ namespace QuantEngine.Infrastructure.External
{ "FID_INPUT_ISCD", code }
}
);
return JsonSerializer.Deserialize<Dictionary<string, object>>(json) ?? new();
}
}
}
@@ -173,7 +173,7 @@ public class KisApiClient : IKisApiClient
);
response.EnsureSuccessStatusCode();
var tokenData = await response.Content.ReadAsAsync<Dictionary<string, object>>();
var tokenData = await response.Content.ReadFromJsonAsync<Dictionary<string, object>>();
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;