決算スケジュール自動取得&アラートツールをPythonで作る

Python実装・コード

決算発表は株価が大きく動くイベントです。「うっかり決算日を忘れていて損した」を防ぐために、Pythonで決算スケジュールを自動取得してアラートを出すツールを作ります。

yfinanceで決算情報を取得する

import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta

def get_earnings_info(ticker_symbol):
    """銘柄の決算情報を取得"""
    ticker = yf.Ticker(ticker_symbol)
    
    # 次回決算日
    calendar = ticker.calendar
    print(f"\n=== {ticker_symbol} 決算情報 ===")
    if calendar is not None and not calendar.empty:
        print(f"次回決算日(予定): {calendar}")
    
    # 過去の決算実績
    earnings = ticker.earnings_history
    if earnings is not None:
        print("\n過去の決算実績:")
        print(earnings.tail(4))
    
    # 四半期決算
    quarterly = ticker.quarterly_earnings
    if quarterly is not None:
        print("\n四半期EPS(予想 vs 実績):")
        print(quarterly.tail(4))
    
    return calendar

# 主要銘柄の決算情報を確認
for ticker in ["AAPL", "NVDA", "9984.T"]:
    get_earnings_info(ticker)

ウォッチリストの決算スケジュール一覧

def get_upcoming_earnings(watchlist, days_ahead=30):
    """今後N日以内に決算がある銘柄を抽出"""
    today = datetime.today()
    cutoff = today + timedelta(days=days_ahead)
    upcoming = []
    
    for ticker_symbol in watchlist:
        try:
            ticker = yf.Ticker(ticker_symbol)
            cal = ticker.calendar
            if cal is None or cal.empty:
                continue
            
            # 決算日を取得
            if hasattr(cal, "loc") and "Earnings Date" in cal.index:
                earnings_dates = cal.loc["Earnings Date"]
                if not isinstance(earnings_dates, pd.Series):
                    earnings_dates = [earnings_dates]
                
                for ed in earnings_dates:
                    try:
                        ed_date = pd.to_datetime(ed).replace(tzinfo=None)
                        if today <= ed_date <= cutoff:
                            days_until = (ed_date - today).days
                            upcoming.append({
                                "Ticker": ticker_symbol,
                                "決算日": ed_date.strftime("%Y-%m-%d"),
                                "あと何日": days_until,
                            })
                    except:
                        pass
        except Exception as e:
            pass
    
    if not upcoming:
        print(f"今後{days_ahead}日以内に決算はありません")
        return pd.DataFrame()
    
    df = pd.DataFrame(upcoming).sort_values("あと何日")
    return df

watchlist = ["AAPL", "NVDA", "MSFT", "GOOGL", "AMZN", "TSLA", "META"]
upcoming = get_upcoming_earnings(watchlist, days_ahead=30)
print(upcoming)

決算サプライズ分析

def analyze_earnings_surprise(ticker_symbol, quarters=8):
    """決算サプライズ(予想vs実績)を分析"""
    ticker = yf.Ticker(ticker_symbol)
    earnings = ticker.earnings_history
    
    if earnings is None or earnings.empty:
        print(f"{ticker_symbol}: 決算データなし")
        return
    
    df = earnings.tail(quarters).copy()
    
    if "epsEstimate" in df.columns and "epsActual" in df.columns:
        df["サプライズ"] = df["epsActual"] - df["epsEstimate"]
        df["サプライズ率(%)"] = (df["サプライズ"] / df["epsEstimate"].abs()) * 100
        df["結果"] = df["サプライズ"].apply(lambda x: "上振れ" if x > 0 else "下振れ")
        
        print(f"\n=== {ticker_symbol} 決算サプライズ履歴 ===")
        print(df[["epsEstimate", "epsActual", "サプライズ", "サプライズ率(%)", "結果"]].round(2))
        
        beat_rate = (df["サプライズ"] > 0).mean()
        print(f"\n予想超過率: {beat_rate:.0%} ({quarters}四半期中)")

for t in ["AAPL", "NVDA", "MSFT"]:
    analyze_earnings_surprise(t)

メール通知システムの実装

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def send_earnings_alert_email(
    smtp_server, smtp_port, sender_email, sender_password,
    recipient_email, upcoming_df
):
    """決算アラートメールを送信"""
    if upcoming_df.empty:
        return
    
    subject = f"【決算アラート】今後の決算スケジュール ({len(upcoming_df)}銘柄)"
    
    body = "今後の決算スケジュールをお知らせします。\n\n"
    for _, row in upcoming_df.iterrows():
        body += f"- {row['Ticker']}: {row['決算日']} (あと{row['あと何日']}日)\n"
    body += "\n※ このメールはPythonスクリプトにより自動送信されています。"
    
    msg = MIMEMultipart()
    msg["From"] = sender_email
    msg["To"] = recipient_email
    msg["Subject"] = subject
    msg.attach(MIMEText(body, "plain", "utf-8"))
    
    with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
        server.login(sender_email, sender_password)
        server.send_message(msg)
    
    print(f"メール送信完了: {recipient_email}")

# Gmailで送信する場合(要:アプリパスワード設定)
# send_earnings_alert_email(
#     "smtp.gmail.com", 465,
#     "your@gmail.com", "your_app_password",
#     "your@gmail.com", upcoming
# )

自動実行の設定(cron/タスクスケジューラ)

#!/usr/bin/env python3
"""earnings_alert.py - 毎朝8時に実行するスクリプト"""

import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta

WATCHLIST = [
    "AAPL", "NVDA", "MSFT", "GOOGL", "AMZN",
    "7203.T", "9984.T", "6758.T"
]

def main():
    print(f"決算アラートチェック: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    upcoming = get_upcoming_earnings(WATCHLIST, days_ahead=7)  # 1週間以内
    
    if not upcoming.empty:
        print("【要注意】1週間以内に決算があります:")
        print(upcoming)
        # メール送信やSlack通知をここに追加
    else:
        print("1週間以内に決算なし")

if __name__ == "__main__":
    main()

# Linuxのcronに登録する場合(毎朝8時実行):
# 0 8 * * 1-5 /usr/bin/python3 /home/user/earnings_alert.py

まとめ

決算スケジュールを自動監視することで、大事な決算発表を見逃すリスクがなくなります。メール通知と組み合わせれば、完全自動の決算アラートシステムが完成します。

タイトルとURLをコピーしました