본문 바로가기
래리개미 생존일지

📈 전략별 종목 발굴 코딩

by 바람의전설! 2025. 11. 11.

 "돌파형", "눌림형", "저점회복형", "박스탈출형"에 대한 아이디어를 코드로 구현해볼게! 이건 아주 기본적인 로직이니까, 실제 투자할 때는 여기에 여러 보조지표나 조건을 더해서 정교하게 만들어야 해.

1. 돌파형 (Breakout Strategy)

  • 개념: N일 최고가를 돌파하는 강한 상승 흐름을 보이는 종목을 찾는 거야. 거래량 동반은 필수!
  • 아이디어: 최근 N일간의 최고 종가를 뚫고, 평균 거래량보다 훨씬 많은 거래량이 터진 종목.
  • def find_breakout_stocks(df, period=20, volume_multiple=2):
        """
        돌파형 종목 발굴: N일 최고가 돌파 및 거래량 증가
        :param df: 종목 데이터 (DataFrame)
        :param period: 최고가 체크 기간 (N일)
        :param volume_multiple: 평균 거래량 대비 몇 배 이상이어야 하는지
        :return: 돌파형 조건 만족 여부 (Boolean)
        """
        if len(df) < period + 1:
            return False

        # 최근 N일간의 종가 데이터
        recent_closes = df['종가'].iloc[-(period+1):-1] # 오늘 제외하고 과거 N일
        today_close = df['종가'].iloc[-1]
        today_volume = df['거래량'].iloc[-1]

        # N일 최고 종가
        highest_close_in_period = recent_closes.max()

        # N일 평균 거래량
        avg_volume_in_period = df['거래량'].iloc[-(period+1):-1].mean()

        # 조건: 오늘 종가가 N일 최고 종가를 돌파했고, 거래량이 평균 거래량의 일정 배수 이상
        is_breakout = (today_close > highest_close_in_period) and \
                      (today_volume > avg_volume_in_period * volume_multiple)

        return is_breakout

    # 사용 예시 (삼성전자 데이터로 테스트)
    if samsung_data is not None:
        is_samsung_breakout = find_breakout_stocks(samsung_data, period=20, volume_multiple=2.5)
        print(f"\n삼성전자 20일 돌파형 종목인가요? {is_samsung_breakout}")

2. 눌림형 (Pullback Strategy)

  • 개념: 상승 추세 중에 잠시 조정을 받거나 가격이 내려왔을 때 매수 기회를 잡는 거야.
  • 아이디어: 주가가 20일 이동평균선(MA20) 위에 있으면서 상승 추세(MA20이 MA60 위에)인데, 최근 며칠간 가격이 소폭 하락(5일 이동평균선이 20일 이동평균선 아래로 내려왔다가 다시 반등)하거나 고점 대비 일정 비율 하락한 후 다시 상승하는 초기 신호.
  • def find_pullback_stocks(df, short_ma=5, mid_ma=20, long_ma=60, pullback_ratio=0.03):
        """
        눌림형 종목 발굴: 상승 추세 중 조정 후 반등 시도
        :param df: 종목 데이터 (DataFrame)
        :param short_ma, mid_ma, long_ma: 이동평균선 기간
        :param pullback_ratio: 고점 대비 몇 % 하락했는지 (옵션)
        :return: 눌림형 조건 만족 여부 (Boolean)
        """
        if len(df) < long_ma:
            return False

        df['MA_short'] = df['종가'].rolling(window=short_ma).mean()
        df['MA_mid'] = df['종가'].rolling(window=mid_ma).mean()
        df['MA_long'] = df['종가'].rolling(window=long_ma).mean()
        
        # NaN 값 제거
        df = df.dropna()

        if df.empty:
            return False

        today_close = df['종가'].iloc[-1]
        yesterday_close = df['종가'].iloc[-2] if len(df) >= 2 else today_close
        ma_short = df['MA_short'].iloc[-1]
        ma_mid = df['MA_mid'].iloc[-1]
        ma_long = df['MA_long'].iloc[-1]
        
        # 상승 추세 조건: MA_mid가 MA_long 위에 있고, 주가가 MA_mid 위에 있음
        is_uptrend = (ma_mid > ma_long) and (today_close > ma_mid)
        
        # 눌림목 발생 조건: 이전에는 상승했는데 최근에 단기 MA가 꺾이거나 고점 대비 하락
        # (MA_short가 MA_mid 아래로 내려갔다가 다시 올라오는 상황 또는 고점 대비 하락 후 반등)
        # 여기서는 간단하게, 5일 이평선이 20일 이평선 아래였다가 오늘 종가가 어제보다 높으면 반등 신호로 볼게
        is_pullback_and_rebound = (df['MA_short'].iloc[-2] < df['MA_mid'].iloc[-2]) and \
                                  (ma_short >= ma_mid) and \
                                  (today_close > yesterday_close)

        # 더 단순화: 고점 대비 3% 이상 하락했다가 다시 오르는 경우 (옵션)
        # high_past_N_days = df['고가'].iloc[-mid_ma:].max() # mid_ma 기간 고점
        # current_drop_from_high = (high_past_N_days - today_close) / high_past_N_days
        # is_pullback_ratio_met = (current_drop_from_high >= pullback_ratio) and (today_close > yesterday_close)

        return is_uptrend and is_pullback_and_rebound

    # 사용 예시
    if samsung_data is not None:
        is_samsung_pullback = find_pullback_stocks(samsung_data)
        print(f"삼성전자 눌림형 종목인가요? {is_samsung_pullback}")

