반응형
세상에는 코딩을 잘하는 사람이 매우 많고, 알고리즘 트레이딩에 관심이 많은 사람 역시 매우 많다.
이들을 따라해보며 실력을 기르려고 한다.
먼저, Code Trading 이란 채널의 "Automated Candlestick Strategy in Python | testing the shooting star" 을 따라해보았다.
https://www.youtube.com/watch?v=eN4zh3PEH6c
구현해본 결과는 다음과 같다.
import pandas as pd
from ta.volatility import *
from ta.momentum import *
### 데이터 가져오기
interval = '1h'
df = pd.read_csv(f'C:\\Users\\gudwn\\PycharmProjects\\pythonProject1\\Tradingbot_Maker\\Backtest_file\\Data\\BTC-USDT_Data\\BTC-USDT_Data_{interval}\\BTC_USDT_{interval}_All.csv')
df = df.iloc[:,:5]
### 필요한 지표값 넣기
df['ATR'] = average_true_range(df['High'],df['Low'],df['Close'],window=10,fillna=True)
df['RSI'] = rsi(df['Close'],window=3)
### 캔들패턴 활용한 추세전환 포착 함수
def Reversal_signal_1(df):
df.dropna() # na 떨구기
df.reset_index(drop=True,inplace=True) # 없는 값 떨구고 나머지로 다시 세팅
length = len(df)
open = list(df['Open'])
high = list(df['High'])
low = list(df['Low'])
close = list(df['Close'])
signal = [0] * length
high_diff = [0] * length
low_diff = [0] * length
body_diff = [0] * length
ratio_1 = [0] * length
ratio_2 = [0] * length
# 윗꼬리, 아랫꼬리 비율 계산
for row in range(length):
high_diff[row] = high[row] - max(open[row],close[row]) # 윗꼬리 절대 크기
body_diff[row] = abs(open[row]-close[row]) # 몸통 절대 크기
low_diff[row] = min(open[row], close[row]) - low[row] # 아랫꼬리 절대크기
if high_diff[row] < 0.002:
high_diff[row] = 0.002 # ZerodivisionError 방지
if body_diff[row] < 0.002:
body_diff[row] = 0.002 # ZerodivisionError 방지
if low_diff[row] < 0.002:
low_diff[row] = 0.002 # ZerodivisionError 방지
ratio_1[row] = high_diff[row] / body_diff [row] # 윗꼬리 비율
ratio_2[row] = low_diff[row] / body_diff [row] # 아래꼬리 비율
# 발동 조건 체크
# 상승 추세 -> 하락 추세 전환으로 short 주문 조건
if (ratio_1[row] > 2.5 # 윗꼬리 크기가 몸통 크기의 2.5배 이상
and low_diff[row] < 0.3 * high_diff[row] # 아랫꼬리가 윗꼬리의 30% 이하
and body_diff[row]/low_diff[row] > 0.7 # 몸통이 아랫꼬리보다 70% 이상일때
and df.RSI[row] < 70): # RSI < 70일때
signal[row] = 1
# 하락 추세 -> 상승 추세 전환으로 long 주문 조건
elif (ratio_2[row] > 2.5 # 윗꼬리 크기가 몸통 크기의 2.5배 이상
and high_diff[row] < 0.3 * low_diff[row] # 윗꼬리가 아래꼬리의 30% 이하
and body_diff[row]/high_diff[row] > 0.7 # 몸통이 아랫꼬리보다 70% 이상일때
and df.RSI[row] < 50 and df.RSI[row] > 30): # 30 < RSI < 50 일때
signal[row] = 2
return signal
### signal 뜬 것을 원래의 dataframe에 넣기
df['signal_1'] = Reversal_signal_1(df)
df['signal_2'] = Reversal_signal_1(df)
print(df[df['signal_1']==1].count())
print(df[df['signal_2']==2].count())
### 백테스트 시작
### Target 도달 여부 (익절가 먼저 touch 하는지, 손절가 먼저 touch하는지 체크)
# 익절가 먼저 도달하면 take profit
# 손절가 먼저 도달하면 stop loss
# barsupfront 이내에 익절, 손절하지 못할 경우 해당 캔들 종가에 청산
def My_target(barsupfront,df):
length = len(df)
open = list(df['Open'])
high = list(df['High'])
low = list(df['Low'])
close = list(df['Close'])
d_atr = list(df['ATR'])
trend_cat = [None] * length
for line in range(0,length-barsupfront-1):
value_Open_Low = 0
value_Open_High = 0
high_diff = high[line] - max(open[line],close[line])
body_diff = abs(open[line] - close[line])
pip_diff = d_atr[line] * 1
if pip_diff < 1000:
pip_diff = 1000
StopLoss_to_TakeProfit_Ratio = 2 # pip diff * ratio = TP
for i in range(1,barsupfront+1):
value1=close[line] - low[line+i]
value2=close[line] -high[line+i]
value_Open_Low = max(value1,value_Open_Low)
value_Open_High = min(value2,value_Open_High)
if ( (value_Open_Low) >= (StopLoss_to_TakeProfit_Ratio * pip_diff)) \
and (abs(value_Open_High) < pip_diff):
trend_cat[line] = 1 # 하락 추세
break
elif ( (value_Open_Low) < (pip_diff)) \
and (abs(value_Open_High)) >= (StopLoss_to_TakeProfit_Ratio * pip_diff):
trend_cat[line] = 2 # 상승 추세
break
else:
trend_cat [line] = 0 # no trend
return trend_cat
### 트렌드 여부
df['Trend'] = My_target(50, df)
conditions = [(df['Trend'] == 1) & (df['signal_1'] == 1), # 일치
(df['Trend'] == 2) & (df['signal_1'] == 2)] # 일치
values = [1,2]
df['result'] = np.select(conditions,values)
trend_Id=2
print(df[df['result']==trend_Id].result.count()/df[df['signal_1']==trend_Id].signal_1.count()) # True positive sell signal / All sell signal
# print(df[(df['result'] != trend_Id) & (df['signal_1'] == trend_Id)])
# histrs =df[(df['result'] != trend_Id) & (df['signal_1'] == trend_Id)].RSI
### 그림그리기
# 그림 그리기
dfpl = df[900:1000] # 900~1000번째 캔들 그림그리기
import plotly.graph_objects as go
from datetime import datetime
fig = go.Figure(data=[go.Candlestick(x=dfpl.index,
open=dfpl['Open'],
high=dfpl['High'],
low=dfpl['Low'],
close=dfpl['Close'])])
fig.show()
ta 라이브러리를 활용하여 ATR, RSI를 계산하였고,
나머지는 그대로 따라하였다.
이를 통해 배운 것은,
1. 익절/손절 라인을 정하고, 익절 손절 라인에 도달하지 못했을때 특정 봉에서 마감하도록 한 로직을 어떻게 구현하는지
2. 캔들스틱 패턴을 활용한 백테스트를 어떻게 구현하는지
등이 있다.
앞으로도 꾸준히 다른 사람의 영상, 글을 보며 배워야겠다.
반응형
'프로그래밍 공부 > 파이썬 구현' 카테고리의 다른 글
[변동성 돌파 전략 4] 변동성 돌파 전략 성과 시각화 (0) | 2022.01.24 |
---|---|
[변동성 돌파 전략 3] 변동성 돌파 전략 백테스트 k 최적화 (베이지안 최적화) (0) | 2022.01.24 |
[변동성 돌파 전략 2] 변동성 돌파 전략 백테스트 k 최적화 (그리드 서치) (0) | 2022.01.24 |
[변동성 돌파 전략 1] 변동성 돌파 전략 백테스트 로직 구현하기 (0) | 2022.01.15 |
[데이터 수집] 바이낸스 과거 데이터 저장하기 (0) | 2022.01.15 |
댓글