feat(kis): KIS API 클라이언트 .NET 포팅 완료

**구현:**
- IKisApiClient.cs: 완전한 read-only 메서드 인터페이스
  - GetCurrentPriceAsync, GetAskingPrice10LevelAsync
  - GetDailyShortSaleAsync, GetDailyItemChartPriceAsync
  - GetInvestorTrendAsync

- KisApiClient.cs: 완전한 .NET 구현 (kis_api_client_v1.py 포팅)
  - KisCredentials: 환경변수 + Windows 레지스트리 폴백
  - ITokenCache 통합: PostgreSQL 기반 토큰 캐싱
  - AssertReadOnly: 주문 API 차단 (governance/rules/06_no_direct_api_trading.yaml)
  - HttpClient: 비동기 API 호출 + 헤더 관리
  - 모든 quotation 조회 메서드 구현

**보안:**
- FORBIDDEN_PATH_SUBSTRINGS: "/trading/" 경로 차단
- FORBIDDEN_TR_ID_PREFIXES: TTTC/VTTC 주문 TR_ID 차단
- 매수/매도 API 절대 호출 불가 (2차 방어)

**DI 통합:**
- Program.cs: builder.Services.AddScoped<IKisApiClient, KisApiClient>();
- HttpClientFactory 패턴 활용

**다음 단계:**
- PostgresTokenCache 구현
- CollectionRepository PostgreSQL 구현
- Collection 엔드포인트 완성
- Web API 통합 테스트

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 23:15:40 +09:00
parent 66f75d9014
commit c56c9cc903
46 changed files with 921 additions and 15 deletions
@@ -3,12 +3,40 @@ using System.Threading.Tasks;
namespace QuantEngine.Core.Interfaces
{
/// <summary>
/// KIS Open API 클라이언트 (read-only 전용).
/// 매수/매도 주문은 절대 금지 (governance/rules/06_no_direct_api_trading.yaml).
/// </summary>
public interface IKisApiClient
{
Task<string> GetCurrentPriceAsync(string code);
Task<string> GetAskingPrice10LevelAsync(string code);
Task<string> GetDailyShortSaleAsync(string code, string startDate, string endDate);
Task<string> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D");
Task<string> GetInvestorTrendAsync(string code);
/// <summary>
/// 주식현재가 시세 조회.
/// TR_ID: FHKST01010100
/// </summary>
Task<Dictionary<string, object>> GetCurrentPriceAsync(string code, string account = "mock");
/// <summary>
/// 주식현재가 호가/예상체결 (10단계).
/// TR_ID: FHKST01010200
/// </summary>
Task<Dictionary<string, object>> GetAskingPrice10LevelAsync(string code, string account = "mock");
/// <summary>
/// 국내주식 공매도 일별추이.
/// TR_ID: FHPST04830000
/// </summary>
Task<Dictionary<string, object>> GetDailyShortSaleAsync(string code, string startDate, string endDate, string account = "mock");
/// <summary>
/// 주식현재가 일자별 차트.
/// TR_ID: FHKST03010100
/// </summary>
Task<Dictionary<string, object>> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D", string account = "mock");
/// <summary>
/// 주식현재가 투자자 매매동향 (개인/외국인/기관).
/// TR_ID: FHKST01010900
/// </summary>
Task<Dictionary<string, object>> GetInvestorTrendAsync(string code, string account = "mock");
}
}
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("QuantEngine.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+aad4788e8430ad7244d0628047aaf40d0590ef95")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+66f75d90147cc79aede830c90dd0b6fefe5dce0b")]
[assembly: System.Reflection.AssemblyProductAttribute("QuantEngine.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("QuantEngine.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
a275438f4b4df0f8d54e6834eea46c8f83eabbb1cf21ee0533f06d867e49ec68
a42f144c7048f344f7d30f4862120ef236c2b6773e17f93afe31b500b0ce422d
@@ -1 +1 @@
79145411294c3e36a015e6e3a0e89de48f8827bccbb71741b1505491550e55a3
b49c624a74a19d171e6b45c0e42dc7f77445eb8fdde390082a56dd78ecd8c3b8