그리드매매를 위한 코딩 3단계

civimanwp

Updated on:

그리드매매를 위한 코딩 3단계

그리드매매란 주식이나 코인 자동매매를 할때, 일정비율을 정하여 하락하면 매수하고 상승하면 매도하는 방법을 말한다. 이런 방법을 구현하고자 3단계로 그리드를 만드는 코드를 짜보았다.
그리드를 만들고 이것을 json형태로 저장하여 다음번 스케쥴러 작동시 새로 계산하지 않고 불러와서 적용할수 있도록 짜보았다.

그리드매매를 위한 코딩 3단계

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

그리드매매용 그리드 만들기

tier_maker라는 함수를 만들어서 입력값에 따른 그리드를 데이터프레임 형태의 출력값으로 받고, json파일로 저장하도록 했다.
입력값은 종목(ticker), 투자금(Ini_money), 1티어가격(first_tier)으로 정했다.

import pandas as pd

def tier_maker(ticker, Ini_money, first_tier):

고정값은 매수를 위한 하락비율과 매도를 위한 상승비율로 하락비율은 1%, 상승비율은 3%로 정했다.

    buy_ratio = 0.99 # -1%
    sell_ratio = 1.03 # +3%

출력값에 들어갈 내용은 표와 같다.
최초값은 모두 0으로 설정한다.

변수값 설명

변수설명
tier티어값
stock_count티어당 보유한 주식수
tier_money티어당 할당된 금액
tier_avg티어 평균매수금액
buy_price매수금액 – 이 금액 아래에서 매수한다
buy_count매수갯수 – 이 갯수만큼 매수한다
sell_price매도금액 – 이 금액 위에서 매도한다
sell_count매도갯수 – 이 갯수만큼 매도한다
    stock_count = 0
    tier_money = 0
    tier_avg = 0
    buy_price = 0
    buy_count = 0
    sell_price = 0
    sell_count = 0

데이터프레임을 만들기 위해 사용할 빈 리스트(AVT_list)를 정의하고, 리스트를 저장할 json파일명(grid_file)을 설정한다.
첫번째 매수금액을 1티어가격에 매수비율을 곱한 값으로 설정한다.

    AVT_list = []
    grid_file = f'{ticker}_grid.json' 
    buy_price = first_tier * buy_ratio

반복문을 통해 각각의 값을 계산한다.
각각의 값을 리스트에 저장한다.

    for tier in range(1,tiers+1):
        tier_money = Ini_money / tiers
        buy_price = int(buy_price * buy_ratio)
        buy_count = tier_money // buy_price
        sell_price = int(buy_price * sell_ratio)
        sell_count = buy_count
        stock_count += buy_count
        AVT_list.append([tier, stock_count, tier_money, tier_avg, buy_price, buy_count, sell_price, sell_count])

리스트를 데이터프레임으로 만들고, json파일로 저장한다.
데이터프레임을 반환한다.

    AVT_df = pd.DataFrame(AVT_list, columns=['티어','잔고량','투자금','티어평단','매수가','매수량','매도가','매도량'])
    AVT_df = AVT_df.sort_values(by='티어', ascending=True)
    AVT_df.to_json(grid_file,orient='records')

    return AVT_df

그리드 새로 만들기

그리드 매매를 하다보면 매수 매도 범위를 벗어나는 경우가 발생한다.
설정해놓은 그리드의 최고 매도가를 초과하거나, 최소 매수가 이하로 떨어지는 경우를 말한다.
이럴때 어떤 이들은 버티고, 어떤 이들은 그리드를 바꾼다.
나는 바꾸기로 했다. 그것도 자동으로.

파이썬 코드

### 그리드 변경 코드
# 현재가가 그리드 범위내에 있는지 체크
if CurrentPrice > grid.iloc[0]['매도가']: # 현재가가 최상위 매도가 보다 클 경우, 1티어를 현재가의 105%로 설정 
            old_tier = first_tier
            first_tier = CurrentPrice * 1.05
            grid = tier_maker(stock_code, tier_money, first_tier) 
            grid.to_json(grid_file,orient='records')
elif CurrentPrice < grid.iloc[24]['매수가']: # 현재가가 최하위 매수가 보다 작을 경우, 1티어를 현재가의 125%로 설정
            old_tier = first_tier
            first_tier = CurrentPrice * 1.25
            grid = tier_maker(stock_code, tier_money, first_tier) 
            grid.to_json(grid_file,orient='records')

