기존 코드를 한번 더 리펙토링을 해야할 것 같습니다.

 

이번에 수정하고자 하는 부분은 아래와 같습니다.

1. 지표를 추가할 때 변경하는 부분 최소화

2. 기존 전략을 수정하거나 새로운 전략을 추가할 때 변경할 부분 최소화

 

우선 지표를 추가하는 부분을 다시 보겠습니다.

일단 새로운 지표인 경우에는 지표를 코딩하는 부분은 어쩔 수가 없이 추가하여야 합니다. 다만 새로운 지표가 추가되었을 때 simulation 과정에서 중간 값을 저장하는 부분에 새로운 지표를 추가하여야 하는데요. 이런 경우에 관계없는 부분도 변경하여야 하기 때문에 좋은 구조라고 볼 수 없습니다.

 

우선 기존 코드입니다. save_mid_values 함수 하나로 모든 변수를 저장하였습니다. 이러다 보니 관계없는 부분에서도 수정을 해야합니다.

def save_mid_values(candle_data, buy_price, sell_price, profit, total_profit, dd, trend, ma7) :

 

이 문제를 해결하는 방법은 함수를 쪼개는 것입니다.

관련 변수를 모아서 몇 개의 함수로 나눠보겠습니다. 우선 save_mid_values()에 default 값을 추가하여 초기화하는 부분에서는 save_mid_values()만 호출하면 됩니다. 

만약 새로운 지표가 추가된다면 save_mid_values()에 인자를 추가하고, save_mid_values_jipyo()에 관련 변수를 추가하면 됩니다. 

# 지표가 추가되는 경우에는 마지막에 변수 추가 
def save_mid_values(candle_data, buy_price=0, sell_price=0, profit=0, total_profit=0, dd=0, trend=0, ma7=0) :
    save_mid_values_buy_sell(candle_data, buy_price, sell_price)
    save_mid_values_result(candle_data, profit, total_profit, dd)
    save_mid_values_jipyo(candle_data, trend, ma7)

def save_mid_values_buy_sell(candle_data, buy_price, sell_price) :
    candle_data['buy_price'] = buy_price # buy 여부 저장
    candle_data['sell_price'] = sell_price # buy 여부 저장

def save_mid_values_result(candle_data, profit, total_profit, dd) :
    candle_data['profit'] = profit # profit 저장
    candle_data['total_profit'] = total_profit # total_profit 저장
    candle_data['dd'] = dd # downd draw 저장

def save_mid_values_jipyo(candle_data, trend, ma7) :
    candle_data['trend'] = trend # 추세값 저장
    candle_data['ma7'] = ma7 # downd draw 저장

 

이 함수를 사용하는 부분도 적절하게 변경하였습니다.

 

 

다음은 전략 부분을 refactoring해보겠습니다.

이전 글에서 횡보구간에서는 매수를 하지 않는 전략을 추가하였는데요. 아래와 같이 적용할 전략이 아닌 부분은 # 처리했었습니다. 이렇게 되면 코드 관리가 어려워집니다. 따라서 어떤 방식건 # 처리를 하지 않고 각 전략에 쉽게 적용할 수 있어야 합니다. 이 문제를 풀기위해 전략 코딩 부분을 refactoring 해보겠습니다.

    def is_enter_condition(self, candle) :  
        enter = 0
        # 아래 세 조건 중에 원하는 조건 선택
#        if self.range > 0 :
#        if self.range > 0 and self.trend > 0.2 # trend 동시 적용
        if self.range > 0 and self.trend > 0.2 and (self.MA != 0 and self.MA < candle.open) : # trend & MA 동시 적용

 

전략코딩 부분을 찬찬히 살펴보면 이런 식으로 구성되어 있습니다.

 

candle이 변경되었을 때 관련 변수 수정

if 매수 중이면 

   전략에 따른 매도할 가격을 받는다.

   현재 candle 기준으로 매도 조건이면

      매도주문    

