0Pricing
AI Agents · レッスン

リスクとコンプライアンスのガードレール

ポジションサイズの上限、禁止金融商品のチェック、監査ログを実装します。

「リスクとコンプライアンスのガードレール」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。

金融エージェントに厳格なガードレールが必要な理由

制限なしに任意の取引を推奨できる金融エージェントは、ユーザーを壊滅的な損失や規制違反にさらす可能性があります。人間のアドバイザーとは異なり、エージェントは推奨ロジックを一貫して実行します。つまり、バグや設定ミスがすべてのユーザーに影響するということです。

厳格なガードレールによって、最悪の結果を防止します。

ポジションサイズの上限

エージェントが単一の資産に投資するよう推奨できるポートフォリオの割合を制限します。一般的なルールとして、単一のポジションをポートフォリオ総額の20%以下にします。これにより、壊滅的な集中リスクを防止します。

MAX_POSITION_PCT = 0.20   # 20% of portfolio max per asset

def check_position_size(ticker: str, trade_usd: float,
                        portfolio_value: float) -> dict:
    proposed_pct = trade_usd / portfolio_value
    if proposed_pct > MAX_POSITION_PCT:
        return {
            'allowed': False,
            'reason': (
                f'Position size {proposed_pct:.1%} exceeds limit {MAX_POSITION_PCT:.1%}. '
                f'Max trade for this portfolio: USD {portfolio_value * MAX_POSITION_PCT:.0f}'
            )
        }
    return {'allowed': True, 'position_pct': round(proposed_pct, 4)}

if __name__ == '__main__':
    print('Large trade:', check_position_size('TSLA', 30000, 100000))
    print('Small trade:', check_position_size('TSLA', 10000, 100000))

禁止銘柄リスト

エージェントが推奨してはならない金融商品(ペニー株、レバレッジの高いETF、制裁対象の証券、個人投資家に適していない商品など)のリストを管理します。

PROHIBITED_TICKERS = {
    'UVXY',   # VIX leveraged ETF — too volatile
    'TVIX',   # Delisted leveraged VIX
    'JDST',   # 3x leveraged gold miners short
    'NUGT',   # 3x leveraged gold miners long
    'YANG',   # 3x China short
}

PROHIBITED_TYPES = {'penny_stock', 'leveraged_3x', 'inverse_volatility'}

def check_prohibited_instrument(ticker: str) -> dict:
    if ticker.upper() in PROHIBITED_TICKERS:
        return {
            'allowed': False,
            'reason': f'{ticker} is on the prohibited instruments list'
        }
    return {'allowed': True}

if __name__ == '__main__':
    print("Checking UVXY:", check_prohibited_instrument('UVXY'))
    print("Checking AAPL:", check_prohibited_instrument('AAPL'))

パターン・デイトレーダー(PDT)ルールの確認

米国では、25,000米ドル未満の口座が5営業日以内に4回以上の往復取引を行うと、パターン・デイトレーダー(PDT)に該当します。同日取引を推奨する前に、エージェントは必ず取引頻度を確認しなければなりません。

from datetime import datetime, timedelta, timezone

def check_pdt_rule(account_value_usd: float,
                   recent_trades: list[dict]) -> dict:
    if account_value_usd >= 25_000:
        return {'at_risk': False, 'reason': 'Account above PDT threshold'}

    cutoff = datetime.now(timezone.utc) - timedelta(days=5)
    recent = [
        t for t in recent_trades
        if datetime.fromisoformat(t['timestamp']) > cutoff
        and t.get('is_day_trade', False)
    ]

    if len(recent) >= 3:
        return {
            'at_risk': True,
            'day_trades_in_5_days': len(recent),
            'reason': (
                f'Account has {len(recent)} day trades in the last 5 days. '
                f'A 4th would trigger the PDT restriction.'
            )
        }
    return {'at_risk': False, 'day_trades_in_5_days': len(recent)}

if __name__ == '__main__':
    now = datetime.now(timezone.utc)
    trades = [
        {'timestamp': (now - timedelta(days=1)).isoformat(), 'is_day_trade': True},
        {'timestamp': (now - timedelta(days=2)).isoformat(), 'is_day_trade': True},
        {'timestamp': (now - timedelta(days=3)).isoformat(), 'is_day_trade': True},
    ]
    result = check_pdt_rule(account_value_usd=10000, recent_trades=trades)
    print('PDT rule check:', result)

ボラティリティに基づく取引サイズの調整

ボラティリティの高い資産ほど大きなリスクを伴います。ボラティリティに反比例するようにポジションサイズを調整します。資産のボラティリティが基準値の2倍であれば、ポジションサイズを半分にするよう提案します。

import yfinance as yf, numpy as np

BASELINE_VOL = 0.15   # 15% annualized vol — S&P 500 average

