Pythonで自動売買シグナルをX(Twitter)に自動投稿する方法|Gemini + tweepy

AI×自動売買

この記事でわかること

  • DiscordからX(Twitter)への通知移行の手順
  • tweepy v4 + Twitter API v2(OAuth 1.0a)の正しい設定方法
  • Gemini APIのクォータ問題とモデル選定の注意点
  • APSchedulerで1〜2時間おきに自動実行する方法
  • 実際に踏んだエラーと解決策まとめ

📘 外部参考Tweepy 公式ドキュメントX API(旧Twitter)公式

📘 外部参考Google Gemini API(公式)


なぜDiscordからXに切り替えたか

もともと、AI自動売買ボットのシグナル通知はDiscord Webhook URLで実装していた。コード1行で送れるお手軽さが魅力だった。

📘 外部参考Discord Webhook ガイド(公式・日本語)

しかし、運用してみると以下の課題が見えてきた。

  • 通知を確認するにはDiscordアプリを開く必要がある
  • 外部への情報発信にならない(クローズドな環境)
  • X(Twitter)と連携すれば、フォロワーにリアルタイムでシグナルを届けられる

というわけで、通知先をX(Twitter)に全面移行することにした。


X(Twitter) APIの取得手順

1. X Developer Portalでアプリを作成

developer.twitter.com にアクセスし、アプリを作成する。

重要なポイント:
アプリの権限設定を 「Read and Write」 にすること。デフォルトは「Read only」になっており、ツイートの投稿ができない。権限変更後は必ずAccess TokenとAccess Token Secretを再生成すること(古いトークンは無効になる)。

2. 必要なAPIキー(4つ)

キー名 取得場所
API Key App Settings > Keys and Tokens
API Secret 同上
Access Token 同上(Generate後)
Access Token Secret 同上

3. .envファイルへの設定

X_API_KEY=xxxxxxxxxxxxxxxxxxxx
X_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X_ACCESS_TOKEN=xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X_ACCESS_TOKEN_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

X通知モジュールの実装(x_notifier.py)

import tweepy
import os
from datetime import datetime
from dotenv import load_dotenv

load_dotenv()

class XNotifier:
def __init__(self):
api_key = os.getenv("X_API_KEY")
api_secret = os.getenv("X_API_SECRET")
access_token = os.getenv("X_ACCESS_TOKEN")
access_token_secret = os.getenv("X_ACCESS_TOKEN_SECRET")
if not all([api_key, api_secret, access_token, access_token_secret]):
self.client = None
return
self.client = tweepy.Client(
consumer_key=api_key,
consumer_secret=api_secret,
access_token=access_token,
access_token_secret=access_token_secret
)

def post(self, text: str) -> bool:
if not self.client:
print("[X] APIキー未設定 - スキップ")
return False
try:
if len(text) > 140:
text = text[:137] + "..."
self.client.create_tweet(text=text)
print(f"[X] 投稿成功: {text[:50]}...")
return True
except Exception as e:
print(f"[X] 投稿エラー : {e}")
return False

def notify_signal(self, symbol: str, decision: str, score: float, reasoning: str):
emoji = {"BUY": "📈", "SELL": "📉", "HOLD": "⏸"}.get(decision, "❓")
reason_short = reasoning[:40] + "…" if len(reasoning) > 40 else reasoning
now = datetime.now().strftime("%m/%d %H:%M")
text = f"{emoji}【{symbol}】{decision} {now}\nスコア:{score:+.2f} {reason_short}\n#AI自動売買 #アルゴトレード"
return self.post(text)

def notify_weekly_report(self, report_text: str):
now = datetime.now().strftime("%m/%d %H:%M")
text = f"📊【週次レポート】{now}\n" + report_text[:100] + "\n#AI自動売買"
return self.post(text)

ポイント:

  • 140字制限は post() 内で自動トリミング
  • datetimeタイムスタンプを毎回入れることで「重複ツイート」エラーを回避
  • tweepy.Client はTwitter API v2対応(v4系ライブラリ)

APSchedulerで定期実行

