1편에 이어지는 글이다.
1편의 문제점은 손절로직, 보유일 계산로직, 시드를 분할값으로 나누어 매수개수를 계산하는 로직이었다.
2편에서는 이 3가지만 해보자/
매수개수
생각해보면 별거 아닌 로직이다. 내가 가진 시드를 분할로 나누면 된다. 다만, 소수점이 나오면 안되니까 몫 많을 취하면 된다.
tiermoney = float(stock['StockNowMoney']) // ratio_0458
if CurrentPrice != 0:
buy_count = tiermoney // CurrentPrice
else:
buy_count = 0
tiermoney는 분할별로 배당된 금액을 말하며, 내가 가지고 있는 현금자산 전체float(stock[‘StockNowMoney’]) 를 분할ratio_0458로 나누어서 값을 정한다. 이렇게 구한 분할당 금액을 현재가격CurrentPrice으로 나누어 몫을 구하면 매수개수buy_count가 된다. 이유는 모르겠지만, (궁금하지도 않고) 백테스트 중에 0으로 나누는 에러가 발생해서 조건문을 사용했다. 자동매매 특성상 실제 작동시키면 언제 어디서 에러가 날지 모르니 불필요해 보여도 이런 저런 조건문을 붙여야 안심이 된다.
보유일
보유일은 생각으로는 쉽다. 매수일과 오늘의 날짜차이를 계산하면 된다. 분할과 손절일을 여러조합으로 백테스트를 할때 1분할 1손절일도 보유일이 11일까지 나타났다. 처음에는 무슨 에러인가 했다. 곰곰히 생각해보니 연말끼고 쉬는날이 연속으로 11일이 있었던거 같다. 그다음 고민은 주식거래일만 계산했으면 했다. 내 실력에 그건 한참 무리이고 인공지능의 도움으로 영업일만 계산하는 함수로 보유일을 계산했다.
def get_business_days_diff(start_date, end_date, holidays=None):
if holidays is None:
holidays = []
business_days = pd.bdate_range(start=start_date, end=end_date, holidays=holidays)
return len(business_days) - 1
buy_date = trade['Date']
sell_date = today
hold_days = get_business_days_diff(buy_date, sell_date)
판다스에 영업일만 구하는게 있고, 이 안에 휴일을 리스트로 넣는 기능이 있긴하지만, 사용하지 않았다. 보유일과 매수/매도가격 그리고 갯수를 저장하기 위해 보유기록리스트를 만들고 json파일로 저장해야한다. (이 내용은 다른 포스트에서) 아무튼 json파일에서 불러온 매수날짜와 오늘의 차이를 get_business_days_diff 함수로 구하여 보유일을 정했다.
손절일
손절일은 고정값이다. (물론 내맘대로 바꿀수는 있지만, 프로그램상에서는 고정이다.) 손절일이 되면 무조건 시장가에 매도한다는 로직은 가장 앞에 나와야 된다. 즉, 손절로직 – 익절로직 – 매수로직 순으로 작성해야 제대로 작동하는 거 같다. 이유는 모르고 궁금하지 않다.
holddays = 5 # 손절일
if hold_days > holddays:
buy_count = trade['Buy_count']
pprint.pprint(KisKR.MakeSellLimitOrder(stock_code,buy_count,CurrentPrice*0.9))
trades.remove(trade)
로직 구현은 간단하다. 계산된 보유일이 설정한 손절일보다 크면 시장가 매도이다. 이해도 안되고 궁금하지도 않은 것중 하나는 시장가 매도는 작동이 잘 안되고, 현재가의 90%에 주문을 거는 것은 작동이 된다. 언젠가는 왜인지 알겠지.
다음 포스트에서는 매수에 관한 내용과 보유기록을 보존하는 방법을 해보겠다. 이 로직은 하루 한번 작동시키는 거라서 외부파일로 필수 정보를 저장해놔야하고, 일반적으로 json을 이용한다.
백테스트 결과중 관심이 가는 부분은 시가매매가 종가매매 보다 성과가 좋다는 것이다. 이유는 모르겠지만, 궁금하지도 않고, 어차피 국내장에서는 LOC가 없기 때문에 종가매매는 구현하기도 어려우니 잘됐다는 생각이다.