본문 바로가기

backup

[HFT 시스템 트레이딩]기초 데이타 가공2

지난 글에서 썼던 데이타 기초 가공을 실제로 하는 것을 해보겠습니다.


제가 가지고 있는 원본 틱데이타는 아래와 같은 형식으로 되어 있습니다.


EUR/USD,20130902 00:00:01.905,1.32047,1.32091
EUR/USD,20130902 00:00:01.906,1.32058,1.32083
EUR/USD,20130902 00:00:02.005,1.32056,1.32081
EUR/USD,20130902 00:00:04.189,1.32061,1.32082
EUR/USD,20130902 00:00:04.190,1.32048,1.32094
EUR/USD,20130902 00:00:04.191,1.32059,1.32086
EUR/USD,20130902 00:00:04.305,1.32051,1.32095
EUR/USD,20130902 00:00:04.306,1.32065,1.3208
EUR/USD,20130902 00:00:06.104,1.32057,1.32082
EUR/USD,20130902 00:00:06.105,1.32059,1.32084



이 데이타는 시간 간격이 일정하지 않죠. 이 데이타를 시간 간격이 일정한 형태의 데이타로 변환을 해보겠습니다.


참고로 말씀드린다면, 위의 데이타를 물론 DB에 저장하고 SQL 쿼리를 한다면 훨씬 쉬울 수도 있습니다.

뭐 말하기 민망하기는 하지만, SQL 저도 누구못지 않게 다룰 줄 압니다. 복잡하고 시간 오래 걸리는 query들 빠르고 간단하게 동작하도록 튜닝도 많이 해봤습니다.

하지만, 여기서는 sql로 하지 않고, 오로지 c++ 프로그래밍으로만 데이타를 다루려고 합니다.


그 첫번째 이유는 데이타 분석을 빅데이타 단위로 확장하기 위해서입니다. 빅데이타 분석의 performance를 극대화하기 위해서

c++로 데이터 분석을 위해서 하는 것이고, 틱데이타 등의 시계열 데이타는 db에 저장했다가 다시 꺼내는 것보다, 바로 파일에서 읽고 쓰는 것이 제일 빠릅니다. 데이타 양이 많아지게 되면 하둡을 구성하고 big table을 만들어서 no sql형식으로 데이터를 불러다가 분석을

할 수 있습니다.


두번째 이유는 일단 처음 구축은 힘들지만, 기초만 만들어지면 sql이나 일반 상용프로그램에서 지원해주는 이상의 분석이 가능해집니다. 어떤게 가능해지는지는 나중에 보여드리도록 하겠습니다. 그리고 c++로 만드는게 속도 또한 가장 빠릅니다. matlab에서 며칠 돌아갈 분석이 c++에서는 몇 분만에 끝날 수 있습니다. matlab에서 이미 많은 것이 구현이 되어 있겠지만, 속도를 위해서 그냥 c++하기로 했습니다.


본론으로 돌아와서


위의 데이터를 가공하기 위해서는 기초적인 함수들이 필요로 합니다.



위의 함수는 c++ 의 기본 시간 변수인 time_t와 문자열간 변환을 위한 기본 함수입니다. strftime과 strptime에 대한 사용방법만 알면 간단한 내용입니다.






그리고 위의 함수는 그냥 평범한 평균과 표준편차 구하는 함수입니다.



위의 함수는 1.32047,1.32091 의 형식의 문자열로 되어 있는 bid와 ask를 double로 바꿔주는 함수입니다. 간단하게 설명을 하자면 ','를 만나기 전까지 price를 계산하다가, ','를 만나면 그 값을 bid로 저장하고, 다시 price 계산을 하여서 문자열이 끝나면 그걸 ask로 저장을 하게 됩니다.


문자열에서 double로 바꾸는 것은 문자열을 int형으로 바꾸는 방식에서 약간 변형을 한 방식으로 '.'를 만가기 전까지는 일반 int형으로 변환과 같이 처리를 하다가. '.'를 만난 이후로는 나눌 값에 곱하기 10을 하여서 값을 증가시키다가 마지막 bid, ask에 값을 넣을 때 나누기를 하는 방식입니다.




그리고 간단하게 시간이 불규칙한 틱데이타를 일정한 간격의 시간 데이타로 바꾸는 간단한 개념의 순서도 입니다.




