본문 바로가기
가상화폐 퀀트 전략

# 트레이딩 전략 1 : 저가매수, 고가매도 (buy low, sell high)

by TenMillionQuant 2022. 3. 15.

 

 

이번 글에서는 아주 간단한 트레이딩 저가매수/고가매도 전략을 통해 가상화폐 트레이딩에 대해 배워보자

 

저번 글에서 배웠던 pybithumb을 통해 데이터를 준비하자.

 

 

API를 이용해 비트코인 시세 가져오기 - pybithumb

가상화폐 퀀트 전략 시작을 위해 API를 통해 가상화폐 시세 및 가격을 가져오는 방법을 실습해보자 가상화폐 데이터를 가져오기 위해선 주로 API를 사용한다. 가장 많이 사용하는 API가 빗썸과 업

tenmillionquant.tistory.com

 

 

 

Chapter1_알고리즘트레이딩기초_저가매수고가매도
In [33]:
#창 맞추기위함

from IPython.core.display import display, HTML

display(HTML("<style>.container { width:90% !important; }</style>"))

데이터 준비

일단, pybithumb API를 통해 데이터를 준비하자. 필요한 라이브러리를 가져온다.

In [13]:
import pandas as pd
import pybithumb
import numpy as np
In [8]:
# 약 10년치 데이터이므로, 2년 정도의 데이터만 사용한다
df = pybithumb.get_ohlcv("BTC")

# 2년치 데이터만 가져온다
df = df[-600:]

시그널 구현

트레이딩 전략의 주요 부분은 트레이딩 시점(증권 또는 기타 자산을 매수/매도)을 결정하는 것이다. 주문 전송을 발동시키는 이벤트를 "signal" 이라고 한다.

이 전략에서는 '저가 매수, 고가 매도'이므로 연속 2일간의 종가 차이를 계산해, 값이 음수이면 전날의 가격이 다음날의 가격보다 높았고 가격이 낮아지므로 매수할 수 있다. 반면, 이 값이 양수이면 가격이 높기 때문에 매도한다.

In [14]:
# 연속 2일간의 종가 차이를 계산하기 위해 data_signal이라는 dataframe을 만든다.

data_signal = pd.DataFrame(index = df.index)
data_signal['price'] = df['close']
data_signal['daily_difference'] = data_signal['price'].diff()

# 이제 daily_difference 값을 기반으로 signal을 만든다. 값이 양수이면 1을 값이 음수이면 0 한다
data_signal['signal'] = 0
data_signal['signal'] = np.where(data_signal['daily_difference'] > 0, 1, 0)

시그널 열을 읽으면 매수해야 할때 0을 갖고, 매도해야 할 때 1을 갖는다.

시장이 계속 하락하면 지속적으로 매수하거나 시장이 상승할 때 지속적으로 매도하기를 원하지 않기 때문에 시장에 대한 포지션 수로 제한함으로써 주문 수를 제한할 것 이다.

시장에서의 포지션을 제한하고자 여러 번 연속으로 매수하거나 매도하는 것은 불가능하다고 가정한다. 따라서 시그널 열에 diff()를 적용한다.

그러면 만약 positions값이 1인 경우 매수하게 되고 -1이 되면 매도하게 된다.

In [17]:
data_signal['positions'] = data_signal['signal'].diff()
data_signal['positions']
Out[17]:
time
2020-07-24 00:00:00    NaN
2020-07-25 00:00:00    1.0
2020-07-26 00:00:00    0.0
2020-07-27 00:00:00    0.0
2020-07-28 00:00:00    0.0
                      ... 
2022-03-11 00:00:00    1.0
2022-03-12 00:00:00   -1.0
2022-03-13 00:00:00    0.0
2022-03-14 00:00:00    1.0
2022-03-15 12:00:00   -1.0
Name: positions, Length: 600, dtype: float64

시그널 시각화

이제 매수/매도 상황을 시각화 해보자

In [25]:
# 필요한 라이버르리를 임포트한다
import matplotlib.pyplot as plt