def volatility_scaled_size(ticker: str, base_allocation_usd: float) -> dict:
    hist = yf.Ticker(ticker).history(period='1y')['Close'].pct_change().dropna()
    vol = float(hist.std() * np.sqrt(252))

    scaling_factor = BASELINE_VOL / max(vol, 0.01)
    adjusted_usd   = base_allocation_usd * scaling_factor

    return {
        'ticker':             ticker,
        'annualized_vol':     round(vol, 4),
        'scaling_factor':     round(scaling_factor, 3),
        'adjusted_size_usd':  round(adjusted_usd, 2),
        'note': 'High-vol asset: position scaled down' if scaling_factor < 1 else 'Normal sizing'
    }

すべての推奨を監査ログに記録する

すべての取引推奨は、承認されたか却下されたかにかかわらず、タイムスタンプ、ユーザーID、推奨アクション、実行したガードレールチェック、結果などの完全なコンテキストとともに記録しなければなりません。これにより、コンプライアンス審査に利用できる完全な監査証跡が作成されます。

import json, hashlib, time, logging

audit_logger = logging.getLogger('financial_agent.audit')
audit_logger.setLevel(logging.INFO)

def audit_log(user_id: str, action: str, ticker: str,
              amount_usd: float, guardrail_results: list[dict],
              approved: bool, reason: str):
    log_entry = {
        'timestamp':         time.time(),
        'user_id':           user_id,
        'action':            action,
        'ticker':            ticker,
        'amount_usd':        amount_usd,
        'guardrails':        guardrail_results,
        'approved':          approved,
        'reason':            reason,
        'entry_id':          hashlib.md5(f'{user_id}{time.time()}'.encode()).hexdigest()[:12]
    }
    audit_logger.info(json.dumps(log_entry))

if __name__ == '__main__':
    import sys
    audit_logger.addHandler(logging.StreamHandler(sys.stdout))
    audit_log('user_42', 'BUY', 'AAPL', 5000.0,
               [{'check': 'position_size', 'allowed': True}],
               True, 'Within limits')

免責事項の自動付加

エージェントが生成するすべての金融関連出力には、個別の金融アドバイスではないことを示す免責事項を含めなければなりません。これを自動的に付加し、LLMが毎回一貫して追加することには決して依存しないでください。

FINANCIAL_DISCLAIMER = (
    '\n\n---\n'
    'DISCLAIMER: This output is generated by an AI agent and is for '
    'informational purposes only. It does not constitute personalized financial advice. '
    'Past performance does not guarantee future results. '
    'Please consult a licensed financial advisor before making investment decisions.'
)

def inject_disclaimer(response: str) -> str:
    if 'DISCLAIMER' not in response:
        return response + FINANCIAL_DISCLAIMER
    return response

if __name__ == '__main__':
    response = 'AAPL is currently trading at $150 with strong upward momentum.'
    print(inject_disclaimer(response))

すべてのガードレールを順番に実行する

すべてのチェックを順番に実行し、理由とともに合格または不合格の判定を返す単一のguardrail_check()関数を作成します。エージェントは、推奨を確定する前にこの関数を呼び出します。

def guardrail_check(user_id: str, ticker: str, action: str,
                    amount_usd: float, portfolio_value: float,
                    account_value: float, recent_trades: list[dict]) -> dict:
    checks = []

    # 1. Prohibited instruments
    prohibited = check_prohibited_instrument(ticker)
    checks.append({'check': 'prohibited_instrument', **prohibited})
    if not prohibited['allowed']:
        audit_log(user_id, action, ticker, amount_usd, checks, False, prohibited['reason'])
        return {'approved': False, 'reason': prohibited['reason'], 'checks': checks}

    # 2. Position size
    size_check = check_position_size(ticker, amount_usd, portfolio_value)
    checks.append({'check': 'position_size', **size_check})
    if not size_check['allowed']:
        audit_log(user_id, action, ticker, amount_usd, checks, False, size_check['reason'])
        return {'approved': False, 'reason': size_check['reason'], 'checks': checks}

    # 3. PDT rule
    if action == 'day_trade':
        pdt = check_pdt_rule(account_value, recent_trades)
        checks.append({'check': 'pdt_rule', **pdt})
        if pdt['at_risk']:
            return {'approved': False, 'reason': pdt['reason'], 'checks': checks}

    audit_log(user_id, action, ticker, amount_usd, checks, True, 'All guardrails passed')
    return {'approved': True, 'checks': checks}

リスクプロファイルによる適合性チェック

推奨をユーザーが申告したリスク許容度に合わせます。保守的な投資家に高ベータの成長株を推奨してはなりません。一方、積極的な投資家はより高いボラティリティを許容できます。

