iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Software Development

30 天打造專屬盯盤機器人:資料爬取、策略指標到 Telegram/LINE 推播系列 第 15 篇

Day 15:邁向全自動化 — 導入 APScheduler 打造盤後定時自動推播!

  • 分享至 

  • xImage
  •  

今天是第十五天!前幾天我們完成了一連串的大工程:從第九天繪製精美 K 線圖、第十一天計算 RSI/MACD 技術指標、第十二天加入籌碼量能監控、第十三天實現 Telegram /stock 即時互動點播,到昨天完成漂亮的專案模組化重構!

但現在我們的機器人還有一個小小的遺憾:要嘛是你手動傳指令 /stock 它才動,要嘛是你得親自跑去電腦前執行程式。真正的「全自動看盤小幫手」,應該要能在每天台股盤後(例如下午 2:00),自己時間一到就自動起床、掃描自選股清單,並把最新的分析報告推送到你的手機!

今天我們的目標,就是在模組化後的專案結構中,導入 Python 強大的排程套件 APScheduler,打造出真正的「全自動定時推播服務」!

步驟一:先釐清邏輯
自動排程的邏輯非常簡單直覺:

  1. 重新找回 CHAT_ID:因為「定時推播」是機器人主動發送訊息給我們,這時候就需要把 CHAT_ID 加回 config.py 設定檔中。
  2. 安裝與設定 APScheduler:使用 AsyncIOScheduler,讓它能在 Python 異步環境(asyncio)中與 Telegram Bot 完美共存。
  3. 設定觸發時間:設定每天台股盤後(例如週一至週五 下午 14:00),自動執行多股掃描任務。
  4. 背景自動執行:排程器會在背景倒數,時間一到就抓資料、畫圖、產生診斷,並透過 Telegram 主動發送圖片報告!
    接下來,知道邏輯後,我們就可以來安裝套件並更新程式碼了!
    步骤二:安裝排程套件
    請確認終端機前面有 (venv),並輸入以下指令:
pip install apscheduler

步驟三:改寫實作程式碼
我們只需要更新 config.py、在 bot.py 加入自動掃描函式,並在 main.py 把排程器啟動起來即可!
1. config.py(加入 CHATID 與設定時間)

# config.py
# 1. Telegram 設定
TOKEN = "你的_BOT_TOKEN"
CHAT_ID = "你的_CHAT_ID"
# 2. 排程時間設定 (每天下午 14:00 觸發)
SCHEDULE_HOUR = 14
SCHEDULE_MINUTE = 0
# 3. 預設自選股清單
DEFAULT_STOCKS = [
    {"symbol": "2330.TW", "name": "台積電"},
    {"symbol": "2317.TW", "name": "鴻海"},
    {"symbol": "2454.TW", "name": "聯發科"},
    {"symbol": "0050.TW", "name": "元大台灣50"}
]

2. bot.py(新增定時全自動巡檢函式)
在原本的 bot.py 底部,加入主動推播的 scheduled_job 處理邏輯:

# bot.py (請在原本檔案內容下方新增以下程式碼)
import time
from config import CHAT_ID, DEFAULT_STOCKS
# 排程自動觸發的巡檢任務
async def scheduled_job(context: ContextTypes.DEFAULT_TYPE):
    print("[INFO] 觸發定時排程,開始執行全自動盤後巡檢...")
    
    for item in DEFAULT_STOCKS:
        raw_symbol = item["symbol"]
        stock_name = item["name"]
        
        # 1. 抓取資料
        symbol, df = get_stock_data(raw_symbol)
        if df is None:
            print(f"[WARNING] 找不到 {stock_name} ({raw_symbol}) 資料,略過。")
            continue

        # 2. 畫圖與產生文字
        img_path = create_stock_chart(symbol, df)
        caption_text = f"【{stock_name} 盤後自動巡檢報告】\n" + generate_report_text(symbol, df)

        # 3. 主動發送至 Telegram 頻道/個人對話框
        try:
            with open(img_path, 'rb') as photo:
                await context.bot.send_photo(chat_id=CHAT_ID, photo=photo, caption=caption_text)
            print(f"[SUCCESS] {stock_name} 盤後報告已發送!")
        except Exception as e:
            print(f"[ERROR] 發送 {stock_name} 失敗: {e}")

        # 4. 清理暫存檔
        if os.path.exists(img_path):
            os.remove(img_path)
            
        time.sleep(1)

    print("[FINISH] 本次定時巡檢任務完成!")

3. main.py

# main.py
from telegram.ext import ApplicationBuilder
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from config import TOKEN, SCHEDULE_HOUR, SCHEDULE_MINUTE
from bot import setup_handlers, scheduled_job

if __name__ == "__main__":
    print("[START] 機器人與自動排程系統啟動中...")

    # 1. 初始化 Telegram Bot Application
    app = ApplicationBuilder().token(TOKEN).build()

    # 2. 註冊指令處理器 (/start, /stock)
    setup_handlers(app)

    # 3. 初始化並設定 APScheduler 自動排程
    scheduler = AsyncIOScheduler()
    
    # 設定每週一至週五 下午 14:00 自動執行 scheduled_job
    scheduler.add_job(
        scheduled_job,
        trigger=CronTrigger(day_of_week="mon-fri", hour=SCHEDULE_HOUR, minute=SCHEDULE_MINUTE),
        args=[app]
    )
    
    scheduler.start()
    print(f"[INFO] 排程設定完成:每週一至週五 {SCHEDULE_HOUR:02d}:{SCHEDULE_MINUTE:02d} 自動推播。")
    # 4. 開始持續監聽
    app.run_polling()

解釋一下程式碼吧!
主動推播的 context.bot.send_photo():
先前互動點播使用的是 update.message.reply_photo(),那是「被動回覆」;而這次在排程任務中,我們改用 context.bot.send_photo(chat_id=CHAT_ID, ...),直接指定 CHAT_ID 進行「主動推播」!
CronTrigger(精準時間觸發):
我們使用 CronTrigger(day_of_week="mon-fri", hour=14, minute=0),這代表只在「週一到週五的 14:00」觸發,自動避開週末休市的時間,非常智慧又省資源!
步驟四:執行程式
在終端機輸入:

pythom main.py

最後會長下面這樣!


上一篇
Day 14:邁向專業工程師 — 專案模組化重構與架構優化!
下一篇
Day 16:盤中即時警報 — 打造個股關鍵價位與技術指標觸發警示!
系列文
30 天打造專屬盯盤機器人:資料爬取、策略指標到 Telegram/LINE 推播 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言