3. 저점회복형 (Bottom Recovery Strategy)

  • 개념: 바닥을 찍고 다시 반등하는 종목을 잡는 거야. 리스크는 크지만 수익률도 높은 경우가 많지.
  • 아이디어: 주가가 장기 이평선(예: MA120)보다 한참 아래에 있다가, 최근 N일 저점 대비 특정 비율 이상 반등하고 5일 이평선이 우상향 전환하는 시점.
  • def find_bottom_recovery_stocks(df, long_ma=120, low_period=20, recovery_ratio=0.10):
        """
        저점회복형 종목 발굴: 장기 이평선 아래에서 저점 찍고 반등
        :param df: 종목 데이터 (DataFrame)
        :param long_ma: 장기 이동평균선 기간
        :param low_period: 저점 대비 반등을 체크할 기간
        :param recovery_ratio: 저점 대비 최소 반등 비율 (예: 10%)
        :return: 저점회복형 조건 만족 여부 (Boolean)
        """
        if len(df) < long_ma:
            return False

        df['MA_long'] = df['종가'].rolling(window=long_ma).mean()
        df = df.dropna()
        
        if df.empty:
            return False

        today_close = df['종가'].iloc[-1]
        ma_long = df['MA_long'].iloc[-1]
        
        # 과거 N일 최저가
        recent_low = df['저가'].iloc[-low_period:].min()

        # 조건: 주가가 장기 이평선보다 한참 아래에 있었고 (바닥권)
        #       최근 저점 대비 충분히 반등했으며, 오늘 종가가 어제 종가보다 높음 (반등 지속 신호)
        is_at_bottom = (today_close < ma_long * 0.9) # 장기이평선보다 10% 이상 아래에 위치
        is_recovered_enough = (today_close - recent_low) / recent_low >= recovery_ratio
        is_bouncing_today = df['종가'].iloc[-1] > df['종가'].iloc[-2] if len(df) >= 2 else False

        return is_at_bottom and is_recovered_enough and is_bouncing_today

    # 사용 예시
    if samsung_data is not None:
        is_samsung_bottom_recovery = find_bottom_recovery_stocks(samsung_data)
        print(f"삼성전자 저점회복형 종목인가요? {is_samsung_bottom_recovery}")

4. 박스탈출형 (Box Breakout Strategy)

  • 개념: 주가가 일정 가격 범위(박스권) 내에서 움직이다가, 그 박스권을 강하게 뚫고 나가는 시점을 잡는 거야.
  • 아이디어: 최근 N일간 주가의 최고점과 최저점의 차이(변동성)가 작다가, 오늘 종가가 그 N일간의 최고점을 돌파하고 거래량도 터진 종목.
  • def find_box_breakout_stocks(df, box_period=30, volatility_threshold=0.05, volume_multiple=2):
        """
        박스탈출형 종목 발굴: 박스권 돌파 및 거래량 증가
        :param df: 종목 데이터 (DataFrame)
        :param box_period: 박스권 형성 기간
        :param volatility_threshold: 박스권 변동성 기준 (예: N일간 최고-최저가 차이가 N일 저가 대비 5% 이내)
        :param volume_multiple: 평균 거래량 대비 몇 배 이상이어야 하는지
        :return: 박스탈출형 조건 만족 여부 (Boolean)
        """
        if len(df) < box_period + 1:
            return False

        # 박스권 기간 데이터 (오늘 제외)
        box_data = df.iloc[-(box_period+1):-1]
        today_close = df['종가'].iloc[-1]
        today_volume = df['거래량'].iloc[-1]

        # 박스권 상단, 하단
        box_high = box_data['고가'].max()
        box_low = box_data['저가'].min()

        # 박스권 변동성
        box_volatility = (box_high - box_low) / box_low if box_low != 0 else float('inf')

        # 박스권 형성 조건: 변동성이 작음
        is_box_formed = box_volatility <= volatility_threshold

        # 박스권 돌파 조건: 오늘 종가가 박스권 고점을 돌파
        is_breakout = today_close > box_high
        
        # 거래량 조건: 평균 거래량의 일정 배수 이상
        avg_volume_in_period = box_data['거래량'].mean()
        is_volume_high = today_volume > avg_volume_in_period * volume_multiple

        return is_box_formed and is_breakout and is_volume_high

    # 사용 예시
    if samsung_data is not None:
        is_samsung_box_breakout = find_box_breakout_stocks(samsung_data, box_period=30, volatility_threshold=0.07, volume_multiple=3)
        print(f"삼성전자 박스탈출형 종목인가요? {is_samsung_box_breakout}")

⚠️ 중요! 이거 완전 실전 꿀팁인데!

이 코드들은 그냥 시작점이야! 실제 투자에서는 더 많은 지표와 조건(예: 시가총액, 섹터, 재무제표 등)을 고려해야 하고, 손절 기준은 무조건 철저히 지켜야 해. 그리고 중요한 건, 코드를 짰으면 과거 데이터를 가지고 잘 작동하는지 꼭 테스트(백테스팅)해봐야 해. 이거 안 하고 바로 실전에 투입하면 뚝배기 깨질 수 있다?! ㅠㅠ