
本記事は個人の技術記録であり、売買や投資を勧めるものではありません。売買ロジックや成績には触れません。
はじめに:どんなシステムか
日本の先物市場の日中セッションとナイトセッションに合わせて、Windows PC を平日ほぼ24時間動かし続ける自動取引システムを作っています。言語は Python で、証券会社が提供する取引ツールと、その API を使います。
このシステムには、次の3つの前提があります。
- 自宅の常駐 PC で動かす。 API を使うには取引ツールが起動し、ログインしている必要があるためです。
- 取引は API、ログインは画面操作の自動化で行う。 ログインだけは API で行えないため、画面操作を自動化しています。
- 異常時だけメールで通知する。 「メールが来なければ正常」という運用です。
シリーズ1回目の今回は、システム全体の構成を説明します。
全体像:3つの層で役割を分ける
システムは、時間の単位と壊れやすさで3つの層に分けています。

以下、下の層から順に見ていきます。
OS 層:PC とプロセスを起こす
朝の起動
PC は BIOS の RTC(リアルタイムクロック)機能で、平日の朝 06:00 に自動で電源が入ります。その後、Windows のタスクスケジューラが各プロセスを起動します。
登録しているタスク
タスク | 実行タイミング | 役割 |
|---|---|---|
MondayLogin | 月 06:35 | 週の最初の自動ログイン |
AutoPull | 月〜金 06:40 |
|
Main | 月〜金 06:50 |
|
補助プロセス | 月〜金 06:52〜 | 本体とは独立したプロセス群 |
参照データ取得 | 月〜金 07:30 | 取引の前に必要なデータを取得 |
これらのタスクは、register_task.ps1 で一括登録できるようにしています。
ポイントは Main タスクの扱いです。main.py は月曜の朝に起動したら、金曜まで止めずに動かし続けます。それでも毎朝 06:50 にタスクを登録しているのは、途中でプロセスが落ちていた場合に翌朝起こし直すための保険です。MultipleInstances = IgnoreNew を設定しているので、すでに動いているときは新しく起動しません。
補助プロセスを本体と分けているのは、どれかが落ちても、ほかを巻き込まないようにするためです。
週末は、土曜にシャットダウンし、日曜に Windows Update を適用するために停止します。
スリープと Windows Update への対策
常駐システムの大敵は、意図しないスリープと自動再起動です。
- スリープ: OS の設定で禁止したうえで、
main.py自身もSetThreadExecutionStateを呼んでスリープを抑えています。二重の対策です。 - Windows Update: アクティブ時間の設定、プレビュー更新の無効化、ログオン中の自動再起動の禁止を組み合わせています。更新そのものは止めず、週末の停止時間に適用します。
アプリ層:main.py が1日を回す
main.py は、1日の中の「何時に何をするか」をすべて受け持つ本体です。
ジョブの管理
APScheduler で約30本のジョブを管理しています。時刻の指定はすべて CronTrigger で、実行の遅れは60秒まで許容します。売買のほかに、価格の記録、建玉の突合、限月ロールオーバーの確認、ログイン状態の確認などがあります。
祝日には取引をしないため、istradingday() で判定して、取引関連のジョブをスキップします。
状態の保持
ポジションなどの状態は、1つのプロセスの中で持ちます。同時に state.json にも保存しているので、再起動しても状態を引き継げます。
起動時の安全策
起動するときに、次の3つを確認します。
- 管理者権限があるか。 ないと取引ツールを制御できないため、起動を止めます。
- すでに起動していないか。 ロックファイルで二重起動を防ぎます。
- 前回はどう終わったか。 前回のハートビート(後述)からの経過時間と、OS のイベントログ(再起動を引き起こしたプロセスなど)を記録します。異常終了から復旧した場合は、件名を変えてメールを送ります。
また、終了シグナルを受け取ったときは、その理由をログに残します。
落ちても戻れる仕組み
- ハートビート: 30分ごとにログへ書き込みます。前回の書き込みから時間が空きすぎていれば「スリープしていた」と判断し、復旧処理を行います。ログには現在値も載せているので、稼働確認にも使えます。
- キャッチアップ: 起動が遅れたときやスリープから復帰したときは、実行し損ねた処理(価格の記録や前処理など)を判定して補います。
エラーの通知
logger.error() を呼ぶと、自動でメールが送られます。同じエラーのメールは5分に1通までに抑えています。
認証層:ログインを本体から切り離す
取引ツールへのログインは、画面操作と二段階認証を伴うため、失敗や固まりが起きやすい処理です。そこで full_login.py という別スクリプトに切り出し、本体とは別のプロセスで実行しています。
ログインを実行する経路は、曜日によって2つあります。
- 月曜: 週末に止めたあとなので、
main.pyはまだ動いていません。そのためMondayLoginタスクが、リトライ付きのラッパーloginwithretry.pyを実行します。 - 火〜金:
main.pyが前日から動き続けているので、main.py内のジョブが同じ手順を実行します。手順は「ツールを強制終了 → ログイン → 失敗したら待って再試行(最大3回)」です。
どちらの経路でも、失敗したらメールで通知します。
なお、2026年9月には、証券会社の夜間メンテナンスの終了が遅れ、ログインが失敗することが続きました。そのため、ログインの開始時刻を5分遅らせています。
朝の流れを時系列で見る
ここまでの内容を、平日の朝の流れにまとめます。
06:00 BIOS が PC を起動
06:35 取引ツールにログイン(月曜はタスク、火〜金は main.py のジョブ)
06:40 AutoPull で git pull
06:45 main.py が restart.flag を確認 → あれば自己再起動(os.execv)
06:50 Main タスク(main.py が稼働中なら何もしない)
06:52〜 補助プロセスが起動
06:55 祝日チェック
07:00 ログイン状態の確認
07:30 API の接続確認
08:05〜 取引関連の各ジョブが始まるコードの更新は「06:40 に pull → 06:45 に再起動の判定」という順番にして、取引が始まる前に必ず終わらせます。自己再起動は、プロセスを終了してから起動し直すのではなく、os.execv でその場で自分自身を実行し直す方式です。
再起動フラグは、プロセスごとに別のファイルにしています。1つを共有すると、先に読んだプロセスがフラグを消してしまい、ほかのプロセスが再起動を見逃すからです。
設計の考え方
最後に、このシステムを作るうえで意識した5つの方針をまとめます。
- 「いつ起こすか」と「1日で何をするか」を分ける。 週・日の単位は OS に、分・秒の単位はアプリに任せます。
- 壊れやすい処理は別プロセスに出す。 ログインが固まっても、本体まで巻き込まれません。
- 落ちることを前提に作る。 ハートビート、キャッチアップ、状態の保存によって、復帰を自動化します。
- 異常だけを通知する。 正常時にはメールを送りません。通知が多すぎると、本当の異常を見落とすためです。
- 直さないと決めた弱点は、記録に残す。 たとえば、稼働中に停電が起きると、次の平日の朝まで
main.pyは再起動されません。停電はめったに起きず、被害も小さいため、本番で検証できない復帰コードを足すよりも許容する方を選びました。
次回予告
②では自動更新(git pull)と自己再起動の仕組みを、③では実際に起きた事故の記録と再発防止策を書く予定です。
この記事が役に立ったらフォローしてください

