Claude Codeで東証の株取引を半自動化する【ペーパートレードで-19万円編】
Claude Code を使って東証の株取引を半自動化するシリーズ。ペーパートレード開始から5日間で14件の決済が行われ、勝率0%、実現損失は-186,250円。全敗だった。しかし、これはペーパートレードだからこそ見つけられた17件のバグの記録でもある。 免責事項: 本記事は技術的な解説であり、特定の投資戦略や銘柄を推奨するものではない。株式投資には元本割れのリスクがある。投資判断は自己責任で行うこと。また、APIを介した自動売買にはプログラムの不具合による意図しない発注のリスクが伴う。必ず少額から始め、十分な検証を経てから運用すること。 8連敗からの始まり ペーパートレード開始から3日目。決算データを使った戦略が8連敗した。損失は-68,550円。 下降トレンド中でも買う。損切り直後に同じ銘柄を再び買う。ストップ幅が狭すぎて、通常の値動きで損切りに引っかかる。人間のトレーダーなら「3連敗したら今日はやめよう」と判断する。AIにはその判断が最初からプログラムされていなかった。 タイミングも悪かった。ペーパートレードを始めた週、イラン情勢の緊迫化で日経平均もTOPIXも大幅に下落していた。バグだらけのシステムが、下落相場に突っ込んだ格好だ。 AIが書いたコードは「動く」。だが「正しく動く」とは限らない このシリーズでは、Claude Code を使って東証の株取引を半自動化する方法を紹介してきた。プログラミング不要で、AIに「やって」と言うだけ。それは嘘ではない。実際に Claude Code はスクリーニングから発注まで、動くコードを書いてくれた。 問題は「動く」と「正しく動く」の間に深い溝があることだ。 ペーパートレードを始めてから5日間で、17件のバグが見つかった。全て、ライブでも同じように発生するバグだ。一つ残らず実弾を撃つ前に発見できた。逆に言えば、ペーパートレードをスキップしていたら、17個の地雷を踏みながらライブトレードをしていたことになる。 「AIで簡単に自動売買」はSNSでよく見かけるフレーズだ。ツールとしてのAIは確かに強力だが、「簡単に」の部分は幻想だ。少なくとも私の場合はそうだった。長年コードを書いてきたエンジニアが、Claude Code にコードを書かせて、それでも17件のバグを出した。 ここから先は、その17件のうち特に危険だったものを紹介する。 放置すれば資金が溶けるバグ 8連敗して止まらない 冒頭の決算系戦略8連敗。-68,550円。 原因は安全機構の欠如だ。クールダウン(損切り後に一定期間エントリーを見送る仕組み)がない。戦略あたりのポジション上限がない。動的ストップ(値動き幅に応じて損切りラインを調整する仕組み)がない。 AIは「損切りラインを-5%に設定する」コードは書ける。だが「この銘柄のボラティリティなら-5%は狭すぎる」という判断はしない。ATR(平均的な1日の値動き幅)が3%の銘柄に5%のストップを置けば、2日間の通常の値動きで引っかかる。 ポジションサイズが制御されていない 1銘柄あたりの投資上限を設定するパラメータが、コードのどこにも参照されていなかった。パラメータは存在するが、使われていない。設定画面だけ立派で中身が空のセキュリティソフトのようなものだ。 ライブなら、1銘柄に資金が偏り、その銘柄が暴落したときに取り返しのつかない損失になる。 損切りしても枠が空かない 「損切りが先、新規エントリーが後」であるべき処理が、逆の順序で実行されていた。 1戦略あたりのポジション上限は3件。朝の処理で、まず新規エントリーを判定し、その後でストップ注文を処理する。すると、損切りで空くはずの枠が認識されず、新規エントリーがブロックされる。損切りされた銘柄の代わりに入るべき新しい銘柄が、いつまでも入れない。 暴落の朝に無防備にエントリーする 前日比10%のギャップダウン。市場が恐慌状態にある朝に、通常通りエントリーしていた。 ギャップの大きさを検出するロジックが存在しなかった。修正後は、10%以上のギャップで停止、5%以上でストップ幅を自動拡張するようにした。 50銘柄を超えると価格が取れなくなる kabu Station API には銘柄登録の上限がある。50件だ。株価の取得を要求するたびに銘柄が自動登録され、上限に達すると51件目以降は全てエラーになる。 110件の候補のうち36件が脱落した。ライブなら、高スコアの候補が価格を取得できずエントリー機会を逃す。あるいは、保有銘柄の価格が取れずストップ注文が発動しない。 「動いている」が「正しく動いている」ではないバグ 荒れた板でも平気でエントリーする 寄り付き直後の特別気配(売り買いの注文が極端に偏った状態)、スプレッドが通常の10倍、出来高ゼロ——そんな状態でも注文が通っていた。 板の品質を評価する仕組みが、単一時点のスプレッドチェックしかなかった。修正後は、出来高・スプレッド・気配の状態・特別気配・ストップ高ストップ安を総合的に評価し、回復可能な状態なら最大5分間リトライする仕組みにした。 全候補がQTY=0で1件もエントリーできない ある朝、40件の候補全てが「数量ゼロ」で見送られた。 資金300万円を5戦略で均等割りすると、1戦略あたり48万円。株価1,000円以上の銘柄は最低購入単位(100株=10万円)を確保できるが、戦略ごとの予算上限に引っかかって多くの銘柄が除外された。高株価の優良銘柄ほど買えないという、本末転倒な状態だった。 戦略の成績評価が壊れている 戦略の良し悪しを評価する指標(プロフィットファクター)の計算に、まだ決済していない注文のデータが混入していた。買い注文(損益ゼロ)が分母に加算され、評価値が実態と乖離する。 本来なら停止すべき戦略が「成績は悪くない」と判定され、損失を出し続ける。 ポジション管理がデータ不整合 取引ログでは全件決済済みなのに、ポジション管理ファイルには9件が残存していた。ゴーストポジション——実在しないポジションに対してストップ注文が出され続けるか、あるいは実在するポジションが管理から漏れる。 AIから見えない世界のバグ スケジュールが誰にもキックされていない 朝8:10のスクリーニングが、3日間実行されていなかった。 設定ファイルにはちゃんと書いてある。だが、それを読んで実行するスケジューラが、別件で停止したまま放置されていた。設定ファイルに書いた=実行される、ではない。 3日前の古い候補で取引するところだった。手動で気づいたから事なきを得た。 キャッシュが空で30分タイムアウト スクリーニングが30分以上かかり、朝9:10のエントリーに間に合わない。 ローカルに株価データのキャッシュを持つ仕組みを作ったが、キャッシュを更新する定期ジョブの登録を忘れていた。キャッシュが空なので、毎回APIから全銘柄のデータを個別取得する。1,590銘柄×APIレート制限で30分超。 時計が9時間ずれている 「9:10にエントリーを開始する」と書いたコードが、UTC基準で動いていた。WSL(Windows上のLinux環境)のシステム時刻がUTCで、Python の datetime.now() がタイムゾーン指定なしで呼ばれていた。 日本時間の9:10に動いたのは偶然だ。JST前提で書いたはずのコードがUTCで動いている——この種のバグは、テスト環境と本番環境でタイムゾーンが異なるだけで発生する。 Slack通知が全部失敗している 損切りもエントリーも、通知が何も届いていなかった。 ...