コンテンツにスキップ

PDT Guardian

PDT(Pattern Day Trader)ルール管理モジュール。$25,000未満の口座でのデイトレード制限を管理します。


概要

PDTルールとは

FINRA Rule 4210

$25,000未満の口座で5営業日に4回以上のデイトレードを行うと、口座が90日間凍結されます。

デイトレードの定義

同一銘柄を同一営業日にエントリー(買い/売りオープン)とエグジット(売り/買いクローズ)すること。


PDTGuardian の機能

機能 説明
週単位カウンター 5営業日(月〜金)で3回までのデイトレードを許可
$25k超で自動解除 口座残高が$25,000を超えると制限が自動解除
緊急時例外 VIX > 30 または損失 > 30%で即決済可能
記録保持 デイトレード履歴を14日間保持

定数設定

# core/risk_guardian.py

PDT_THRESHOLD_USD = 25000.0          # この金額以上でPDTルール解除
PDT_MAX_DAY_TRADES_PER_WEEK = 3      # 5営業日で最大3回
PDT_EMERGENCY_VIX_THRESHOLD = 30.0   # 緊急時VIX閾値
PDT_EMERGENCY_LOSS_PCT = 0.30        # 緊急時損失閾値(30%)

判定フロー

flowchart TD
    A[同日決済リクエスト] --> B{同日か?}
    B -->|No| C[✅ 許可]
    B -->|Yes| D{口座 ≥ $25k?}
    D -->|Yes| E[✅ 許可<br>PDT_UNRESTRICTED]
    D -->|No| F{VIX ≥ 30?}
    F -->|Yes| G[✅ 許可<br>EMERGENCY_VIX]
    F -->|No| H{損失 ≥ 30%?}
    H -->|Yes| I[✅ 許可<br>EMERGENCY_LOSS]
    H -->|No| J{週のデイトレード < 3回?}
    J -->|Yes| K[✅ 許可<br>PDT_ALLOWED]
    J -->|No| L[❌ ブロック<br>PDT_LIMIT_REACHED]

使用方法

初期化

from core.risk_guardian import PDTGuardian, create_pdt_guardian

# $13k口座でPDTGuardianを作成
pdt = create_pdt_guardian(initial_equity=13000.0)

毎日の更新

# 口座残高を更新($25k超で自動的に制限解除)
pdt.update_equity(portfolio.equity())

# VIXを更新(緊急時判定用)
pdt.update_vix(current_vix)

同日決済のチェック

# スプレッドのエントリー日を取得
entry_date = spread.opened_at

# エグジット前にPDTチェック
can_exit, reason = pdt.can_exit_same_day(
    symbol="AAPL",
    entry_date=entry_date,
    current_date=today,
    current_loss_pct=current_loss / max_loss,  # 損失率
)

if can_exit:
    # 決済実行
    execute_exit()

    # 同日の場合は記録
    if entry_date == today:
        pdt.record_day_trade(
            symbol="AAPL",
            trade_date=today,
            entry_time=entry_time,
            exit_time=datetime.now(),
            is_emergency=(reason.startswith("EMERGENCY")),
        )
else:
    # 翌日まで待機
    logger.warning(f"PDT制限: {reason}")

状態確認

# PDT状態のサマリー
summary = pdt.get_summary()
print(f"制限状態: {summary['status']}")
print(f"残りデイトレード: {summary['remaining_day_trades']}回")

# 残り回数を直接取得
remaining = pdt.get_remaining_day_trades(today)
if remaining == -1:
    print("無制限($25k以上)")
else:
    print(f"今週残り{remaining}回")

戦略への影響

Beat Shield

影響: 極めて低い

  • エントリー時DTE = 30-60日
  • 満期7日前に決済
  • 最短でも23日保有のためデイトレードにならない

Sunacchan Spear

影響: 中程度(要注意)

  • エントリー時DTE = 7-30日
  • モメンタム反転や損切りで同日決済の可能性あり
  • PDTGuardianで管理

$13k口座での動作例

月曜: AAPL Spear → モメンタム反転 → 同日決済(1回目 ✅)
火曜: MSFT Spear → 損切り → 同日決済(2回目 ✅)
水曜: NVDA Spear → 利確 → 同日決済(3回目 ✅ 最後の枠)
木曜: TSLA Spear → 反転 → 週4回目 → ❌ ブロック(翌日まで待機)
金曜: TSLA → 翌日決済OK ✅

→ 週明けでカウンターリセット → また3回使える

API リファレンス

PDTGuardian クラス

class PDTGuardian:
    def __init__(self, initial_equity: float = 13000.0):
        """初期化"""

    def update_equity(self, equity: float) -> None:
        """口座残高を更新"""

    def update_vix(self, vix: float) -> None:
        """VIXを更新"""

    @property
    def is_pdt_restricted(self) -> bool:
        """PDT制限が適用されるか"""

    @property
    def pdt_status(self) -> str:
        """PDT状態 ('RESTRICTED' or 'UNRESTRICTED')"""

    def can_exit_same_day(
        self,
        symbol: str,
        entry_date: date,
        current_date: date,
        current_loss_pct: float = 0.0,
    ) -> tuple[bool, str]:
        """同日決済が可能かチェック"""

    def record_day_trade(
        self,
        symbol: str,
        trade_date: date,
        entry_time: datetime,
        exit_time: datetime,
        is_emergency: bool = False,
    ) -> None:
        """デイトレードを記録"""

    def get_remaining_day_trades(self, current_date: date) -> int:
        """今週の残りデイトレード可能回数"""

    def get_summary(self) -> Dict[str, Any]:
        """PDT状態のサマリー"""

    def cleanup_old_records(self, keep_days: int = 14) -> int:
        """古い記録を削除"""

関連ファイル

  • core/risk_guardian.py - PDTGuardianクラス実装
  • strategies/beat_shield.py - Beat Shield戦略
  • strategies/sunacchan_spear.py - Sunacchan Spear戦略

参考資料