<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://devcafe.co.kr/w/index.php?action=history&amp;feed=atom&amp;title=%EC%BD%94%EC%8A%A4%ED%94%BC_%EB%8C%80%ED%98%95%EC%A3%BC_%EA%B3%BC%ED%8F%AD%EB%9D%BD_%EC%A3%BC%EC%8B%9D_%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81</id>
	<title>코스피 대형주 과폭락 주식 모니터링 - 편집 역사</title>
	<link rel="self" type="application/atom+xml" href="https://devcafe.co.kr/w/index.php?action=history&amp;feed=atom&amp;title=%EC%BD%94%EC%8A%A4%ED%94%BC_%EB%8C%80%ED%98%95%EC%A3%BC_%EA%B3%BC%ED%8F%AD%EB%9D%BD_%EC%A3%BC%EC%8B%9D_%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81"/>
	<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EC%BD%94%EC%8A%A4%ED%94%BC_%EB%8C%80%ED%98%95%EC%A3%BC_%EA%B3%BC%ED%8F%AD%EB%9D%BD_%EC%A3%BC%EC%8B%9D_%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81&amp;action=history"/>
	<updated>2026-05-17T09:39:39Z</updated>
	<subtitle>이 문서의 편집 역사</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EC%BD%94%EC%8A%A4%ED%94%BC_%EB%8C%80%ED%98%95%EC%A3%BC_%EA%B3%BC%ED%8F%AD%EB%9D%BD_%EC%A3%BC%EC%8B%9D_%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81&amp;diff=2399&amp;oldid=prev</id>
		<title>Devcafe: 새 문서: **✅ Telegram 알림 기능이 추가된 최종 버전**입니다.  ### 1. 먼저 Telegram Bot 설정 방법 (필수)  1. Telegram에서 **@BotFather** 검색 → `/newbot` 명령어로 봇 생성 2. Bot Token 복사 (예: `123456789:AAH...`) 3. 봇을 본인 채팅방에 추가 후, 아래 링크로 Chat ID 확인:        ```    https://api.telegram.org/bot[YOUR_BOT_TOKEN]/getUpdates    ``` 4. Chat ID 복사 (보통 `-`로 시작하는 숫자)  -----  ### 2. 완전한 코드 (...</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EC%BD%94%EC%8A%A4%ED%94%BC_%EB%8C%80%ED%98%95%EC%A3%BC_%EA%B3%BC%ED%8F%AD%EB%9D%BD_%EC%A3%BC%EC%8B%9D_%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81&amp;diff=2399&amp;oldid=prev"/>
		<updated>2026-05-12T01:22:03Z</updated>

		<summary type="html">&lt;p&gt;새 문서: **✅ Telegram 알림 기능이 추가된 최종 버전**입니다.  ### 1. 먼저 Telegram Bot 설정 방법 (필수)  1. Telegram에서 **@BotFather** 검색 → `/newbot` 명령어로 봇 생성 2. Bot Token 복사 (예: `123456789:AAH...`) 3. 봇을 본인 채팅방에 추가 후, 아래 링크로 Chat ID 확인:        ```    https://api.telegram.org/bot[YOUR_BOT_TOKEN]/getUpdates    ``` 4. Chat ID 복사 (보통 `-`로 시작하는 숫자)  -----  ### 2. 완전한 코드 (...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;새 문서&lt;/b&gt;&lt;/p&gt;&lt;div&gt;**✅ Telegram 알림 기능이 추가된 최종 버전**입니다.&lt;br /&gt;
&lt;br /&gt;
### 1. 먼저 Telegram Bot 설정 방법 (필수)&lt;br /&gt;
&lt;br /&gt;
1. Telegram에서 **@BotFather** 검색 → `/newbot` 명령어로 봇 생성&lt;br /&gt;
2. Bot Token 복사 (예: `123456789:AAH...`)&lt;br /&gt;
3. 봇을 본인 채팅방에 추가 후, 아래 링크로 Chat ID 확인:&lt;br /&gt;
   &lt;br /&gt;
   ```&lt;br /&gt;
   https://api.telegram.org/bot[YOUR_BOT_TOKEN]/getUpdates&lt;br /&gt;
   ```&lt;br /&gt;