from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.cron import CronTrigger

scheduler = BlockingScheduler(timezone="Asia/Tokyo")

60分ごとにシグナル確認・X投稿

scheduler.add_job(run_cycle, IntervalTrigger(minutes=60))

毎週月曜9:00 JSTに週次レポートをX投稿

scheduler.add_job(send_weekly_report, CronTrigger( day_of_week="mon", hour=9, minute=0, timezone="Asia/Tokyo" ))

scheduler.start()

起動コマンド:

# バックグラウンド実行(Windows・ターミナルを閉じても継続)
start /B pythonw main_trader.py --schedule 60

ログを確認しながら実行

python main_trader.py --schedule 60

Gemini APIのモデル選定と注意点

AI判断エンジンにはGoogle Gemini APIを使っている。モデル選びで何度かつまずいたのでまとめておく。

モデル変遷

モデル名 状況
gemini-2.5-flash(無料枠) 20リクエスト/日 → すぐクォータ超過
gemini-1.5-flash 404エラー(廃止済み)
gemini-2.0-flash 無料枠:1500リクエスト/日 ✅
gemini-2.5-flash(課金後) 利用可能 ✅

2シンボル(SPY・USDJPY)× 60分サイクルで1日24リクエスト。gemini-2.0-flash の1500/日で十分に余裕がある。

クォータ超過時の安全なフォールバック実装

from google.api_core.exceptions import ResourceExhausted

try:
response = model.generate_content(prompt)
except ResourceExhausted:
return {"decision": "HOLD", "score": 0.0, "reasoning": "APIクォータ超過のためスキップ"}
except Exception as e:
return {"decision": "HOLD", "score": 0.0, "reasoning": f"エラー: {str(e)[:50]}"}

クォータ超過でもHOLDとして処理を継続し、ボットが止まらない設計にしている。


実際に踏んだエラーと解決策

エラー① 401 Unauthorized

原因: アプリ権限が「Read only」のままだった。
解決: Developer Portalで「Read and Write」に変更 → Access Tokenを再生成。

エラー② 403 Forbidden(duplicate content)

原因: SPYとUSDJPYが同じ HOLD score:0.00 で全く同じツイート文になっていた。
解決: ツイート文に日時(%m/%d %H:%M)を追加して毎回内容を変える。

エラー③ 404 Not Found(Gemini)

原因: gemini-1.5-flash は廃止済み。課金前に gemini-2.5-flash を使おうとした。
解決: 無料枠は gemini-2.0-flash、課金後は gemini-2.5-flash を使用。

エラー④ Windows ターミナルでの文字化け

原因: ⏸(U+23F8)などの絵文字がWindows CP932コンソールで表示できない。
解決: main_trader.py の先頭に以下を追加。

import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

完成した自動投稿ツイートのイメージ

HOLDの場合:

⏸【SPY】HOLD 04/27 17:23
スコア:+0.00 市場の方向性が不明確なため様子見…
#AI自動売買 #アルゴトレード

BUYシグナルの場合:

📈【SPY】BUY 04/28 09:00
スコア:+0.75 移動平均線のゴールデンクロスを確認…
#AI自動売買 #アルゴトレード


まとめ

Discordと違いXへの投稿は外部発信になるため、フォロワーへのリアルタイム情報提供ができる。実装上のポイントは以下の3点だ。

  1. OAuth 1.0a(4キー)を使うこと(OAuth 2.0ではツイート投稿不可)
  2. 毎回ツイート内容を変える(タイムスタンプ追加で重複エラーを回避)
  3. Geminiモデルは課金状況に合わせて選ぶ(無料:gemini-2.0-flash、課金後:gemini-2.5-flash)

自動売買×自動投稿の組み合わせで、売買シグナルを透明性高く発信できる環境が整った。


免責事項:本記事で紹介しているシステムはペーパートレード(模擬取引)環境での動作を前提としています。実際の投資は自己責任でお願いします。

🔗 関連記事

cronでPython株価分析スクリプトを毎日自動実行する方法【VPS・Linux】

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