로직은 단순하다.
현재가를 기준으로 그리드 상의 최고 매도가 grid.iloc[0][‘매도가’] 를 초과하면 그리드를 바꾼다.
아니면, 현재가를 기준으로 그리드 상의 최소 매수가 grid.iloc[24][‘매수가’] 미만이면 그리드를 바꾼다.

첫번째 고민이 생겼다.
바꾸는 건 좋은데 얼마나 바꿔야하는지?
나의 기본적인 생각은 5티어 (25티어 그리드 기준) 정도 추가하는 것이었다. (상승이거나 하락이거나)
하지만 내가 만든 그리드메이커 코드는 티어갯수로 추가하기에는 무리가 많았다.
tier_maker(stock_code, tier_money, first_tier)
종목명, 시드, 첫 티어금액 만으로 그리드를 만드는 코드라서 첫 티어금액만으로 추가티어 갯수를 맞춰야 했다.
궁금하실까봐 tier_maker 함수에 관한 링크를 붙인다.

시행착오 끝에 상승시에는 첫 티어금액을 5% 상향하면 5티어 정도 확보할 수 있었다.
실제 작동시에는 4티어 정도 확보 되었다.
하락시는 현재가의 125%를 첫 티어금액으로 설정했다.
하락시에도 4티어 정도 아래로 확보되었다.
백테스트에서 잘 작동되었다.
백테스트 상에서 연속으로 그리드를 올리거나 내린 경우는 못 찾았다. (최근 5년 데이터의 경우임)

한 가지 주목할 내용은 코드에는 잘 표현되어 있지 않지만 시드 부분이다.
현재 그리드 자동매매 코드에는 한번 그리드를 짜면 최고티어를 돌파하던지 최저티어 아래로 갈 경우만 그리드가 변경되도록 되어 있다.
이 말이 갖는 의미는 아무리 시드가 늘어나도 그리드가 바뀌기 전에는 시드를 활용하지 않는 방식이라는 뜻이다.

남김없이 쓰기

처음 목적은 단순히 그리드를 만드는 것이었다.
그러다보니 시드를 단순히 티어로 나눈 값이 티어당 할당액이고,
티어당 할당액을 매수가로 나눈 것이 티어당 개수였다.
그러다보니 티어당 잔돈이 남게 되고,
결국에는 노는 돈이 생기게 되었다.
아래 표에서 보듯이 티어당 잔돈이 꽤 생긴다.
이 점을 개선하고자 했다.

티어티어당할당액매수가티어당 개수티어당 잔돈
1100001000100
21000097010300
31000094111351
4100009131143
잔돈이 남는다는 예시

수정된 파이썬 코드

for tier in range(1,tiers+1):
        # tier_money = Ini_money / tiers                # v2 삭제내용
        if tier == 1 :                                  # v2 추가내용
            tier_money = int(Ini_money / tiers)              # v2 추가내용 (한국)
        elif tier == 25:                                # v2 추가내용
            tier_money = remain_money                   # v2 추가내용
        else:                                           # v2 추가내용
            tier_money = int(remain_money / (tiers - tier))  # v2 추가내용
        buy_price = int(buy_price * buy_ratio)
        buy_count = tier_money // buy_price
        sell_price = int(buy_price * sell_ratio)
        sell_count = buy_count
        stock_count += buy_count
        remain_money = remain_money - (buy_price * buy_count) # v2 추가내용

로직은 간단하다.
기존에 일괄적으로 적용된 시드를 티어로 나눈 값 대신 조건문으로 대체한다.
조건문은 다음과 같다.

  • 1티어 : 시드를 티어로 나눈값을 티어당 할당액으로 사용
  • 25티어 (마지막 티어) : 나머지 돈 전부를 티어당 할당액으로 사용
  • 2-24티어 (중간 티어들) : 앞 티어를 매수하고 남은 돈을 남은 티어수로 다시 나눈 값을 티어당 할당액으로 사용

마지막에 나머지 돈을 계산하는 코드를 넣어서 티어당 반복문이 돌아갈 때 반영되도록 한다.

이렇게 수정해보니 대부분의 티어는 고르게 증가하지만, 마지막 티어의 할당이 많이 줄어든다.
마지막 티어는 추후에 고민해서 다시 업데이트 하겠다.