본문 바로가기
Python

파이썬을 이용한 주식 및 가상화폐 매매 전략 - CCI & Normalized MACD

by 아짱이아빠 2022. 1. 23. 17:45
반응형

주가나 가상화폐에 적용할 수 있는 매매 전략으로서 CCI와 Normalized MACD를 이용하는 것에 대해 파이썬 코드로 구현해 본다.

 

Normalized MACD에 대해서는 아래의 링크에 있는 이전 글을 참고하고 여기서는 자세한 설명은 하지 않겠다. 

 

 

파이썬을 이용한 주식 및 가상 화폐 매매 전략 - Normalized MACD

주식이나 가상화폐 매매 전략에 있어서 정규화된(Normalized) MACD를 적용하는 방법과 효과에 대한 내용을 파이썬을 통해 알아본다. [MACD] MACD는 Moving Average Convergence & Divergence의 약자로 주가나 시세..

superhky.tistory.com

 

CCI는 Commodity Channel Index의 약자이며 최근의 가격이 평균 가격의 이동평균과 얼마나 떨어져 있는가를 표시하여 추세의 강도와 방향을 나타내는 보조지표이다.

CCI를 이용하여 매매를 하는 방법 중 대표적인 것은 CCI 값이 100이 넘으면 과매수 구간으로 보고 매도를 하고 반대로 -100 이하에 있으면 과매도 구간으로 보고 매수를 하는 것이다.

이는 RSI와 유사하다. 

또 다른 방법은 CCI의 시그널 선을 이용하는 것이며 MACD 때와 마찬가지로 CCI의 시그널 선을 CCI 값이  상향 돌파할 때에 매수를 하고 반대로 하향 돌파할 때에는 매도를 하는 것이다.

그러나 항상 그렇듯이 많은 false 신호들이 존재하기 때문에 다른 보조지표를 같이 적용하는 것이 조금 더 유리할 수 있다. 

 

[매매 전략]

MACD는 대표적인 추세를 확인하는 보조지표이고 CCI 역시 추세를 알아보는 지표이지만 모멘텀을 확인하는 보조지표라고도 할 수 있다.

여기서 만들어 볼 매매 전략은 다음과 같다.

우선 매수는 Normalized MACD를 이용한다.

Normalized MACD는 일반 MACD 보다 일반적으로 false 신호가 적고 조금 더 빠르게 실제 가격에 반응한다.

(물론 항상 그러한 것은 아니다.)

그래서 Normalized MACD 선이 Normalized Signal 선을 상향 돌파할 때에 매수를 한다.

 

매도는 CCI 지표를 이용한다.

CCI 값이 100을 넘은 상태에서 현재의 CCI 값이 바로 직전의 CCI 값보다 작으면 매도를 한다.

이렇게 하는 것은 상승세에 있던 추세가 이제는 꺾여 가격이 떨어질 때에 매도를 하기 위함이다. 

이를 통해 Normalized MACD 선이 Normalized Signal 선을 하향 돌파할 때에 매도를 하는 것보다 더 빠르게 가격에 반응하여 가격이 더 떨어지기 전에 매도를 함으로써 이익을 낼 수 있을 것으로 기대한다.

또한 CCI 값이 100을 넘지 못하고 계속 하락하면 매도를 하지 못하고 물려 큰 손해를 볼 수 있다.

이러한 손해를 줄이기 위해 Normalized MACD가 Normalized Signal 선을 하향 돌파할 때에 매도하는 조건을 추가해 놓는다.

 

[파이썬 코드 - CCI 계산]

먼저 아래와 같이 프로그램에 필요한 라이브러리를 불러온다.

import pyupbit
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

아래는 분석하고자 하는 가상 화폐를 입력하여 3분 봉 데이터 200개를 가져오는 코드이다.

coin = input("코인 :")
df = pyupbit.get_ohlcv(coin,interval="minutes3", count=200)

 

원화 데이터를 가져오려면 입력은 “KRW-XRP”와 같이 입력한다.

 

불러온 데이터에서 Normalized MACD를 구하는 코드는 앞에서의 링크를 참고하고 여기서는 넘어가도록 하겠다.

 

CCI는 다음의 식으로 구한다.

CCI 계산식
(CCI 계산식)

 - 평균 가격 : (고가 + 저가 + 종가) / 3

 - 이동평균 가격 : n 동안의 이동평균

 - 평균 오차 : 절대값(평균 가격-이동평균 가격)의 n 동안 이동평균

 

이는 파이썬 코드로 다음과 같다.

df['AP'] = (df['high'] + df['low'] + df['close']) / 3
df['SMA'] = df['AP'].rolling(14).mean()
df['ADV'] = df['AP'].rolling(14).apply(lambda x:pd.Series(x).mad())
df['CCI'] = (df['AP'] - df['SMA']) / (0.015 * df['ADV'])

평균 가격을 계산하여 ‘AP’ column에 저장하고 이 평균 가격 14개에 대한 이동평균을 계산하여 column ‘SMA’에 저장한다.

세 번째 줄 코드는 14개의 데이터에 대해 ‘lambda x’ 함수를 수행한다.

‘.mad()’ 함수는 데이터의 평균을 구하고 이 평균값으로부터의 차를 계산하여 평균 오차를 산출한다.

 

이렇게 계산한 CCI와 Normalized MACD를 그래프로 그리는 코드는 아래와 같으며 그 밑은 가상화폐 온톨로지가스(ONG)에 CCI와 Normalized MACD를 표현한 결과이다.