4. Chat ID 복사 (보통 `-`로 시작하는 숫자)&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
### 2. 완전한 코드 (pandas_ta + Telegram 알림)&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import FinanceDataReader as fdr&lt;br /&gt;
import pandas as pd&lt;br /&gt;
import pandas_ta as ta&lt;br /&gt;
from datetime import datetime, timedelta&lt;br /&gt;
import requests&lt;br /&gt;
import warnings&lt;br /&gt;
warnings.filterwarnings(&amp;#039;ignore&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
# ==================== 설정 ====================&lt;br /&gt;
# ==================== Telegram 설정 ====================&lt;br /&gt;
TELEGRAM_BOT_TOKEN = &amp;quot;YOUR_BOT_TOKEN_HERE&amp;quot;      # ← 여기에 Bot Token 입력&lt;br /&gt;
TELEGRAM_CHAT_ID = &amp;quot;YOUR_CHAT_ID_HERE&amp;quot;           # ← 여기에 Chat ID 입력&lt;br /&gt;
&lt;br /&gt;
RSI_THRESHOLD = 30&lt;br /&gt;
BB_PERIOD = 20&lt;br /&gt;
BB_STD = 2.0&lt;br /&gt;
MA_SHORT = 20&lt;br /&gt;
MA_LONG = 60&lt;br /&gt;
&lt;br /&gt;
MONTH1_THRESHOLD = -15   # %&lt;br /&gt;
MONTH3_THRESHOLD = -20   # %&lt;br /&gt;
&lt;br /&gt;
# ==================== Telegram 메시지 전송 함수 ====================&lt;br /&gt;
def send_telegram_message(message):&lt;br /&gt;
    if not TELEGRAM_BOT_TOKEN or TELEGRAM_BOT_TOKEN == &amp;quot;YOUR_BOT_TOKEN_HERE&amp;quot;:&lt;br /&gt;
        print(&amp;quot;⚠️ Telegram 설정이 완료되지 않았습니다.&amp;quot;)&lt;br /&gt;
        return False&lt;br /&gt;
    &lt;br /&gt;
    url = f&amp;quot;https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage&amp;quot;&lt;br /&gt;
    payload = {&lt;br /&gt;
        &amp;quot;chat_id&amp;quot;: TELEGRAM_CHAT_ID,&lt;br /&gt;
        &amp;quot;text&amp;quot;: message,&lt;br /&gt;
        &amp;quot;parse_mode&amp;quot;: &amp;quot;Markdown&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    try:&lt;br /&gt;
        response = requests.post(url, json=payload, timeout=10)&lt;br /&gt;
        if response.status_code == 200:&lt;br /&gt;
            print(&amp;quot;📤 Telegram 알림 전송 완료&amp;quot;)&lt;br /&gt;
            return True&lt;br /&gt;
        else:&lt;br /&gt;
            print(f&amp;quot;❌ Telegram 전송 실패: {response.text}&amp;quot;)&lt;br /&gt;
            return False&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        print(f&amp;quot;❌ Telegram 전송 오류: {e}&amp;quot;)&lt;br /&gt;
        return False&lt;br /&gt;
&lt;br /&gt;
# ==================== Top 100 추출 ====================&lt;br /&gt;
def get_kospi_top100():&lt;br /&gt;
    kospi = fdr.StockListing(&amp;#039;KOSPI&amp;#039;)&lt;br /&gt;
    if &amp;#039;Marcap&amp;#039; in kospi.columns:&lt;br /&gt;
        top100 = kospi.nlargest(100, &amp;#039;Marcap&amp;#039;).reset_index(drop=True)&lt;br /&gt;
    else:&lt;br /&gt;
        top100 = kospi.head(100).reset_index(drop=True)&lt;br /&gt;
    &lt;br /&gt;
    print(f&amp;quot;✅ KOSPI 시가총액 Top 100 로드 완료: {len(top100)}개&amp;quot;)&lt;br /&gt;
    return top100[[&amp;#039;Symbol&amp;#039;, &amp;#039;Name&amp;#039;]]&lt;br /&gt;
&lt;br /&gt;
# ==================== 지표 계산 ====================&lt;br /&gt;
def calculate_indicators(df):&lt;br /&gt;
    if len(df) &amp;lt; 100:&lt;br /&gt;
        return None&lt;br /&gt;
    &lt;br /&gt;
    close = df[&amp;#039;Close&amp;#039;]&lt;br /&gt;
    high = df[&amp;#039;High&amp;#039;]&lt;br /&gt;
    low = df[&amp;#039;Low&amp;#039;]&lt;br /&gt;
    &lt;br /&gt;
    df = df.copy()&lt;br /&gt;
    &lt;br /&gt;
    df[&amp;#039;RSI&amp;#039;] = ta.rsi(close, length=14)&lt;br /&gt;
    bb = ta.bbands(close, length=BB_PERIOD, std=BB_STD)&lt;br /&gt;
    df = pd.concat([df, bb], axis=1)&lt;br /&gt;
    &lt;br /&gt;
    df[&amp;#039;MA20&amp;#039;] = ta.sma(close, length=MA_SHORT)&lt;br /&gt;
    df[&amp;#039;MA60&amp;#039;] = ta.sma(close, length=MA_LONG)&lt;br /&gt;
    &lt;br /&gt;
    latest = df.iloc[-1]&lt;br /&gt;
    &lt;br /&gt;
    return_1m = (latest[&amp;#039;Close&amp;#039;] / df[&amp;#039;Close&amp;#039;].iloc[-22] - 1) * 100 if len(df) &amp;gt;= 22 else None&lt;br /&gt;
    return_3m = (latest[&amp;#039;Close&amp;#039;] / df[&amp;#039;Close&amp;#039;].iloc[-66] - 1) * 100 if len(df) &amp;gt;= 66 else None&lt;br /&gt;
    &lt;br /&gt;
    return {&lt;br /&gt;
        &amp;#039;RSI&amp;#039;: latest[&amp;#039;RSI&amp;#039;],&lt;br /&gt;
        &amp;#039;BB_Lower&amp;#039;: latest[f&amp;#039;BBL_{BB_PERIOD}_{BB_STD:.1f}&amp;#039;],&lt;br /&gt;
        &amp;#039;Close&amp;#039;: latest[&amp;#039;Close&amp;#039;],&lt;br /&gt;
        &amp;#039;MA20&amp;#039;: latest[&amp;#039;MA20&amp;#039;],&lt;br /&gt;
        &amp;#039;MA60&amp;#039;: latest[&amp;#039;MA60&amp;#039;],&lt;br /&gt;
        &amp;#039;Return_1M&amp;#039;: return_1m,&lt;br /&gt;
        &amp;#039;Return_3M&amp;#039;: return_3m&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# ==================== 메인 함수 ====================&lt;br /&gt;
def monitor_stocks():&lt;br /&gt;
    top100 = get_kospi_top100()&lt;br /&gt;
    results = []&lt;br /&gt;
    &lt;br /&gt;
    end_date = datetime.today().strftime(&amp;#039;%Y-%m-%d&amp;#039;)&lt;br /&gt;
    start_date = (datetime.today() - timedelta(days=500)).strftime(&amp;#039;%Y-%m-%d&amp;#039;)&lt;br /&gt;
    &lt;br /&gt;
    print(&amp;quot;🔄 기술적 지표 계산 중...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    for idx, row in top100.iterrows():&lt;br /&gt;
        try:&lt;br /&gt;
            symbol = row[&amp;#039;Symbol&amp;#039;]&lt;br /&gt;
            name = row[&amp;#039;Name&amp;#039;]&lt;br /&gt;
            &lt;br /&gt;
            df = fdr.DataReader(symbol, start_date, end_date)&lt;br /&gt;
            if df.empty or len(df) &amp;lt; 80:&lt;br /&gt;
                continue&lt;br /&gt;
                &lt;br /&gt;
            ind = calculate_indicators(df)&lt;br /&gt;
            if ind is None or pd.isna(ind[&amp;#039;RSI&amp;#039;]):&lt;br /&gt;
                continue&lt;br /&gt;
            &lt;br /&gt;
            conditions_met = []&lt;br /&gt;
            &lt;br /&gt;
            if ind[&amp;#039;RSI&amp;#039;] &amp;lt;= RSI_THRESHOLD:&lt;br /&gt;
                conditions_met.append(f&amp;quot;RSI({ind[&amp;#039;RSI&amp;#039;]:.1f})&amp;quot;)&lt;br /&gt;
            &lt;br /&gt;
            if ind[&amp;#039;Close&amp;#039;] &amp;lt;= ind[&amp;#039;BB_Lower&amp;#039;] * 1.01:&lt;br /&gt;
                conditions_met.append(&amp;quot;BB Lower&amp;quot;)&lt;br /&gt;
            &lt;br /&gt;
            ma20_dev = (ind[&amp;#039;Close&amp;#039;] / ind[&amp;#039;MA20&amp;#039;] - 1) * 100&lt;br /&gt;
            ma60_dev = (ind[&amp;#039;Close&amp;#039;] / ind[&amp;#039;MA60&amp;#039;] - 1) * 100&lt;br /&gt;
            &lt;br /&gt;
            if ma20_dev &amp;lt;= -15 or ma60_dev &amp;lt;= -25:&lt;br /&gt;
                conditions_met.append(f&amp;quot;MA괴리({ma20_dev:.1f}%)&amp;quot;)&lt;br /&gt;
            &lt;br /&gt;
            if (ind[&amp;#039;Return_1M&amp;#039;] and ind[&amp;#039;Return_1M&amp;#039;] &amp;lt;= MONTH1_THRESHOLD) or \&lt;br /&gt;
               (ind[&amp;#039;Return_3M&amp;#039;] and ind[&amp;#039;Return_3M&amp;#039;] &amp;lt;= MONTH3_THRESHOLD):&lt;br /&gt;
                conditions_met.append(f&amp;quot;하락({ind[&amp;#039;Return_1M&amp;#039;]:.1f}%/{ind[&amp;#039;Return_3M&amp;#039;]:.1f}%)&amp;quot;)&lt;br /&gt;
            &lt;br /&gt;
            if conditions_met:&lt;br /&gt;
                results.append({&lt;br /&gt;
                    &amp;#039;순위&amp;#039;: idx + 1,&lt;br /&gt;
                    &amp;#039;종목코드&amp;#039;: symbol,&lt;br /&gt;
                    &amp;#039;종목명&amp;#039;: name,&lt;br /&gt;
                    &amp;#039;현재가&amp;#039;: int(ind[&amp;#039;Close&amp;#039;]),&lt;br /&gt;
                    &amp;#039;RSI&amp;#039;: round(ind[&amp;#039;RSI&amp;#039;], 1),&lt;br /&gt;
                    &amp;#039;조건&amp;#039;: &amp;quot; | &amp;quot;.join(conditions_met),&lt;br /&gt;
                    &amp;#039;1개월&amp;#039;: f&amp;quot;{ind[&amp;#039;Return_1M&amp;#039;]:.1f}%&amp;quot; if ind[&amp;#039;Return_1M&amp;#039;] else &amp;quot;-&amp;quot;,&lt;br /&gt;
                    &amp;#039;3개월&amp;#039;: f&amp;quot;{ind[&amp;#039;Return_3M&amp;#039;]:.1f}%&amp;quot; if ind[&amp;#039;Return_3M&amp;#039;] else &amp;quot;-&amp;quot;&lt;br /&gt;
                })&lt;br /&gt;
        except:&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
    # 결과 처리&lt;br /&gt;
    if results:&lt;br /&gt;
        df_result = pd.DataFrame(results)&lt;br /&gt;
        &lt;br /&gt;
        print(&amp;quot;\n&amp;quot; + &amp;quot;=&amp;quot;*140)&lt;br /&gt;
        print(f&amp;quot;🔥 KOSPI Top 100 조건 충족 종목 ({len(df_result)}개) - {datetime.today().strftime(&amp;#039;%Y-%m-%d %H:%M&amp;#039;)}&amp;quot;)&lt;br /&gt;
        print(&amp;quot;=&amp;quot;*140)&lt;br /&gt;
        print(df_result.to_string(index=False))&lt;br /&gt;
        &lt;br /&gt;
        # Telegram 메시지 만들기&lt;br /&gt;
        msg = f&amp;quot;🔥 *KOSPI Top 100 고급지표 알림*\n&amp;quot;&lt;br /&gt;
        msg += f&amp;quot;📅 {datetime.today().strftime(&amp;#039;%Y-%m-%d %H:%M&amp;#039;)}\n&amp;quot;&lt;br /&gt;
        msg += f&amp;quot;📊 조건 충족: {len(df_result)}개\n\n&amp;quot;&lt;br /&gt;
        &lt;br /&gt;
        for _, row in df_result.iterrows():&lt;br /&gt;
            msg += f&amp;quot;• *{row[&amp;#039;종목명&amp;#039;]}* ({row[&amp;#039;종목코드&amp;#039;]})\n&amp;quot;&lt;br /&gt;
            msg += f&amp;quot;   현재가: {row[&amp;#039;현재가&amp;#039;]:,}원 | RSI: {row[&amp;#039;RSI&amp;#039;]}\n&amp;quot;&lt;br /&gt;
            msg += f&amp;quot;   조건: {row[&amp;#039;조건&amp;#039;]}\n\n&amp;quot;&lt;br /&gt;
        &lt;br /&gt;
        send_telegram_message(msg)&lt;br /&gt;
        &lt;br /&gt;
    else:&lt;br /&gt;
        print(&amp;quot;✅ 오늘은 조건을 충족하는 대형주가 없습니다.&amp;quot;)&lt;br /&gt;
        # send_telegram_message(&amp;quot;✅ 오늘 KOSPI Top 100 중 조건 충족 종목이 없습니다.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    monitor_stocks()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
### 사용법&lt;br /&gt;
&lt;br /&gt;
1. `TELEGRAM_BOT_TOKEN`과 `TELEGRAM_CHAT_ID`를 실제 값으로 바꾸기&lt;br /&gt;
2. 파일 저장 후 `python kospi_monitor.py` 실행&lt;br /&gt;
&lt;br /&gt;
원하시면 **매일 자동 실행**을 위한 스케줄러(crond / Windows Task Scheduler) 설정 방법도 알려드릴 수 있어요!&lt;/div&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
</feed>