SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

トレーディングボット用VPSで本当に重要なこと

トレーディングボットに必要なのは、systemdの再起動設定、UTC時刻、APIキー保護、heartbeat監視です。systemdは10秒間に5回で再試行を諦めるため、設定と遅延の限界を確認します。

トレーディングボットにVPSが必要とするもの

トレーディングボット用のVPSは、4つの点で評価します。プロセスが停止した後に復旧するか、時刻が正確か、API(application programming interface)キーを盗まれにくくできるか、停止したときに把握できるかです。個人向けボットでは、処理速度の優先度は大幅に低くなります。注文経路で時間がかかるのは、ホスト上のPythonではなく、ブローカーとホストからブローカーまでの距離だからです。

これはエンジニアリングガイドです。ここに金融に関する助言はありません。取引戦略についても説明しません。

稼働率はセールスページの数字ではなく、再起動の運用です

表示される稼働率の保証はサービスによって異なります。AWS は、単一の EC2 インスタンスについて少なくとも 99.5 percent、複数のアベイラビリティーゾーンにまたがる対象構成について 99.99 percent を規定しています。これらの保証が対象とするのはインフラストラクチャの可用性であり、bot の健全性ではありません。未処理の例外、再接続しない websocket、または OOM (out of memory) killer によって bot が停止しても、サーバー自体は稼働し続けます。したがって重要なのは、プロセスが終了した後の 10 秒間に何が起きるかです。

bot は systemd service として実行し、再起動は init system に任せます。unit file で設定できます。

[Unit]
Description=Trading bot
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=bot
WorkingDirectory=/opt/tradingbot
EnvironmentFile=/etc/tradingbot/api.env
ExecStart=/opt/tradingbot/venv/bin/python -m tradingbot
Restart=always
RestartSec=10
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/tradingbot

[Install]
WantedBy=multi-user.target

StartLimitIntervalSec=0 は見落とされやすい行です。upstream systemd の既定値では、最初の起動と手動起動を含め、10 秒間に 5 回まで起動できます。manager の設定でこの既定値を上書きできます。上限に達すると自動再起動の試行は停止しますが、間隔の経過後であれば unit を手動で起動したり、timer や socket から起動したりできます。0 に設定するとレート制限が無効になり、crash-loop する bot は停止せずに再試行を続けます。RestartSec=10 はこのループが再接続を繰り返して exchange に過剰な負荷をかけることを防ぎます。

ファイルを信頼する前に確認し、その後で起動します。

sudo systemd-analyze verify /etc/systemd/system/tradingbot.service
sudo systemctl daemon-reload
sudo systemctl enable --now tradingbot
systemctl status tradingbot

enable は再起動後も bot を動かし続けるための設定です。kernel の更新では再起動が必要になります。bot がひそかに停止し続けていないか確認するには、systemd に再起動カウンターを表示させます。

systemctl show tradingbot -p NRestarts
journalctl -u tradingbot --since "24 hours ago" | tail -50

NRestarts=0 は、カウンターが最後にリセットされてから発生した自動再起動ジョブがないことを示します。正常稼働していることや、1 週間クラッシュしていないことを証明するものではありません。手動での再起動と systemctl reset-failed によってカウンターはリセットされます。また、応答しなくなった bot でも 0 と表示されることがあります。NRestarts=812 は 812 回の再起動ジョブを数えるだけで、exchange への再接続や取引の成功数ではありません。さらに、それらがいつ発生したかも示しません。時刻と原因を確認するには journal を調べます。bot が接続する前の失敗も確認対象です。daily report などの定期ジョブ用 timer を含む unit file の全体構造については、systemd service としてプログラムを実行するで説明しています。

UTC に設定し、同期済みであることを確認する

Exchange API は、署名付きリクエストの検証にタイムスタンプを使用します。Binance Spot のデフォルトの受信ウィンドウは 5 秒で、サーバー時刻より少なくとも 1 秒進んだタイムスタンプは拒否されます。時計がずれると、認証失敗に見えるエラーが発生します。そのため、時刻を確認する前に何時間も鍵をローテーションしてしまうことがあります。Binance 系 API では、メッセージは文字どおり Timestamp for this request was 1000ms ahead of the server's time です。

サーバーを UTC に設定します。ローカルタイムゾーンを使用すると、表示時刻に夏時間による変化が生じます。一方、API が使用する Unix タイムスタンプは、表示タイムゾーンを変更しても変化しません。

sudo timedatectl set-timezone UTC
timedatectl

