Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 3개 있습니다.)
닷넷: 2183. C# - eFriend Expert OCX 예제를 .NET Core/5+ Console App에서 사용하는 방법
; https://www.sysnet.pe.kr/2/0/13482

닷넷: 2186. 한국투자증권 KIS Developers OpenAPI의 C# 래퍼 버전 - eFriendOpenAPI NuGet 패키지
; https://www.sysnet.pe.kr/2/0/13498

닷넷: 2199. C# - 한국투자증권 KIS Developers OpenAPI의 WebSocket Ping, Pong 처리
; https://www.sysnet.pe.kr/2/0/13521




한국투자증권 KIS Developers OpenAPI의 C# 래퍼 버전 - eFriendOpenAPI NuGet 패키지

지난 글에도 언급했지만,

C# - eFriend Expert OCX 예제를 .NET Core/5+ Console App에서 사용하는 방법
; https://www.sysnet.pe.kr/2/0/13482

한국 투자 증권은 2가지 유형의 HTS API를 지원합니다.

  • KIS Developers 서비스 (Web API 기반)
  • eFriend Expert 서비스 (OCX 기반)

그렇습니다. 위의 "KIS Developers"는 OCX 없이, 우리가 익히 알고 있던 OpenAPI의 개념 그대로 AppKey와 AppSecret 키를 신청해서 받기만 하면, 이후 런타임 시에 그 키를 전달해 Access Token을 발급받아 통신할 수 있는 순수 Web API 유형의 통신 방식을 따릅니다.

사용법도 어렵지 않은데요, 단지 코드가 번잡해 그런 부분은 지면(?) 관계상 생략하고 제가 예제로 만든 라이브러리를 사용하는 방법을 간단하게 살펴보겠습니다. ^^

우선, NuGet으로부터 패키지 참조를 추가하고,

Install-Package eFriendOpenAPI

// Web API 기반의 서비스 이름이 "KIS Developers"인데, 이게 좀 식별자로는 어울리지 않는 느낌이어서 이름 자체는 "eFriendOpenAPI"로 한 것입니다.
// 즉, 이름으로는 OCX 버전의 래퍼같지만 Web API의 래퍼입니다.

API 신청을 통해 받은 AppKey, AppSecret 값을 초기화합니다.

(string appKey, string secretKey, string account) = (... 여러분의 키값, 계좌번호...);

이때, 계좌번호에 해당하는 account 값도 함께 설정해야 하는데요, 왜냐하면, 한국 투자 증권의 개발자 사이트에서 계좌별로 AppKey, AppSecret을 신청하기 때문입니다.

그다음, 모의 도메인을 대상으로 할지에 대한 여부만 결정하고,

bool isVTS = false; // true: 모의 Domain, false: 실전 Domain

이렇게 eFriendClient 인스턴스를 생성해 줍니다.

eFriendClient client = new eFriendClient(isVTS, appKey, secretKey, account);

본격적인 Open API 호출을 하기에 앞서, Access Token을 받아와야 하는데요, 이에 대한 처리는 CheckAccessToken 메서드에 구현했으므로 다음과 같이만 호출해 주면 됩니다.

if (await client.CheckAccessToken() == false)
{
    Console.WriteLine("Failed to get AccessToken");
    return;
}

한국 투자 증권은 Access Token의 유효 기간을 1일로 설정하고 있는데요, 따라서 한 번 받으면 그동안에는 다시 생성할 필요가 없으므로 제가 만든 CheckAccessToken 메서드에서는 내부적으로 파일을 생성해 재사용하고 있습니다. 즉, 하루가 지나기 전에 CheckAccessToken 메서드를 다시 호출하면 Web API 호출을 하지 않고 파일로부터 Access Token을 읽어 반환합니다.

자, 그다음부터는 원하는 메서드를 호출하기만 하면 됩니다. 현재 제가 만들어 둔 API 호출은 딱 5개인데요,

  • 주식주문(현금)[v1_국내주식-001]
  • 주식주문(정정취소)[v1_국내주식-003]
  • 주식잔고조회
  • 주식현재가시세
  • 국내주식 실시간체결가(웹소켓)

이에 대한 사용을 대충 다음과 같이 할 수 있습니다.

// 좀 더 자세한 사용법은 NuGet README에서 설명합니다.
// https://www.nuget.org/packages/eFriendOpenAPI#readme-body-tab

{
    var dto = await client.주식현재가시세("305720");
    Console.WriteLine(dto);
    // 출력 결과:
    // (최저가: 23235) ~ (현재가: 23235) ~ (최고가: 23895), 전일 대비: -465, 호가 단위: 5, (305720, ETF)
}