RISK_PROFILES = {
    'conservative':   {'max_beta': 0.8,  'max_vol_pct': 15},
    'moderate':       {'max_beta': 1.2,  'max_vol_pct': 25},
    'aggressive':     {'max_beta': 2.0,  'max_vol_pct': 50},
}

def suitability_check(risk_profile: str, ticker_beta: float,
                       ticker_vol_pct: float) -> dict:
    limits = RISK_PROFILES.get(risk_profile, RISK_PROFILES['moderate'])
    if ticker_beta > limits['max_beta']:
        return {
            'suitable': False,
            'reason': f'Beta {ticker_beta:.2f} exceeds {risk_profile} limit {limits["max_beta"]}'
        }
    if ticker_vol_pct > limits['max_vol_pct']:
        return {
            'suitable': False,
            'reason': f'Volatility {ticker_vol_pct:.1f}% exceeds {risk_profile} limit {limits["max_vol_pct"]}%'
        }
    return {'suitable': True}

if __name__ == '__main__':
    print('Conservative check:', suitability_check('conservative', ticker_beta=1.5, ticker_vol_pct=20))
    print('Aggressive check:  ', suitability_check('aggressive', ticker_beta=1.5, ticker_vol_pct=20))

推奨のレート制限

取引推奨を頻繁に生成するエージェントは、過剰取引を促し、コストとリスクを増大させます。同じ資産に対する推奨の間にクールダウン期間を設けてください。

import time

last_recommendation: dict[str, float] = {}  # ticker -> timestamp
COOLDOWN_HOURS = 24

def check_recommendation_cooldown(ticker: str) -> dict:
    last = last_recommendation.get(ticker, 0)
    elapsed_hours = (time.time() - last) / 3600

    if elapsed_hours < COOLDOWN_HOURS:
        remaining = COOLDOWN_HOURS - elapsed_hours
        return {
            'allowed': False,
            'reason': f'Recommendation cooldown: {remaining:.1f} hours remaining for {ticker}'
        }
    return {'allowed': True}

def record_recommendation(ticker: str):
    last_recommendation[ticker] = time.time()

if __name__ == '__main__':
    print('Before recommending:', check_recommendation_cooldown('AAPL'))
    record_recommendation('AAPL')
    print('Right after recommending:', check_recommendation_cooldown('AAPL'))

損切りとドローダウンのサーキットブレーカー

個々のポジション上限に加えて、ポートフォリオレベルのサーキットブレーカーを実装します。ポートフォリオ全体が1日でX%を超えて下落した場合、人間が状況を確認するまで、エージェントは新たな買い推奨を停止します。

MAX_DAILY_DRAWDOWN_PCT = 0.05   # 5% daily loss limit

def check_daily_drawdown(portfolio_start_of_day: float,
                          portfolio_current: float) -> dict:
    daily_loss = (portfolio_current - portfolio_start_of_day) / portfolio_start_of_day
    if daily_loss < -MAX_DAILY_DRAWDOWN_PCT:
        return {
            'circuit_breaker': True,
            'daily_loss_pct':  round(daily_loss * 100, 2),
            'reason': (
                f'Portfolio down {abs(daily_loss)*100:.1f}% today. '
                f'Agent suspended — human review required.'
            )
        }
    return {'circuit_breaker': False, 'daily_loss_pct': round(daily_loss * 100, 2)}

if __name__ == '__main__':
    print('Small loss day:', check_daily_drawdown(100000, 98000))
    print('Big loss day:  ', check_daily_drawdown(100000, 92000))

パターン・デイトレーダー(PDT)ルールは何を制限しますか

PDTルールは、米国市場で運用する金融エージェントが遵守しなければならない米国の規制要件です。このルールを理解することで、エージェントが意図せず信用取引口座の制限を発生させることを防げます。

リスクとコンプライアンスのガードレールまとめ

金融エージェントのガードレールには、ポジションサイズ制限、取引禁止金融商品のリスト、PDTルールチェック、ボラティリティに応じたポジションサイズ調整、リスクプロファイルとの適合性マッチング、すべての推奨内容に対する監査ログの記録、およびすべての出力への免責事項の挿入が含まれます。

取引推奨を確定する前に、必ずすべてのガードレールを実行してください。

よくある質問

「リスクとコンプライアンスのガードレール」レッスンは無料ですか?

はい。「リスクとコンプライアンスのガードレール」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。

「リスクとコンプライアンスのガードレール」で何を学びますか?

ポジションサイズの上限、禁止金融商品のチェック、監査ログを実装します。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Agentsを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「リスクとコンプライアンスのガードレール」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Agentsレッスンでコードを書いて実行できますか?

はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 市場データ API 連携
  2. ポートフォリオ分析エージェントツール
  3. リスクとコンプライアンスのガードレール
  4. エージェントの意思決定をバックテストする
← AI Agentsに戻る