1. はじめに:RSA攻撃の次は株で一攫千金...のはずだった
前回の記事で、Shorのアルゴリズムの現実の厳しさを体験しました。
「暗号はダメだった...でも株価予測ならイケるんじゃね?」
という浅はかな考えのもと、**量子フーリエ変換(QFT)**を使った株価予測に挑戦しました。
結果は...
2. 前提:量子フーリエ変換で周期性を検出する
アイデア
株価には隠れた周期性があるのでは?
- 景気循環
- 決算サイクル
- 季節性
↓
量子フーリエ変換で周期を検出
↓
その周期でトレードすれば儲かる!(はず)
実装方針
1. 過去データで周期を検出(QFT)
2. その周期でOOS期間(未来)を予測
3. Buy & Holdと比較
3. 実験結果:衝撃の数値たち
検証対象(日本株5銘柄)
| 銘柄 | 量子戦略 | 買い持ち | 判定 |
|---|---|---|---|
| トヨタ | +433% | +359% | ✅ 勝ち |
| NTT | +286% | +418% | ❌ 負け |
| 藤田観光 | +1293% | -0.7% | ✅ 勝ち? |
| 丸善CHI | +142% | +57% | ✅ 勝ち |
| イオン | +208% | +338% | ❌ 負け |
一見の印象
- 😍 藤田観光すげええええ!+1293%!!
- 🤔 トヨタと丸善も勝ってる
- 😅 NTTとイオンは負けてる...
4. 現実:これ、完全にオーバーフィッティングです
4.1 藤田観光の異常値
+1293% って...おかしいだろ
理由:
- テストデータでパラメータを最適化しすぎ
- たまたまその期間だけ当たった
- 再現性ゼロ
4.2 NTT・イオンで負けてる理由
買い持ちに負けるなら、戦略として意味がない
4.3 最大の問題:バックテストの罠
# こういうことをやってた
for window in rolling_windows:
train_data = data[window-60:window]
test_data = data[window:window+12]
# 量子で周期検出
period = quantum_detect_period(train_data)
# その周期でテストデータをトレード
strategy_return = trade_with_period(test_data, period)
問題点:
- 12ヶ月後の未来データ(test_data)は実際には見えない
- SMA(移動平均)も未来の情報を使ってる可能性
- つまりタイムマシンを使ったズル
5. 実験コード(教育用・簡易版)
免責事項
⚠️ このコードは教育目的です。実際の投資に使用しないでください。
※日本語表示するにはjapanize_matplotlibを
使っているqBraidのPythonカーネルのPackageに追加してから下記を一度だけ実行してください。
# --- 日本語フォント自動設定ヘルパー(おまじない)--------------------------------
import japanize_matplotlib # ← 日本語の呪いを解く魔法の呪文
import os
import matplotlib
from matplotlib import font_manager as fm
import matplotlib.pyplot as plt
def setup_japanese_font():
"""
日本語が豆腐にならないようにフォントを自動設定。
1) システムにある日本語フォントを探索
2) プロジェクト同梱フォント(./fonts/*.ttf/otf)があれば登録
"""
candidates = [
"IPAexGothic", "IPAGothic",
"Noto Sans CJK JP", "Noto Sans JP", "Noto Serif CJK JP",
"TakaoGothic",
"Yu Gothic", "YuGothic",
"Hiragino Sans", "Hiragino Kaku Gothic ProN",
"MS Gothic"
]
available = {f.name for f in fm.fontManager.ttflist}
for name in candidates:
if name in available:
plt.rcParams["font.family"] = name
plt.rcParams["axes.unicode_minus"] = False
print(f"日本語フォント: {name} を使用します")
return name
# ローカル同梱フォントのパス候補
local_paths = [
"./fonts/ipaexg.ttf",
"./fonts/NotoSansJP-Regular.otf",
"./NotoSansJP-Regular.otf"
]
for p in local_paths:
if os.path.exists(p):
fm.fontManager.addfont(p)
family = fm.FontProperties(fname=p).get_name()
plt.rcParams["font.family"] = family
plt.rcParams["axes.unicode_minus"] = False
print(f"ローカル日本語フォント {p} を登録して使用します({family})")
return family
print("⚠ 日本語フォントが見つかりません。豆腐が出る場合は IPAex または Noto Sans JP を導入してください。")
print(" 例: Ubuntu系 → `sudo apt-get install fonts-noto-cjk`(No Tofu フォント)")
return None
# アプリ起動時に一度だけ設定
setup_japanese_font()
# -------------------------------------------------------------------------
# ============================================================
# 量子フーリエ変換による株価周期性検出(超簡易版)
# ============================================================
import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit
from qiskit.circuit.library import QFT
from qiskit_aer import AerSimulator
from qiskit import transpile
print("="*70)
print("🔮 量子フーリエ変換で株価の周期を探る(教育デモ)")
print("="*70)
# ============================================================
# 1. 模擬データ生成(実際の株価の代わり)
# ============================================================
def generate_mock_stock_data(length=100, period=12):
"""周期性のある模擬株価データを生成"""
t = np.arange(length)
trend = 0.01 * t # 緩やかな上昇トレンド
cycle = 0.1 * np.sin(2 * np.pi * t / period) # 周期成分
noise = 0.05 * np.random.randn(length) # ノイズ
return trend + cycle + noise
# サンプルデータ生成
stock_data = generate_mock_stock_data(length=100, period=12)
print(f"\n📊 模擬株価データ生成完了: {len(stock_data)}日分")
print(f" 実際は周期{12}日の正弦波 + トレンド + ノイズです")
# ============================================================
# 2. 量子回路で周期検出
# ============================================================
def detect_period_with_qft(data, n_qubits=4):
"""QFTで周期を検出(超簡易版)"""
# データを正規化
normalized = (data - np.mean(data)) / np.std(data)
# 量子回路作成
qc = QuantumCircuit(n_qubits, n_qubits)
# 重ね合わせ状態
for i in range(n_qubits):
qc.h(i)
# データエンコード(位相回転)
for i, val in enumerate(normalized[:2**n_qubits]):
angle = np.pi * val
qc.rz(angle, i % n_qubits)
# QFT適用
qft = QFT(n_qubits)
qc.append(qft.inverse(), range(n_qubits))
# 測定
qc.measure(range(n_qubits), range(n_qubits))
# シミュレータで実行
backend = AerSimulator()
job = backend.run(transpile(qc, backend), shots=1024)
counts = job.result().get_counts()
# 周期推定
periods = []
total = sum(counts.values())
for bitstring, count in counts.items():
if count > total * 0.05: # 5%以上の確率
measured = int(bitstring, 2)
if measured > 0:
period = len(data) / measured
if 2 <= period <= len(data) // 2:
periods.append((period, count / total))
return sorted(periods, key=lambda x: x[1], reverse=True)
print("\n🔮 量子回路で周期検出中...")
detected_periods = detect_period_with_qft(stock_data)
print("\n✨ 検出された周期:")
for period, confidence in detected_periods[:5]:
print(f" 周期 {period:.1f}日 (信頼度: {confidence:.3f})")
# ============================================================
# 3. 可視化
# ============================================================
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
# 株価データ
ax1.plot(stock_data, label='模擬株価', linewidth=2)
ax1.set_title('📈 模擬株価データ(実際は12日周期)', fontsize=14, weight='bold')
ax1.set_xlabel('日数')
ax1.set_ylabel('価格')
ax1.legend()
ax1.grid(alpha=0.3)
# 検出された周期
if detected_periods:
periods, confidences = zip(*detected_periods[:8])
ax2.bar(range(len(periods)), confidences, color='blue', alpha=0.7)
ax2.set_title('🔮 量子フーリエ変換で検出された周期', fontsize=14, weight='bold')
ax2.set_xlabel('周期ランキング')
ax2.set_ylabel('検出信頼度')
ax2.set_xticks(range(len(periods)))
ax2.set_xticklabels([f'{p:.1f}日' for p in periods], rotation=45)
ax2.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
print("\n" + "="*70)
print("🎯 結論:")
print(" ・量子フーリエ変換は周期を検出できる")
print(" ・しかし、それが「未来も続く」保証はない")
print(" ・バックテストで良くても、実運用では...")
print("="*70)
6. 何が問題だったのか:5つの教訓
教訓1: バックテストは未来を保証しない
過去に有効だった戦略が、未来も有効とは限らない。
教訓2: オーバーフィッティングは簡単に起きる
複雑な手法ほど、データに過剰適合しやすい。
教訓3: 量子は万能じゃない
量子コンピュータは計算の仕方が違うだけ。
魔法じゃない。
教訓4: 情報リーク(Look-Ahead Bias)
未来の情報を使っていないか、常に疑え。
教訓5: 単純な手法の方が頑健
- Buy & Hold
- インデックス投資
- ドルコスト平均法
↑こういうシンプルな戦略の方が、長期的には強い。
7. それでも得られたもの
技術的知見
- QFTの実装経験
- Qiskit 2.1の使い方
- バックテストフレームワークの設計
教訓
「失敗から学ぶことは、成功から学ぶことより多い」
8. 次回予告:量子乱数の奇妙な世界
第三弾(完結編)では、量子乱数の不思議な性質に迫ります。
- 真の乱数とは?
- 古典乱数との違い
- 奇妙な偏りの正体
お楽しみに! 🎲✨
参考文献
おわりに
量子コンピュータで株価予測...夢がありますよね。
でも、現実は甘くなかった。
失敗を公開する勇気こそが、技術コミュニティの財産だと信じています。
この記事が、同じ道を歩もうとしている誰かの助けになれば幸いです。
次回の量子乱数編で、ようやく「面白い発見」をお届けできると思います!
この記事が役に立ったら、いいね👍とフォローをお願いします!
ご質問やコメントもお気軽にどうぞ。一緒に量子の世界を探求しましょう!