'주식투자 자동화' 태그의 글 목록 :: Horizontal Grays S2

 

책을 아직도 다 읽진 않았지만 - 앞으로도 다 읽진 않겠지만 - 

매수종목 선정 방법 관련해서는 자세히 나온것이 없다. 

그래서 임의로 내가 방법을 세우고 프로그래밍해려고 한다.

 

검색해보면 이러한 종목이 오를 것이다라는 여러 이야기 들이 있지만 복잡한것까지는 잘 모르겠다.

내 경험상으로도 그렇고 검색 결과로도 그렇고 일단 거래량이 가장 중요한 것 같다.

그래서 일단 단순하게

 

1. 이틀전 거래량 - 하루전 거래량 으로 거래량 증가폭이 높은 순으로 정렬해서 최상단 20종목 추리고

2. 그중 하루전 거래량 기준으로 절대 거래량 높은 순으로 10종목 추려서 매수종목 리스트에 넣는다.

 

이런 단순한 방법을 우선 취해보기로 했다. 

이렇게 한 근거는 일단 없다. 이렇게 해보고 결과가 안좋으면 수정해야겠다.

 

크레온 플러스 API 예제를 이용하면 더 편할것 같기도 한데 이게 제한이 있다.

   조회 제한  실시간 제한
시세
오브젝트
15초에 최대 60건으로제한
초과 요청시 첫 요청으로부터 15초가
지날 때까지 내부적으로기다림
최대 400건의요청으로제한
초과요청시오류
주문관련오브젝트 15초에 최대 20건으로제한
초과 요청시 첫 요청으로부터 15초가
지날 때까지 요청함수(Request, BlockRequest, BlockRequest2)에서
4를 반환
제한 없음

그래서 일단 네이버 스크래핑을 위주로 이용해보기로 한다.

 

먼저 처음 예제였던 종목정보 구하기 예제를 차후에 파일로 가공할 것을 감안하여 조금 수정하고

실행해서 전체종목의 코드를 구해봤다. (이건 크레온 플러스 API 이용)

 

import win32com.client

# 연결 여부 체크
objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos")
bConnect = objCpCybos.IsConnect
if (bConnect == 0):
    print("PLUS가 정상적으로 연결되지 않음. ")
    exit()
 
# 종목코드 리스트 구하기
objCpCodeMgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")
codeList = objCpCodeMgr.GetStockListByMarket(1) #거래소
codeList2 = objCpCodeMgr.GetStockListByMarket(2) #코스닥
 
 
print("번호",",","종목코드",",","종목명",",","구분코드",",","금액")
for i, code in enumerate(codeList):
    secondCode = objCpCodeMgr.GetStockSectionKind(code)
    name = objCpCodeMgr.CodeToName(code)
    stdPrice = objCpCodeMgr.GetStockStdPrice(code)
    print(i,",",code,",", name,",", secondCode,",", stdPrice)
    
for i, code in enumerate(codeList2):
    secondCode = objCpCodeMgr.GetStockSectionKind(code)
    name = objCpCodeMgr.CodeToName(code)
    stdPrice = objCpCodeMgr.GetStockStdPrice(code)
    print(i+len(codeList),",",code,",", name,",", secondCode,",", stdPrice)
 
#print("거래소 + 코스닥 종목코드 ",len(codeList) + len(codeList2))

실행할 때 단지 아래와 같이 하면 print 결과값을 파일로 저장한다.

python test1.py > codelist.txt

 

이로써 codelist.txt라는 종목정보파일이 만들어졌다.

이 파일의 끝을 보면 "거래소 + 코스닥 종목코드  3306" 으로 총 3306 종목이 있슴을 알 수 있고

위 그림과 같이 ETF도 포함되어 있슴을 알 수 있다. 

 

이 txt파일을 엑셀에서 읽어서 금일거래량, 전일거래량, 거래량증가비 열을 추가하고 codelist.xlsx 로 저장했다.

 

우선 파이썬에서 엑셀 데이터를 다루기 위해서 openpyxl을 설치해주도록 한다.

pip install openpyxl을 cmd 창에서 실행

 

 

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

이렇게 하다가 문제가 발생했다.

여튼 엑셀데이터의 종목코드를 읽고 거래량을 구하는 과정에서 현재 거래정지된 종목의 경우 에러가 발생하는 것이었다.

여기서 예외처리를 할까 하다가 전면 수정을 하기로 하고 다시 프로그램을 작성했다.