else # 매수대기

   전략에 따른 매수할 가격을 받는다.

   현재 candle 기준으로 매수 조건이면

       매수주문

 

따라서 이런 구조로 class를 정의하면 새로운 전략을 추가하는 경우에 필요한 부분만 변경하면 됩니다. class를 사용하면 이런 구조를 아주 효과적으로 개발할 수 있습니다.

 

기존적인 전략에 대한 코딩은 base class에서 하고, 새로운 전략을 적용하는 경우에는 매수/매도 가격 결정, 매수/매도 조건 결정하는 함수만 개발하면 됩니다.

 

class의 가장 큰 장점이 상속기능입니다. 개념이 조금 복잡하지만 쉽게 설명하면 공통으로 사용하는 함수는 부모 클래스가 가지고 있고 차이가 나는 부분은 자식클래스에서 개발하자는 취지입니다.

 

앞에서 소개한 TR_LW를 base class로 옮기고, 이 중 전략별로 다르게 개발하여햐하는 함수만 자식 class에서 개발하면 됩니다.

 

우선 TR_Basic()은 기존 TR_LW와 같다고 보시면 됩니다. 특이한 부분은 자식 클래스입니다. 우선 TR_LW_SIM 선언시에 누가 부모인지를 인자로 넣습니다. 그 후 필요한 경우에는 초기화를 하는데요. 이때 부모 클래스의 초기화를 진행해야하기 때문에 super()라는 키워드를 사용하여 부모 클래스에 있는 함수를 호출합니다. 그 후 자기 class에서 필요한 변수를 만들고 초기화합니다. LW 전략이므로 range와 k 값을 초기화합니다.

class TR_Basic() :  # 전략 부모 클래스
    def __init__(self, interval, num) :
        # 공통 초기화 부분
        
class TR_LW_SIM(TR_Basic) : # LW 시뮬레이션용 클래스 
    def __init__(self, interval, num) :
        super().__init__(interval, num)
        self.range = 0
        self.k = 0.5

 

전략에서 필요한 함수는 크게 5가지로 구분할 수 있습니다.

    def update_new_candle(self, cur) : # candle이 변경되었을 때 관련 변수 변경
    def get_buy_price(self, candle) : # 매수할 가격 구하기
    def is_meet_buy_cond(self, candle, buy_price) : # 매수 조건 만족?
    def get_sell_price(self, candle) : # 매도할 가격 구하기
    def is_meet_sell_cond(self, candle, sell_price) : # 매도 조건 만족?

 

이렇게 만든 상태에서 비추세 구간에는 매수를 하지 않는 전략으로 수정을 한다고 가정을 합시다.

기존 TR_LW_SIM과 비교하여 차이가 나는 부분은 매수 가격을 정하는 부분입니다. 따라서 TR_LW_SIM을 부모로 갖는 TR_LW_TREND라는 classs를 만들고 get_buy_price함수에 관련 코드를 작성하면 됩니다.

 

class TR_LW_TREND(TR_LW_SIM) :
    # 매수 조건을 만족하면 매수가를 돌려준다.
    def get_buy_price(self, candle) :
        if self.range > 0 and self.trend > 0.2 : # trend 동시 적용
            buy_price = (candle.open + self.range * self.k)
            return buy_price
        return 0

 이렇게 만든 전략을 사용하는 경우에는 아래와 같이 class 명을 명시하시면 됩니다. 비추세와 이평을 이용하는 전략도 함께 수정해놓았으니 참고하시기 바랍니다.

 

tr_logic = TR_LW_TREND('min', 1)

 

시뮬레이션은 비교적 간단한 개발이기 때문에 이 정도로 동작을 하지만 실제 매매와 연동을 하게되면 구조가 좀 더 복잡해집니다. 이것도 시간이 되면 정리해서 올리도록 하겠습니다.

 

관련 src코드 파일명과 github 위치는 아래와 같습니다.

Larry_williams4.py
TR_LW_1.py
my_candle.py
my_util.py

github.com/multizone-quant/System_trading_ex

반응형

설정

트랙백

댓글