t1은 틱데이타의 시간이고 t2는 일정한 간격의 시간 데이타입니다. 만약 시간 간격을 1초 단위로 한다면 t1과 t2가 시간이 같을 때는 tick 하나를 읽을 때마다 마지막 bid, ask값을 저장하고, tick count를 1 증가시킵니다. 그렇게 하다가 만약 t1이 t2보다 값이 커질 때 t2 시간의 데이타를 기록을 합니다. 마지막 bid, ask와 tick count를 t2의 데이타로 기록을 합니다.


만 약 t1이 t2보다 1초가 큰 경우라면 그냥 t2를 하나 증가시키고, 다시 위의 작업을 반복하면 되지만, 만약 t1이 t2보다 10초 크다면 t2는 일정하게 증가하면서 마지막에 기록했던 bid, ask값을 그대로 저장을 하고 tick count는 0로 기록을 합니다.


그런데 휴일 같은 경우는 tick데이타가 없을테니 그 날은 tick 값을 기록하지 말아야 하므로 t1과 t2가 1시간 이상 차이가 나는 경우는 그 사이에 값을 기록하지 말고, 바로 t2를 t1까지 점프 시킵니다.


위의 내용을 c++ 코드로 하면 다음과 같습니다.

아래의 코드는 1초 간격이 아니라 10초 간격으로 증가를 시켰습니다.

avg는 평균값인데 산술평균말고 기하평균을 썼습니다.

ret는 return 값으로 현재 평균에서 바로 전의 평균을 뺐습니다.

ret1는 1분의 평균이고,

var1는 1분간의 표준편차입니다.


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


if(t1 > t2){
                if(avg != 0){
                    bAvg = avg;
                    avg = sqrt(lastBid*lastAsk);
                    int a = avg * 100000;
                    int b = bAvg * 100000;
                    ret = (b - a);

                    memmove(((char*)rets) + sizeof(int), (char*)(rets), sizeof(rets) - sizeof(int));
                    rets[0] = ret;
                    t2 += 10;

                    ++n;

                    if(n >= 6){
                        int size = 6;
                        ret1 =  getAverage(rets, size);
                        var1 = getSigma(rets, size, ret1);

                    }else{
                        ret1 = 0;
                        var1 = 0;

                    }

                    cout << getString(t2) << "\t" << lastBid << "\t" << lastAsk << "\t" << avg << "\t" << ret << "\t" << ret1 << "\t" << var1 << "\t" << tick << endl;
                    tick = 0;

                }else{
                    avg = sqrt(lastBid*lastAsk);
                    ret = 0;
                }


                if(t1 - t2 > 3600){
                    t2 = t1;
                    avg = 0;
                    n = 0;
                }else {
                    while(t2 < t1){
                        t2 += 10;
                        ++n;
                        memmove(((char*)rets) + sizeof(int), (char*)(rets), sizeof(rets) - sizeof(int));
                        rets[0] = 0;
                        if(n >= 6){
                            int size = 6;
                            ret1 =  getAverage(rets, size);
                            var1 = getSigma(rets, size, ret1);

                        }else{
                            ret1 = 0;
                            var1 = 0;

                        }
                        cout << getString(t2) << "\t" << lastBid << "\t" << lastAsk << "\t" << avg << "\t" << 0 << "\t" << ret1 << "\t" << var1 << "\t" << 0 << endl;
                    }
                }
            }

            ++tick;
            lastBid = bid;
            lastAsk = ask;




----------------------------------------------------------------------------------------------------------------------------------


위의 로직을 실행시키면 처음의 데이타가


20130930 23:58:20    1.35234    1.35242    1.35238    1    0.5    0.763763    1
20130930 23:58:30    1.35233    1.3524    1.35236    1    0.666667    0.745356    2
20130930 23:58:40    1.35232    1.35239    1.35235    1    0.833333    0.687184    2
20130930 23:58:50    1.35232    1.35239    1.35235    0    0.833333    0.687184    0
20130930 23:59:00    1.35232    1.35239    1.35235    0    0.5    0.5    0
20130930 23:59:10    1.35232    1.35239    1.35235    0    0.5    0.5    0
20130930 23:59:20    1.35232    1.35239    1.35235    0    0.333333    0.471405    0
20130930 23:59:30    1.35232    1.35239    1.35235    0    0.166667    0.372678    0


이런 형식으로 변화가 됩니다. 10초 간격으로 데이타가 만들어지게 됩니다.


이렇게 데이타 가공하는 것도 sql로 짜는 것보다는 c코드로 만드는게 속도가 훨씬 빠르겠네요.


위의 내용의 전체 소스코드는 참고하시라고 파일로 첨부합니다.


가지고 계신 tick data형식에 맞게 변형해서 쓰세요.


TickConverter.cpp