Shooting

눌림목 전략

눌림목 전략은 기본적으로 큰 거래량을 동반하면서 상승한 종목이 눌림 (하락) 을 받고, 다시 상승할 때 매수 하는전략이다. 코드를 보면서 이해를 해보겠다.

매수 전략


Capital = x['시가총액'].values
Rate = x["시총변화율"].values
PER = x["PER"].values
minimum_cap = config.minimum_cap * 100000000000 #(1000억)
maximum_cap = config.maximum_cap * 100000000000
idx = np.where((Capital > minimum_cap) & (Rate > config.w1) & ((Rate < 30)) &(PER>0))[0]

먼저 x 에 대해 이해를 해보겠다. x 는 현재 날짜의 코스피/코스닥 모든 종목의 정보를 담고 있다. 예를 들어, x를 출력하면 다음과 같이 뜬다.

티커       PER    PBR   시가총액   시총변화율      거래량
054950    0.4    1.0    30000000       4.5 %    1000000
033220    1.4    0.4    50000000      -3.5 %    3000000
013200    0.7    1.5    60000000       8.5 %    80000000
078889    0.5    2.5    70000000       5.5 %
'
'
'
321032    0.6    18.0   10000000       10.5 %

따라서 x의 총 행의 개수는 코스피/코스닥 모든 종목을 합한 숫자가 나올것이다. 대략 2000개 정도 나온다.

idx는 필터링을 통해 내가 원하는 종목만 뽑아오게 된다. 여기선 최소 시가총액 minimum_cap을 넘겨야 하고, Rate는 시총변화율 (어제 종가 기준 현재 종가에 대해 변화율) 을 뜻하는데, 이것이 config.w1이라는 상수를 넘겨야 하며, 30보단 작아야한다. Rate는 당연히 30보다 작을수 밖에 없는데, 가끔 가격 정보가 잘못 입력되어 30을 초과하는 경우가 생겨 넣었다. 이렇게 되면, 저 조건을 통과한 종목들만 살아남게 될 것이다.

필자는 w1을 (5,10,15,20,25) 을 모두 테스트해서 좋은 값을 뽑아냈고, 그 값은 10이다. 또한 거래를 자주하고 싶어서 minimum_cap 은 0 으로 설정하였다.

따라서, 어떤 날 종목을 봤을 때 10퍼센트 이상의 상승을 가지고 있는 종목들이 필터링 될것이다. 다음은 거래량을 동반하는지 다시 한 번 필터링을 해야할 것이다.

먼저, idx를 통해 얻어낸 것들을 얻어내기 위해 다음과 같은 코드를 적용한다.

x_test = x.iloc[idx]

이제 x_test 는 강한 상승을 얻은 종목들로 구성될 것이다. 다음은 거래량을 동반하는지 살펴볼 것이다. x_test 에 포함된 각 종목들에 대해, 지난 n일간에 거래량과 지난 m일 간의 고점을 조사한다.

for rank,ticker in enumerate(x_test["티커"].values):
    highest_price = price_ticker["종가"].iloc[date_idx-int(config.w2):date_idx].max()
    max_trades = price_ticker["거래량"].iloc[date_idx-int(config.w3):date_idx].max()
    cur_price = price_ticker["종가"].iloc[date_idx]
    cur_trades = price_ticker["거래량"].iloc[date_idx] 

  • highest_price 는 현재 날짜 (date_idx) 에서 부터 config.w2 전날 까지 고점(.max()) 을 의미한다.
  • max_trades 는 현재 날짜 (date_idx) 에서 부터 config.w3 전날 까지 거래량 최대(.max()) 을 의미한다.
  • cur_price 는 현재 날짜 (date_idx) 의 종가를 의미한다.
  • cur_trades 는 무엇을 의미하겠는가? 현재 날짜의 거래량을 의미한다.

이제, 10퍼센트 이상의 상승을 가진 종목들이, 강한 거래량과 고점도 넘었는지 필터링 하기 위해 다음과 같이 코드를 작성해준다.

