0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude APIで自動売買エージェントを個人開発した話【リスク管理編】

0
Posted at

前回はバックテスト最適化を解説しました。今回は 実際に資金を守るためのリスク管理レイヤーの実装です。


リスク管理の全体像

自動売買で最も重要なのは「いくら稼ぐか」より「いくら失わないか」です。Hermes Agent には複数の防衛レイヤーがあります。

1. ポジションサイジング    — 1トレードのリスクを資産の2%以内に
2. ATRボラティリティガード — 異常なボラに自動でサイズ半減
3. 最大ポジション数制限   — 同時8ポジションまで
4. サーキットブレーカー   — 連続損失N回でEXECUTE停止
5. ドローダウン停止       — 総資産がピークから X% 下落で停止
6. セクター集中制限       — 同セクターは最大N枚
7. VIXレジームフィルター  — 恐怖指数が高い局面は見送り
8. 経済指標ブロック       — CPI/FOMC前60分はStage 1でHOLD

ポジションサイジング

「1トレードで資産の2%しか失わない」を実現します。

// position-sizer.ts
const riskTarget = equity * (riskPct / 100);    // 例: 10000 × 2% = 200ドル
const quantity   = Math.floor(riskTarget / Math.abs(entry - stopLoss));
// 例: 200 / 5ドル(SL幅) = 40株

// 重要:equity(含み益込み)ではなく buying_power(使える現金)で上限
const capital      = buyingPowerCap ?? equity;
const maxByCapital = Math.floor(capital / entry);
quantity = Math.min(quantity, maxByCapital);

このコードに至るまで「Alpaca 403 insufficient buying power」エラーで詰まりました。equity は含み益で膨らむため、既存ポジションがある状態では実際の buying power を大きく超える注文が生成されてしまいます。buying_power(実際の買付余力)でキャップすることで解決しました。

アセット別の計算

アセット 単位 equity参照元 最小単位
株数(整数) Alpaca equity 1株
暗号資産 小数可 Alpaca equity 0.0001
FX units(整数) OANDA NAV 1,000 unit

サーキットブレーカー

連続損失が閾値(デフォルト3回)に達すると EXECUTE をブロックします。

// memory.ts
getConsecutiveLosses(): number {
  const closed = this.entries
    .filter(e => e.type === "real" && e.outcome)
    .sort((a, b) => b.closedAt.localeCompare(a.closedAt));

  let count = 0;
  for (const e of closed) {
    if (e.outcome === "LOSS") count++;
    else break; // WINがあったらリセット
  }

  // 最後の損失から24時間以上経過していたら自動リセット
  const timeoutH = parseFloat(process.env.CIRCUIT_BREAKER_TIMEOUT_H ?? "24");
  if (count > 0 && ageH >= timeoutH) return 0;

  return count;
}

重要な設計判断:タイムアウト機能。ブレーカーが発動したまま次の WIN を記録できないデッドロック(「ブレーカー発動中は EXECUTE 禁止 → EXECUTE しないと WIN が記録されない」)を防ぐため、24時間後に自動解除します。


ドローダウン停止

口座残高がピーク比 X% 以上下落したら全トレードを停止します。

// hermes.ts
if (drawdownPct >= ddHaltPct) {
  logInfo(`[DD HALT] Peak $${peak} → current $${current} = ${drawdownPct.toFixed(1)}% DD. EXECUTE blocked.`);
  return { blocked: true, reason: "DD halt" };
}

口座残高は毎サイクル Alpaca/OANDA API から取得して logs/equity.jsonl に記録しています。


経済指標ブロック

Finnhub の経済指標カレンダーを取得し、CRITICAL イベント(NFP、FOMC、CPI、GDP)の60分前はすべての EXECUTE をブロックします。

function imminentEventBlock(events: EconomicEvent[]): string | null {
  for (const e of events) {
    if (e.tier === "critical" && e.minutesUntil < 60) {
      return `[CRITICAL] "${e.event}" in ${e.minutesUntil}min`;
    }
    if (e.impact === "high" && e.minutesUntil < 30) {
      return `[HIGH] "${e.event}" in ${e.minutesUntil}min`;
    }
  }
  return null;
}

このチェックは Stage 1 で行うため、Claude を呼ぶ前にブロックできます(APIコスト節約)。


ファントムトレードとキャリブレーション

Claudeが WAIT を選んだとき、「もしエントリーしていたら?」を仮想トレードとして記録します。

// hermes.ts(WAIT時)
if (isMarketTradeable(symbol)) {
  this.memory.phantomRecord({
    symbol, direction, entryPrice: indicators.price,
    stopLoss: decision.stop_loss ?? preliminary.stopLoss,
    takeProfit: decision.take_profit ?? preliminary.takeProfit,
    reasoning: decision.reasoning_brief,
  });
}

phantom の WIN/LOSS が蓄積されると、Claude へのコンテキストに警告が入ります:

Calibration: You have been too conservative — your WAITs are
missing more wins than losses.

これにより「Claudeが慎重になりすぎて勝てるトレードを見逃している」状態を自動検知・補正できます。


リスクパラメータの設定例(.env)

RISK_PER_TRADE_PCT=2       # 1トレード最大リスク(資産の2%)
MAX_POSITIONS=8            # 同時最大ポジション数
CIRCUIT_BREAKER_LOSSES=3   # 連続損失でブレーカー発動
DD_HALT_PCT=15             # ドローダウン15%で全停止
MAX_ATR_PCT=3.0            # ATR%がこれ以上ならサイズ半減

まとめ

実際にお金を動かすシステムでは、「どうやって稼ぐか」よりも「どうやって守るか」の設計のほうが重要です。Hermes Agent は複数の防衛レイヤーが独立して機能しており、一つが突破されても他が守る構造になっています。

次回(第5回・最終回)は 本番運用とバグ修正の実録。実際に発生したバグとその原因分析を、コード差分と共に詳しく紹介します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?