도식화와 관련된 코드 설명은 다른 글에서 설명하였다.

plt.style.use('fivethirtyeight')
plt.figure(figsize=(20, 13))

plt.subplot(3,1,1)
plt.plot(df['close'], lw=1.2)

plt.subplot(3,1,2)
plt.plot(df['CCI'], label='CCI', lw=1.2)

plt.subplot(3,1,3)
plt.plot(df['norm_MACD'], label='Normalized MACD', lw=1.2)
plt.plot(df['norm_Signal'], label='Normalized Signal', lw=1.2)

 

CCI(n=14) & Normalized MACD : 온톨로지가스(ONG)
(CCI(n=14) & Normalized MACD : 온톨로지가스(ONG))

 

 

[파이썬 코드 - 매매 전략]

def buy_sell(data, case1, case2, case3):
  BuySignal = []
  SellSignal = []
  buy_price=0

  flag = 1
  for i in range(0, len(data)):
    if ((data[case1][i-1] < data[case2][i-1]) and (data[case1][i] > data[case2][i])) and flag == 1:
      BuySignal.append(data['close'][i])
      SellSignal.append(np.nan)
      flag = 0

    elif (data[case3][i] > 100) and (data[case3][i] - data[case3][i-1] < 0) and flag == 0:
      SellSignal.append(data['close'][i])
      BuySignal.append(np.nan)
      flag = 1

    elif ((data[case1][i-1] > data[case2][i-1]) and (data[case1][i] < data[case2][i])) and flag == 0:
      SellSignal.append(data['close'][i])
      BuySignal.append(np.nan)
      flag = 1

    else:
      SellSignal.append(np.nan)
      BuySignal.append(np.nan)

 

매매 전략은 앞에서 얘기 했듯이 매수는 Normalized MACD를 기준으로 하고 매도는 CCI가 100을 넘은 상태에서 CCI 선이 하향으로 바뀔 때 수행한다.

또한, 혹시나 CCI가 100까지 못 가고 하락 추세로 바뀌면 손해를 계속 볼 수 있기 때문에 Normalized MACD를 기준으로 한 매도 조건을 추가하였다.

 

반응형
x = buy_sell(df, 'norm_MACD', 'norm_Signal', 'CCI')
df['Buy_Signal_Price'] = x[0]
df['Sell_Signal_Price'] = x[1]

위의 코드로 매매 전략 함수를 수행시키며 결과는 아래와 같다.

 

CCI(n=14) & Normalized MACD 매매 전략 수행 결과 : 온톨로지가스(ONG)
(CCI(n=14) & Normalized MACD 매매 전략 수행 결과 : 온톨로지가스(ONG))

 

위의 결과를 보면 가격이 꽤 오르는 구간이 있어서 매매가 잘 되었으면 수익이 있었을 텐데 매도가 빠르게 일어나 수익을 얻지 못했다.

Backtesting을 통해 얼마큼 수익이 있었는지를 보면 아래와 같다.

CCI(n=14) & Normlized MACD Backtest 결과 : 온톨로지가스(ONG)
(CCI(n=14) & Normlized MACD Backtest 결과 : 온톨로지가스(ONG))

위의 기간 동안 가격은 올랐으나 Backtesting 결과인 누적 수익률은 오히려 마이너스이다.

그 이유는 매수 이후 바로 CCI 결과가 매도 조건이 되었기 때문인데 CCI를 계산하는 기간 또는 데이터 개수 n을 14로 설정하니 CCI는 결과가 100을 쉽게 넘고 가격의 변동에 민감하게 반응하는 경향있어서 인 것으로 생각된다. 

 

그래서 이를 둔감하게 하기위해 동일한 데이터에서 n을 42로 바꾸어 수행한 결과는 아래와 같다.

CCI(n=42) & Normalized MACD : 온톨로지가스(ONG)
(CCI(n=42) & Normalized MACD : 온톨로지가스(ONG))
CCI(n=42) & Normalized MACD 매매 전략 수행 결과 : 온톨로지가스(ONG)
(CCI(n=42) & Normalized MACD 매매 전략 수행 결과 : 온톨로지가스(ONG))
CCI(n=42) & Normlized MACD Backtest 결과 : 온톨로지가스(ONG)
(CCI(n=42) & Normlized MACD Backtest 결과 : 온톨로지가스(ONG))

 

CCI의 계산 기간 n을 42로 바꾸면 CCI의 결과가 가격에 둔감해지면서 일종의 false 신호를 제거하는 효과가 있었으며 그 결과 가격이 오름세에 있을 때에 고점에서 매도를 하게 되었고 누적 수익률은 거의 30%의 결과가 나왔다.



[종합 결론]

CCI와 Normalized MACD를 조합하여 가상화폐 매매 전략을 만들어보고 파이썬 코드로 이를 구현하고 Backtesting도 해보았다.

 

CCI의 계산 기간을 잘 조절하면 꽤 괜찮은 전략이 될 수 있는 가능성을 보았다.

Normalized MACD의 계산도 기간을 어떻게 기준을 잡을지에 따라 결과가 달라질 것이고 이 기간 설정은 몇 분 봉 데이터를 적용할 것인지에 따라 설정을 해야 할 것으로 생각된다.

 

현재 이 전략을 3분 봉 데이터로 실시간 매매를 통해 시험 중에 있는데 요즈음 전체적으로 가상화폐 시장이 큰 하락세에 있어 계속 손해를 보고 있다.

추후에 어느 정도 괜찮은 결과가 나오면 그 때 다시 정리하도록 하겠다.  

 

반응형

댓글