종목코드 자체를 매일 실시간으로 읽어서 진행하기로...

 

검색해보니 pykrx 라고 주식관련 라이브러리가 아주 잘되어 있었고 어차피  엑셀을 이용해도 이 라이브러리를 이용했어야 했다. ("GitHub - sharebook-kr/pykrx: KRX 주식 정보 스크래핑" 참고)

 

기본적인 구상은 다음과 같다.

매일 장을 종료하면 이 프로그램을 실행하여

1. 종목코드를 get_market_ticker_list() 로 읽어와서

2. get_market_ohlcv_by_date() 로 거래량 정보를 읽고 가공 후 DataFrame에 집어넣고

3. 각 DataFrame을 거래량 별로 정렬 후 상위 추출, 거래량 변화율 별로 정렬 후 상위 추출

4. ETF는 70%, KOSPI/KOSDAQ에서는 30%로 구성해서 20개 종목을 최종 List 만들어서

5. 파일로 저장

6. 다음날 자동거래 프로그램에서 매수대상 리스트는 이 파일을 읽어서 20개의 후보군으로 실행

 

파이썬을 잘 모르기도 하고 혼자서 단순하게 막 짜다보니 좀 비효율적인 프로그램이 된것 같긴 하지만 일단 테스트로 돌려본 결과 잘 돌아가긴 한다.

 

내일 자동거래 프로그램을 백테스팅용으로 수정을 좀 하고 목,금 백테스팅을 좀 하고 4월부터는 실제거래를 해봐야겠다.

 

 

from pykrx import stock
import time,sys
import pandas as pd
from datetime import datetime,timedelta

#DataFrame define
kospi_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])
kosdaq_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])
etf_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])

today = datetime.today()- timedelta(0)      #오늘날짜 구하기 timedelta(1)을 빼면 어제날짜
yesterday = datetime.today()- timedelta(1)
str_today = today.strftime("%Y%m%d")        #구한 날짜를 String type으로
str_yesterday = yesterday.strftime("%Y%m%d")        #구한 날짜를 String type으로

print(str_today)
print(str_yesterday)
bt_day = stock.get_nearest_business_day_in_a_week(date=str_today)   #오늘 날짜 집어넣고 장을 여는 가장 가까운 날을 구함 오늘 장을 열면 오늘 날짜 반환
by_day = stock.get_nearest_business_day_in_a_week(date=str_yesterday)
print("btday=",bt_day)
print("byday=",by_day)
if bt_day != str_today: #오늘 날짜와 구한 날짜가 같지 않다는건 오늘 장을 열지 않는다는 것
    print("오늘은 장을 열지 않으므로 프로그램 종료")
    sys.exit(0)

kospilist = stock.get_market_ticker_list(date=bt_day, market="KOSPI")   #KOSPI 종목코드를 list로 반환
kosdaqlist = stock.get_market_ticker_list(date=bt_day, market="KOSDAQ") #KOSDAQ 종목코드를 list로 반환
etflist = stock.get_etf_ticker_list(date=bt_day)                        #ETF 종목코드를 list로 반환

kospi_stock_list_count = 0      #나중에 Dataframe에 count로 사용할 변수 초기화
kosdaq_stock_list_count = 0
etf_stock_list_count = 0

