어설픈 0458 – 3편

civimanwp

Updated on:

이번 포스팅에서는 작동을 하는 로직과 저장해야하는 정보, 그리고, 저장하고 불러오는 방법에 대해 이야기 해보자

로직

로직은 4가지이다. 어제보다 싸면 사고, 어제보다 싸도 분할을 채웠으면 안사고, 산거보다 비싸면 시장가에 팔고, 손절일이 지나면 청산하는 것이다. 4개의 로직 중 매수는 어제보다 싸고, 분할을 못 채웠을때 사는 것으로 해서 3가지로 줄일수 있다. 다만, 앞선 포스팅에서도 말했듯이 자동매매는 매도를 먼저하고 매수를 해야하니 매도로직을 앞에 두기로 한다. 아마도 산걸 바로 파는 오작동 탓인듯 싶다. 매도로직 중에 무엇이 우선일까 고민하다가 손절일을 먼제하기로 했다.

if hold_days > holddays: # 손절일 초과
        buy_count = trade['Buy_count'] # 보유기록에서 매도개수 가져오기
        pprint.pprint(KisKR.MakeSellLimitOrder(stock_code,buy_count,CurrentPrice*0.9))
        trades.remove(trade) # 보유기록에서 매도항목 삭제
        
 elif CurrentPrice > trade['Buy_price']: # 손절일 초과 안하고, 현재가가 매수가 보다 높음
        buy_count = trade['Buy_count'] # 보유기록에서 매도개수 가져오기
        pprint.pprint(KisKR.MakeSellLimitOrder(stock_code,buy_count,CurrentPrice*0.9))
        trades.remove(trade) # 보유기록에서 매도항목 삭제
        
if CurrentPrice < last_price and len(trades) < tiers: # 어제보다 싸고, 분할이 남음
    buy_date = today # 매수일자 기록
    if CurrentPrice != 0:
        buy_count = tiermoney // CurrentPrice # 매수개수 기록
    else:
        buy_count = 0
    pprint.pprint(KisKR.MakeBuyLimitOrder(stock_code,buy_count,CurrentPrice*1.1))
    trades.append({'Date': buy_date, 'Buy_price': CurrentPrice,'Buy_count': buy_count})
    # 보유기록에 매수날짜, 매수가격, 매수개수 기록

로직은 이런데 문제가 하나 있다. 시장가 매수로 했더니 매수가 안되더라. 그래서 지정가매수로 1.1배에 걸어서 매수를 한다. 그러다 보니 보유기록에 기록되는 매수가격이 실제 매수가격과 다르다. 이건 또 다른 포스팅에서 해결해야할 문제이다.

보유기록

보유기록은 매수일자, 매수가격, 매수개수를 저장한다. 보유기록에서 매수일자 매수가격 매수개수를 불러오고, 이로부터 보유일수를 계산하고, 현재가격과 비교한다. 매수일자는 오늘날짜로 하고, 매수가격은 현재가의 1.1배 지정가 매수로 매수가 확실히 일어나게 한다. 매수개수는 분할당 시드를 현재가로 나눈 몫으로 하고 오류 방지를 위해 조건문을 설정한다. 이 내용을 보유기록 리스트에 저장한다. 매도시에도 매도된 내용을 보유기록 리스트에서 반드시 삭제한다.

for trade in trades[:]:
    buy_date = trade['Date']
    sell_date = today
    hold_days = Ray.get_business_days_diff(buy_date, sell_date)
    buy_count = trade['Buy_count']
    print(trade)

저장방법

저장은 json으로 한다. 한동안 csv를 사용했었는데, 파이썬을 계속 쓰다보니 json이 편하다. 편하니까 많이들 쓰는거겠지. json 읽고 쓰기는 수없이 많은 포스팅이 존재한다. 한가지 팁을 주자면, 최초 작동시나 어떠한 이유로든 json파일이 없을수 있으므로 에러에 대처하는 코드를 넣어줄것 (except Exception as e:)과 굳이 필요없을수도 있는 한글 관련 코딩(encoding=’utf-8′, ensure_ascii=False)을 넣어주는 것이다. 또한 보기 좋은 포멧을 위해 저장시에 indent=4 도 추천한다

# json 파일 읽어오기
try:
    with open(json_file, 'r', encoding='utf-8') as f:
        trades = json.load(f)
except Exception as e:
    trades = []
    print ('No trade data')

# json 파일 쓰기
with open(json_file, 'w', encoding='utf-8') as f:
    json.dump(trades, f, ensure_ascii=False, indent=4)

대충 1,2,3 편을 조합하면 돌아는 간다. 유사한 로직으로 분할과 손절일별로 성과를 검증해본 결과는 놀랍게도 적은 분할, 짧은 손절이 유리하다. 개인적으로 3분할 5손절을 계획하고 있는데, 적은 분할이 유리한 이유는 시드의 크기 탓인것 같다. 손절일도 5일로 했을때 582 거래중 손절은 39회였다.