AIをただの道具にしない。Geminiから「ダメ出し」をもらって成長する株価予測システムを作ってみた
はじめに:「Twin-KANNON Ver2.0」のコンセプト
AI(Gemini)と『対等なパートナー』として日経平均株価を予測するPythonシステム、「Twin-KANNON」を構築しました。
通常の生成AIの使い方は、「データを投げて予測結果をもらう」という、AIを単なる便利な道具として見做すものが大半だと思います。しかし、このシステムで最もこだわったのは、AI(Gemini)から人間側の情報収集に対するフィードバックをもらうという点です。
明日の日経平均を予測するために「人間が集めてきたデータは十分だったか?」「次はどんなデータを足すべきか?」をAIに客観評価(シナジー評価)させるスタイルを取っています。
動作環境の準備
実行には以下のライブラリが必要です。市場データは安定して取得できる yfinance を使用しています。
pip install yfinance feedparser python-dotenv google-genai
ソースコード
ポイントは get_gemini_advice 関数内のプロンプトです。AI自身の予測タスクと同時に、「人間(パートナー)が提供した情報がどれほど寄与したか評価せよ」と指示を出し、扱いやすいようにJSON形式で出力させています。
# ==========================================================
# System Name: Twin-KANNON (v2.0)
# Concept: Harmonic Intelligence of Carbon & Silicon
# ==========================================================
import os
import json
import csv
import ssl
import re
from datetime import datetime
from dotenv import load_dotenv
import feedparser
from google import genai
import yfinance as yf
# SSL認証のエラー回避
ssl._create_default_https_context = ssl._create_unverified_context
# 1. 設定: yfinance用のティッカーシンボル
MARKET_SOURCES = {
"Gold": "GC=F",
"Silver": "SI=F",
"Copper": "HG=F",
"CrudeOil": "CL=F",
"NIKKEI225": "^N225",
"為替(ドル円)": "JPY=X",
"米国債利回り(5年)": "^FVX",
"米国債利回り(10年)": "^TNX",
"VIX指数(恐怖指数)": "^VIX"
}
RSS_URLS = [
"https://news.google.com/rss/search?q=site%3Areuters.com&hl=en-US&gl=US&ceid=US%3Aen",
"https://news.google.com/rss/search?q=Commodity+Market&hl=ja&gl=JP&ceid=JP:ja"
]
# 環境変数の読み込みとGeminiクライアントの初期化
load_dotenv()
api_key = os.getenv("GEMINI_API_KEY")
client = genai.Client(api_key=api_key)
def fetch_all_rss(urls):
"""RSSから最新ニュースのヘッドラインを取得"""
all_headlines = []
for url in urls:
feed = feedparser.parse(url)
# 各URLから最新の5件を取得
for entry in feed.entries[:5]:
all_headlines.append(f"・{entry.title}")
return "\n".join(all_headlines)
def fetch_market_prices(sources):
"""yfinanceを用いて市場の最新価格(終値)を取得"""
results = {}
print("--- 市場データを収集中 ---")
for name, ticker in sources.items():
try:
# yfinanceでティッカー情報を取得
ticker_obj = yf.Ticker(ticker)
# 直近1日分のデータを取得
hist = ticker_obj.history(period="1d")
if not hist.empty:
# 最新の終値を小数点第2位まで丸めて保存
price = round(hist['Close'].iloc[-1], 2)
results[name] = price
print(f"{name:15}: {price}")
else:
results[name] = "データなし"
print(f"{name:15}: データなし")
except Exception as e:
results[name] = "取得失敗"
print(f"{name:15}: 取得失敗 ({e})")
return results
def get_gemini_advice(news, prices):
"""Geminiに判断を仰ぎ、同時に人間が提供した情報の有用性を評価させる"""
prompt = f"""
あなたはプロの日経平均225先物トレーダー、および戦略コンサルタントです。
以下のデータに基づき、明日の日経平均225先物の売買判断を行ってください。
また、今回の思考プロセスにおいて、人間(パートナー)が提供した情報(価格・ニュース)が
どれほど意思決定に寄与したか、客観的に評価してください。
【提供された市場データ】
{json.dumps(prices, indent=2, ensure_ascii=False)}
【提供された最新ニュース】
{news}
【出力形式】
以下のJSON形式でのみ回答してください。余計なマークダウンや説明は不要です。
{{
"summary": "市場全体の要約を30文字以内で",
"judgments": {{
"NIKKEI225": {{"action": "BUY/SELL/HOLD", "reason": "理由"}}
}},
"score": 0から100の強気度,
"synergy_evaluation": {{
"utility_score": 0から100の情報の有用性点数,
"feedback": "提供された情報の質や、次にどのようなデータがあればより精度が上がるかへの助言"
}}
}}
"""
try:
# 指定モデルでの生成実行 (モデル名はお使いの環境に合わせて変更してください)
response = client.models.generate_content(
model='gemini-3.1-pro-preview',
contents=prompt
)
text = response.text
# JSON部分のみを抽出
match = re.search(r'\{.*\}', text, re.DOTALL)
if match:
return json.loads(match.group())
return None
except Exception as e:
print(f"Gemini API通信エラー: {e}")
return None
def save_log(data):
"""結果とAIからのフィードバックをCSVに保存"""
file_path = "trading_log2.csv"
file_exists = os.path.isfile(file_path)
with open(file_path, mode='a', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
if not file_exists:
# ヘッダーの書き込み
writer.writerow(["Timestamp", "Summary", "Score", "Action", "Synergy_Score", "AI_Feedback"])
writer.writerow([
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
data["summary"],
data["score"],
data["judgments"]["NIKKEI225"]["action"],
data["synergy_evaluation"]["utility_score"],
data["synergy_evaluation"]["feedback"]
])
def main():
print("=== Twin-KANNON システム始動 ===")
news = fetch_all_rss(RSS_URLS)
prices = fetch_market_prices(MARKET_SOURCES)
print("\n--- Geminiが分析 & パートナーシップ評価中... ---")
advice = get_gemini_advice(news, prices)
if advice:
print(f"\n【市場の要約】: {advice['summary']}")
print(f"【全体スコア】: {advice['score']}")
print("-" * 30)
action = advice['judgments']['NIKKEI225']['action']
reason = advice['judgments']['NIKKEI225']['reason']
print(f"NIKKEI225: {action}\n理由: {reason}")
print("-" * 30)
print(f"【シナジー評価】: {advice['synergy_evaluation']['utility_score']}点")
print(f"【AIからの助言】: {advice['synergy_evaluation']['feedback']}")
save_log(advice)
print("\nログ(評価を含む)を保存しました。")
else:
print("AIからの有効な回答が得られませんでした。")
if __name__ == "__main__":
main()
出力結果(2026年3月20日金曜日午後の場合)
=== Twin-KANNON システム始動 ===
--- 市場データを収集中 ---
Gold : 4718.7
Silver : 73.74
Copper : 5.54
CrudeOil : 93.96
NIKKEI225 : 53372.53
為替(ドル円) : 158.37
米国債利回り(5年) : 3.92
米国債利回り(10年) : 4.28
VIX指数(恐怖指数) : 24.06
--- Geminiが分析 & パートナーシップ評価中... ---
【市場の要約】: 中東情勢悪化とVIX上昇による警戒相場
【全体スコア】: 30
------------------------------
NIKKEI225: SELL
理由: VIX指数が24台と警戒水準にあり、中東の地政学リスクや米国のタカ派的な金利見通しが重なっているため、短期的にはリスク回避の売りが適切と判断します。
------------------------------
【シナジー評価】: 80点
【AIからの助言】: 地政学リスクのニュースとVIXや原油高といった市場データが合致しており、迅速なリスク評価に非常に有用でした。今後は日米の金融政策スケジュールや国内企業の業績動向が加わると、より精度の高い判断が可能になります。
ログ(評価を含む)を保存しました。
開発秘話
当初、日経平均株価を予測するためにスクリプトが収集していた情報は「ニュースソース」と「商品先物(金、銀、銅)価格」のみでした。
しかし、実行するたびにGeminiから、
「株価を予測するなら、米国の金利動向(米国債利回り)のデータがないと厳しいです」「市場のセンチメントを測るためにVIX指数(恐怖指数)を追加してください」といった具体的なダメ出し(フィードバック)を受けました。
その助言に沿って、人間側が yfinance のティッカーシンボル(^TNX や ^VIX など)を追加していくことで、現在の形に進化しました。
ただAIを呼び出すだけのシステムから、「AIのアドバイスでシステム自体が成長していく」という体験は、まさにパートナー(Twin)としてのAIの新しい使い方だと感じています。