바이오시그널이란 우리 몸에서 내보내는 전기신호, 뇌파, 심전도, 근전도와 같은 타임시리즈 데이터로, 본 기술은 기계학습 기법을 이용하여 바이오시그널을 학습하고 모델링하여 새로운 환자나 질병을 진단하고 예측하는데 이용하는 기술이다. 본 기술은 간단한 센서와 통신 장비만을 갖춘 저사양 하드웨어로도 구현이 가능하며, 휴대형 소형 의료 진단 장비로 개발하여 집이나 외부에서 실시간으로 질병을 진단할 수 있게 한다.

 

 

 

KISTI_vol.80_interview_Kim.pdf
0.28MB

posted by Dr.Deeeep

올해(2019년)는 논문도 못쓰고 특허만 3건을 받았다.

모두 딥러닝을 이용한 치매 진단 관련이다. 모두 미국 특허 출원 진행중이다.

 

딥러닝 기술 이용 치매 진단 관련 3건 특허

 

1. "질병예측 장치 및 이를 이용한 질병 예측 방법 (등록번호: 10-2057047)"은 뇌파나 심전도를 분석하여 치매를 조기 진단함에 있어 자질 추출 및 진단 과정의 블랙박스를 없애고 계산 복잡도를 낮추어 실시간 진단을 가능하게 하는 기술이다. '인바디' 처럼 휴대용 소형 치매 진단기를 개발하기 위해서 필수적인 기술이다.

 

개념도

 

2. "바이오 시그널 가시화 시스템 및 유효 패턴 추출 방법 (등록번호: 10-2009758)"은 뇌파나 심전도등 바이오 시그널에서 질병인과 정상인 그룹의 시그널을 모델링 및 가시화하고, 두 그룹을 구별하는 결정적인 패턴을 결정/인식/추출하는 방법이다.

 

 

3. "배회 감지 서버 및 이를 이용한 배회 감지 방법 (등록번호: 10-1996212)"는 치매 환자가 배회를 시작 할때 이 상황을 빨리 인식하고 보호자에게 연락하기 위한 특허이다. 딥러닝의 임베딩 기술을 이용하여 걸음 걸이의 요소(이동, 방향전환)등을 벡터화한 후 벡터 연산을 통해 비정상 상황을 빨리 감지한다.

 

 

 

posted by Dr.Deeeep

word2vec 용 US 특허 (USPTO) 데이터

상념 2019. 1. 10. 10:21

 

최근에는 word2vec을 이용하여 문서 데이터 분석을 많이 하는데 미국 특허 데이터 (USPTO)를 분석하면서 만들어 놓은 word2vec ready 데이터를 공개하고자 한다.

word2vec은 이제 공개된 것도 많아서 일반인들도 쉽게 사용할 수 있다. 문제는 USPTO 데이터가 너무 방대하고 word2vec 에 걸기 위해서는 먼저 청킹이 되어야 하는데 컴퓨팅 파워 뿐 아니라 시간도 많이 걸려서 쉽게 할 수 없다는 거다.

청킹은 복합명사를 구분하는 것으로 텍스트 분석에서는 필수적 단계이다. 예를 들어 data mining이라는 기술명을 청킹 없이 그냥 word2vec에 걸면 data와 mining이 별개로 입력이 되므로 "data mining"이라는 복합 명사가 갖는 의미는 사라져 버리는 것이다.

이번에 공개하는 데이터는 Stanford core NLP를 이용하여 POS tagging를 한 후 자체 chunking 알고리즘을 이용하여 복합명사를 표시('_' 로 연결)한 데이터로 1994년부터 2017년도까지 전체 USPTO 이며 타이틀, abstract, claims를 커버하고 있다. 2018년이후 데이터도 향후 특허가 공개되는대로 계속해서 추가로 공개할 계획이다.

다운로드 방법은 researchgate.net에서 "USPTO word2vec ready"으로 검색하면 된다.

데이터 인용시에는 "Seonho Kim (2017), Processed Word2Vec ready US Patent research data, ResearchGate, https://doi.org/10.13140/RG.2.2.17439.66721" 라고 달아주시면 감사.

 

 

 

 

 

 

 

posted by Dr.Deeeep

딥러닝에서 데이터 normalization 범위

상념 2018. 11. 7. 09:50

 

 

딥러닝에서 데이터 전처리시 가장 궁굼한 것 중 하나가, normalization의 대상 범위를 어떻게 정할 것인가? 인데 신경망을 연구하는 사람들은 이미 다 알고 있는 것인지도 모르겠다.

normalization 방법을 단순히 try and error 방법으로 실험으로만 결정할 문제는 아닌것이다. 

아래 이미지는 UCI EEG에서의 normalization을 이거 저거 해보면서 만든 슬라이드 중 일부인데. 이 이외에도 여러 가지 있고 각각 결정해야할 변수들이 많다. 또 실제 각 normalization 시 참고 백데이터 범위를 global 데이터를 대상으로 할 것인가 현재 인스턴스만을 대상으로 할 것인가까지 고려해야 하므로 더 다양한 조합의 방법이 있으므로 이거 저거 다 실험해 보는것은 만만치 않다.