if cur_price > highest_price and cur_trades > max_trades:  
    myStock.interesting_stocks[ticker] = [cur_price,cur_trades,config.w5,highest_price]

식을 해석하면, 현재 가격이 지난 config.w2 전날 까지 고점을 넘은 경우에, 그리고 (and) 현재 거래량이 config.w3 까지의 거래량 최대를 넘었는가? 를 의미한다.

필자는 w2와 w3을 모두 20으로 설정하였다. 이 조건을 만족한 종목들을 관심종목 사전에 넣어둔다. 코드는 어려워 보이지만 간단하다. 관심종목티커를 myStock.interesing_stocks 에 넣어두는 것 뿐이다. 필자는 여기에 조건을 만족했을 때의 종가, 거래량 등을 넣어두었다.

이렇게 넣어두면, 나중에 이 정보를 그대로 가져올 수 있다. 예를 들어 POSCO홀딩스 (‘005490’) 이 관심종목에 들어갔다면, myStock.interesing_stocks['005490'] 에 상승을 이루었을 때의 종가, 거래량 등이 들어가게 되는 것이다.

이제 마지막 단계인데, 이 관심종목으로부터 눌림으로부터의 반등이 나오는지 확인하고, 관심 종목을 매수 리스트로 옮길 것이다.

# 관심종목 하나하나 살펴본다.
for ticker in myStock.interesting_stocks.copy().keys():
    at_time_trade =  myStock.interesting_stocks[ticker][2]
    at_time_price = myStock.interesting_stocks[ticker][1]

at_time_trade 는 관심종목에 올랐을 때, 강한 상승을 이루었을 때의 거래량을, at_time_price 는 그때의 가격을 의미한다. 모두 myStock.interesting_stocks[ticker] 에 정보가 담겨있는 것을 알 수 있다.

필자는 다음과 같은 조건일 때 관심 종목을 매수 리스트로 옮겼다. 조건은 다음과 같다.

# rate 는 오늘의 시총 변화량이다. 우리가 주식 어플에서 보는 그 숫자.
condition = rate < config.w6 and rate > config.w7  and price < at_time_price #and price > at_time_support_price

if condition :

    myStock.target_upper[ticker] =  config.upper
    myStock.target_lower[ticker] =  config.lower

    recommend_indexes.append(np.where(watch_idx == True)[0].item())

condition 이 그것인데, 현재 rate 가 config.w6 보다 작고, config.w7 보다 크면서, 관심 종목에 올랐을 때의 가격보다 작을 때 종목을 매수 리스트로 옮긴다.

필자는 confdig.w6 은 수익률에 크게 연관을 주지 않으며, config.w7 은 0 일 때 수익률이 좋다는 것을 발견하였다. 그래서 config.w6 은 30으로, config.w7 은 0 으로 설정하였다.

즉, 관심종목에 올라와 있는 종목의 가격이 at_time_price 보다 낮으면서 (눌림) 상승을 이루기 시작했을 때 (rate > config.w7 ) 매수를 하는 것이다.

매도 전략

필자는 처음의 경우에 단순하게 다음과 같이 매도를 하였다.

if (rate < config.lower or rate > config.upper or 보유하고 있는 일수 > config.hold):
    매도

즉, 내가 설정한 하한보다 작거나, 상한보다 크거나 (목표 달성), 보유일이 내가 설정한 config.hold 보다 높을 때 매도를 하였다.

이때 rate 는 종가기준이다. 하지만, 목표 수익의 경우 그날의 종가 기준이 아닌 고가 기준으로 하면 성공 확률을 올릴 수 있지 않을까? 왜냐하면 주식을 사고, trailing 기법을 이용해서 기준을 정해두기만 한다면, 고가 근처에서 파는 것은 가능하다고 판단했기 때문이다. 따라서, 다음과 같이 가운데 조건의 ratehieghest_rate 로 바꿔 매도 전략을 수정할 수 있다.

if (rate < config.lower or highest_rate > config.upper or 보유하고 있는 일수 > config.hold):
    매도

