호돌찌의 AI 연구소
article thumbnail

이번 글은 python을 이용하여 매매에 있어서 참고할 수 있는 보조지표를 구현해보겠습니다. 보조지표대로 매매를 해서 부자가 되면 좋겠습니다만 절대 만능이 아닙니다. 매매를 하다 보면 절대 마법공식이라는 것이 존재하지 않기 때문입니다. 하지만 의사결정하는데 있어 참고 정도만 하는 데에는 도움이 될 수 있습니다. 많이 지표들 중 가장 직관적으로 활용하기 좋은 RSI(Relative Strength Index)를 소개하고 비슷한 지표인 MFI(Money Flow Index)와 CCI(Commodity Channel Index)를 다루어보도록 하겠습니다. 지표에 대한 정말 디테일한 개념은 Reference만 남기도록 하고, 여기 글에서는 Dataframe을 부르고 나서 사용자함수로 어떻게 구현하는지 보여드릴 예정입니다. 

 

 

 

데이터 부르기


사용할 데이터는 아래 글에서의 코드를 참고하려고 합니다. 

2022.07.01 - [Programming/Crypto] - pyupbit 활용 - 암호화폐 데이터 부르기

 

import pickle
import pyupbit

# 이전 글에서 작성한 API의 Key들 활용 
with open('./keypair/upbit_secret_key.pkl', 'rb') as k:
    secret_key = pickle.load(k)
    
upbit = pyupbit.Upbit(secret_key['access key'], secret_key['secret key'])


# 15분봉 비트코인 데이터 부름
temp_df = pyupbit.get_ohlcv('KRW-BTC',                      
                       interval = "minute15", 
                      count = 500,
                       to = '20220827 22:00:00',
                      period = 0.1)

 

15분 데이터 최근 20봉을 조회하면 다음과 같습니다. 

위의 Dataframe의 close(종가)가격과 차트 상에서 8월 27일 17시 종가 가격이 같음을 알 수 있습니다. 

 

 

 

RSI


RSI 공식 (Disnat)

RSI(Relative Strength Index) 개념 및 정의는 이 글을 참고하면 됩니다. 일반적으로 70이 넘으면 과매수 구간이고, 30 아래를 밑돌면 매도 국면이라고 익히 알려져 있습니다. 

 

아래와 같이 코드를 구현합니다. 

import numpy as np
import pandas as pd

def get_rsi(df, period = 14):
    df["close"] = df["close"]
    delta = df["close"].diff() # 종가의 차이를 계산
    up, down = delta.copy(), delta.copy() # 상승분과 하락분을 따로 계산하기 위해 복사
    up[up < 0] = 0 # 상승분, U
    down[down > 0] = 0 # 하락분, D
    _gain = up.ewm(com=(period - 1), min_periods=period).mean() # AU(U값의 평균)
    _loss = down.abs().ewm(com=(period - 1), min_periods=period).mean() # DU(D값의 평균)
    RS = _gain / _loss
    rsi_14 = pd.Series(100 - (100 / (1 + RS)), name="RSI")
    df['rsi'] = rsi_14
    return df
    
    
get_rsi(temp_df).tail(20)

 

보통 기간(period)은 14일을 기준으로 두고 계산하기 때문에 14일을 기준으로 계산하면 아래와 같습니다.

붉은색 동그라미 값과 위의 Dataframe에서의 8월 27일 rsi 값과 같음을 알 수 있습니다. 

 

 

MFI


 

RSI는 가격에만 초점을 맞추지만 여기에 거래량까지 반영한 모멘텀 지표로는 MFI(Money Flow Index)가 있습니다. 개념글로는 이 글을 참고 하면 됩니다. 20 아래에 하락국면, 80 이상이면 상승국면으로 이야길 하곤 합니다. 구현하는 코드는 아래와 같습니다. 