그런데 요즘 몇가지 실험을 해보면서 확인한 바로는 뉴럴넷에 사용되는 액티베이션 펑션에 따라 결정이 되어야한다는 것이다. 액티베이션 펑션이 출력하는 범위의 데이터로 전처리 해야만 전파 중 정보 손실이 없는 것이다. 예를 들어 sigmoid 같은 경우는 0.0~1.0, tanh 같은 경우는 -1.0~1.0 정도이다. 따라서 이러한 펑션을 사용하는 신경망에서 z-score normalization은 다시 한번 생각해 봐야한다.

 

 

 

 

posted by Dr.Deeeep

딥러닝에서 노이즈의 중요성??

상념 2017. 1. 12. 00:59

 

 

위 그림은 이글과 아무 관련이 없고 구글에서 퍼온 그림임.

뇌파를 보다보면 점점 노이즈 처리의 어려움으로 분석의 한계에 봉착하게 된다.아니 노이즈 처리의 어려움까지 가기전에 어디까지를 노이즈로 할것이고 어느 영역까지를 뇌파로 할것인지 결정하는 것부터 큰문제거리다. 그만큼 뇌파라는게 온갖 생체,환경,장비시그널의 결합체인것이다. 뇌파에는 뇌파이외에도, 심전도, 관측장비시그널, 근육움직임파동, 눈깜빡임, 눈동자 움직임, 턱근육 움직임, 전류, 저항잡음, 주변환경신호,등등이 섞여 있는데. 이건 마치 수백명이 물장구치는 수영장에서 철수가 만드는 파형만을 뽑아분석하려는 것과 같다... 어쩄든 그런 얘기를 하려는 건 아니고.

노이즈가 극히 적다는 가정하에 노이즈가 러닝에 어떤 영향을 끼지는지 조사를 해보았다. 몇가지 실험을 해보면 노이즈가 있는 데이터는 러닝 효율이 좋다. 내가 가진 정신착란 생쥐의 뇌파의 경우는 96퍼센트의 정확률로 분류하기까지 한다. 어마어마하게 뭔가 잘못된것이다. 물론 오버피팅이 되는 것이다. 첨부 이미지처럼 저렇게 electric pop 노이즈의 경우는 특히 그렇다. 쉽게 말해 저렇게 특이한 데이타(노이즈)가 들어오면 기계가 기억하기 쉽기 때문에 오버피팅이 되는 것이다. 마치 학생들 이름을 잘 못외우는 교사가 코에 유난히 큰 점이 있는 학생의 이름은 잘 기억하는 것과 같다( 맞는 예인가? ) 이러한 노이즈는 학습된 기계의 지능자체를 올려주는 것은 아니기때문에 지양해야한다.

하지만 저런 노이즈 말고 좀더 부드러운 노이즈는 어떨까? 몇몇 논문에서는 마일드한 노이즈를 섞어서 학습하는 것이 기계의 지능을 높이는 바람직한 학습을 가능하게 한다고 밝히고 있다. 즉, 앞의 예를 이용하면, 거의 대부분의 학생들 얼굴에 적절히 주근깨와 점들이 있다면 그 교사는 주근깨와 점에 집중하지 않고 학생들의 얼굴과 그외 본질에 연관하여 이름을 기억하게 되므로 더 많은 학생의 이름을 오래 기억할 수 있다. 딥러닝에 드롭아웃을 주는 이유도 아마 이와 같은 맥락인듯하다. 데이터에 노이즈를 넣을 수는 없으니까 학습할 때 노이즈를 줘서 학습 효과를 떨어뜨리는 것이다.

현실로 돌아와서..  뇌파에서는 저 그림과 같은 노이즈를 지우는 것은 사실 큰 의미는 없어 보인다. 이미 뇌파는 앞서 말한 노이즈 아닌 불필요 데이터들과 섞여 크게 요동치고 있고 자동화된 노이즈 제거 노력은 오히려 데이터를 일그러뜨려 망칠뿐이다. 그 보다는 뇌파와 섞이는 다른 신호들도 모두 저장하고 모두 같이 분석하는 기술의 개발이 필요한듯하다. 그럴려면 엄청난 양의 데이터 분석이 필요하겠지만..

 

posted by Dr.Deeeep

딥러닝모델6 (A31) 설계

카테고리 없음 2016. 9. 30. 04:18

Bigdata-trader.com의 31번째 알고리즘(모델번호 A31이며 6번째 딥러닝 모델)을 개발하기 위한 연구 노트

목적
딥러닝 기술을 이용하여 급등주의 사전 조짐을 학습 가능한가 테스트 하기 위함. 여기서 급등주란 일반적인 우상향주가 아닌 장기간 소외되던 종목이 5일간 연속 으로 하루평균 10%이상의 가격 상승을 경험 한 종목으로 정의 하기로 함.