하지만 또 생각이 든것이, 내가 종가 까지 기다리다가 config.lower 를 확 넘어버린다면 실제 테스트와 괴리가 생길것이라고 판단하였다. 그래서, 안전하게 아예 시가에서의 rate를 보고 , 이 시가에서의 rate가 config.lower 보다 작으면 팔아버리는 편이 안전하다고 판단하였다. 따라서, 코드를 다음과 같이 첫번째 조건을 ratestart_rate로 수정하였다.

if (start_rate < config.lower or highest_rate > config.upper or 보유하고 있는 일수 > config.hold):
    매도

마지막으로 바꾼것은, 내가 주식을 보유하고 있는데, 이미 수익을 보고있는 경우에 어떡할 것인가를 생각해보았다. 가령 난 이미 2~3 % 의 수익을 보고 있는데, config.upper 가 4로 설정되어 팔지 않는다면 괜히 욕심을 부리다가 손해를 볼 수 있겠다는 생각이 들었다. 따라서, 줄 때 먹자 라는 마인드로, 그날의 종가 기준으로 어느정도 수익을 보고있다면 그냥 팔아치우자라는 생각이 들었다.

따라서 식은 다음과 같이 바뀐다.

condition_A = cur - buyDateIdx >= config.hold
condition_B = start_rate < config.lower
condition_C = highest_rate >= config.upper
condition_D = last_rate > config.first_upper

if (condition_A or condition_B or condition_C or condition_D):
    매도
  • condition_A 는 내가 보유하고있는 주식의 최대 저장 일 수
  • condition_B 는 내가 아침 9시에 장 시작직후 보는 수익률이, 설정한 config.lower 보다 작을 경우 매도
  • condition_C 는 장 중에, 설정한 config.upper 를 돌파한 경우 바로 매도 (이건 매수하자마자 설정해놔야하는 것이 되겠다.)
  • condition_D 는 내가 장이 끝나고 보는 수익률이, 설정한 config.fisrt_upper 보다 큰 경우

이렇게 하면, 내가 실제 매수,매도를 하는것과 유사하게 하면서도 시가 ~ 종가 사이에 벌어나는 일을 최대한 커버할 수 있겠다는 생각이 들었다.

결과

2020년 2월 24일부터 8월 까지의 결과는 다음과 같다.

2405 번의 승, 881번의 패 , 승률 : 73 %
이겼을 때, 시스템 매매대로 팔아치웠다고 가정했을 때, 이겼을 때의 평균 수익률을 U%,
손실이 났을 때의 평균수익률을 L% 라고 하자.

종목당 100만을 들어간다고 한다면, 이길 때 U 만원, 질 때 -L 만원을 잃고, 이것에 대한 승률이 73 % 이므로 평균 수익률을 계산할 수 있다.

73/100 * U - 27/100 * L  을 계산 해보면, 0.89 가 나온다. 
이를 E = 0.89  라고 표기하자. 
즉, 한 번 거래할때 기대 수익이 0.89 만원이며, 나는 총 거래를 3200여번 정도를 했으므로, 총 수익은 E * 3200 = 2800 여 만원이 나온다.
종목 당 200만원을 투입한다면? 2800 * 2 만원이 될 것이다. 

마무리

꽤나 고무적인 결과인 것 같으면서도, 실제로 매매할 때 발생하는 일을 까먹진 않았는지 확인해보는 작업이 필요하다. 또한, 기대수익 E 를 어떻게 하면 최대화할 수 있을지 고민해봐야하는데, 지금 백 테스트상으로는 무조건 종가에 매수를 하기 때문에, 이것을 이용한다면 E 를 더 키울 수 있지 않을까라는 생각이다.

가령, 관심종목리스트는 왠만하면 항상 가지고 있기 때문에 관심종목 중 어떤 종목이 종가에 조건을 만족할 것 같으면 미리 매수하는 방법이 있다. 간단한 방법으로는 관심종목 중에 + 가 찍히고 있는것들을 미리 매수하는 방법이 있다.