RiskGuardian(コツコツドカン防止)¶
概要¶
RiskGuardian は、「コツコツ稼いでドカンと負ける」パターンを防ぐための多層防御機構です。
問題の背景
オプション売り戦略は勝率が高い一方、一度の大負けで複数回の勝ちを帳消しにするリスクがある。 Geminiとの議論で「口座の50%を失わない」ための具体的な防御策を設計。
3層防御アーキテクチャ¶
graph TD
A[Level 1: ポジション管理] -->|エントリー前| B{can_enter_position?}
B -->|No| C[エントリー拒否]
B -->|Yes| D[ポジションオープン]
D --> E[Level 2: リスク監視]
E -->|保有中| F{should_exit_position?}
F -->|Yes| G[通常イグジット]
F -->|No| H[継続保有]
H --> I[Level 3: 緊急対応]
I -->|危機時| J{is_emergency_exit_required?}
J -->|Yes| K[全ポジション強制決済]
J -->|No| E
Level 1: ポジション管理(エントリー前)¶
can_enter_position() チェック項目¶
def can_enter_position(
self,
symbol: str,
strategy: str,
risk_amount: float
) -> tuple[bool, str]:
"""新規ポジションを建てられるかチェック"""
# 1. VIXチェック
if self.current_vix > self.config.vix_limit:
return False, f"VIX過高 ({self.current_vix:.1f} > {self.config.vix_limit})"
# 2. アロケーションチェック
if self.current_allocation_pct > self.config.max_allocation_pct:
return False, f"アロケーション上限 ({self.current_allocation_pct:.1f}%)"
# 3. セクター集中チェック
sector = self._get_sector(symbol)
if self.sector_count[sector] >= self.config.max_per_sector:
return False, f"セクター集中 ({sector}: {self.sector_count[sector]})"
# 4. 決算フィルター
if self._has_earnings_before_expiry(symbol):
return False, "決算リスク"
# 5. 相関チェック
if self._is_highly_correlated(symbol):
return False, f"高相関 (SPY相関 > {self.config.max_correlation})"
return True, "OK"
設定パラメータ($50,000口座向け)¶
| パラメータ | 値 | 根拠 |
|---|---|---|
| Max Allocation | 60% ($30,000) | 40%は常に現金で保持 |
| VIX Limit | 30 | VIX 30超えで新規停止 |
| Max per Sector | 4 | 同一セクター最大4ポジション |
| Max Correlation | 0.7 | SPYとの相関制限 |
Level 2: リスク監視(保有中)¶
should_exit_position() チェック項目¶
def should_exit_position(
self,
position: OptionSpread,
current_pnl_pct: float
) -> tuple[bool, str]:
"""ポジションを決済すべきかチェック"""
# 1. VIX急騰チェック
if self.current_vix > self.config.vix_limit:
return True, "VIX急騰"
# 2. 日次ドローダウンチェック
if self.daily_drawdown_pct > self.config.daily_dd_limit:
return True, "日次DD超過"
# 3. ガンマリスクチェック(DTE < 3)
if position.dte < self.config.gamma_filter_dte:
return True, "ガンマリスク"
# 4. 損切りチェック(プレミアム倍率ベース)
if current_pnl_pct < -self.config.stop_loss_pct:
return True, "損切り"
# 5. 利確チェック
if current_pnl_pct > self.config.profit_take_pct:
return True, "利確"
return False, ""
設定パラメータ¶
| パラメータ | 値 | 根拠 |
|---|---|---|
| Daily DD Limit | 3% ($390) | 日次ドローダウン制限 |
| Gamma Filter | DTE < 3 | 残存3日で強制決済 |
| Stop Loss | 200% of Credit | プレミアム倍率ベース |
| Profit Taking | 50% of Max Profit | 勝ち逃げ |
Level 3: 緊急対応(危機時)¶
is_emergency_exit_required() トリガー¶
def is_emergency_exit_required(self) -> tuple[bool, str]:
"""全ポジション強制決済が必要かチェック"""
# 1. VIX 30超え
if self.current_vix > 30:
return True, f"VIX緊急 ({self.current_vix:.1f})"
# 2. 日次DD 3%超え
if self.daily_drawdown_pct > 3.0:
return True, f"日次DD緊急 ({self.daily_drawdown_pct:.1f}%)"
# 3. 週次DD 6%超え
if self.weekly_drawdown_pct > 6.0:
return True, f"週次DD緊急 ({self.weekly_drawdown_pct:.1f}%)"
return False, ""
80:20 バーベル戦略¶
Gemini推奨の資金配分戦略:
口座 $50,000
├── Beat Shield (80% = $40,000)
│ ├── 役割: 防御・生活費
│ ├── 戦略: Put Credit Spread / Iron Condor
│ ├── リスク: 2% per trade ($1,000)
│ └── 最大ポジション: 8
│
└── Sunacchan Spear (20% = $10,000)
├── 役割: 攻撃・ボーナス
├── 戦略: Option Buying (Directional)
├── リスク: 1% per trade ($500)
└── 最大ポジション: 4
戦略別リスク設定¶
| 戦略 | 配分 | 1トレードリスク | 最大ポジション |
|---|---|---|---|
| Beat Shield | 80% | 2% ($1,000) | 8 |
| Sunacchan Spear | 20% | 1% ($500) | 4 |
「50%を失わない」シミュレーション¶
最悪シナリオ¶
初期口座: $50,000
最大アロケーション: 60% = $30,000
最悪ケース: 全ポジション同時最大損失
損失額: $30,000
残高: $50,000 - $30,000 = $20,000
残存率: 40%
リスク許容度
アグレッシブな設定では最大60%の損失が発生しうる。 ただし、12ポジション(Shield 8 + Spear 4)が同時に最大損失となる確率は極めて低い。
リカバリー計算¶
| 損失率 | 残高 | 復帰に必要なリターン |
|---|---|---|
| 10% | $45,000 | 11.1% |
| 20% | $40,000 | 25.0% |
| 30% | $35,000 | 42.9% |
| 40% | $30,000 | 66.7% |
| 50% | $25,000 | 100.0% |
実装詳細¶
core/risk_guardian.py¶
@dataclass
class RiskGuardianConfig:
"""RiskGuardian設定"""
# 口座設定
account_capital: float = 50000.0
# アロケーション
max_allocation_pct: float = 60.0
beat_allocation_pct: float = 80.0
spear_allocation_pct: float = 20.0
# リスク設定
beat_risk_per_trade_pct: float = 2.0
spear_risk_per_trade_pct: float = 1.0
# ポジション上限
beat_max_positions: int = 8
spear_max_positions: int = 4
max_per_sector: int = 4
# 監視閾値
vix_limit: float = 30.0
daily_dd_limit_pct: float = 3.0
weekly_dd_limit_pct: float = 6.0
gamma_filter_dte: int = 3
max_correlation: float = 0.7
# 損益設定
stop_loss_pct: float = 200.0 # プレミアムの200%
profit_take_pct: float = 50.0 # 最大利益の50%
class RiskGuardian:
"""多層防御リスク管理エンジン"""
def __init__(self, config: RiskGuardianConfig = None):
self.config = config or RiskGuardianConfig()
self._positions: List[OptionSpread] = []
self._daily_pnl: float = 0.0
self._weekly_pnl: float = 0.0
# Level 1
def can_enter_position(self, ...) -> tuple[bool, str]: ...
# Level 2
def should_exit_position(self, ...) -> tuple[bool, str]: ...
# Level 3
def is_emergency_exit_required(self) -> tuple[bool, str]: ...
# ヘルパー
def get_available_risk_budget(self, strategy: str) -> float: ...
def update_daily_pnl(self, pnl: float): ...
def reset_daily_stats(self): ...
ペーパートレードでの使用¶
# run_paper_trading.py
class PaperTradingEngine:
def __init__(self):
self.risk_guardian = RiskGuardian(RiskGuardianConfig(
account_capital=13000.0 # 仮想資本
))
async def _try_entry(self, symbol: str, strategy: str):
# RiskGuardianでエントリー可否をチェック
can_enter, reason = self.risk_guardian.can_enter_position(
symbol=symbol,
strategy=strategy,
risk_amount=self._calculate_risk(...)
)
if not can_enter:
logger.info(f"[{symbol}] エントリー拒否: {reason}")
return
# エントリー実行
await self._execute_entry(...)
async def _check_exits(self):
# 緊急決済チェック
is_emergency, reason = self.risk_guardian.is_emergency_exit_required()
if is_emergency:
logger.warning(f"⚠️ 緊急決済発動: {reason}")
await self._close_all_positions()
return
# 通常イグジットチェック
for position in self.positions:
should_exit, reason = self.risk_guardian.should_exit_position(
position=position,
current_pnl_pct=position.unrealized_pnl_pct
)
if should_exit:
await self._execute_exit(position, reason)
バックテストでの使用¶
# バックテストサマリーに追加される統計
{
"risk_guardian_stats": {
"entries_blocked": 45,
"block_reasons": {
"VIX過高": 12,
"アロケーション上限": 18,
"セクター集中": 8,
"決算リスク": 5,
"高相関": 2
},
"emergency_exits": 2,
"max_daily_dd": 2.8,
"max_weekly_dd": 4.5
}
}
ログ出力例¶
[RiskGuardian] Level 1 チェック:
VIX: 22.5 ✅
アロケーション: 32% ✅
セクター(Tech): 1/2 ✅
決算: なし ✅
相関: 0.45 ✅
結果: エントリー許可
[RiskGuardian] Level 2 チェック:
VIX: 28.5 ✅
日次DD: 1.2% ✅
DTE: 8日 ✅
PnL: +35% → 利確推奨
[RiskGuardian] ⚠️ Level 3 緊急発動:
理由: VIX 32.5 > 30
アクション: 全ポジション強制決済
関連ファイル¶
| ファイル | 役割 |
|---|---|
core/risk_guardian.py |
RiskGuardian本体 |
core/risk.py |
基本リスク計算 |
scripts/run_paper_trading.py |
ペーパートレード統合 |
scripts/run_beat_sunacchan_backtest.py |
バックテスト統合 |
更新履歴¶
| 日付 | 変更内容 |
|---|---|
| 2025-11-30 | $50,000口座向けに設定更新(ポジション数増加: Shield 4→8, Spear 2→4) |
| 2025-11-30 | Max Allocation を 40% → 60% に変更 |
| 2025-11-30 | セクター上限を 2 → 4 に変更 |
| 2025-11-29 | Gemini推奨パラメータに基づき実装 |
| 2025-11-29 | 80:20バーベル戦略を設定に反映 |
| 2025-11-29 | ペーパートレード・バックテストに統合 |