가설
주가의 급변(급 상승)은 새로운 호재 나 수익성 개선에 따른 예측 불가의 시장의 자연스러운 가격 변동이 아닌 특정 매수 세력의 의도된 행위의 결과이고, 매수 세력이 사전에 수년에서 수 개월간 해당 종목에서 준비를 한 후 행한 행위의 결과임을 가정. 이러한 준비 행위는 급등 직전 몇 달간의 거래 데이터를 기계 학습함으로써 포착 할 수 있는 특이한 패턴을 갖음을 가정 함. 

방법
과거 데이터에서 급등주를 필터링 및 수집함. 세력주 지수를 이용하여 20일 눌림목 지수 특정값 이상 종목중 급등주 정의에 해당하는 것만 선택. 급등전 강기간 소외 되었음을 확인 하는 루트 추가 필요. 1차 수집정보는 (종목번호와 급등 시작 날짜). 1차 수집 정보만을 ann_builder를 이용하여 2차 수집 정보를 수집함. 2차 수집 정보(시간, 주가, 국내외 인덱스, 외인 거래량, 외인 포션등)는 시계열 데이터로 생성하며 수집기간을 파라미터 입력으로 받아 디비에서 추출하여 ann_builder 입력 폼으로 변형. 어느정도의 수집 기간이 보장되어야 하므로 신규 종목은 제외되어야함 (수집 시작일에 데이터 시작일보다 이전인 종목 제외). 
네거티브 클래쓰 데이터로 급등주 외의 일반적 우상향주, 우하향주 등도 같이 모아야함.

서비스를 위해서는 트레이닝이 끝난 네트워크를 종목별로 파일로 저장하여 가지고 있어야 하는데 cafe24에서는 그들의 정책상 keras를 수행할 수 없을 듯. 자바만 가능하므로 A26~A30과 같이 A31과 관련된 모든 코드는 dl4j로 작성해야 할 듯.

추가적으로 개발해야 할 툴. 패키지에 util_rapidSoaringANNBuilder.java 추가. 박스권 상향 이탈과 동시에 급등하는 패턴을 찾는 유틸리티. 급등주의 조건이 까다로우므로 퀄리파이하는 루틴필요. 다음과 같은 순서로..

1) 새로운 테이블 추가: 다른 쪽에서도 공유할 수 있도록 패턴 이름으로 분리하여 저장 

mysql>create table patternfound
(
  patternname varchar(30) not null,
  itemcode varchar(8) not null,
  a varchar(10) not null,         // start date of soaring
  b varchar(10),    
  c varchar(10),    
  d varchar(10),
  primary key (patternname, itemcode, a) 
);

2) 매일 자동 업데이트시 세력지수 테이블내 모든 종목 추출 => 후보들

3) 후보들 중 원하는 패턴인가 qualify

4) qualify 리턴 값은 soaring starting date 임. 테이블의 a 에 저장

5) 장기간 수집 후 patternfound 테이블을 이용 디비 재검색하여 2차 데이터 수집

6) 2차 데이터이용 학습 데이터 생성

7) 학습 데이터 생성시 중복 체크 필수. 같은 "종목+startdate" 혹은 같은 종목코드인테 startdate가 근소하게 무의미하게 차이가 나는 레코드가 존재할 수 있으므로 확인 필요

 

 

 

posted by Dr.Deeeep

나만의 로보 어드바이저(robo-advisor) 만들기 [5]

금융 2016. 9. 23. 16:23

 

 

 

 

오늘은 Python과 CybosPlus를 이용하여 장중 실시간 종목 가격 변동을 모니터링하고 특정 조건(매수 혹은 매도가 도달)만족시 이벤트를 생성하는 방법을 알아보자. 

 

먼저 첨부된 python 코드는, 깔끔하지는 않지만, 장중 정해준 종목을 계속 모니터링하다가 정해진 이벤트(트레이딩)이 발생할 경우 발생한 트레이딩 정보와 변동률을 화면에 뿌려주는 기능을 한다. 

이 코드를 조금 수정하면 이벤트가 발생한 경우에 사용자 펑션 호출하여 원하는 조건(매수 혹은 매도 조건 도달, 특정 가격이상 변동, 급작스런 가격변동 탐지등)을 만족하는가를 체크하고 만족하는 경우 특정 행동을 하도록 할 수 있을것이다.

 

특정 조건 만족시 매수, 혹은 매도를 실행하는 코드를 추가하면 실시간 트레이딩이 가능해지는데 이 부분은 다음 시간에 다루기로 한다.

 

 

 

코드 설명:

 

 

 

 

 

__author__ = 'Dr. Deeeep'

import win32com.client

import io

 

 

""" Memo

02: change rate

13: currentprice

18: currenttime

"""

activeFlag = [        1,        1,        0,       0,       0,       0,      0]

itemcode =   ['A017680','A052790','A032860', 'A900110', 'A033130']

############### deco, actoz, steel, EAH, cho

crArray =    [       '',       '',       '',      '',      '',  '']

 

