검색결과 리스트
이동평균선구하기에 해당되는 글 1건
- 2020.11.22 [시스템트레이딩] 전략 시뮬레이션(5) - 추세구간, 이동평균선 추가하기 2
글
[시스템트레이딩] 전략 시뮬레이션(5) - 추세구간, 이동평균선 추가하기
LW 전략 적용해보고, 그 결과를 차트로 그려서 매매 상황을 확인해 볼 수 있는 부분까지 마무리를 하였습니다. 이번에는 기본 LW 전략에 몇몇 아이디어를 추가해보도록 하겠습니다.
일단 비추세 구간에서는 LW 매수 시그널이 나오더라도 이익도 적고, 손실이 발생할 확률이 높습니다. 따라서 비추세 기간에는 매매를 하지 않도록 수정해보겠습니다.
비추세 구간을 확인하는 방법은 여러가지가 있겠지만, 이번에는 아래 글에 나오는 추세추종 필터를 적용해보겠습니다.
여기에서 사용하는 추세추종 필터는 아래와 같습니다.
A : 7일간 코인 가격 차이의 절대값 = abs(1일전 코인종가 - 7일전 코인종가)
B : 7일간 당일 코인 움직임 절대값의 총합 : abs(7일전 시/종가 차이)+ ...... + abs(1일전 시/종가 차이)
추세추정필터는 A/B 값으로 계산합니다. 값이 크면 추세가 강하다는 의미입니다.
결국 매일의 시/종 가격 변화의 합과 시작/킅 날의 가격 차이의 비율로 추세를 판단하는 방법입니다.
이전에 만들었던 프로그램에서 추가할 사항들은 아래와 같습니다.
1. simultaion 중간에 저장할 값으로 추세추종 필터 값 추가 (debuging용)
2. tr_lw에서 추세추종 필터 계산하는 함수
3. candle update하는 update_new_range() 함수에서 추세주총필터 계산하는 함수 호출하기
4. tr_lw에서 is_enter_condition() 수정
비교적 변경하는 부분이 적다고 볼 수 있습니다.
그럼 하나씩 추가해보겠습니다.
1. 중간값을 저장하는 함수 수정
def save_mid_values(candle_data, buy_price, sell_price, profit, total_profit, dd, trend) :
candle_data['buy_price'] = buy_price # buy 여부 저장
candle_data['sell_price'] = sell_price # buy 여부 저장
candle_data['profit'] = profit # profit 저장
candle_data['total_profit'] = total_profit # total_profit 저장
candle_data['dd'] = dd # downd draw 저장
candle_data['trend'] = trend # 추세값 저장
중간값을 저장하는 함수를 부르는 곳에도 trend 값을 전달할 수 있도록 수정합니다.
# simulation 중 파일에 저장할 변수들 추가
trend = tr_logic.get_trend()
save_mid_values(candle_data[i], 0, 0, 0, 0, 0, trend)
2. TR-LW.py에 추세를 계산하는 함수를 추가합니다.
def __init__(self, interval, num) :
:
self.trend = 1 # 변수 추가
def get_trend(self) :
cur = self.history[-1] # last one
day_sum = 0
candle = None
hist_len = len(self.history)
if hist_len >= 8 :
range_total = 0
pos = len(self.history)-1
for i in range(7) :
candle = self.history[pos]
day_sum += abs(candle.open - candle.close) # candle 시/종가 차이의 절대치 합
pos -= 1
period_range = abs(candle.close - cur.close)
self.trend = period_range / day_sum
self.trend = float(format(self.trend, '.2f')) # 소숫점 2자리 값으로 변경
return self.trend
history에는 candle 정보가 오름차순으로 저장되어 있으므로, 최신 7 candle의 값을 구하기 위해서는 뒤에서 부터 계산을 해야합니다. 그리고 float 값은 소숫점 이하 긴 숫자로 저장되므로, 소숫점 이하 2자리만 가지고 있기 위해서는 .2f 포맷으로 변경한 후(문자열) 이것을 다시 float로 변경하면 소숫점 2자리 실수를 가지고 있을 수 있습니다.
3. 다음은 get_trend() 함수를 부르는 곳을 추가해야 합니다.
def update_new_range(self, cur) : #
self.pre = cur
self.history.append(cur)
self.range = cur.high - cur.low # 전 candle의 range
self.get_trend()
새로운 candle이 들어오면 range값을 계산하고 history에 추가하는 함수입니다. 여기에서 get_trend()를 부르면 될 것 같습니다.
4. 마지막으로 매수 조건에 trend 값이 특정 값 이상이면 매수하도록 수정합니다. 일단 0.4로 해보겠습니다.
def is_enter_condition(self, candle) :
enter = 0
if self.range > 0 and self.trend > 0.4 : # 매수 조건
buy_price = (candle.open + self.range * self.k)
if candle.high > buy_price : # 최고가가 buy_price보다 높으면 매수되었다고 가정
enter = 1
self.bought_price = buy_price
추세추종 필터를 추가하기 위하여 필요한 코딩이 마무리되었습니다. 새로운 기능이 들어오면 변경할 곳이 많아집니다. 이 중 한 곳이라도 수정하지 않으면 정확하게 동작하지 않게 됩니다. 따라서 본인이 작성한 프로그램 구조를 정확하게 파악을 해야합니다.
이렇게 반영한 결과를 확인해보겠습니다.
profit : ticker : KRW-BTC
total # trading : 215
total profit : 1,926,201.75
trading fee : 151,161.74
total Net Profit : 1,775,040.00
# winning : 121
# losing : 94
MDD : 51.78
max loss : -17,060.96
max gain : 1,926,201.75
아쉽게도 추세추종 필터를 추가하기 전 보다 수익이 더 떨어졌군요. 그 원인을 확인해 보도록 하겠습니다. 두 그래프를 비교해보니 아래 그림과 같이 급락하였다가 다시 원래로 돌아오는 경우에 추세추종 필터가 추가된 경우에는 매수에 참여를 안하고 있습니다. 추세추종 값이 0.18, 0.33이군요.
추세추종 정도를 변경하면서 돌려본 결과입니다. 수익률 면에서는 추세추종 필터를 사용하지 않은 경우가 제일 좋습니다. 다만 추세추종 필터를 추가하면 수익률은 다소 떨어지지만 MDD 값은 개선이 됨을 알 수 있습니다. 각자 장단점이 있을 것 같습니다.
결국 어떤 전략에서 특정 필터를 사용할 때 적용 여부를 판단하는 파라미터 값을 찾는 것이 중요합니다. 트레이딩하는 코인의 종류에 따라 최적의 값은 달라질 것입니다. 따라서 실전에서는 많은 시도를 해보면서 계속 변경해야할 것 같습니다.
매매를 한 시점을 분석해보니 하락 시점에 매수를 하면 손실이 발생하는 경우가 많군요.
하락 기간에는 매수를 하지 않으면 수익이 좋아질지 궁금합니다.
하락 추세를 판단하는 방법도 여러가지가 있겠지만 일단 이동평균선을 사용해보겠습니다. 주식에서는 MA(5일)을 사용하지만 코인은 주말에도 거래가 되므로 MA(7일)을 사용하겠습니다.
하락추세추종 필터와 하는 역할이 같으니 변경되는 부분도 비슷합니다.
1. save_mid_values()에 ma값 추가하고 save_mid_values()를 부르는 함수에 ma값 추가
2. TR-LW.py에 MA 계산하는 함수 추가, 원하는 일자로 변경할 수 있도록 일자를 함수 인자로 받도록 하겠습니다.
def __init__(self, interval, num) :
:
self.MA = 0 # 변수 추가
def get_MA(self, num_days) :
hist_len = len(self.history)
if hist_len >= num_days :
day_sum = 0
pos = len(self.history)-1
for i in range(num_days) :
candle = self.history[pos]
pos -= 1
day_sum += candle.close # 종가 합
self.MA = day_sum / num_days
self.MA = float(format(self.MA, '.2f')) # 소숫점 2자리 값으로 변경
return self.MA
3. get_MA()를 부르는 곳 변경. get_trend()와 같이 update_new_range() 함수에 추가하면 됩니다.
4. is_enter_condition() 변경
MA 값이 candle의 open 가격보다 낮으면 상승 추세로 가정합니다.
def is_enter_condition(self, candle) :
enter = 0
if self.range > 0 and self.trend > 0.4 and (self.MA != 0 and self.MA < candle.open) :
buy_price = (candle.open + self.range * self.k)
이렇게 변경한 내용을 반영해보았습니다. 추세추종 값은 0.2, MA(7일) 적용 결과입니다.
위에서 언급한 구간에서 매수 후 손실은 사라졌습니다만 수익률은 더 떨어지는군요. 아마 수익이 날 곳에서 매수를 못하고 있을 것 같습니다.
그래프를 다시 비교해보니 아래와 같이 하락 후 상승하는 시기에 나오는 양봉에 매수를 못하고 있습니다. 당연한 결과인 것 같습니다. 하락 추세 중 발생하는 양봉은 아직 하락 추세 중이므로, 당연히 매수가 안됩니다. 하지만 이런 경우에 장대 양봉이 나오는 경우가 종종있습니다.
하락시에 손실이 발생하는 매수를 없애기 위하여 적용한 상승추세 시 매수 전략의 단점이 있군요. A 문제를 풀려고 하니 B 문제가 생기는 셈인데요. 어떻게 할지는 좀 더 고민해봐야 할 것 같습니다.
결론적으로 다양한 필터의 특성을 정확하게 파악해서 특정 움직임에 맞는 필터를 자유자재로 적용할 수 있는 내공이 필요해보입니다. 필터에 필수적으로 필요한 파마미터 값을 결정하는 것도 큰 숙제입니다.
파이썬을 이용하면 최적의 필터와 파라미터의 조합을 비교적 빠르게 찾을 수 있습니다. 파이썬을 이용하여 시뮬레이션을 하는 이유도 이것 때문이고요.
지금까지 간단하게 전략 시뮬레이터를 만들어 보았습니다. 최대한 간단하게 코딩을 했으니, 코드를 읽는데 큰 문제는 없을 것이라고 생각합니다. 수정한 코드는 아래위치에 있습니다. Larry_williams3.py에 지금까지의 수정 사항이 반영되어 있습니다.
github.com/multizone-quant/System_trading_ex
여기에서 아래 프로그램을 다운받으시면 됩니다.
Larry_williams3.py
TR_LW.py
my_candle.py
my_util.py
sim_data/*
이외에도 lw 매수 조건 계산할 때 k 값을 평균 값으로 변경하기 등 추가할 사항이 더 있습니다. 이 부분도 차후에 반영하겠습니다.
오늘 지표를 추가하면서 수정할 부분을 찬찬히 살펴보면 tr_lw.py에 기능 추가하는 부분 이외에 Larry_williams3.py에 추가하는 지표를 저장하기 위하여 코드를 수정하는 부분이 있습니다. 이렇게 여러 파이썬 파일을 수정하는 경우에는 실수할 확률이 높아지므로, 이 부분도 모으면 좋습니다.
다음에는 업비트에서 실시간 시세를 받으면서 실제로 투자하는 실전용 코드를 소개하도록 하겠습니다.
'시스템트레이딩' 카테고리의 다른 글
[시스템트레이딩] 전략 시뮬레이션(7) - 과거 데이터(분봉) 가져오기 (2) | 2020.12.03 |
---|---|
[시스템트레이딩] 전략 시뮬레이션(6) - 리펙토링 (0) | 2020.11.26 |
[시스템트레이딩] 전략 시뮬레이션(4) - 차트에 문자열 출력하기 (2) | 2020.11.21 |
[시스템트레이딩] 전략 시뮬레이션(3) (0) | 2020.11.19 |
[시스템트레이딩] 전략 시뮬레이션(2) (0) | 2020.11.18 |