※本記事のコードや情報は執筆時点の仕様に基づいています。投資は自己責任であり、必ずデモ環境や少額資金でテストした上で運用してください。
Pythonで株式投資を自動化したいと考える個人投資家は多いですが、実現方法の情報が断片的で、どこから始めればよいかわからないという状況に直面することがほとんどです。証券会社のAPI仕様は頻繁に変更され、ネット上のサンプルコードは古いか、実際には動かないものばかりです。
自動売買システムを自作することで、自分のルールに基づいた規則正しい取引を実行でき、感情的な判断による失敗を減らせます。また、複数銘柄の監視や取引機会の見落としを防ぐことができるため、手動トレードよりも効率的です。
しかし、初心者が直面する課題は、SBI証券や楽天証券といった国内証券会社の個人向けAPIが制限されており、自由にPythonから発注できない点です。GitHub上には非公式ライブラリがありますが、セキュリティリスクと仕様変更への対応コストが大きく、実務的ではありません。
この障壁が生じる理由は、国内証券会社がセキュリティと規制への対応を厳格に行っているため、個人向けの自由度の高いAPIを公開することが難しいからです。一方、世界的に使われているオープンソースライブラリ「yfinance」を使えば、リアルタイムには近い株価データを無料で取得でき、テクニカル指標の計算や売買シグナルの生成は完全に自動化できます。
本記事では、SBI証券のAPI現状を冷徹に説明した上で、yfinanceを軸とした「実装可能な自動売買システム」の全手順をコード付きで解説します。データ取得から売買シグナル生成、LINEでの自動通知まで、すぐにコピペで動くPythonコードを複数提供し、初心者が詰まるポイントも網羅しています。
SBI証券APIの現状と個人投資家への現実的な選択肢
SBI証券は国内最大手の証券会社ですが、個人向けのPython実装用APIは実質的に非公開状態です。この現状を理解することが、効率的なシステム構築の第一歩になります。
SBI証券がAPIを制限する理由と限界
SBI証券は確かに「Hyper SBI 2」や「SBIハイブリッド預金」といったツールを提供しており、一部の機関投資家や認定パートナー向けにはAPIアクセスが許可されています。しかし、個人投資家向けには以下の壁があります。
- セキュリティ上の制約: 個人口座への不正アクセスを防ぐため、自動発注用のAPIは提供されていない
- 規制対応コスト: 金融庁の監督下での個人向けAPI提供には、法的・技術的な対応が膨大
- 情報公開の少なさ: ドキュメントやサンプルコードがほぼ存在しない
その結果、GitHubなどでは「SBI証券にブラウザ自動操作でログインするライブラリ」が有志によって開発されていますが、これは推奨されません。理由は以下のとおりです。
| 接続方法 | 実装難度 | 安定性 | セキュリティリスク | 推奨度 |
|---|---|---|---|---|
| 公式API(法人向け) | 低 | 非常に高い | 低い | ◎(ただし個人は申請困難) |
| スクレイピング + 自動ログイン | 高 | 低い(サイト変更で即停止) | 非常に高い(認証情報の漏洩リスク) | × |
| yfinance + テクニカル指標 | 中 | 高い | 低い(データ取得のみ) | ◎ |
結論として、個人投資家が自動売買を実装する場合は、yfinanceでデータを取得し、自分で売買ルールを構築するというアプローチが最も現実的です。
yfinanceとは:世界標準のオープンソースライブラリ
yfinanceはGoogleが開発・保守しているPythonライブラリで、Yahoo! Financeから株価データを自動取得します。以下の特徴があります。
- 無料・無登録: APIキーやユーザー認証が不要
- 日本株対応: トヨタ(7203.T)のような日本株も取得可能
- 世界規模での使用: 金融機関や投資ファンドでも実際に運用されている
- 定期的な更新: 2025年現在も活発にメンテナンスされている
ただし、以下の制約があります。
- 遅延データ: 株価データに数分~20分程度の遅延がある(デイトレードには不向き)
- 発注機能なし: 売買データの取得はできても、実際の発注はできない
- 可用性: Yahoo! Financeのサービス状況に依存
【コピペOK】yfinanceを使った株価データ取得の基礎
まずは、yfinanceで株価データを取得し、基本的なテクニカル指標を計算するコードから始めます。
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T" # トヨタ自動車
PERIOD = "1y" # 取得期間:1年
INTERVAL = "1d" # 足の種類:日足
# ==============================
# 株価データ取得関数
# ==============================
def fetch_stock_data(symbol, period, interval):
"""
yfinanceから株価データを取得する
Args:
symbol (str): 銘柄コード(例:7203.T)
period (str): 取得期間(例:1y, 3mo, 1d)
interval (str): ローソク足の間隔(1m, 5m, 15m, 30m, 60m, 1d, 1wk, 1mo)
Returns:
pd.DataFrame: OHLCV(始値、高値、安値、終値、出来高)データ
"""
print(f"[{datetime.now()}] データ取得開始: {symbol}")
try:
ticker = yf.Ticker(symbol)
df = ticker.history(period=period, interval=interval)
if df.empty:
print(f"警告: {symbol} のデータが取得できませんでした。")
return None
print(f"[{datetime.now()}] データ取得完了: {len(df)}行のデータを取得")
return df
except Exception as e:
print(f"エラー: データ取得に失敗しました。{e}")
return None
# ==============================
# テクニカル指標の計算
# ==============================
def calculate_rsi(df, period=14):
"""RSI(相対力指数)を計算"""
delta = df['Close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def calculate_macd(df, fast=12, slow=26, signal=9):
"""MACD(移動平均収束発散)を計算"""
ema_fast = df['Close'].ewm(span=fast).mean()
ema_slow = df['Close'].ewm(span=slow).mean()
macd = ema_fast - ema_slow
signal_line = macd.ewm(span=signal).mean()
histogram = macd - signal_line
return macd, signal_line, histogram
def add_technical_indicators(df):
"""複数のテクニカル指標をDataFrameに追加"""
df['RSI'] = calculate_rsi(df, 14)
df['MA20'] = df['Close'].rolling(window=20).mean()
df['MA50'] = df['Close'].rolling(window=50).mean()
df['MACD'], df['Signal'], df['Histogram'] = calculate_macd(df)
return df
# ==============================
# メイン処理
# ==============================
if __name__ == "__main__":
# データ取得
df = fetch_stock_data(SYMBOL, PERIOD, INTERVAL)
if df is not None:
# テクニカル指標を追加
df = add_technical_indicators(df)
# 直近5行を表示
print("\n直近5日間のデータ:")
print(df[['Close', 'RSI', 'MA20', 'MA50']].tail())
# CSVファイルに保存
csv_filename = f"{SYMBOL}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
df.to_csv(csv_filename)
print(f"\nデータを保存しました: {csv_filename}")
このコードの処理フロー:
fetch_stock_data()関数がyfinanceを使ってYahoo! Financeからデータを取得- 取得したデータに対して、RSI、MACD、移動平均線を計算
- 直近5行をコンソールに表示し、CSVファイルとして保存
売買シグナルの自動生成:ルール設計から実装まで
株価データを取得できたら、次は「どのような条件で買う/売るか」というシグナル生成ロジックを定義します。
テクニカル指標による売買ルール設計
個人投資家が実装可能な売買ルールは、シンプルで検証可能なものに限定すべきです。複雑なルールはバックテストでは高い成績を出しますが、実運用では失敗しやすくなります(過学習)。
推奨する売買ルール:
- ゴールデンクロス: 短期移動平均線(20日)が長期移動平均線(50日)を上抜ける → 買いシグナル
- デッドクロス: 短期移動平均線が長期移動平均線を下抜ける → 売りシグナル
- RSI補助ルール: RSIが30以下で買いシグナルが出た場合、さらに確度が高い
これらは統計的に有意性があり、バックテストでも検証しやすいという利点があります。
【コピペOK】売買シグナル生成エンジンの実装
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime
# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"
PERIOD = "1y"
MA_SHORT = 20
MA_LONG = 50
RSI_PERIOD = 14
RSI_OVERSOLD = 30
RSI_OVERBOUGHT = 70
# ==============================
# テクニカル指標計算関数
# ==============================
def calculate_rsi(series, period=14):
"""RSIを計算"""
delta = series.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def add_indicators(df):
"""テクニカル指標をDataFrameに追加"""
df['MA_SHORT'] = df['Close'].rolling(window=MA_SHORT).mean()
df['MA_LONG'] = df['Close'].rolling(window=MA_LONG).mean()
df['RSI'] = calculate_rsi(df['Close'], RSI_PERIOD)
return df
# ==============================
# シグナル生成関数
# ==============================
def detect_signal(df):
"""
売買シグナルを検出する
Returns:
dict: {
'signal': 'BUY' | 'SELL' | 'HOLD',
'reason': シグナルの理由,
'current_price': 現在価格,
'rsi': 現在のRSI値
}
"""
if len(df) < 2:
return {'signal': 'HOLD', 'reason': 'データ不足', 'current_price': None, 'rsi': None}
# 現在(直近)と前営業日のデータ
current = df.iloc[-1]
previous = df.iloc[-2]
current_price = current['Close']
current_rsi = current['RSI']
# ゴールデンクロス検出:短期MA > 長期MA かつ 前日は短期MA < 長期MA
if previous['MA_SHORT'] < previous['MA_LONG'] and current['MA_SHORT'] > current['MA_LONG']:
reason = f"ゴールデンクロス(短期MA: {current['MA_SHORT']:.0f}円 > 長期MA: {current['MA_LONG']:.0f}円)"
# RSIが買われ過ぎでなければ買いシグナル確度が高い
if current_rsi < RSI_OVERBOUGHT:
return {
'signal': 'BUY',
'reason': reason,
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'HIGH'
}
else:
return {
'signal': 'BUY',
'reason': reason + f"(ただしRSI {current_rsi:.0f} は買われ過ぎ)",
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'MEDIUM'
}
# デッドクロス検出:短期MA < 長期MA かつ 前日は短期MA > 長期MA
if previous['MA_SHORT'] > previous['MA_LONG'] and current['MA_SHORT'] < current['MA_LONG']:
reason = f"デッドクロス(短期MA: {current['MA_SHORT']:.0f}円 < 長期MA: {current['MA_LONG']:.0f}円)"
# RSIが売られ過ぎなら売りシグナル確度が高い
if current_rsi > RSI_OVERSOLD:
return {
'signal': 'SELL',
'reason': reason,
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'HIGH'
}
else:
return {
'signal': 'SELL',
'reason': reason + f"(RSI {current_rsi:.0f} は売られ過ぎ)",
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'MEDIUM'
}
# RSI単体シグナル
if current_rsi < RSI_OVERSOLD and previous['RSI'] >= RSI_OVERSOLD:
return {
'signal': 'BUY',
'reason': f"RSI売られ過ぎから回復(RSI: {current_rsi:.0f})",
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'LOW'
}
if current_rsi > RSI_OVERBOUGHT and previous['RSI'] <= RSI_OVERBOUGHT:
return {
'signal': 'SELL',
'reason': f"RSI買われ過ぎを示唆(RSI: {current_rsi:.0f})",
'current_price': current_price,
'rsi': current_rsi,
'confidence': 'LOW'
}
# シグナルなし
return {
'signal': 'HOLD',
'reason': '売買シグナルなし',
'current_price': current_price,
'rsi': current_rsi
}
# ==============================
# メイン処理
# ==============================
if __name__ == "__main__":
# データ取得
print(f"[{datetime.now()}] {SYMBOL} のデータ取得中...")
ticker = yf.Ticker(SYMBOL)
df = ticker.history(period=PERIOD)
if df.empty:
print("データ取得失敗")
else:
# インジケータ追加
df = add_indicators(df)
# シグナル検出
signal_result = detect_signal(df)
# 結果表示
print(f"\n【{SYMBOL} 売買シグナル分析結果】")
print(f"時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"シグナル: {signal_result['signal']}")
print(f"理由: {signal_result['reason']}")
print(f"現在価格: {signal_result['current_price']:.0f}円")
print(f"RSI: {signal_result['rsi']:.1f}")
if 'confidence' in signal_result:
print(f"確度: {signal_result['confidence']}")
このコードの処理フロー:
add_indicators()で移動平均線とRSIを計算detect_signal()で移動平均線のクロスを検出- ゴールデンクロス(買いシグナル)、デッドクロス(売りシグナル)を判定
- RSIの値も考慮して、シグナルの確度(HIGH / MEDIUM / LOW)を段階付け
LINE通知による自動アラート機能の実装
売買シグナルが生成されたら、すぐに通知を受け取る仕組みが必要です。LINEは個人投資家の間で最も使われているため、LINE Notifyを使った自動通知を実装します。
LINE Notifyの設定と認証トークン取得
LINE Notifyは、LINEアカウントを持っていれば誰でも無料で使用できます。以下の手順で準備します。
- https://notify-bot.line.me/my/ にアクセス
- 「アクセストークンを生成する」をクリック
- 「通知を送信するサービス名」(例:「株自動売買システム」)を入力
- 1トークンが発行されるので、コピーして安全に保管
- Pythonコード内の
LINE_TOKEN変数に貼り付け
【コピペOK】LINE自動通知機能の完全実装
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime
import requests
import json
# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"
PERIOD = "1y"
MA_SHORT = 20
MA_LONG = 50
RSI_PERIOD = 14
# LINE Notify設定
LINE_TOKEN = "YOUR_LINE_NOTIFY_TOKEN" # ここに自分のトークンを貼り付け
LINE_API_URL = "https://notify-api.line.me/api/notify"
# ==============================
# テクニカル指標計算
# ==============================
def calculate_rsi(series, period=14):
"""RSIを計算"""
delta = series.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def add_indicators(df):
"""テクニカル指標をDataFrameに追加"""
df['MA_SHORT'] = df['Close'].rolling(window=MA_SHORT).mean()
df['MA_LONG'] = df['Close'].rolling(window=MA_LONG).mean()
df['RSI'] = calculate_rsi(df['Close'], RSI_PERIOD)
return df
# ==============================
# シグナル検出関数
# ==============================
def detect_signal(df):
"""売買シグナルを検出"""
if len(df) < 2:
return None
current = df.iloc[-1]
previous = df.iloc[-2]
# ゴールデンクロス
if previous['MA_SHORT'] < previous['MA_LONG'] and current['MA_SHORT'] > current['MA_LONG']:
return {
'signal': 'BUY',
'price': current['Close'],
'rsi': current['RSI'],
'reason': 'ゴールデンクロス'
}
# デッドクロス
if previous['MA_SHORT'] > previous['MA_LONG'] and current['MA_SHORT'] < current['MA_LONG']:
return {
'signal': 'SELL',
'price': current['Close'],
'rsi': current['RSI'],
'reason': 'デッドクロス'
}
return None
# ==============================
# LINE通知関数
# ==============================
def send_line_notification(message, token=LINE_TOKEN):
"""
LINEに通知を送信する
Args:
message (str): 送信するメッセージ
token (str): LINE Notifyのアクセストークン
Returns:
bool: 送信成功=True, 失敗=False
"""
try:
headers = {"Authorization": f"Bearer {token}"}
data = {"message": message}
response = requests.post(LINE_API_URL, headers=headers, data=data)
if response.status_code == 200:
print(f"[{datetime.now()}] LINE通知送信成功")
return True
else:
print(f"[{datetime.now()}] LINE通知送信失敗: ステータスコード {response.status_code}")
return False
except Exception as e:
print(f"[{datetime.now()}] エラー: {e}")
return False
# ==============================
# メイン分析・通知処理
# ==============================
def analyze_and_notify(symbol, token):
"""
株価分析を実施し、シグナル検出時に通知を送信する
Args:
symbol (str): 銘柄コード
token (str): LINE Notifyトークン
"""
print(f"[{datetime.now()}] {symbol} の分析開始")
try:
# データ取得
ticker = yf.Ticker(symbol)
df = ticker.history(period=PERIOD)
if df.empty:
print("データ取得失敗")
return
# インジケータ追加
df = add_indicators(df)
# シグナル検出
signal = detect_signal(df)
if signal:
# メッセージ作成
message = f"\n【{symbol} 売買シグナル発生】\n\n"
message += f"シグナル: {signal['signal']}\n"
message += f"価格: ¥{signal['price']:.0f}\n"
message += f"RSI: {signal['rsi']:.1f}\n"
message += f"理由: {signal['reason']}\n"
message += f"時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
print(message)
# LINE通知を送信
send_line_notification(message, token)
else:
print(f"[{datetime.now()}] {symbol} - シグナルなし")
except Exception as e:
print(f"分析エラー: {e}")
# ==============================
# メイン処理
# ==============================
if __name__ == "__main__":
# ※重要: LINE_TOKEN を自分のトークンに置き換えてください
if LINE_TOKEN == "YOUR_LINE_NOTIFY_TOKEN":
print("エラー: LINE_TOKEN を設定してください")
else:
analyze_and_notify(SYMBOL, LINE_TOKEN)
このコードの処理フロー:
detect_signal()で売買シグナルを検出- シグナルが検出されたら、メッセージを組み立て
send_line_notification()を呼び出してLINEで通知- 失敗時のエラーハンドリングも含む
複数銘柄の監視と定期実行の仕組み
単一銘柄だけでなく、複数銘柄を同時に監視するには、スクリプトをループで実行する仕組みが必要です。
【コピペOK】複数銘柄の一括分析と定期実行
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime
import requests
import schedule
import time
# ==============================
# 設定エリア
# ==============================
SYMBOLS = ["7203.T", "7201.T", "8058.T", "9984.T"] # 監視対象銘柄
ANALYSIS_INTERVAL = 60 # 分析実行間隔(秒)
LINE_TOKEN = "YOUR_LINE_NOTIFY_TOKEN"
LINE_API_URL = "https://notify-api.line.me/api/notify"
# ==============================
# ユーティリティ関数
# ==============================
def calculate_rsi(series, period=14):
"""RSIを計算"""
delta = series.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def add_indicators(df):
"""テクニカル指標をDataFrameに追加"""
df['MA_SHORT'] = df['Close'].rolling(window=20).mean()
df['MA_LONG'] = df['Close'].rolling(window=50).mean()
df['RSI'] = calculate_rsi(df['Close'], 14)
return df
def detect_signal(df):
"""売買シグナルを検出"""
if len(df) < 2:
return None
current = df.iloc[-1]
previous = df.iloc[-2]
if previous['MA_SHORT'] < previous['MA_LONG'] and current['MA_SHORT'] > current['MA_LONG']:
return {
'signal': 'BUY',
'price': current['Close'],
'rsi': current['RSI'],
'reason': 'ゴールデンクロス'
}
if previous['MA_SHORT'] > previous['MA_LONG'] and current['MA_SHORT'] < current['MA_LONG']:
return {
'signal': 'SELL',
'price': current['Close'],
'rsi': current['RSI'],
'reason': 'デッドクロス'
}
return None
def send_line_notification(message):
"""LINEに通知を送信"""
try:
headers = {"Authorization": f"Bearer {LINE_TOKEN}"}
data = {"message": message}
response = requests.post(LINE_API_URL, headers=headers, data=data)
return response.status_code == 200
except Exception as e:
print(f"LINE送信エラー: {e}")
return False
# ==============================
# メイン分析処理
# ==============================
def analyze_all_symbols():
"""すべての監視銘柄を分析"""
print(f"\n[{datetime.now()}] 定期分析実行")
for symbol in SYMBOLS:
try:
# データ取得
ticker = yf.Ticker(symbol)
df = ticker.history(period="1y")
if df.empty:
print(f"⚠️ {symbol}: データ取得失敗")
continue
# インジケータ追加
df = add_indicators(df)
# シグナル検出
signal = detect_signal(df)
if signal:
message = f"\n【{symbol} {signal['signal']}シグナル】\n"
message += f"価格: ¥{signal['price']:.0f}\n"
message += f"RSI: {signal['rsi']:.1f}\n"
message += f"理由: {signal['reason']}\n"
message += f"時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
print(f"✅ {symbol}: {signal['signal']}")
send_line_notification(message)
else:
print(f"- {symbol}: シグナルなし")
except Exception as e:
print(f"❌ {symbol}: エラー - {e}")
# ==============================
# スケジューリング定期実行
# ==============================
def schedule_analysis():
"""分析をスケジューリング"""
# 毎日16時30分(株式市場の引け後)に実行
schedule.every().day.at("16:30").do(analyze_all_symbols)
print(f"[{datetime.now()}] スケジューラ起動(毎日16:30に実行)")
# 無限ループでスケジューラを実行
while True:
schedule.run_pending()
time.sleep(60)
# ==============================
# メイン処理
# ==============================
if __name__ == "__main__":
if LINE_TOKEN == "YOUR_LINE_NOTIFY_TOKEN":
print("エラー: LINE_TOKEN を設定してください")
else:
print("複数銘柄の自動分析を開始します")
print(f"監視対象: {SYMBOLS}")
print(f"トークン設定: OK\n")
# スケジュール実行
schedule_analysis()
# または1回限りの実行:
# analyze_all_symbols()
このコードを実行するには、以下のライブラリをインストールしてください。
pip install yfinance pandas numpy requests schedule
Windowsのタスクスケジューラで自動実行する仕組み
Pythonスクリプトを毎日自動実行するには、Windowsの「タスクスケジューラ」を使用します。
タスク登録の手順
- スクリプト保存: 上記のコードを
auto_trading.pyとして保存(例:C:\Users\YourName\Desktop\auto_trading.py) - タスクスケジューラを開く:
Win + R→taskschd.msc→ Enter - 基本タスクを作成: 右ペインから「基本タスクを作成」をクリック
- タスク名:
Stock Auto Trading - 説明:
株式自動売買分析
- タスク名:
- トリガー設定: 「毎日」を選択し、実行時刻を「16:30」に設定
- 操作を設定:
- プログラム/スクリプト:
C:\Users\YourName\AppData\Local\Programs\Python\Python311\python.exe - 引数の追加:
C:\Users\YourName\Desktop\auto_trading.py - 開始位置:
C:\Users\YourName\Desktop
- プログラム/スクリプト:
- 完了して保存
注意: Pythonの実行パスは環境によって異なります。
python.exeの正確なパスは、コマンドプロンプトでwhere pythonを実行して確認してください。
よくあるエラーと対処法
yfinanceからデータが取得できません
yfinanceは遅延データを提供しているため、Yahoo! Financeのサービス状況に依存します。以下を確認してください。
原因:
- 銘柄コードが誤っている(日本株の場合、末尾に
.Tが必須) - ネットワーク接続が切れている
- Yahoo! Financeのサービスが一時的に停止している
対処法:
- 銘柄コードの確認:
yf.Ticker("7203.T").infoで仕様確認 - ネットワークをチェック: ブラウザでYahoo! Financeにアクセス可能か確認
- リトライロジックを追加: コードに
try-exceptブロックを組み込む
LINE通知が送信されません
原因:
- LINE_TOKENが間違っている、または期限切れ
- インターネット接続が切れている
- requestsライブラリがインストールされていない
対処法:
- LINE_TOKENの確認: https://notify-bot.line.me/my/ で新しいトークンを生成し直す
- ネットワーク接続を確認:
ping google.comでインターネット接続を確認 pip install requestsでrequestsをインストール
スクリプトが実行されません(ImportError)
原因:
- 必要なライブラリがインストールされていない
- Pythonのバージョンが古い
対処法:
- 全ライブラリをインストール:
pip install yfinance pandas numpy requests schedule - Pythonのバージョン確認:
python --version(3.8以上推奨)
バックテストで高い利益率が出たが、実運用で利益が出ません
原因:
- 過学習(カーブフィッティング): 過去データに最適化されすぎたモデル
- スリッページ: 実際の約定価格とシグナル価格の差
- 手数料の計上漏れ: バックテスト時に手数料を含めていない
対処法:
- バックテスト期間を分割して検証: 2018~2022年で訓練、2023年で検証
- シンプルなルール設計: 複雑なロジックは避ける
- デモ口座で実運用テスト: 最低1~3ヶ月は少額で検証
定期実行がうまくいきません(Windowsのタスクスケジューラ)
原因:
- Pythonのパスが誤っている
- スクリプトの権限設定に問題がある
- ネットワークドライブのパスを指定している
対処法:
- Pythonパスを確認: コマンドプロンプルで
where pythonを実行し、完全なパスをコピーして貼り付け - スクリプトを絶対パスで指定:
C:\Users\...の形式で指定(相対パスは避ける) - ローカルドライブに保存: ネットワークドライブではなくC:ドライブに保存
まとめ
本記事では、Pythonを使った株の自動売買システムを自作するための完全なロードマップを解説しました。
要点を整理します。
- SBI証券は個人向けAPIを非公開としているため、yfinanceを使ったアプローチが現実的
- yfinanceは世界標準のオープンソースライブラリで、無料かつ安全にデータ取得が可能
- 移動平均線のクロスとRSIを組み合わせたシンプルなルールが、個人投資家には最適
- LINENotifyで自動通知を設定すれば、シグナル検出時に即座に通知が届く
- 複数銘柄の監視には、Pythonのスケジュール機能とWindowsのタスクスケジューラを組み合わせる
- バックテストで高い成績が出ても、実運用では異なるため、デモ環境での十分な検証が必須
次のステップとしては、まず単一銘柄で1~2週間のデモテストを行い、シグナル検出とLINE通知が正常に動作することを確認してください。その後、複数銘柄に拡張し、最終的に小額資金での実運用に進むことをお勧めします。
本記事のコードはすべてコピペで動作するように設計されており、Pythonの基礎知識があれば実装可能です。個人投資家が「自分のルール」で取引を自動化することで、感情的な判断を排除し、より規律ある投資が実現できます。