class CpEvent0:

    #print("E0: flag=", activeFlag[0])

    instance = None

    def OnReceived(self):

        #print("E0: flag=", activeFlag[0])

        if (activeFlag[0]>0):

            currentprice = CpEvent0.instance.GetHeaderValue(13)

            changeprice = CpEvent0.instance.GetHeaderValue(2)

            changerate = round(((changeprice / (currentprice - changeprice)) * 100.0),2)

            crArray[0] = changerate

            prt_style_all(0, changerate, currentprice, changeprice)

            #prt_style(0, changerate, currentprice, changeprice)

            #print(itemcode[0], " ", changerate, "         E0: ", currentprice, "  ", changeprice);  

        

class CpEvent1:

    #print("E1: flag=", activeFlag[1])

    instance = None

    def OnReceived(self):

        #print("E1: flag=", activeFlag[1])

        if (activeFlag[1]>0):

            currentprice = CpEvent1.instance.GetHeaderValue(13)

            changeprice = CpEvent1.instance.GetHeaderValue(2)

            changerate = round(((changeprice / (currentprice - changeprice)) * 100.0),2)

            crArray[1] = changerate

            prt_style_all(1, changerate, currentprice, changeprice)

            #prt_style(1, changerate, currentprice, changeprice)

            #print(itemcode[1], "      ", changerate, "     E1: ", currentprice, "  ", changeprice);  

        

class CpEvent2:

    #print("E2: flag=", activeFlag[2])

    instance = None

    def OnReceived(self):

        #print("E2: flag=", activeFlag[2])

        if (activeFlag[2]>0):

            currentprice = CpEvent2.instance.GetHeaderValue(13)

            changeprice = CpEvent2.instance.GetHeaderValue(2)

            changerate = round(((changeprice / (currentprice - changeprice)) * 100.0),2)

            crArray[2] = changerate

            prt_style_all(2, changerate, currentprice, changeprice)

            #prt_style(2, changerate, currentprice, changeprice)

            #print(itemcode[2], "          ", changerate, " E2: ", currentprice, "  ", changeprice);  

 

class CpEvent3:

    #print("E3: flag=", activeFlag[3])

    instance = None

    def OnReceived(self):

        #print("E3: flag=", activeFlag[3])

        if (activeFlag[3]>0):

            currentprice = CpEvent3.instance.GetHeaderValue(13)

            changeprice = CpEvent3.instance.GetHeaderValue(2)

            changerate = round(((changeprice / (currentprice - changeprice)) * 100.0),2)

            crArray[3] = changerate

            prt_style_all(3, changerate, currentprice, changeprice)

            #prt_style(3, changerate, currentprice, changeprice)

            #print(itemcode[3], "          ", changerate, " E3: ", currentprice, "  ", changeprice);  

 

class CpEvent4:

    #print("E4: flag=", activeFlag[4])

    instance = None

    def OnReceived(self):

        #print("E4: flag=", activeFlag[4])

        if (activeFlag[4]>0):

            currentprice = CpEvent4.instance.GetHeaderValue(13)

            changeprice = CpEvent4.instance.GetHeaderValue(2)

            changerate = round(((changeprice / (currentprice - changeprice)) * 100.0),2)

            crArray[4] = changerate

            prt_style_all(4, changerate, currentprice, changeprice)

            #prt_style(4, changerate, currentprice, changeprice)

            #print(itemcode[4], "          ", changerate, " E4: ", currentprice, "  ", changeprice);  

 

def prt_style_all(classnum, chrate, curprice, chprice):

    print(classnum, ", ", enter_crArray(), curprice, ",", chprice)

 

def prt_style(classnum, chrate, curprice, chprice):

    print(classnum, enter_spc(classnum), chrate, ",", exit_spc(classnum), ",", curprice, ",", chprice)

    #print(itemcode[classnum], enter_spc(classnum), chrate, ", ", curprice, ", ", chprice)

 

def enter_crArray():

    crnum = len(crArray)

    rtnline = ""

    for n in range(0, crnum):

        rtnline = rtnline + str(crArray[n]) + ","

    return rtnline

    

def enter_spc(classn):

    spc = ""

    for n in range(0, classn):

        spc = spc + "     "

    return spc

 

def exit_spc(classn):

    spc = ""

    rev = 4 - classn

    for n in range(0, rev):

        spc = spc + "     "

    return spc

 

#not working

def sprintf(buf, fmt, args):

    buf.write(fmt % args)

 

    

inst0 = win32com.client.Dispatch("dscbo1.StockCur")

inst1 = win32com.client.Dispatch("dscbo1.StockCur")

inst2 = win32com.client.Dispatch("dscbo1.StockCur")

inst3 = win32com.client.Dispatch("dscbo1.StockCur")

inst4 = win32com.client.Dispatch("dscbo1.StockCur")

 

win32com.client.WithEvents(inst0, CpEvent0)

win32com.client.WithEvents(inst1, CpEvent1)

win32com.client.WithEvents(inst2, CpEvent2)

win32com.client.WithEvents(inst3, CpEvent3)

win32com.client.WithEvents(inst4, CpEvent4)

 

inst0.SetInputValue(0,itemcode[0])

inst1.SetInputValue(0,itemcode[1])

inst2.SetInputValue(0,itemcode[2])