Ubuntu は 25.10 以降、デフォルトで chrony を使用します。古いインストール環境では、SNTP(Simple Network Time Protocol)クライアントである systemd-timesyncd を使用できます。systemd-timesyncd は時計を調整しますが、複数のサーバーを同時にポーリングして、誤った時刻ソースを検出することはできません。代わりに chrony を使用します。

sudo apt update && sudo apt install -y chrony
sudo systemctl enable --now chrony
chronyc tracking
chronyc sources -v

chronyc tracking から読み取る行は System time です。たとえば System time : 0.000031415 seconds fast of NTP time のようになります。小さい値は、chrony の NTP クロックに残っている補正量が小さいことを示します。正確性を判断する前に、同期状態、Root delay、Root dispersion も確認してください。Leap status : Not synchronised と表示される場合、サーバーが応答していても chrony は同期されていません。測定値が不正確すぎるとして拒否されることがあります。1 分待ってから再度確認し、ファイアウォールのルールを変更するのはその後にしてください。

コピーする場所に API key を置かない

漏えいした exchange key は、漏えいした SSH key より危険です。withdrawal permission があると、即座に資金を引き出せるためです。リスクの大半は、2 つの習慣で抑えられます。

まず、bot key に withdrawal permission を決して付与しないでください。exchange が対応している場合は、key をサーバーの IP address にバインドします。盗まれた key をほぼ無価値にできる、最も重要な対策です。

次に、secret を code directory の外に置きます。/opt/tradingbot 内のファイルは、遅かれ早かれ git repository または backup archive に入ります。systemd が読み取る root 所有のファイルに保存してください。

sudo install -d -m 750 -o root -g bot /etc/tradingbot
sudo install -m 640 -o root -g bot /dev/null /etc/tradingbot/api.env
sudo nano /etc/tradingbot/api.env

このファイルには、引用符と export を含まない plain KEY=value 行を記述します。Mode 640 では、root owner に read/write access を付与し、group bot のメンバーに read access のみを付与します。他の user には権限を付与しません。sudo -u bot cat /etc/tradingbot/api.env で確認し、続いて group bot に所属しない unprivileged user でも確認します。この場合は読み取りに失敗しなければなりません(Permission denied)。

bot 自体を root または login user として実行してはいけません。service を開始する前、または group bot が所有するファイルを作成する前に、nologin shell と /var/lib/tradingbot を home directory に設定した system account を作成します。

sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/lib/tradingbot --create-home bot

各 flag の意味と、ProtectSystem=strict で実際にできる範囲については、unprivileged user として service を実行するで説明しています。その他の server baseline、SSH keys、firewall については、新しい VPS の最初の 10 分を参照してください。

ブローカーより先に停止を検知する

systemctl statusはプロセスが実行中であることを示します。ボットが実際に処理していることまでは示しません。停止した websocket に対してプロセスが再試行ループを続けている場合でも、上記の unit のプロセスチェックは通過します。

代わりに heartbeat を使用します。Uptime Kuma には push monitor があります。これは、ボットが一定間隔で URL を呼び出すことを前提とし、呼び出しが届かなくなるとアラートを送信します。呼び出しは main loop の末尾に追加します。ボットが稼働していることを証明できる処理(market data の読み取りに成功した箇所など)の後に置いてください。

curl -fsS "http://monitor.example.com:3001/api/push/YOUR_TOKEN?status=up&msg=loop_ok"

monitor の間隔は、通常の揺らぎで通知が発生しないよう、loop の実行時間の約 2 倍に設定します。monitor はボットとは別のサーバーで実行してください。監視対象と同時に停止する monitor では、何も報告できないためです。設定方法は Uptime Kuma によるセルフホスト型ステータス監視で説明しています。

ディスクアラートも追加します。詳細なログを書き込むボットは数週間で root filesystem を使い果たすことがあります。ディスクが満杯になると、network call ではなく database write が停止するため、症状が分かりにくくなります。journalctl --vacuum-time=14dと /etc/systemd/journald.conf 内の SystemMaxUse= 行により、journal のサイズを制限できます。

率直な話: レイテンシの大部分はホストでは決まりません

ここで、取引向け VPS 製品の市場は技術的な話から離れます。マーケティングページではサブミリ秒の数値を掲げ、約定を左右するのはホストであるかのように示します。しかし、ほとんどすべての個人向け bot では、そうではありません。

注文は、bot からパブリックインターネットを経由して、取引所またはブローカーのエンドポイントへ送信されます。この経路は、物理的な距離と、プロバイダー間のピアリングに大きく左右されます。さらに、ブローカー側のシステムでキュー処理、リスクチェック、レート制限が行われます。

推測せずに測定してください。curl は、実際のエンドポイントへの接続時間と最初のバイトを受信するまでの時間を表示します。

