Microsoft MVP성태의 닷넷 이야기
.NET Framework: 894. eBEST C# XingAPI 래퍼 - 연속 조회 처리 방법 [링크 복사], [링크+제목 복사]
조회: 732
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

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)와 동일
    }
}




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





[최초 등록일: ]
[최종 수정일: 2/20/2020 ]

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

비밀번호

댓글 쓴 사람
 



2020-07-03 09시19분
[나그네] 그저 스치다 본 글입니다만.. 한번 해보니 잘되네요.
예전에 생각하던 그런 로직을 이걸로 구현했습니다. 덕분에 감사합니다. 많이 도움이 되었습니다.

참고로..
올려주신 로직이 잘 안되고..
그냥 인자값을 InBlock으로 넣고. 그냥 Get으로 받아서 하는게 편한듯 합니다.
이건 증권사가 초기에 만든 구조에서 변경을 한것인지 여튼.. 저의 경우는 별 생각없이 되는듯 싶네요.
//일단은.. 차트 정보를 조회해보도록 하자.
            XQt8415 q = new XQt8415();
            XQt8415InBlock args = new XQt8415InBlock();
            args.shcode = "90199999";
            //args.shcode = StockDerivative.근월물;
            args.ncnt = 1; //1분을 의미
            args.qrycnt = 500; //? 이걸 정해도.. 무조건 다 가져온다. 1분이 396개인데.. 여기 개수랑 상관이 없나?
            //args.nday = "1"; //
            args.sdate = dateString8;
            args.edate = dateString8;
            args.comp_yn = 'N'; //압축

            //1. 값을 셋팅한다.
            bool TF = q.SetBlock(args);

            //2. 요청한다.
            int x = q.Request();

            //3. 가져온다.
            XQt8415OutBlock one = q.GetBlock();
            XQt8415OutBlock1[] datas = q.GetBlock1s();


[손님]

1  2  3  4  5  6  7  [8]  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12211정성태4/27/2020588개발 환경 구성: 486. WSL에서 Makefile로 공개된 리눅스 환경의 C/C++ 소스 코드 빌드
12210정성태4/20/2020819.NET Framework: 903. .NET Framework의 Strong-named 어셈블리 바인딩 (1) - app.config을 이용한 바인딩 리디렉션 [1]파일 다운로드1
12209정성태4/13/2020489오류 유형: 614. 리눅스 환경에서 C/C++ 프로그램이 Segmentation fault 에러가 발생한 경우 (2)
12208정성태4/12/2020596Linux: 29. 리눅스 환경에서 C/C++ 프로그램이 Segmentation fault 에러가 발생한 경우
12207정성태4/2/2020553스크립트: 19. Windows PowerShell의 NonInteractive 모드
12206정성태4/2/2020649오류 유형: 613. 파일 잠금이 바로 안 풀린다면? - The process cannot access the file '...' because it is being used by another process.
12205정성태4/2/2020507스크립트: 18. Powershell에서는 cmd.exe의 명령어를 지원하진 않습니다.
12204정성태4/1/2020428스크립트: 17. Powershell 명령어에 ';' (semi-colon) 문자가 포함된 경우
12203정성태3/18/2020767오류 유형: 612. warning: 'C:\ProgramData/Git/config' has a dubious owner: '...'.
12202정성태3/18/20201021개발 환경 구성: 486. .NET Framework 프로젝트를 위한 GitLab CI/CD Runner 구성
12201정성태3/18/2020614오류 유형: 611. git-credential-manager.exe: Using credentials for username "Personal Access Token".
12200정성태3/18/2020962VS.NET IDE: 145. NuGet + Github 라이브러리 디버깅 관련 옵션 3가지 - "Enable Just My Code" / "Enable Source Link support" / "Suppress JIT optimization on module load (Managed only)"
12199정성태3/17/2020475오류 유형: 610. C# - CodeDomProvider 사용 시 Unhandled Exception: System.IO.DirectoryNotFoundException: Could not find a part of the path '...\f2_6uod0.tmp'.
12198정성태3/17/2020602오류 유형: 609. SQL 서버 접속 시 "Cannot open user default database. Login failed."
12197정성태3/17/2020692VS.NET IDE: 144. .NET Core 콘솔 응용 프로그램을 배포(publish) 시 docker image 자동 생성 - 두 번째 이야기
12196정성태3/17/2020607오류 유형: 608. The ServicedComponent being invoked is not correctly configured (Use regsvcs to re-register).
12195정성태3/17/2020759.NET Framework: 902. C# - 프로세스의 모든 핸들을 열람 - 세 번째 이야기
12194정성태3/16/2020735오류 유형: 607. PostgreSQL - Npgsql.NpgsqlException: sorry, too many clients already
12193정성태3/16/2020636개발 환경 구성: 485. docker - SAP Adaptive Server Enterprise 컨테이너 실행
12192정성태3/14/2020789개발 환경 구성: 484. docker - Sybase Anywhere 16 컨테이너 실행
12191정성태3/14/20201235개발 환경 구성: 483. docker - OracleXE 컨테이너 실행 [1]
12190정성태3/14/2020439오류 유형: 606. Docker Desktop 업그레이드 시 "The process cannot access the file 'C:\Program Files\Docker\Docker\resources\dockerd.exe' because it is being used by another process."
12189정성태3/13/20201217개발 환경 구성: 482. Facebook OAuth 처리 시 상태 정보 전달 방법과 "유효한 OAuth 리디렉션 URI" 설정 규칙
12188정성태9/24/2020648Windows: 169. 부팅 시점에 실행되는 chkdsk 결과를 확인하는 방법
12187정성태3/12/2020500오류 유형: 605. NtpClient was unable to set a manual peer to use as a time source because of duplicate error on '...'.
12186정성태3/12/2020609오류 유형: 604. The SysVol Permissions for one or more GPOs on this domain controller and not in sync with the permissions for the GPOs on the Baseline domain controller.
1  2  3  4  5  6  7  [8]  9  10  11  12  13  14  15  ...