inst3.SetInputValue(0,itemcode[3])

inst4.SetInputValue(0,itemcode[4])

 

CpEvent0.instance = inst0

CpEvent1.instance = inst1

CpEvent2.instance = inst2

CpEvent3.instance = inst3

CpEvent4.instance = inst4

 

inst0.Subscribe()

inst1.Subscribe()

inst2.Subscribe()

inst3.Subscribe()

inst4.Subscribe()

 

 

 

이벤트 발생시 해당 종목의 가격을 체크하여 정해진 STOPLOSS 보다 작거나 STOPGAIN보다 큰 경우 적절한 행동을 하도록 하려면 다음과 같은 class를 정해주면 된다.  

 

 

class CpEvent000:

    instance = None

    monitoring = 1  # 0 no, 1 yes

    def OnReceived(self):

        if (monitoring = 1)

            value13_cprice = CpEvent1.instance.GetHeaderValue(13)

            value18_ctime = CpEvent1.instance.GetHeaderValue(18)

            print("E1: ",value18_ctime,", ", value13_cprice)

            if (value13_cprice >= stopgain_price)

                print("E1: STOPGAIN, Exit")

                monitoring = 0 # 정해진 일을 이곳에 코딩

            elif (value13_cprice <= stoploss_price)

                print("E1: STOPLOASS, Exit")

                monitoring = 0  # 정해진 일을 이곳에 코딩

 

 

<to be continued..>

 

 

 

posted by Dr.Deeeep

Common deep learning predictive modeling problem types

상념 2016. 9. 13. 17:24

 

딥러닝에서의 예측 모델링 문제

 

크게 세가지 타입이 있다.

 

1. Regression

예측값을 얻기 위한 문제로 원하는 예측값의 수만큼의 출력 노드 사용

loss function으로 mean squared error or 'mse' 사용

예: 다음 단계 뇌파 전압, 다음 순간 주가, 내일의 기온, 지진 피해 예상액등

 

2. Binary Classification

yes 냐 no냐를 분리하는 문제로 한개의 출력 노드 필요

loss function으로 logarithmic loss, a.k.a cross entropy or 'binary_crossentropy'

예: 조기 치매인가 정상인가? 주가가 오를것인가 내릴것인가? 지진 피해액이 특정 금액보다 클것인가 작을 것인가?

 

3. Multiclass Classification

여러개의 클래쓰로 분류하는 문제로 분류하는 클래스의 총 수만큼의 출력 노드 사용

loss function으로 multiclass logarithmic loss or 'categorical_crossentro

예: 치매 환자의 종류 분류 (혈관성 치매, 알츠하이머, 파킨슨, ... ), 치매의 진행 단계 분류 (MCI, 경증 치매, 중증 치매, ... ), 주식 종목을 정해진 클래스로 분류 (관심주지 말아야 할 종목, 관찰 종목, 관찰 후 매수 종목, 반드시 매수 종목, 시장가 매수 종목, ... ) 

 

 

optimization algorithm으로는 일반적으로 sgd 이용.

많이 사용되는 optimization algorithms.

- stochastic gradient descent: 'sgd' requires the tuning of a learning rate and momentum

- ADAM: or 'adam' requires the tuning of learning rate

- RMSprop: or 'rmsprop' also requires the tuning of learning rate

 

 

 

 

 

 

 

 

 

 

 

 

 

posted by Dr.Deeeep

Time Series Prediction을 위한 Deep learning

 

이번 글에서는 주가 예측의 기본 개념인 time series prediction 을 딥러닝 기술로 구현하는 방법에 대해 알아보도록 하겠다.

 

 

위 그림은 구글 이미지 검색에서 time series prediction 으로 검색을 해서 찾아낸 그림 중 하나인데, 오늘 설명할 deep learning을 이용한 time series prediction의 개념을 쉽게 도식화 한 것이다.

time series 데이터란 시간 축에 따라 변하는 데이터를 (시간,값)의 형태로 쭉 기록한 데이터를 말하는데 주가 데이터, 뇌파 데이터, 기온 데이터 등이 이에 해당한다. 주가 데이터라면 x 축이 시간(월, 일, 주, 시, 초 등)이고 y 축이 주가 데이터(주가, 거래량, 변동률 등등)이 되겠다. 

time series prediction의 가장 대표적인 알로리즘은 일정 기간의 데이터를 관찰하고 바로 다음 순간의 값을 예측하는 것이다. 

 

 

<to be continued...>  

posted by Dr.Deeeep

나만의 로보 어드바이저(robo-advisor) 만들기 [2]

금융 2016. 8. 30. 15:37

Python을 이용한 주가 데이터 크롤링

 

기본적으로 로보 어드바이저는 대용량의 주가 및 환경 데이터 + 지능적 트레이딩 알고리즘에 의해 구동된다. 따라서 나만의 로보 어드바이저를 만들기 위해서는 나만의 트레이딩 알고리즘을 구현할 수 있는 프로그램 능력과 대용량 데이터를 분석할 수 있는 분석 능력뿐 아니라 데용량 데이터를 수집할 수 있는 수집 능력이 필수 적이다. 따라서 주가 데이터의 크롤러가 필수적이다. 이 글에서는 주가 데이터의 크롤러 제작에 필요한 기술과 구현 방법에 대해 살펴보겠다.

 