curl -s -o /dev/null -w 'dns=%{time_namelookup}s connect=%{time_connect}s ttfb=%{time_starttransfer}s\n' \
  https://api.kraken.com/0/public/Time
mtr -rwzc 100 api.kraken.com

契約する前に、候補サーバーからこれを実行してください。connect が 0.180 秒の場合、DNS 解決と TCP 接続が含まれます。ただし、どの大陸にいるかまでは判断できません。connect が 0.004 秒で、ttfb が 0.140 秒の場合、その差には TLS の確立、リクエストの送信、ネットワーク遅延、サーバー処理が含まれます。ホストを変更すると、これらの一部に影響する可能性があります。そのため、候補地から測定した結果を比較してください。

では、ホストが重要になるのはいつでしょうか。取引所と同一施設にコロケーションするか、クロスコネクトで接続し、キュー内の位置を競う場合です。これは、異なる予算が必要な別のビジネスです。また、自分のコードがボトルネックになる場合も該当します。毎ティックで全履歴に対してインジケーターを再計算する bot は、ループごとに CPU を 200 ミリ秒消費することがあります。これは、自分で制御できる実際のレイテンシです。より高速なサーバーを探す前に、ループをプロファイリングしてください。

選ぶホストで重要なのは、地理的な位置、安定したネットワーク、そして OOM killer が動作する余地を与えない十分なメモリです。ティック履歴をローカルデータベースに保存する場合は、メモリを増設してください。

本番前の短いチェックリスト

  1. systemctl is-enabled tradingbot は enabled を出力し、サービスは sudo reboot 後も稼働します。
  2. chronyc tracking は同期状態を報告し、システム時刻のずれが数ミリ秒未満で、root delay と dispersion がタイミング予算内に収まっていることを確認します。
  3. API key には取引権限だけを付与し、出金権限は付与しません。取引所が対応している場合は IP allowlist も設定します。
  4. sudo systemctl kill -s SIGKILL tradingbot でプロセスを終了すると、RestartSec の待機時間と起動時間の後にプロセスが復旧します。
  5. heartbeat monitor は、設定した間隔の後に通知を送り、bot を意図的に停止した場合は再試行します。
  6. ログの容量が制限され、root filesystem に df -h の空き容量があります。

実際の資金を使う前に、取引所の sandbox または paper mode で全体を 1 週間実行します。その 1 週間の間に、上記の各項目は少なくとも 1 回失敗します。これが 1 週間実行する目的です。

FAQ

取引ボットには低レイテンシまたはベアメタルのサーバーが必要ですか?

同じ取引所で他の自動取引参加者と約定速度を競う場合だけ必要です。通常は、汎用 VPS ではなくコロケーションを利用します。個人向けのボットでは、往復時間の大部分を地理的な距離とブローカー側の処理が占めます。そのため、API エンドポイントに近いサーバーを選び、より高速な環境に料金を支払う前に curl と mtr で測定してください。

取引ボットにはどの程度の RAM と CPU が必要ですか?

単一戦略のボットの多くはネットワーク待ちで、イベント間はアイドル状態です。プロセス内にティック履歴を保持したり、ローカルデータベースを実行したりすると、メモリが制約になります。推測で判断せず、OOM kill メッセージがないか free -h と journal を確認してください。

取引所 API がタイムスタンプエラーでリクエストを拒否するのはなぜですか?

リクエストのタイムスタンプが、取引所の許容範囲外です。クロックのずれとリクエストの遅延が、どちらも影響します。chrony をインストールし、chronyc tracking で System time のオフセットが小さく、leap status が同期済みであることを確認してください。root delay と dispersion も確認します。マシンを UTC に設定すると表示時刻は統一できますが、クロックのずれは修正されません。API key をローテーションしても、クロックの問題は解決しません。

ボットが夜間に停止しても気付けない状況を防ぐにはどうすればよいですか?

systemd で Restart=always と StartLimitIntervalSec=0 を指定して実行してください。クラッシュループが start rate limit に達する前に再試行されます。さらに、各ループが正常に完了した時点でボットが送信する heartbeat を追加します。restart はプロセスを処理します。heartbeat は、プロセスが生存しているものの停止している状態を検出します。

ボットと監視を同じ VPS で実行できますか?

実行できます。ただし、障害が発生した日に監視が誤った状態を伝えることになります。ボットを停止させる障害では、監視も同時に停止するためです。アラート機能は別のマシンに配置してください。できれば、異なるプロバイダーまたはリージョンを使用します。ボットのサーバーは、ボットとそのログ専用にしてください。

この記事は役に立ちましたか?