{
    Console.WriteLine($"[계좌번호: {client.Account}]");
    var array = await client.주식잔고조회();

    foreach (주식잔고조회DTO dto in array)
    {
        Console.WriteLine($"\t{dto}");
    }
}

사실, 제가 전문적인 e-trader는 아니라서 앞으로 얼마나 더 API를 추가할지는 모르겠습니다. 단지, 저 스스로보다는 어떤 고마운 분이 저 C# 코드 뼈대를 보고 살을 붙여 나가 PR을 보내주시면 ^^ 기꺼이 nuget 패키지로 말아 올리는 수고는 제가 하는 정도로만... 봐주시면 좋겠습니다. 혹은 여러분이 직접 라이브러리를 구현할 때 뭔가 오류가 발생하면 제 코드와 비교해 문제를 해결하는 용도로도 괜찮을 것입니다. ^^

소스코드는 github에 있습니다.

stjeong/KIS
; https://github.com/stjeong/KIS




한국 투자 증권이 이렇게 획기적인 Open API를 내놓은 것은 환영할 만한 일입니다. 그렇지만, 아직 단점이 하나 있는데, 기존의 OCX가 제공하는 API만큼 풍부한 기능을 제공하지 않는다는 점입니다.

그러니까, Open API를 사용하기에 앞서 자신이 원하는 값을 제공하는지 먼저 꼼꼼하게 살펴보고 사용을 결정하는 것이 좋습니다. 괜히 구현을 시작했다가, 그 미진한 부분 하나 때문에 OCX 코드로 다시 선회해야 하는 귀찮음을 감수하고 싶진 않을 테니까요. ^^

그래도 좀 다행인 점은, 제법 활발(?)하게 기능 추가가 꾸준히 되고 있다는 점입니다. 관련해서는 한국 투자 증권 측의 "공지 사항"에 올라오고 있으니 가끔씩 들어가서 변경 사항을 확인하는 것이 좋겠습니다.

마지막으로, 혹시나 프로그램하다가 오류가 발생하면 구글 검색보다는 개발자 포럼의 Q&A 게시판을 검색하는 것이 더 좋습니다. 저도 라이브러리를 개발하면서 몇 가지 오류를 맞닥뜨렸는데 하나같이 구글 검색에는 어떠한 관련 글도 나오지 않았고, Q&A 게시판을 검색해야만 단서를 찾을 수 있었습니다.

여기서도 아쉬운 점이 있다면, 가뜩이나 검색 결과도 적은데 Q&A에 올린 질문들이 대부분 "잠긴" 글들이어서 어떤 경우에는 답변을 보는 것조차 할 수 없었습니다.




아래는 제가 겪은 오류 2개를 정리한 것입니다. 우선, Access Token을 정상적으로 받아와 처음 잔고 조회 API에 사용을 했더니 403 오류만이 반환되었습니다.

{StatusCode: 403, ReasonPhrase: 'Forbidden', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  ...[생략]...
  Content-Length: 77
  Content-Type: application/json
}
{"rt_cd":"1","msg_cd":"EGW00205","msg1":"credentials_type이 유효하지 않습니다.(Bearer)"}

처음엔 이게 뭔 오류인가 싶었는데 HTTP 헤더에 "/oauth2/tokenP" 인증 결과로 받은 access_token을 그대로 전달했기 때문입니다.

client.DefaultRequestHeaders.Add("authorization", "...Access Token...");

명시적으로 Bearer 유형임을 지정해야 합니다. ^^

client.DefaultRequestHeaders.Add("authorization", $"Bearer {access_token}");

// 위에서처럼 "Bearer"라고 명시해도 되지만,
// access token을 받아오는 /oauth2/tokenP의 반환에 token_type 값이 함께 날아오는 데 바로 그 값이 "Bearer"입니다.
// 따라서 현재는 하드 코딩해도 되지만, 그냥 안전하게 token_type으로 넘기는 것이 더 좋습니다.
// client.DefaultRequestHeaders.Add("authorization", $"{token_type} {access_token}");

또 한 가지가 있었는데요, 계좌 번호가 4개 있었는데 주식잔고조회 API 호출을 하면 그중 1개만 정상적으로 값을 반환하고 나머지는 전부 다음과 같이 INVALID_CHECK_ACNO 오류가 발생했습니다.

StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  ...[생략]...
  X-XSS-Protection: 1; mode=block
  Content-Length: 75
  Content-Type: application/json
}
{"rt_cd":"2","msg_cd":"OPSQ2000","msg1":"ERROR : INPUT INVALID_CHECK_ACNO"}

이에 대해서는 본문에 언급했던 것처럼, AppKey와 AppSecret을 발급받는 당시 아래와 같이 계좌를 1개 지정하게 됩니다.