공학도라면 서론을 길게 말하는것을 싫어한다. 결론 먼저, 설명 나중이므로. 먼저 쿨하게 내가 제작한 주가 데이터 크롤러 소스를 밑에 붙여 놓았다. 바쁜 사람은 그냥 카피해가서 바로 사용하면 된다. 안 바쁜 독자라면 계속 읽어보자.

 

이 코드는 파이썬으로 제작한 주가 데이터 크롤러이다. 로보 어드바이저는 두가지 크롤러가 필요한데, 롱텀 크롤러와 실시간 크롤러가 그것이다. 롱텀 크롤러는 처음 로보 어드바이저를 기동하기 위해 최초 한번은 몇 년치 주가 데이터를 한꺼번에 크롤링 하는 작업이 필요한데 그때 사용하기 위한 크롤러 이다. 밑에 소스는 롱텀 크롤러 소스이다. 이 후에는 변경(추가)된 데이터만을 매일매일, 혹은 실시간으로, 가져오는 간략화된(속도가 빠른) 실시간 크롤러가 필요한데 그것은 나중에 올리기로 한다. 물론 롱텀 그롤러와 실시간 크롤러는 비슷한 코드로 구성된다. 단지 용도에 맞게 프로그램 흐름도가 조금 다를뿐이다.

 

이 크롤러는 CybosPlus와 Python으로 구현되었다. CybosPlus는 대신증권에서 제공하는 시스템 트레이딩을 위한 API이다. CybosPlus에 대한 정보는 쉽게 찾아 볼 수 있으므로 생략하기로 한다.

 

(임시저장...)

 

 

 

 

#
# Developed by "Dr.Deeeep"
#
# intelligent version of crawler, in this version
#   - it check the last day of item in the database and crawling from the last day.
#   - the data of last day will be overwritten because they may are not the final value
#

 

import time
import mysql.connector
import win32com.client

config = {
  'user': 'USERID',
  'password': 'PASSWORD',
  'host': 'yourhost.com',
  'database': 'DBNAME',
  'raise_on_warnings': True,
}
# Don't forget to change the server setting to arrow remote connection to MySQL.
# mysql examples are available at
# https://dev.mysql.com/doc/connector-python/en/connector-python-examples.html
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()

 

cpcybos = win32com.client.Dispatch("CpUtil.CpCybos")

if cpcybos.IsConnect == 1:
    print("Cybos connection succeeded")
else:
    print("Cybos connection failed")

   
inStockCode = win32com.client.Dispatch("CpUtil.CpStockCode")    # general stock item info
inStockMst = win32com.client.Dispatch("dscbo1.StockMst")        # Current data
inStockChart = win32com.client.Dispatch("CpSysdib.StockChart")  # Past Data

totalItemNumInCybosPlus = inStockCode.GetCount()
print("Total number of items = ",totalItemNumInCybosPlus)

# print all items in BT format
# Some variables, such as changerate, fortramt, totaltraceprice, should be calculated on the fly, thus filled with dummy '-999.0'

 

#itemcode
finalpriceArray = []        #inStockChart.SetInputValue(5, 5)
startpriceArray = []        #inStockChart.SetInputValue(5, 2)
highpriceArray = []         #inStockChart.SetInputValue(5, 3)
lowpriceArray = []          #inStockChart.SetInputValue(5, 4)
changerateArray = []         #inStockChart.SetInputValue(5, 6)       may need to calculate from (today final / yesterday final)
tramtArray = []             #inStockChart.SetInputValue(5, 8)
orgtramtArray = []          #inStockChart.SetInputValue(5, 20)      THIS data is not complete in cybosdb. cannot use..
fortramtArray = []          # -999.0 #inStockChart.SetInputValue(5, ???) may need to cal from (today fortotal - yesterday fortotal)
fortotalArray = []          #inStockChart.SetInputValue(5, 16)
forportionArray = []        #inStockChart.SetInputValue(5, 17)
totaltradepriceArray = []   # -999.0    #inStockChart.SetInputValue(5, 0) may need to cal from (tramt * final price)

#beyond BT Format
circulationrateArray = []   #inStockChart.SetInputValue(5, 25)
totalstocknumArray = []     #inStockChart.SetInputValue(5, 12)
sichongArray = []           #inStockChart.SetInputValue(5, 13)


###################################################
#
#   This number represents the number of record to crawl for each cybosplus access
#   Must be large enough to cover the gap between the last date in my db and today while keep small enough to prevent the waste of speed of cybosplus access.
numOfCrawling = 200        # n days
#
#   This string number is the starting itemcode for the case of resuming suspened, quitted, crawling job
startingItemCode = "000000"    # 000000 for new start
#
#
###################################################