print("KOSPI 확인 - 종목수 : ",len(kospilist))
for kospi_ticker in kospilist:  #KOSPI 종목
#for i in range(100):   #for test
#    kospi_ticker = kospilist[i]    #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=kospi_ticker)    #KOSPI 종목코드 어제,오늘 관련정보 DataFrame

    yesterday_volume = df.iloc[0]['거래량']     #DataFrame에서 어제 거래량 변수로 입력
    today_volume = df.iloc[1]['거래량']         #DataFrame에서 오늘 거래량 변수로 입력
    today_price = df.iloc[1]['종가']            #DataFrame에서 오늘 종가 변수로 입력
    
    print("종목코드",kospi_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:                   #어제거래량이 없으면 거래량변화 -100
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume     #거래량변화율 

    
    new_data = [kospi_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    kospi_stock_list.loc[kospi_stock_list_count] = new_data     #관련 정보 DataFrame의 행에 추가
    kospi_stock_list_count = kospi_stock_list_count + 1
    time.sleep(1) 

print("KOSDAQ 확인 - 종목수 : ",len(kosdaqlist))
for kosdaq_ticker in kosdaqlist:
#for i in range(100):       #for test
    #kosdaq_ticker = kosdaqlist[i]  #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=kosdaq_ticker)
    
    yesterday_volume = df.iloc[0]['거래량']
    today_volume = df.iloc[1]['거래량']
    today_price = df.iloc[1]['종가']
    
    print("종목코드",kosdaq_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume

    
    new_data = [kosdaq_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    kosdaq_stock_list.loc[kosdaq_stock_list_count] = new_data
    kosdaq_stock_list_count = kosdaq_stock_list_count + 1
    time.sleep(1) 



print("ETF 확인 - 종목수 : ",len(etflist))
for etf_ticker in etflist:
#for i in range(100):   #for test
    #etf_ticker = etflist[i]    #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=etf_ticker)
    
    yesterday_volume = df.iloc[0]['거래량']
    today_volume = df.iloc[1]['거래량']
    today_price = df.iloc[1]['종가']
    
    print("종목코드",etf_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume

    
    new_data = [etf_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    etf_stock_list.loc[etf_stock_list_count] = new_data
    etf_stock_list_count = etf_stock_list_count + 1
    time.sleep(1) 

all_stock_list = pd.concat([kospi_stock_list,kosdaq_stock_list])    #KOSPI와 KOSDAQ은 합쳐서 하나의 DataFrame으로

print("KOSPI")
print(kospi_stock_list)
print("KOSDAQ")
print(kosdaq_stock_list)
print("KOSPI+KOSDAQ")
print(all_stock_list)
print("ETF")
print(etf_stock_list)


all_stock_list.sort_values(['today_volume'],axis=0,ascending=False,inplace=True)    #거래량 우선으로 정렬
sort_volume_list = all_stock_list.head(12)                                          #그중 12개만 추출해서 저장
print("all stock sort by volume")
print(sort_volume_list)
sort_volume_list.sort_values(['volume_ratio'],axis=0,ascending=False,inplace=True)  #12개를 거래량 변화율로 정렬
sort_ratio_list = sort_volume_list.head(6)                                          #그 중 6개만 추출해서 저장
print("all stock sort by volume")
print(sort_ratio_list)

etf_stock_list.sort_values(['today_volume'],axis=0,ascending=False,inplace=True)    #ETF도 같은 과정 
etf_sort_volume_list = etf_stock_list.head(28)
print("ETF stock sort by volume")
print(etf_sort_volume_list)
etf_sort_volume_list.sort_values(['volume_ratio'],axis=0,ascending=False,inplace=True)
etf_sort_ratio_list = etf_sort_volume_list.head(14)             
print("ETF stock sort by volume")
print(etf_sort_ratio_list)

total_stock_list = pd.concat([sort_ratio_list,etf_sort_ratio_list])     #최종 KOSPI,KOSDAQ에서 6개, ETF에서 14개 총 20개 를 하나의 DataFrame으로 합치고
print("Total stock sort by volume")
print(total_stock_list)

final_stock_list = list(total_stock_list['stock_code'])     #DataFrame에서 종목코드만 List로 뽑고
print("final Stock List")
print(final_stock_list)

for i in range(len(final_stock_list)):
    final_stock_list[i] = 'A'+ str(final_stock_list[i])     #List에 'A' 추가해서
print(final_stock_list)

f = open('codelist.txt','w')
f.write(','.join(final_stock_list))     #파일로 저장
f.close()

#symbol_list = open('codelist.txt','r').read().split(',')       #for verify
#print(symbol_list)                                             #for verify

지난 포스팅에서 무엇을 살것인가에서 ETF를, 그리고 ETF 종목의 조회를 어떻게 하는가 봤다

 

그리고 얼마에 살 것인가는 변동성 돌파 전략에서 K값의 결정에 따라 산다 정도로 설명했다.

 

일단 프로그램 전체를 가져와보자.

 

역시 기본적으로 책인 [파이썬 증권 데이터 분석] 에서 제공하는 github의 소스를 이용한다.

StockAnalysisInPython/ch08_03_EtfAlgoTrader.py at master · INVESTAR/StockAnalysisInPython · GitHub

 

GitHub - INVESTAR/StockAnalysisInPython

Contribute to INVESTAR/StockAnalysisInPython development by creating an account on GitHub.

github.com

다만 slack으로 메시지 보내는 방법은 수정되어야 해서 전에 slack 관련 포스팅과 같은 방식으로 수정하였다.

아래와 같이 post_message 함수 정의해서 사용했다.

def post_message(token, channel, text):
    response = requests.post("https://slack.com/api/chat.postMessage",
        headers={"Authorization": "Bearer "+token},
        data={"channel": channel,"text": text}
    )
    print(response)

내가 직접 짠 소스가 아니므로 여기에 모두 포스팅 하지는 못하겠고 이정도 수정은 필요하신 분이시라면 어렵지 않게 하실수 있을것이라 생각한다.

 

같은 과정으로 vscode 실행하고 새 파이썬 파일 만들어서 소스 복붙하고 위의 post_message 부분으로 수정하면 된다.

 

일단 나의 경우 AutoTrade.py라고 저장하였고. 이 AutoTrade를 실행하기전에 이전포스팅에서 설명했던 AutoConnect.py를 먼저 실행해서 CREON Plus와 연결을 한다. 그리고 이 AutoTrade.py를 실행하는 것이다.

 

우선 main 부분만 훑어 보자.

if __name__ == '__main__':
    try:
        symbol_list = ['A122630', 'A252670', 'A233740', 'A250780', 'A225130',
             'A280940', 'A261220', 'A217770', 'A295000', 'A176950'] #매수 대상 종목 리스트
        bought_list = []     # 매수 완료된 종목 리스트
        target_buy_count = 5 # 매수할 종목 수
        buy_percent = 0.19   #종목별 매수 비율 5 종목 * 19%씩 매수 = 95% 매수하고 5% 금액 남게 된다.
        printlog('check_creon_system() :', check_creon_system())  # 크레온 접속 점검
        stocks = get_stock_balance('ALL')      # 보유한 모든 종목 조회
        total_cash = int(get_current_cash())   # 100% 증거금 주문 가능 금액 조회
        buy_amount = total_cash * buy_percent  # 종목별 주문 금액 계산
        printlog('100% 증거금 주문 가능 금액 :', total_cash)
        printlog('종목별 주문 비율 :', buy_percent)
        printlog('종목별 주문 금액 :', buy_amount)
        printlog('시작 시간 :', datetime.now().strftime('%m/%d %H:%M:%S'))
        soldout = False

        while True:
            t_now = datetime.now() #현재시간
            t_9 = t_now.replace(hour=9, minute=0, second=0, microsecond=0)  # 9:00
            t_start = t_now.replace(hour=9, minute=5, second=0, microsecond=0) # 9:05 시작 시간
                                                                                      참고로 유동성 공급자 활동시간 9:05 ~ 15:20
            t_sell = t_now.replace(hour=15, minute=15, second=0, microsecond=0) # 15:15 매도 시간
            t_exit = t_now.replace(hour=15, minute=20, second=0,microsecond=0) # 15:20 종료 시간
            today = datetime.today().weekday() #금일 요일
            if today == 5 or today == 6:  # 토요일이나 일요일이면 자동 종료
                printlog('Today is', 'Saturday.' if today == 5 else 'Sunday.')
                sys.exit(0)
            if t_9 < t_now < t_start and soldout == False:
                                            #9:00~9:05 사이에 시작하기전 혹시나 남은 주식이 있으면 다 매도
                soldout = True
                sell_all()
            if t_start < t_now < t_sell :  # AM 09:05 ~ PM 03:15 : 매수
                for sym in symbol_list: # 매수대상 종목리스트에서
                    if len(bought_list) < target_buy_count: #매수 완료한 종목이 목표수보다 작으면
                        buy_etf(sym)    #매수
                        time.sleep(1)
                if t_now.minute == 30 and 0 <= t_now.second <= 5:   #30분마다 잔고 등의 정보를 알림
                    get_stock_balance('ALL')
                    time.sleep(5)
            if t_sell < t_now < t_exit:  # PM 03:15 ~ PM 03:20 : 일괄 매도
                if sell_all() == True:
                    dbgout('`sell_all() returned True -> self-destructed!`')
                    sys.exit(0)
            if t_exit < t_now:  # PM 03:20 ~ :프로그램 종료
                dbgout('`self-destructed!`')
                sys.exit(0)
            time.sleep(3)
    except Exception as ex:
        dbgout('`main -> exception! ' + str(ex) + '`')

일단 설명할 부분은 주석으로 달아놨고

여기서 매수할 종목 대상 리스트는 ETF든 KOSPI든 KOSDAQ이든 미리 알아서 집어넣어두면 된다.

그리고 얼마에 매수할것인지에 대한 결정은 buy_etf()함수에서 불러오는

아래의 get_target_price()에 함수에서 설정되는 K값 0.5로 결정된다.

def get_target_price(code):
    """매수 목표가를 반환한다."""
    try:
        time_now = datetime.now()
        str_today = time_now.strftime('%Y%m%d')
        ohlc = get_ohlc(code, 10)
        if str_today == str(ohlc.iloc[0].name):
            today_open = ohlc.iloc[0].open
            lastday = ohlc.iloc[1]
        else:
            lastday = ohlc.iloc[0]                                      
            today_open = lastday[3]
        lastday_high = lastday[1]
        lastday_low = lastday[2]
        target_price = today_open + (lastday_high - lastday_low) * 0.5
        return target_price
    except Exception as ex:
        dbgout("`get_target_price() -> exception! " + str(ex) + "`")
        return None

현재 K값을 0.5 상수로 두고 있는데 이를 변수로 두던 상수로 두던 값 역시 수정하면 된다.
다만 K값이 낮으면 매수가 쉽고 높으면 어렵다..... 당연하군 ^^;

실제로 이 프로그램으로 매수/매도를 해보질 않았다.
일단 함수단위 테스트를 먼저 해보자.

바로 위 get_target_price()에 KODEX 200(069500) 을 한번 테스트 해보자. 

일단 test2.py 라는 임의로 파이썬 파일을 만들고 AutoTrade.py에서 일부분만 테스트를 위해 좀 잘라서

다음과 같이 테스트프로그램을 작성해서 실행해본다.

import os, sys, ctypes
import win32com.client
import pandas as pd
from datetime import datetime
import requests
import time, calendar

# 크레온 플러스 공통 OBJECT
cpCodeMgr = win32com.client.Dispatch('CpUtil.CpStockCode')
cpStatus = win32com.client.Dispatch('CpUtil.CpCybos')
cpTradeUtil = win32com.client.Dispatch('CpTrade.CpTdUtil')
cpStock = win32com.client.Dispatch('DsCbo1.StockMst')
cpOhlc = win32com.client.Dispatch('CpSysDib.StockChart')
cpBalance = win32com.client.Dispatch('CpTrade.CpTd6033')
cpCash = win32com.client.Dispatch('CpTrade.CpTdNew5331A')
cpOrder = win32com.client.Dispatch('CpTrade.CpTd0311')  

def get_ohlc(code, qty):
    """인자로 받은 종목의 OHLC 가격 정보를 qty 개수만큼 반환한다."""
    cpOhlc.SetInputValue(0, code)           # 종목코드
    cpOhlc.SetInputValue(1, ord('2'))        # 1:기간, 2:개수
    cpOhlc.SetInputValue(4, qty)             # 요청개수
    cpOhlc.SetInputValue(5, [0, 2, 3, 4, 5]) # 0:날짜, 2~5:OHLC
    cpOhlc.SetInputValue(6, ord('D'))        # D:일단위
    cpOhlc.SetInputValue(9, ord('1'))        # 0:무수정주가, 1:수정주가
    cpOhlc.BlockRequest()
    count = cpOhlc.GetHeaderValue(3)   # 3:수신개수
    columns = ['open', 'high', 'low', 'close']
    index = []
    rows = []
    for i in range(count):
        index.append(cpOhlc.GetDataValue(0, i))
        rows.append([cpOhlc.GetDataValue(1, i), cpOhlc.GetDataValue(2, i),
            cpOhlc.GetDataValue(3, i), cpOhlc.GetDataValue(4, i)])
    df = pd.DataFrame(rows, columns=columns, index=index)
    return df

def get_target_price(code):
    """매수 목표가를 반환한다."""
    try:
        time_now = datetime.now()
        str_today = time_now.strftime('%Y%m%d')
        ohlc = get_ohlc(code, 10)
        print(ohlc)
        if str_today == str(ohlc.iloc[0].name):
            today_open = ohlc.iloc[0].open
            lastday = ohlc.iloc[1]
        else:
            lastday = ohlc.iloc[0]                                      
            today_open = lastday[3]
        lastday_high = lastday[1]
        lastday_low = lastday[2]
        target_price = today_open + (lastday_high - lastday_low) * 0.5
        return target_price
    except Exception as ex:
        print("`get_target_price() -> exception! " + str(ex) + "`")
        return None

target_price = get_target_price('A069500')
print("목표가 = " + str(target_price))

2022년 2월 24일 현재 실행결과 아래와 같이 나온다.

즉 KODEX200 의 열흘간 시작가, 최고가, 최저가, 종가 가 출력되고 이를 토대로

K값이 0.5일때 목표가는 \36642.5 원이라는 것이다.

그럼 이제 K값을 변화해서 살펴보자.

K = 0.3 일 때
K = 0.7 일 때

자 각각 K가 0.3, 0.7로 바꿔서 놓고 실행해보면 목표가가 0.3일 때 36561.5원, 0.7일 때 36723.5원 으로 바뀌는 것을 볼 수 있다.

K = 0.3 K = 0.5 K = 0.7
\36561.5 \36642.5 \36723.5

이 매수조건에 현재가가 5일 이동평균선과 10일 이동평균선 위에 있어야 한다는 조건이 추가되어 있는데

이 부분이 buy_etf() 함수에서 get_movingaverage() 함수를 불러 이동평균을 구하고 조건을 추가하는식이다.

...
        ma5_price = get_movingaverage(code, 5)   # 5일 이동평균가
        ma10_price = get_movingaverage(code, 10) # 10일 이동평균가
...
        if current_price > target_price and current_price > ma5_price and current_price > ma10_price:  
         


자 그렇다면 이제

1. 무엇을 살 것인가는 ETF 중에서 또는 관심가는 종목 중 골라서 종목코드를 매수대상 종목리스트 symbol_list에 넣어두면 되고

2. 얼마에 살 것인가는 위에 조건처럼 K값과 이동평균선 조건에 따라서 매수하고 장마감에 매도

이런 아주 기초적인 조건으로 매매는 시작할 수 있게 되겠다.

 

그러고보니 매수대상을 종목리스트에 넣어두는 것은 자동은 아니네 --a 

그리고 추가로 설명할 부분이 주문조건과 주문호가가 있는데 프로그램에서는 ETF를 기본으로 하고 있다보니

거래량이 다른 주식대비 많지 않아 비싼 가격을 지불하지 않도록 [최유리 FOK 매수 주문] 방법으로 매수하고

매도는 [최유리 IOC 매도] 방법으로 매도하도록 되어있다.


비록 아직은 매수대상 종목리스트는 수작업으로 하지만 프로그램의 실행은 윈도우가 알아서 실행하도록 해보자.

 

우선 PC가 켜지는 것은

 1) 켜두거나

 2) BIOS가 지원한다면 BIOS에서 해야하는데 각 회사마다 다르겠지만

   기본적으로 BIOS진입 - Advanced - ACPI Configuration - RTC Alarm Power On 에서 예약 부팅 을 해두면 된다.

 

그리고 PC가 켜지면 윈도우키 + S 를 누른뒤 "작업 스케줄러"로 검색/실행을 하면 아래와 같이 작업스케줄러가 실행이된다.

그리고 좌측 창의 [작업 스케줄러 라이브러리] 클릭하면 가운데 창이 아래 그림처럼 나오는데 그 창에서

우측 클릭 - 새 작업 만들기

그러면 나타나는 창에서

이름과 설명은 원하는 대로 작성하고 형광펜의 '가장 높은 수준의 권한으로 실행' 에 체크

그리고 트리거 탭으로 가서 '새로만들기' 누른뒤 나타나는 창에서 '매일' '오전 8:20' 그리고 아래에 '사용'에 체크

그럼 트리거가 하나 만들어진다.

그리고 동작탭으로 넘어가서 역시 '새로만들기'

설정의 프로그램/스크립트 에서는 찾아보기 버튼을 누른뒤 python.exe가 있는 폴더에 들어가서 선택해주고

인수추가에는 실행할 python 파일 이름 위 그림엔 AutoConnect.py 시작위치는 AutoConnect.py가 있는 폴더의 경로
그리고 확인을 누르면 된다.

 

그리고 같은 방법으로 8:30 정도에 AutoTrade.py도 등록해주면 윈도우즈의 작업스케줄러가 알아서 실행한다.

 


- 지금까지 대부분의 정보는 "파이썬 증권 데이터 분석" 이라는 책의 내용을 보고 정리한 내용이며 일부 현재 동작하지 않는 Slack의 requests 같은 부분은 내가 검색해서 수정하였음을 미리 밝힌다. 그래서 세세한 소스는 직접 책에서 제공하는 github로 링크하였다.

 

- 현재 나도 아직 이 방식으로 주식거래를 시작하지 않았다.  '주식투자자동화' 관련 포스팅은 여기서 끝나는게 아니고

일단 서둘러 해보고 싶은 분들을 위해 1부? 여튼 일단 시작할 수 있는 정도까지 서둘러 포스팅한다.

나는 여기서 종목을 골라서 리스트에 넣는 부분과 K값을 조금씩 조절하고 그에 따른 결과를 자동으로 기록하는 부분까지는 조금 더 프로그램하고 작은 금액이라도 실제 투자해볼 생각이다.

그 부분은 차근차근 여기다 포스팅하고 수익이 나던 손해가 나던 일정 기간 후 역시 결과도 포스팅 해 볼 예정이다.

 

일단은 여기까지!!

이전 포스팅을 보면 늘 실행하기전에 CREON Plus를 실행해야 한다는 말을 쓰곤 했는데

내가 항상 깜빡하고 CREON Plus도 실행하지 않고 실행해서 Error가 발생하곤 했기 때문이다.

추가로 CREON Plus 실행하고 비번 치고, 비번 또 치고 이러는것도 귀찮기도 하고 ㅎ

여튼 그래서 우선 할것은 CREON Plus 자동 실행 프로그램이다.

이 소스는 구매한 책인 [파이썬 증권 데이터 분석] 이 유용하게도 github에 소스도 제공해주는데 여기에 자동 실행 예제가 있다.

 

아래의 링크에 들어가보자.

StockAnalysisInPython/08_Volatility_Breakout at master · INVESTAR/StockAnalysisInPython · GitHub

 

GitHub - INVESTAR/StockAnalysisInPython

Contribute to INVESTAR/StockAnalysisInPython development by creating an account on GitHub.

github.com

위 링크의 8장 말고도 다른 장도 다양한 소스가 있으니 공부에 참고하면 좋을듯하다.

물론 책을 사서 보면서 해야겠지만 ㅎ 나도 책은 아직 보는 중

여기에 보면 ch08_01_AutoConnect.py 이라는 파이썬 파일이 있다.

-------------------------------------------------------------------------------------------------------
from pywinauto import application
import time
import os

os.system('taskkill /IM coStarter* /F /T')
os.system('taskkill /IM CpStart* /F /T')
os.system('taskkill /IM DibServer* /F /T')
os.system('wmic process where "name like \'%coStarter%\'" call terminate')
os.system('wmic process where "name like \'%CpStart%\'" call terminate')
os.system('wmic process where "name like \'%DibServer%\'" call terminate')
time.sleep(5)        

app = application.Application()
app.start('C:\CREON\STARTER\coStarter.exe /prj:cp /id:userid /pwd:pa$$word /pwdcert:certPa$$word /autostart')
time.sleep(60)

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

14번째줄 (끝에서 두번째줄) userid 에 ID 넣고, pwd에 password 넣고 pwdcert에 인증서암호 넣고

그리고 Autoconnect.py 로 저장하고 실행하면 끝

소스의 설명은 딱히 할게 없다. 

11번째 줄까지는 혹시 CREON Plus가 실행하고 있으면 끝내고

5초 대기

CREON Plus 를 실행하고 60초 대기 

그리고 이 소스에서 
-------------------------------------------------------------------------------------------------------
from pywinauto import application
import time
import os

os.system('taskkill /IM coStarter* /F /T')
os.system('taskkill /IM CpStart* /F /T')
os.system('taskkill /IM DibServer* /F /T')
os.system('wmic process where "name like \'%coStarter%\'" call terminate')
os.system('wmic process where "name like \'%CpStart%\'" call terminate')
os.system('wmic process where "name like \'%DibServer%\'" call terminate')
time.sleep(5)    

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

이 부분만 Disconnect.py로 저장하고 끝낼때 종종 쓰곤 한다. ㅋ

 

자 그럼 이제 주식투자 자동화 프로그램을 해보도록 하자.

 

책에서 설명하는 주식 자동프로그램의 기본전략은 변동성 돌파전략이다. 

그럼 변동성 돌파전략이란 무엇인가?

 

변동성 돌파전략(volatility breakout strategy)이란 선물 트레이더의 대가라고 하는 래리 윌리엄스라는 사람이 개발한 투자전략으로 가격이 전일 가격범위의 K% 이상이 될 때 매수하고 장마감시 매도해서 수익을 실현하는 전략이라고 

책에 설명되어 있다.

 

여기서 중요한건 그럼 무엇을 (어느종목을) 과 언제 (K% 이상이 될 때) 의 결정이 가장 중요하지 싶다.

이건 책을 다 봐야 알것 같은데 책을 아직 다 보지 않았... (다 보면 나오긴 할까?)

여튼 나같은 초보에게 가장 쉽게 이해되는 그림을 첨부해보고자 구글링 해봤지만

그래도 책에 나온 그림이 가장 쉽게 이해되는 그림이었다.

변동성 돌파 전략 (책 파이썬 증권 데이터 분석 371페이지 그림)

그렇다면 수많은 종목 중에서 저렇게 스윙하는 종목들을 매수하게 된다고 가정하고

내 자금을 그 종목 1개만 몰빵해서 사기는 위험하고 그런 종목들 중 몇종목을 살것인지도 결정하기도 해야하겠다.

그리고 하루에 한번은 매수/매도도 해야겠고

그럼 그 수수료도 만만치 않을것이다. 

그래서 수수료를 생각해보면 이전에 대신증권은 0.015% 또는 월정액 15000원 + 0.0088% 라고 했는데....

"세금" 이 있다!!

 

CREON 트레이딩 - 제휴은행 계좌개설 - 크레온 (creontrade.com)

 

크레온

대신증권 온라인 주식 거래 서비스. 비대면계좌개설, 수수료 혜택, 주식시세, 종목추천, 투자정보 제공

www.creontrade.com

 

위 링크를 보면 수수료가 나와있는데 "매매관련세금" 탭이 있는 것을 볼 수 있다. 여기를 보면

KOSPI는 거래세 0.08% + 농특세 0.15% = 0.23%

KOSDAQ은 거래세 0.23%

ETF는 0%


정리하면

  매수 매도 합계
KOSPI 0.015% 0.015% + 0.23% 0.26%
KOSDAQ 0.015% 0.015% + 0.23% 0.26%
ETF 0.015% 0.015% 0.03%

하루에 한번꼴로 매수/매도를 하는데 KOSPI 또는 KOSDAQ과 ETF는 약 10배 가량 차이가 난다!
즉 거래를 자주하는데는 ETF가 유리하다!!

물론 KOSPI나 KOSDAQ이 훨씬 수수료 이상의 수익을 내준다면 상관이 없겠다 ㅎ

일단은 ETF 위주로 진행해보는 걸로 계속 진행해보자

 

그 ETF 중에도 당연히 시가총액이 크고 거래량이 많은 종목 중에서 선택을 하는것이 좋겠다.
그래서 ETF 종목 정보를 구해보도록 하자.

 

1. pip install beautifulsoap4 설치

2. pip install pandas 설치

3. pip install selenium으로 selenium 설치

4. Chrome 브라우저 실행하고 주소창에 chrome://version 입력해서 버전 확인  (나의 경우 98.0.4758.102)

5. https://chromedriver.chromium.org/downloads

 에서 버전에 맞는 chromedriver를 다운받고 압축을 푼다음에 chromedriver.exe 파일을 c:\myPackage 폴더 만든후 이 폴더로 복사

6. c:\myPackage의 chromedriver.exe를 관리자권한으로 실행하도록 설정

7. 아래의 파이썬 증권데이터 분석 책에서 제공하는 github 에서 소스

 StockAnalysisInPython/ch08_02_DynamicPageScraping_NaverETF.py at master · INVESTAR/StockAnalysisInPython · GitHub

 

GitHub - INVESTAR/StockAnalysisInPython

Contribute to INVESTAR/StockAnalysisInPython development by creating an account on GitHub.

github.com

 

8. vscode 실행시켜서 새파일(파이썬파일) 만들기 후 복붙  (나의경우 ScrapingETF.py)

9. 저장 후 터미널에서 python ScrapingETF.py를 실행하였더니!

아.. 이건 또 무슨 에러냐... 구글 검색해본 결과 lxml 이 없는게 이유

그럼 터미널에서 pip install lxml 하면 설치하는게 보인다.

 

10. 그리고 다시 실행하면

위와같이 naver에서 518개의 ETF종목의 정보를 가져온것을 확인할수 있다. 순서는 시가총액 순이다.
pandas로 읽은 이정보를 잘 추려서 이 중에서 어떤 종목을 선택할 것인지 이것도 매우 중요한 요소일것이다.

 

오늘은 일단 여기까지!

 

+ Recent posts