728x90
이번 백테스팅에 사용할 지표는 볼린저 밴드입니다.
저의 알고리즘은 다음과 같습니다.
매수 조건: 고점대비 20% 이상 하락을 경험하고, 볼린저밴드의 +1 시그마 상향 돌파시 매수
매도조건1: -1 시그마 터치시 전액 매도
매도조건2: 매도조건 1 충족 안됐을 때, 직전 고점 대비 +10% 달성시 50% 익절
매도조건3: 매도조건 2 충족됐을 때, 1시그마 터치시 전액 청산
본격적으로 저의 코드를 소개하겠습니다.
import talib
import yfinance as yf
stock_data = yf.download('^GSPC')#S&P500 데이터에 해당
count = 5000
stock_data = stock_data.tail(count)
stock_data['upper'], middle, stock_data['lower'] = talib.BBANDS(stock_data["Close"],
nbdevup=1, # 1 표준편차
nbdevdn=1,
timeperiod=120)
s&p500의 5000일 데이터를 다운해줍니다.
talib 패키지를 통해 볼린저 밴드를 만들어줍니다.
필요한 열들을 추가해줍니다.
stock_data = stock_data[["Open","High","Low","Close","upper","lower"]]
stock_data['highest'] = stock_data['High'].cummax()
stock_data['buy_condition'] = 0 # 0 = 안 삼, 1 = 매수조건1 충족, 2 = 매도조건2 충족
stock_data['hpr'] = 1 # 누적 수익률
stock_data['ror'] = 1
stock_data['buy_price'] = 0 # 평단가
stock_data['dr'] = 1 # 금일 수익률
stock_data["weight"] = 0 # 비중
stock_data["trading_number"] = 0
stock_data["win"] = 0
stock_data["lose"] = 0
for문을 통해 backtesting을 진행시켜줍니다.
#전고점
befor_high = 0
#전고점 대비 20퍼 하락시 True
ready = False
for i in range(1,count):
if stock_data.iloc[i-1,7] == 0:
# 고점대비 20퍼 하락
if stock_data.iloc[i-1,3] <= stock_data.iloc[i-1,6]*0.8:
ready = True
# 1시그마 상향 돌파
if ready == True and (stock_data.iloc[i-2,3] < stock_data.iloc[i-2,4] and stock_data.iloc[i-1,3] > stock_data.iloc[i-1,4]):
stock_data.iloc[i,7] = 1 # buy condition
stock_data.iloc[i,11] = stock_data.iloc[i,3]/stock_data.iloc[i,0] # dr
stock_data.iloc[i,9] = stock_data.iloc[i,11]# ror
stock_data.iloc[i,10] = stock_data.iloc[i,0] # buy price
stock_data.iloc[i,12] = 1 # weight
stock_data.iloc[i,13] = stock_data.iloc[i-1,13] + 1 # trading_number + 1
befor_high = stock_data.iloc[i,6]
ready = False
else:
stock_data.iloc[i,13] = stock_data.iloc[i-1,13]
elif stock_data.iloc[i-1,7] == 1:
# -1시그마 터치시 청산
if stock_data.iloc[i-1,3] > stock_data.iloc[i-1,5] and stock_data.iloc[i,2] <= stock_data.iloc[i,5]:
stock_data.iloc[i,7] = 0 # buy condition
stock_data.iloc[i,10] = 0 # buy price
stock_data.iloc[i,9] = stock_data.iloc[i,5]/stock_data.iloc[i-1,10] # ror
stock_data.iloc[i,11] = stock_data.iloc[i,5]/stock_data.iloc[i-1,3] # dr
stock_data.iloc[i,12] = stock_data.iloc[i-1,12] # weight
# 고점대비 +10퍼 -> 50퍼 익절
elif stock_data.iloc[i-1,2] <= befor_high*1.1 and stock_data.iloc[i,1] >= befor_high*1.1:
stock_data.iloc[i,7] = 2 # buy condition
stock_data.iloc[i,10] = stock_data.iloc[i-1,10] # buy price
stock_data.iloc[i,9] = 0.5*(befor_high*1.1 + stock_data.iloc[i,3])/stock_data.iloc[i,10] # ror
stock_data.iloc[i,11] = 0.5*(befor_high*1.1 + stock_data.iloc[i,3])/stock_data.iloc[i-1,3] # dr
n = stock_data.iloc[i,3]/(befor_high*1.1)
stock_data.iloc[i,12] = (0.5*n)/(0.5*n + 0.5) # weight
else:
stock_data.iloc[i,7] = stock_data.iloc[i-1,7] # buy condition
stock_data.iloc[i,10] = stock_data.iloc[i-1,10] # buy price
stock_data.iloc[i,9] = stock_data.iloc[i,3]/stock_data.iloc[i,10] # ror
stock_data.iloc[i,11] = stock_data.iloc[i,3]/stock_data.iloc[i-1,3] # dr
stock_data.iloc[i,12] = stock_data.iloc[i-1,12] # weight
stock_data.iloc[i,13] = stock_data.iloc[i-1,13]
else: #stock_data.iloc[i-1,7] == 2
# 1시그마 터치시 청산
if stock_data.iloc[i-1,3] > stock_data.iloc[i-1,4] and stock_data.iloc[i,2] <= stock_data.iloc[i,4]:
stock_data.iloc[i,7] = 0 # buy condition
stock_data.iloc[i,10] = 0 # buy price
n = stock_data.iloc[i,4]/stock_data.iloc[i-1,3]
stock_data.iloc[i,11] = stock_data.iloc[i-1,12] * n + 1-stock_data.iloc[i-1,12]# dr
stock_data.iloc[i,9] = stock_data.iloc[i-1,9]*stock_data.iloc[i,11] # ror
stock_data.iloc[i,12] = 0
else:
n = stock_data.iloc[i,3]/stock_data.iloc[i-1,3]
stock_data.iloc[i,7] = stock_data.iloc[i-1,7]
stock_data.iloc[i,11] = stock_data.iloc[i-1,12] * n + 1-stock_data.iloc[i-1,12] # dr
stock_data.iloc[i,9] = stock_data.iloc[i-1,9]*stock_data.iloc[i,11]# ror
stock_data.iloc[i,12] = (stock_data.iloc[i-1,12]*n)/(stock_data.iloc[i-1,12]*n + (1-stock_data.iloc[i-1,12])) # weight
stock_data.iloc[i,13] = stock_data.iloc[i-1,13]
stock_data['hpr'] = stock_data['dr'].cumprod()
for i in range(1,count):
if stock_data.iloc[i-1,7] != 0 and stock_data.iloc[i,7] == 0: # 매도했을때
if stock_data.iloc[i,9] > 1: # 이기면
stock_data.iloc[i,14] = stock_data.iloc[i-1,14] + 1
stock_data.iloc[i,15] = stock_data.iloc[i-1,15]
elif stock_data.iloc[i,9] <= 1: # 지면
stock_data.iloc[i,15] = stock_data.iloc[i-1,15] + 1
stock_data.iloc[i,14] = stock_data.iloc[i-1,14]
else:
stock_data.iloc[i,14] = stock_data.iloc[i-1,14]
stock_data.iloc[i,15] = stock_data.iloc[i-1,15]
결과를 plot해봅시다.
mpl_finance 라이브러리를 이용하면 실제 차트처럼 캔들차트를 plot할 수 있습니다.
import matplotlib.pyplot as plt
import mpl_finance
import matplotlib.ticker as ticker
fig, ax = plt.subplots(figsize=(12, 8))
ax.plot(range(count), stock_data['hpr']*stock_data.iloc[120,0], color='black')
ax.plot(range(count), stock_data['upper'], color="yellowgreen")
ax.plot(range(count), stock_data['lower'], color="yellowgreen")
mpl_finance.candlestick2_ohlc(ax, stock_data['Open'], stock_data['High'], stock_data['Low'], stock_data['Close'], width=0.5, colorup='r', colordown='b')
plt.grid(True)
win_ratio=stock_data.iloc[-1,14]/stock_data.iloc[-1,13]
buy_and_hold = stock_data.iloc[-1,3]/stock_data.iloc[0,0]
hpr = stock_data.iloc[-1,8]
print("매매 횟수: ", stock_data.iloc[-1,13])
print("승률: ",win_ratio)
print("buy and hold: ", buy_and_hold)
print("hpr: ",hpr)
매매 횟수: 6
승률: 1.0
buy and hold: 3.970825293074899
hpr: 1.5919956315747747
5000일 동안 6번 밖에 매매를 못했네요. 그래도 승률은 100퍼입니다.
차라리 비중을 100퍼로 하는게 더 수익률은 좋았겠네요.
다음에는 더 나은 알고리즘으로 돌아오겠습니다.
'파이썬으로 퀀트 프로그램 만들기 project > 백테스팅' 카테고리의 다른 글
[백테스팅]MACD와 RSI를 이용한 선물 매매하기 (2) | 2024.02.06 |
---|---|
[백테스팅]MACD 와 MACD signal을 이용하여 매매하기 (2) | 2024.02.05 |
[백테스팅] 하이킨아시 캔들 이용하여 매매하기 (2) | 2024.02.03 |
[백테스팅]EMA 골든 크로스를 응용한 비중 투자 (0) | 2023.11.12 |
[백테스팅]EMA 60 상향 돌파 시 매수 (0) | 2023.11.10 |