currentItemIndex = -1
for aItemcode in range(0, inStockCode.GetCount()):   # for each itemcode
    currentItemIndex = currentItemIndex + 1
    print("### progress = ", ((currentItemIndex * 100) / totalItemNumInCybosPlus), " %")
                     
    dateToCrawlArray = []       #inStockChart.SetInputValue(5, 0)

    # this line print just the item code and name
    # print(inStockCode.GetData(0,i), inStockCode.GetData(1,i), inStockCode.GetData(2,i))

    itemcode = inStockCode.GetData(0,aItemcode)

    # this can be used for resuming suspended process
    # THIS may not necessary for intelligent version of crawler
    if itemcode < "A"+startingItemCode:
        print("Skipping "+itemcode)
        continue

    inStockChart.SetInputValue(0, itemcode)

    ## retrieve LAST DATE in DB of this itemcode ==========================
    ## if no data for this item, set the last date to 20050101
   
    print ("itemcode = ", itemcode)
    shortItemcode = itemcode[1:]

    sqlStr = ("select max(date) from datatable where itemcode='"+ shortItemcode+ "'")

    #print("sqlStr = ", sqlStr, ", newItemcode = ", shortItemcode)
    cursor.execute(sqlStr)

 

    #######################################
    # modified source
    row = cursor.fetchone()
    if row[0]:
        lastDateInMyDB = row[0]
    else:                           # Null. number of returned row is 0. no data in DB.
        print ("itemcode = ", itemcode, " is added newly... skipping..")
        print ("TODO:  add code here to handle newly added items. !!!!!!!!!!!!")
        continue
    #######################################

 


    ## retrieving LAST DATE in CybosPlus ========================
    inStockChart.SetInputValue(1, '2')  # retrieve by num of records
    inStockChart.SetInputValue(4, 1)    # num of record to retrive is. Just the last one
    inStockChart.SetInputValue(5, 0)    # field type, tr amt(8), finalprice(5), date(0)
    inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
    inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
    inStockChart.BlockRequest()
    lastDateInCybosPlus = inStockChart.GetDataValue(0,0)
    print("in itemcode = ", itemcode, ", The latest data in CybosPlus = ", lastDateInCybosPlus)


#TODO:
#    dateToCrawlArray = retieve DATE array from lastDateInMyDB to lastDateInCybosPlus