# 다음으로 차트를 포함할 글미(figure)를 정의한다
fig = plt.figure()
ax1 = fig.add_subplot(111, ylabel = 'Bitcoin price in won')

#이제 처음 선택한 날짜 범위 내에서 주가를 그린다
data_signal['price'].plot(ax=ax1, color='r', lw=2.)

# 코인 주식 하나를 매수할 때 위쪽 화살표를 그린다
ax1.plot(data_signal.loc[data_signal.signal == 1].index, data_signal.price[data_signal.signal == 1], '^', markersize=7, color='b', label='buy')
ax1.plot(data_signal.loc[data_signal.signal == -1].index, data_signal.price[data_signal.signal == -1], 'v', markersize=7, color='b', label='sell')

plt.show()
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\cbook\__init__.py:1402: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  ndim = x[:, None].ndim
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\axes\_base.py:276: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  x = x[:, np.newaxis]
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\axes\_base.py:278: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  y = y[:, np.newaxis]
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\cbook\__init__.py:1402: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  ndim = x[:, None].ndim
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\axes\_base.py:276: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  x = x[:, np.newaxis]
C:\ProgrammingProgram\Anaconda3\lib\site-packages\matplotlib\axes\_base.py:278: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version.  Convert to a numpy array before indexing instead.
  y = y[:, np.newaxis]

백테스팅

백테스팅은 트레이딩 전략의 효과를 보여주는 통계를 얻기 위한 핵심단계다. 앞에서 배운 것처럼 백테스팅은 과거가 미래를 예측한다는 가정에 의존한다. 이 단계에서는 다음과 같이 당신 또는 회사가 중요하게 생각하는 통계량을 제공한다.

  • 손익(PnL) : 거래 수수료 없이 전략으로 번 돈

  • 순손익(순PnL) : 거래 수수료가 포함된 전략으로 번 돈

  • 노출(exposure) : 투자한 자금

  • 트레이딩 수 : 트레이딩 세션 동안 트레이딩의 수

  • 연간 수익률 : 1년간의 트레이딩 수익률

  • 샤프 비율 : 위험 조정 수익. 이 데이터는 전략의 수익을 무위험 전략과 비교하기 때문에 중요하다

In [31]:
# 초기자금 1억
initial_capital = float(100000000)

# 이제 포지션과 포트폴리오에 대한 데이터 프레임을 만든다
positions = pd.DataFrame(index=data_signal.index).fillna(0)
portfolio = pd.DataFrame(index=data_signal.index).fillna(0)

# 다음으로 비트코인 포지션을 다음 데이터프레임에 저장한다.
positions['bitcoin'] = data_signal['signal']

# 그런 다음 포트폴리오에 대한 포지션 금액을 다음에 저장한다
portfolio['positions'] = (positions.multiply(data_signal['price'], axis= 0))

# 다음으로 투자되지 않은 돈(현금)을 계산한다
portfolio['cash'] = initial_capital - (positions.diff().multiply(data_signal['price'], axis = 0)).cumsum()

# 총 투자액은 포지션과 현금을 합산해 계산한다.
portfolio['total'] = portfolio['positions'] + portfolio['cash']
In [32]:
portfolio
Out[32]:
positions cash total
time
2020-07-24 00:00:00 0.0 NaN NaN
2020-07-25 00:00:00 11365000.0 88635000.0 100000000.0
2020-07-26 00:00:00 11748000.0 88635000.0 100383000.0
2020-07-27 00:00:00 12339000.0 88635000.0 100974000.0
2020-07-28 00:00:00 13104000.0 88635000.0 101739000.0
... ... ... ...
2022-03-11 00:00:00 48948000.0 119213000.0 168161000.0
2022-03-12 00:00:00 0.0 167782000.0 167782000.0
2022-03-13 00:00:00 0.0 167782000.0 167782000.0
2022-03-14 00:00:00 48614000.0 119168000.0 167782000.0
2022-03-15 12:00:00 0.0 167437000.0 167437000.0

600 rows × 3 columns

 

 

 

댓글