戦略アルゴリズム(第I部)から運用システム(第II部)まで、約3年分の取引を Python と GPU 搭載 PC で高速にバックテストし、設計と失敗をコードと実測値で追えるようにした一冊です。
軸は「うまくいった話」ではなく、設計と失敗の透明な記録です。1,800 行かけた相場レジーム判定ロジックを過学習で丸ごと廃案にした話。最適化が「98% のドローダウン」を良いスコアと誤判定した話。こうしたうまくいかなかった過程を、各章で主役級に扱っています。売買の"頭脳"も、派手な AI 予測ではありません。ボリンジャーバンドと一次回帰トレンドという枯れた指標を、優先順位つきのルールに整理しただけです。
この記事は、放置していた自作 iOS アプリを Claude Code に近代化してもらった記録です。私はコードを1行も書いていないどころか、Mac にも Claude Code が動く PC にも一切触れていません。指示はすべてスマホから出しただけで、コード修正・調査・ビルド・TestFlight 配信・App Store 申請まで Claude Code が Mac にヘッドレス(SSH 経由)で実行しました。2017年に公開して以来ほぼ放置していた約9年もの(うち7年半は完全放置)の Mastodon ビューアの「何が壊れていて、何をどう直したか」を技術的にまとめます。
この記事でわかること
放置した古い iOS アプリを、自分でコードを書かずに Claude Code へ近代化してもらう進め方
その作業分担(私が頼んだこと / Claude Code が私に求めたこと)
結果として実現した技術的な更新(deprecated API 置き換え・OAuth 移行・Realm 実機クラッシュ修正など)
作業分担:私が頼んだこと、Claude Code が私に求めたこと
最初に私が Claude Code に頼んだのは、ひとことで言えば「7年半放置した Oyakodon を、作り直さずに直して、もう一度 App Store に出せる状態にしてほしい」でした。具体的な実装方針は対話しながら詰めましたが、エディタを開いてコードを書いたのは私ではなく Claude Code です。
Claude Code 側がやったこと(Mac にヘッドレスで):
Swift コードの修正そのもの(後述の Before / After はすべて Claude Code の変更)
クラッシュログ(.ips)を atos でシンボル解決して原因箇所を特定
curl で Mastodon API のレスポンスを叩いて挙動を切り分け
SSH 経由で Mac 上の xcodebuild archive → altool を回し、TestFlight へアップロード
提出ビルドのバージョン番号(CFBundleVersion)の更新と、App Store Connect への審査提出(API 経由)。App Store の初期設定(アプリ枠・契約・基本情報)は旧アプリ時代に済んでいたので、私が App Store Connect に新規ログインする必要はなく、申請まで Claude Code が完結させた
私がやったこと(人間にしかできない部分だけ):
「作り直さず近代化する」という方針を決め、スマホから指示を出すこと
TestFlight に上がったビルドを自分の iPhone で触り、挙動の異常をスクリーンショットで報告すること。後述の「起動直後に落ちる」「画面下端がズレる」はこの実機確認で見つかった。とくに WebView の位置ズレのように言葉で正確に説明しづらい不具合も、私はスクショを1枚送るだけで済み、それを読んで原因を切り分けたのは Claude Code だった
つまり私は Mac にも、Claude Code が動いている PC にも一度も触れていません。コードも見ていないし、App Store Connect にもログインしていません。私が物理的に関わったのは、手元の iPhone に届いた TestFlight ビルドを触って異常を伝えることだけ。Claude Code の役割は「調査・コード修正・ビルド・配信・申請」、私の役割は「方針決め」と「実機で触って異常を伝える目と手」という分担でした。
修正は「触らない」だけ。WKWebView(iOS の Web 表示部品)のセッションは WKWebsiteDataStore が握っているので、ここを消さなければログインは保持されます。
2. Mastodon の ID は Int ではなく String で扱う
古いコードは Status(投稿)の ID を Int として保持し、NSString 経由で数値化していました。Mastodon の ID は時間とともに桁が増え続けるため、Int で扱うとオーバーフローの危険があります。素直に文字列のまま扱うのが正解でした。
// BEFORE: NSString 経由でパース(巨大 ID はオーバーフローの恐れ)
public class Status { public var id: Int! }
if let statusId = (item["id"] as? NSString)?.integerValue {
status.id = statusId
}
let body = ["since_id": "\(sinceId)"] // 毎回文字列に変換
// AFTER: JSON から String として直接取り出す
public class Status { public var id: String! }
if let statusId = item["id"] as? String {
status.id = statusId
}
if !sinceId.isEmpty { body["since_id"] = sinceId } // 空なら送らない
ID を String 化すると大小比較が文字列比較になってしまうので、「桁数が多いほうが新しい、桁が同じなら辞書順」という比較ヘルパーを実装し、ユニットテストを16件付けて担保しています。
3. OAuth:password grant から Authorization Code flow へ
この「何 pt めり込んでいるか」を言葉で正確に伝えるのは難しいのですが、私がやったのは 実機の画面をスクショして送るだけ。ズレの量も方向も、Claude Code が画像から読み取って原因を絞り込んでいきました。テキストだけのやり取りなら何往復もかかったはずの問題が、画像1枚で前に進んだ場面です。実際に私が送った before / after の実機スクショが以下です。
Before: 下端がツールバーにめり込んでいるAfter: 4辺をピン留めしてズレが解消私が実機で撮って Claude Code に送った before / after。この画像から Claude Code がズレ量を読み取った。
Storyboard の Auto Layout:translatesAutoresizingMaskIntoConstraints = false のビューは、レイアウトのたびに制約値へ戻る
App Store 審査リスク:WebView でサイトを表示するだけのアプリは、ガイドライン 4.2(minimum functionality=最低限の機能しかない)で reject されることがある。マルチポスト・OAuth・通知・課金といったネイティブ層が、その防御ラインになっている。
結果として 2.7.2 はリリース済み、2.7.3 を App Store 審査に提出できる状態まで持っていけました。実作業期間は約1週間です。
よくある質問
Q. コードは自分で書いたんですか?
A. いいえ、1行も書いていませんし、コードを見てすらいません。私は「作り直さず近代化する」という方針を決めてスマホから指示しただけで、コード修正・調査・ビルド・TestFlight 配信・App Store 申請まで Claude Code が Mac にヘッドレス(SSH 経由)で実行しました。Mac にも Claude Code が動く PC にも触れていません。私が物理的にやったのは、手元の iPhone に届いた TestFlight ビルドを触って異常を報告することだけ。App Store Connect への申請も Claude Code が API 経由で行っています(App Store の初期設定は旧アプリ時代に完了済みだったため、新規ログインは不要でした)。
Q. シミュレータで動くのに実機で落ちるのはなぜ?
A. 動的フレームワークの埋め込み(Embed Frameworks)有無、コード署名、実機固有のセーフエリアなど、シミュレータが肩代わりしてくれる部分が実機では露出するためです。今回の Realm クラッシュはまさにこれで、リリース前に必ず TestFlight などで実機に配信して起動確認すべきです。
Q. 古いアプリは作り直したほうが速くないですか?
A. 差別化機能がまだ動いているなら、作り直しはおすすめしません。「動く」を再現するコストが高いからです。逆に、コア機能自体が時代遅れ・破綻している場合は書き直しのほうが速いこともあります。判断材料は「壊れているのは中身か、表面か」です。
Q. WebView 内で OAuth を完結させるのは安全ですか?
A. セキュリティ的には ASWebAuthenticationSession のほうが望ましいです。今回は二重ログインを避ける UX 優先で WKWebView 内に閉じましたが、自分が管理する認可サーバーでないアプリでは Apple 推奨方式を検討してください。
HTML テンプレートに font-family: 'Noto Sans JP' を指定して動画を生成すると、日本語テキストが豆腐(□□□)になります。HyperFrames のログには「Fetched 1116 font face(s) for "Noto Sans JP" from Google Fonts」と出るのに、です。
原因
Google Fonts は Noto Sans JP を Unicode の範囲(サブセット)ごとに分割して配信します。HyperFrames がキャッシュしていたのは Latin サブセット(81KB)のみで、日本語グリフを含む CJK サブセット(1 ウェイトあたり 4〜5MB)はダウンロードされていませんでした。
A. cron が weekly_draft.sh を起動して Claude Code が走るが、途中で詰まったり権限が足りなかったりするとログにエラーが残ってドラフトは作られない、というだけ。次の金曜にまた走るだけなので、致命的な事故にはならない。
Q. なぜ Claude Code を 2 セッションに分けたのですか?1 セッションで両方できないのですか?
A. 物理的に別マシン(一方は GPU 搭載 PC、一方は普段使いの Linux PC)なので、それぞれの環境に張り付いた Claude Code セッションが触れる範囲が違います。別セッションで動かすことで、それぞれ自分のリポだけ意識すればよく、認知負荷が下がります。git の仕様書を contract にするとこのスタイルが成立します。
Q. 全自動公開はやらないのですか?
A. やりません。「人間が最後に見る」前提にすることで、AI による生成を試行錯誤しやすくなる、という設計です。誤情報・薬機法・景表法などのリスクを完全には自動チェックできないため、最後の関門は人間に残します。
A. 丸 1 日です。RSS 偵察スクリプト・MCP サーバ・Blogger API 連携・cron 設定・CLAUDE.md(NG ワードや文体ガイド含む)まで、CLI で対話しながら Claude Code が書き上げました。普通なら仕様策定・実装・デバッグで数週間かかる規模の仕組みが、対話するだけで一気に動くところまで進みます。
Q. 文体や記事構成は AI とどうやって揃えるのですか?
A. 過去記事を Blogger API でローカルに取得し、Claude Code に文体の特徴・章立て・カテゴリ傾向を分析させて memory に保存しました。memory はセッションをまたいで残るので、新規記事を書くたびに毎回プロンプトに長文の文体ガイドを貼り付ける必要がありません。Claude Code は「過去の自分の延長」として記事を組み立てます。