#    for aDate in dateArray:
#        do the same with other crawlers


    ## retireve dateToCrawlArray
    print("in itemcode = ", itemcode, ", Now retrieving Date2Crawl array...")
    inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
    inStockChart.SetInputValue(3, lastDateInMyDB) # starting date
    inStockChart.SetInputValue(2, lastDateInCybosPlus) # ending date
    inStockChart.SetInputValue(4, numOfCrawling) # get some data which number is given
    inStockChart.SetInputValue(5, 0)    # field type, tr amt(8), finalprice(5), date(0)
    inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
    inStockChart.BlockRequest()

    numofdate2Crawl = inStockChart.GetHeaderValue(3)    # num of rec retrieved
    print("in itemcode = ", itemcode, ", Num of DATE to crwal = ", numofdate2Crawl, " From = ", lastDateInMyDB, " to = ", lastDateInCybosPlus)
    for i in range(numofdate2Crawl):
        volumn = inStockChart.GetDataValue(0,i)
        dateToCrawlArray.insert(0, volumn)
        if int(volumn) <= int(lastDateInMyDB):
            break

    print("in itemcode = ", itemcode, ", dateToCrawArray = ", dateToCrawlArray)

    for aCrawlDate in dateToCrawlArray:
       
        ## retrieving FINALPRICE =========================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 5)    # finalprice(5)
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_finalprice = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (FP) = ", numofreturned_finalprice)
        if (numofreturned_finalprice > 0):
            finalprice = inStockChart.GetDataValue(0,0)  
            #print("     final price was ", finalprice)
        else:
            finalprice = '-999.0'
            print(itemcode, "     No data. default final price: -999.0")


        ## retrieving STARTPRICE ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 2)    # startprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_startprice = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (SP) = ", numofreturned_startprice)
        if (numofreturned_startprice > 0):
            startprice = inStockChart.GetDataValue(0,0)      
            #print("    start price was ", startprice)
        else:
            startprice = '-999.0'
            print(itemcode, "              No data. default START PRICE : -999.0")


        ## retrieving HIGHPRICE ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 3)    # highprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_highprice = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (HP) = ", numofreturned_highprice)
        if (numofreturned_highprice > 0):
            highprice = inStockChart.GetDataValue(0,0)      
            #print("    high price was ", highprice)
        else:
            highprice = '-999.0'
            print(itemcode, "                 No data. default HIGH PRICE: -999.0")

 

        ## retrieving LOWPRICE ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 4)    # lowprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_lowprice = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (LowP) = ", numofreturned_lowprice)
        if (numofreturned_lowprice > 0):
            lowprice = inStockChart.GetDataValue(0,0)      
            #print("    low price was ", lowprice)
        else:
            lowprice = '-999.0'
            print(itemcode, "                   No data. default LOW PRICE: -999.0")

 

        ## retrieving CHANGERATE ============================
        changerate = '-999.0'     
        #print("    changerate was ", changerate)


        ## retrieving TRAMT ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 8)    # tramt
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_tramt = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (TRAMT) = ", numofreturned_tramt)
        if (numofreturned_tramt > 0):
            tramt = inStockChart.GetDataValue(0,0)      
            #print("    tramt was ", tramt)
        else:
            tramt = '-999.0'
            print(itemcode, "                     No data. default TRAMT: -999.0")

 

 

        ## retrieving ORGTRAMT ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 20)    # org tramt
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_orgtramt = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (ORG TRAMT) = ", numofreturned_orgtramt)
        if (numofreturned_orgtramt > 0):
            orgtramt = inStockChart.GetDataValue(0,0)      
            #print("    orgtramt was ", orgtramt)
        else:
            orgtramt = '-999.0'
            print(itemcode[1:], "                      No data. default ORG TRAMT: -999.0")
           

        ## retrieving FORTRAMT ============================
        fortramt = '-999.0'     
        #print("    fortramt was ", fortramt)

 

        ## retrieving FORTOTAL ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 16)    # startprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_fortotal = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (FORTOTAL) = ", numofreturned_fortotal)
        if (numofreturned_fortotal > 0):
            fortotal = inStockChart.GetDataValue(0,0)      
            #print("    fortotal was ", fortotal)
        else:
            fortotal = '-999.0'
            print(itemcode, "                          No data. default FORTOTAL: -999.0")

       

        ## retrieving FORPORTION ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 17)    # startprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_forportion = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (FORPORTION) = ", numofreturned_forportion)
        if (numofreturned_forportion > 0):
            forportion = inStockChart.GetDataValue(0,0)
            forportion = float("{0:.4f}".format(forportion))
            #print("    forportion was ", forportion)
        else:
            forportion = '-999.0'
            print(itemcode, "                          No data. default FORPORTION: -999.0")

       

        ## retrieving TOTALTRADEPRICE ============================
        totaltradeprice = '-999.0'   
        #print("    total trade price was ", totaltradeprice)


        ## retrieving CIRCULATIONRATE ============================
        circulationrate = '-999.0'   
        #print("    circulation rate was ", circulationrate)
       

        ## retrieving TOTALSTOCKNUM ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 12)    # startprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_totalstocknum = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (TOTALSTOCKNUM) = ", numofreturned_totalstocknum)
        if (numofreturned_totalstocknum > 0):
            totalstocknum = inStockChart.GetDataValue(0,0)      
            #print("    totalstocknum was ", totalstocknum)
        else:
            totalstocknum = '-999.0'
            print(itemcode, "                     No data. default TOTALSTOCKNUM: -999.0")
           


        ## retrieving SICHONG ============================
        inStockChart.SetInputValue(1, '1')  # retrieve by num of specified date
        inStockChart.SetInputValue(3, aCrawlDate) # starting date
        inStockChart.SetInputValue(2, aCrawlDate) # ending date
        inStockChart.SetInputValue(4, 1) # get a data
        inStockChart.SetInputValue(5, 13)    # startprice
        inStockChart.SetInputValue(6, ord('D')) # chart type,  by Day
        inStockChart.SetInputValue(9, '0')  # modified price? yes. 0 for no
        inStockChart.BlockRequest()
        numofreturned_sichong = inStockChart.GetHeaderValue(3)    # num of rec retrieved
        #print(" Num of retrieved record (SICHONG) = ", numofreturned_sichong)
        if (numofreturned_sichong > 0):
            sichong = inStockChart.GetDataValue(0,0)      
            #print("    sichong was ", sichong)
        else:
            sichong = '-999.0'
            print(itemcode, "                No data. default SICHONG: -999.0")
       

        #sqlStr = ("insert into cybosplus date="+str(aCrawlDate)+", itemcode="+itemcode[1:]+", finalprice="+str(finalprice)+", startprice="+str(startprice))
        #print("insert sqlStr = ", sqlStr)

        add_record = ("insert into datatable "
                      "(date, itemcode, finalprice, startprice, highprice, lowprice, changerate, tradeamount, orgtradeamount, fortradeamount, fortotalamount, forportion, totaltradeprice, totalstocknum, sichong) "
                      "values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) "
                      "on duplicate key update "
                      "finalprice=%s, startprice=%s, highprice=%s, lowprice=%s, changerate=%s, tradeamount=%s, orgtradeamount=%s, fortradeamount=%s, fortotalamount=%s, forportion=%s, totaltradeprice=%s, totalstocknum=%s, sichong=%s")
             
        data_record = (aCrawlDate, itemcode[1:], finalprice, startprice, highprice,
                       lowprice, changerate, tramt, orgtramt, fortramt,
                       fortotal, forportion, totaltradeprice, totalstocknum, sichong,
                       finalprice, startprice, highprice,
                       lowprice, changerate, tramt, orgtramt, fortramt,
                       fortotal, forportion, totaltradeprice, totalstocknum, sichong)

        cursor.execute(add_record, data_record)
        cnx.commit()       

cursor.close()
cnx.close()

 


 

posted by Dr.Deeeep