apikey_per_account_1.png

즉, 그 계좌에 대해서만 잔고 조회가 되는 것이고 나머지 계좌들은 그것대로 서비스 신청을 해서 AppKey, AppSecret을 받아야만 잔고 조회를 할 수 있습니다.

(그나저나, "INVALID_CHECK_ACNO"의 "ACNO"는 오타로 보입니다. 아마도 "CANO"가 맞을 것입니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 1/12/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 106  107  [108]  109  110  111  112  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11258정성태8/1/201720312.NET Framework: 668. 지연 서명된 DLL과 서명된 DLL의 차이점파일 다운로드1
11257정성태7/31/201719898.NET Framework: 667. bypassTrustedAppStrongNames 옵션 설명파일 다운로드1
11256정성태7/25/201721830디버깅 기술: 90. windbg의 lm 명령으로 보이지 않는 .NET 4.0 ClassLibrary를 명시적으로 로드하는 방법 [1]
11255정성태7/18/201724342디버깅 기술: 89. Win32 Debug CRT Heap Internals의 0xBAADF00D 표시 재현 [1]파일 다운로드3
11254정성태7/17/201720765개발 환경 구성: 322. "Visual Studio Emulator for Android" 에뮬레이터를 "Android Studio"와 함께 쓰는 방법
11253정성태7/17/201721400Math: 21. "Coding the Matrix" 문제 2.5.1 풀이 [1]파일 다운로드1
11252정성태7/13/201719133오류 유형: 411. RTVS 또는 PTVS 실행 시 Could not load type 'Microsoft.VisualStudio.InteractiveWindow.Shell.IVsInteractiveWindowFactory2'
11251정성태7/13/201718618디버깅 기술: 88. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 (2)
11250정성태7/13/201722214디버깅 기술: 87. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 [1]
11249정성태7/12/201719958오류 유형: 410. LoadLibrary("[...].dll") failed - The specified procedure could not be found.
11248정성태7/12/201726520오류 유형: 409. pip install pefile - 'cp949' codec can't decode byte 0xe2 in position 208687: illegal multibyte sequence
11247정성태7/12/201720834오류 유형: 408. SqlConnection 객체 생성 시 무한 대기 문제파일 다운로드1
11246정성태7/11/201718882VS.NET IDE: 118. Visual Studio - 다중 폴더에 포함된 파일들에 대한 "Copy to Output Directory"를 한 번에 설정하는 방법
11245정성태7/10/201724628개발 환경 구성: 321. Visual Studio Emulator for Android 소개 [2]
11244정성태7/10/201724814오류 유형: 407. Visual Studio에서 ASP.NET Core 실행할 때 dotnet.exe 프로세스의 -532462766 오류 발생 [1]
11243정성태7/10/201721591.NET Framework: 666. dotnet.exe - 윈도우 운영체제에서의 .NET Core 버전 찾기 규칙
11242정성태7/8/201721128제니퍼 .NET: 27. 제니퍼 닷넷 적용 사례 (7) - 노후된 스토리지 장비로 인한 웹 서비스 Hang (멈춤) 현상
11241정성태7/8/201719776오류 유형: 406. Xamarin 빌드 에러 XA5209, APT0000
11240정성태7/7/201723591.NET Framework: 665. ClickOnce를 웹 브라우저를 이용하지 않고 쿼리 문자열을 전달하면서 실행하는 방법 [3]파일 다운로드1
11239정성태7/6/201724246.NET Framework: 664. Protocol Handler - 웹 브라우저에서 데스크톱 응용 프로그램을 실행하는 방법 [5]파일 다운로드1
11238정성태7/6/201721775오류 유형: 405. NT 서비스 시작 시 "Error 1067: The process terminated unexpectedly." 오류 발생 [2]
11237정성태7/5/201723435.NET Framework: 663. C# - PDB 파일 경로를 PE 파일로부터 얻는 방법파일 다운로드1
11236정성태7/4/201727156.NET Framework: 662. C# - VHD/VHDX 가상 디스크를 마운트하지 않고 파일을 복사하는 방법파일 다운로드1
11235정성태6/29/201721392Math: 20. Matlab/Octave로 Gram-Schmidt 정규 직교 집합 구하는 방법
11234정성태6/29/201718859오류 유형: 404. SharePoint 2013 설치 과정에서 "The username is invalid The account must be a valid domain account" 오류 발생
11233정성태6/28/201718773오류 유형: 403. SharePoint Server 2013을 Windows Server 2016에 설치할 때 .NET 4.5 설치 오류 발생
... 106  107  [108]  109  110  111  112  113  114  115  116  117  118  119  120  ...