eBEST C# XingAPI 래퍼 - 연속 조회 처리 방법
아래의 파이썬 강좌를 보면,
[24강] xingAPI를 이용한 데이터 연속 조회 (t1301, t1310)
; https://www.youtube.com/watch?v=oargZbRv7m4
연속 조회를 처리하는 방법이 나옵니다. 규칙은 간단한데요, summary 성격의 OUTBLOCK 결과의 값을 그대로 다음 번 조회 시의 INBLOCK 입력으로 넣어 주고 Request가 연속적임을 알리는 플래그를 설정하면 됩니다.
이런 처리를 XingAPINet에서는,
eBEST XingAPI의 C# 래퍼 버전 - XingAPINet Nuget 패키지
; https://www.sysnet.pe.kr/2/0/12134
다음과 같이 코딩할 수 있습니다. (bold 처리된 부분이 기존의 일반적인 쿼리 문에서와 달라진 코드입니다.)
/*
XingAPI/DevCenterSample/TR/업종/t1301/
; https://github.com/stjeong/XingAPI/tree/master/DevCenterSample/TR/%EC%97%85%EC%A2%85/t1301
*/
using (XingClient xing = new XingClient(useDemoServer))
{
if (xing.ConnectWithLogin(user) == false)
{
Console.WriteLine(xing.ErrorMessage);
return;
}
using (XQt1301 query = new XQt1301())
{
var inBlock = new XQt1301InBlock
{
shcode = Stock.SHCODE.KOSPI.현대건설,
starttime = "0900",
endtime = "1530",
};
while (true) // 1단계
{
query.SetBlock(inBlock);
if (query.Request() < 0)
{
break; // 쿼리 실패
}
var outBlock = query.GetBlock();
if (outBlock.IsValidData == false)
{
break; // 쿼리 해석 실패
}
foreach (var item in query.GetBlock1s())
{
item.Dump(Console.Out, DumpOutputType.Inline80Cols);
}
inBlock.CopyValueFromBlock(outBlock); // 2단계
if (outBlock.cts_time == "") // 3단계
{
break;
}
}
}
}
위의 코드를 말로 표현하면 다음과 같습니다.
1단계. 무한 반복 설정
2단계. 결괏값으로 나오는 outBlock의 값을 그대로 inBlock으로 복사
3단계. 마지막 연속 데이터라면 while 루프 문 탈출
이후, 연속적으로 Request()를 호출하면서 4단계의 조건이 만족될 때까지 반복
간단하죠!!! ^^
위의 코드는 연속 데이터의 끝까지 데이터를 조회하는 반면 원한다면 개수를 정하는 것도 가능합니다. 이에 대한 예제가 t1475에 나오는데요,
XingAPI/DevCenterSample/TR/업종/t1475/
; https://github.com/stjeong/XingAPI/tree/master/DevCenterSample/TR/%EC%97%85%EC%A2%85/t1475
// ...[생략]...
int pageSize = 10;
int totalSize = 30;
using (XQt1475 query = new XQt1475())
{
XQt1475InBlock inBlock = new XQt1475InBlock
{
shcode = Stock.SHCODE.KOSDAQ.이베스트투자증권,
datacnt = pageSize,
};
while (totalSize > 0)
{
query.SetBlock(inBlock);
if (query.Request() < 0)
{
break;
}
XQt1475OutBlock outBlock = query.GetBlock();
if (outBlock.IsValidData == false)
{
break;
}
foreach (var item in query.GetBlock1s())
{
item.Dump(Console.Out, DumpOutputType.Inline80Cols);
totalSize--;
}
inBlock.CopyValueFromBlock(outBlock);
}
}
t1475의 경우 InBlock에서 datacnt라는 속성이 있어 조회할 데이터 수량을 지정할 수 있습니다. 즉, 위의 경우에는 한 번에 10개씩 가져오는데 총 수량이 (최소) 30개가 될 때까지만 연속 데이터를 조회합니다. 역시 간단하죠!!! ^^
알아본 김에 Sqlite 지원도 추가했으니,
eBEST C# XingAPI 래퍼 - Sqlite 지원 추가
; https://www.sysnet.pe.kr/2/0/12145
연속 데이터를 DB에 쌓는 법도 볼까요? ^^ 아래는 t1310의 예제 코드인데,
/*
XingAPI/DevCenterSample/TR/업종/t1310/
; https://github.com/stjeong/XingAPI/tree/master/DevCenterSample/TR/%EC%97%85%EC%A2%85/t1310
*/
using (XQt1310 query = new XQt1310())
{
var inBlock = new XQt1310InBlock
{
shcode = Stock.SHCODE.KOSPI.현대건설,
daygb = XQt1310.DayGB.당일,
timegb = XQt1310.TimeGB.틱,
};
bool createFirst = true;
while (true)
{
query.SetBlock(inBlock);
if (query.Request() < 0)
{
break;
}
var outBlock = query.GetBlock();
if (outBlock.IsValidData == false)
{
break;
}
var blocks = query.GetBlock1s();
foreach (var item in blocks)
{
item.Dump(Console.Out, DumpOutputType.Inline80Cols);
}
blocks.WriteToDB(createFirst, inBlock.shcode);
createFirst = false;
inBlock.CopyValueFromBlock(outBlock);
if (string.IsNullOrEmpty(outBlock.cts_time) == true)
{
break;
}
}
}
보는 바와 같이 달라진 곳은 blocks.WriteToDB에 대한 호출 뿐입니다. 최초 호출 시에는 DB 테이블이 만들어져 있지 않으므로 첫 번째 인자(replace)에 true를 줘서 DB 테이블을 (기존에 있다면 삭제하고) 새로 생성할 수 있도록 합니다. 그다음, 두 번째 인자(tableNamePostfix)는 DB 테이블 명의 접미사인데 기본적으로 OutBlock의 이름을 사용하지만, 현실적으로 봤을 때 XQt1310 쿼리를 수행했을 때 "종목 코드(shcode)" 별로 데이터가 저장되어야 할 것이므로 "XQt1310_000720"과 같은 식의 테이블 명이 지정되도록 합니다.
이후, DB에 저장된 내용을 조회하고 싶다면 마찬가지로 접미사를 지정해 ReadFromDB 메서드를 호출하면 됩니다.
var multiBlock = XQt1310.ReadFromDB("000720"); // 000720 == 현대건설
Console.WriteLine($"# of items: {multiBlock.OutBlock1.Length}");
foreach (var item in multiBlock.OutBlock1)
{
item.Dump(Console.Out, DumpOutputType.Inline80Cols);
}
역시 간단하죠~~~!!! ^^
마지막으로, Request() 메서드는 bNext 인자 값을 하나 받는데 기본값은 null입니다. 그냥 이렇게 null로 설정하면 최초 XQtNNNN 객체 생성 후 첫 번째 Request 호출에 대해서는 "Request(false)"로 처리하고, 그 이후의 호출에 대해서는 "Request(true)"로 처리합니다. 다음 코드는 그에 대한 사례입니다.
using (XQt1301 query = new XQt1301())
{
// ...[생략]...
query.Request(); // == 객체 생성 후 첫 번째 호출이므로, query.Request(false)와 동일
// ...[생략]...
query.Request(); // == 두 번째 호출이므로, query.Request(true)와 동일
}
따라서, 연속 데이터 조회가 아닌데도 쿼리 객체를 재사용해 Request를 사용한다면 다음과 같이 명시적으로 false 설정을 해야 합니다.
using (XQt1301 query = new XQt1301())
{
// ...[생략]...
query.Request(false);
// ...[생략]...
query.Request(false);
}
또는, XQt1301 객체 생성 후 첫 호출은 언제나 false 처리되므로 다음과 같은 식으로 매번 XQtNNNN Query 객체를 생성해 처리할 수 있습니다.
for (int i = 0; i < 2; i ++)
{
using (XQt1301 query = new XQt1301())
{
// ...[생략]...
query.Request(); // == 객체 생성 후 첫 번째 호출이므로, query.Request(false)와 동일
}
}
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]