def get_mfi(df, period = 14): 
	# 우선적으로 각 기간에 맞게 평균 가격(TP)을 구합니다. 
    typical_price = (df['high'] + df['low'] + df['close']) / 3  # TP
    money_flow = typical_price * df['volume']
    positive_flow =[] 
    negative_flow = []
    
    # 반복문을 돌면서 기간별 양의 RMF, 음의 RMF를 구현합니다.
    # Loop through the typical price 
    for i in range(1, len(typical_price)):
        if typical_price[i] > typical_price[i-1]: 
            positive_flow.append(money_flow[i-1])
            negative_flow.append(0) 
        elif typical_price[i] < typical_price[i-1]:
            negative_flow.append(money_flow[i-1])
            positive_flow.append(0)
        else: 
            positive_flow.append(0)
            negative_flow.append(0)
    
    positive_mf = []
    negative_mf = [] 
    # 기간동안 평균 가격들의 분류가 끝난 경우, RMF 계산식을 이용해 평균 가격과 당일 거래량을 곱합니다. 
    # Get all of the positive money flows within the time period
    for i in range(period-1, len(positive_flow)):
        positive_mf.append(sum(positive_flow[i+1-period : i+1]))
    # Get all of the negative money flows within the time period  
    for i in range(period-1, len(negative_flow)):
        negative_mf.append(sum(negative_flow[i+1-period : i+1]))
    
    # MFR을 계산합니다. 그 후 MFI를 구합니다. 
    mfi = list(100 * (np.array(positive_mf) / (np.array(positive_mf)  + np.array(negative_mf) )))
    mfi = list(np.repeat(np.nan,len(df)-len(mfi))) + mfi
    df['mfi'] = mfi
    
    return df
    
    
get_mfi(temp_df).tail(20)

 

 

CCI


CCI(Commodity Channel Index)는 주가와 이동평균의 차이를 측정하는 보조지표로써 이격을 바탕으로 과매수와 과매도를 판단합니다. CCI가 높다는 것은 이동평균의 주가보다 현재 주가가 높다는 뜻입니다. 이동평균을 바탕으로 계산하기 때문에 RSI, MFI보다 더욱 쉽게 계산을 할 수 있습니다. 개념에 대한 글은 이 글을 참고하면 될 것 같습니다. 구현하는 코드는 아래와 같습니다. 기간은 14일 대신 9일을 기본 값으로 설정하여 사용했습니다.

 

def get_cci(df, ndays = 9): 
    df['tp'] = (df['high'] + df['low'] + df['close']) / 3 
    df['sma'] = df['tp'].rolling(ndays).mean()
    df['mad'] = df['tp'].rolling(ndays).apply(lambda x: pd.Series(x).mad())
    df['cci'] = (df['tp'] - df['sma']) / (0.015 * df['mad']) 
    df.drop(columns=['sma','mad','tp'], inplace=True)
    return df

get_cci(temp_df).tail(20)

 

 

 

 

 

마무리 & Reference


모든 보조지표들은 참고만 하는 것이 좋지, 한계가 반드시 존재하며 잘못된 시그널일 수 있음을 반드시 유의하셔야 합니다. 또한 코드는 구글링 하면서 직접 구현해도 좋고, 다른 사람들이 짜놓은 것을 활용하는 것이 좋습니다. 또한 설치가 까다롭지만 약 200개의 Indicator들을 활용할 수 있는 Ta-Lib라는 Library도 있는데 참고하시면 될 것 같습니다.

 

 

참고한 자료들은 다음과 같습니다.

 

https://www.nanumtrading.com/fx-%EB%B0%B0%EC%9A%B0%EA%B8%B0/%EC%B0%A8%ED%8A%B8-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%9D%B4%ED%95%B4/03-rsi/

 

04 RSI | NANUM TRADING

RSI를 이용한 매매 Welles Wilder는 RSI가 70%를 웃돌면 초과매수 국면으로, 30%를 밑돌면 초과매도 국면으로 규정하였습니다. 따라서 RSI가 70%를 넘어서면 매도, 30% 밑으로 떨어지면 매수 포지션을 취하

www.nanumtrading.com

https://m.blog.naver.com/junhyung34/221606117183

 

MFI 지수 (Money Flow Index)

MFI 란? MFI (Money Flow Index)는 주식(혹은 증권)의 가격과 거래량을 사용하여 주식이 과잉 매...

blog.naver.com

https://blog.naver.com/leeys3927/220323668238

 

CCI(Commodity Channel Index)란?

CCI(Commodity Channel Index)란? 주가와 이동평균의 차이를 측정하는 보조지표이다. 즉 현재의 주가...

blog.naver.com

https://github.com/mrjbq7/ta-lib

 

GitHub - mrjbq7/ta-lib: Python wrapper for TA-Lib (http://ta-lib.org/).

Python wrapper for TA-Lib (http://ta-lib.org/). Contribute to mrjbq7/ta-lib development by creating an account on GitHub.

github.com

 

 


아래는 블로그 주인장의 토스 익명 후원 링크입니다. 글이 너무 너무 도움되거나 흡족스러웠다면 후원해주시면 감사하겠습니다.

https://toss.me/hotorch

 

hotorch님에게 보내주세요

토스아이디로 안전하게 익명 송금하세요.

toss.me

 

profile

호돌찌의 AI 연구소

@hotorch's AI Labs

포스팅이 도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!