En 2026, le marché des cryptomonnaies atteint une capitalisation de 3,2 billions de dollars, et avec lui explosent les besoins en gestion des risques en temps réel. Les plateformes de trading traitent désormais des millions d'ordres par seconde, et les systèmes de risque doivent analyser ces flux avec une latence inférieure à 100 millisecondes pour éviter des pertes catastrophiques.

Dans ce tutoriel, je vais vous montrer comment intégrer l'API Kaiko pour les données de marché cryptocurrency avec un système de gestion des risques alimenté par l'intelligence artificielle. Et la bonne nouvelle ? Avec HolySheep AI, vous pouvez accéder aux meilleurs modèles IA à des tarifs défiant toute concurrence.

Comparatif des Coûts IA en 2026 : L'Économie Qui Change Tout

Avant d'entrer dans le vif du sujet, voici les tarifs actuels (2026) pour les principaux modèles de langage utilisés dans l'analyse financière :

Modèle Prix Output ($/MTok) DeepSeek V3.2 Gemini 2.5 Flash GPT-4.1 Claude Sonnet 4.5
Prix par Million de Tokens 0,42 $ 2,50 $ 8,00 $ 15,00 $
Coût pour 10M tokens/mois 4,20 $ 25,00 $ 80,00 $ 150,00 $
Latence moyenne <50ms <80ms <120ms <150ms
Économie vs Claude Sonnet 4.5 97% 83% 47% Référence

Pour un système de gestion des risques crypto traitant 10 millions de tokens par mois (scénario réaliste pour une plateforme de taille moyenne), DeepSeek V3.2 sur HolySheep vous coûte seulement 4,20 $ contre 150 $ sur l'API Anthropic standard. L'économie annuelle atteint 1 750 $, et ce n'est que pour UN modèle.

Pourquoi Intégrer Kaiko API avec un Système de Risque IA

Kaiko fournit des données de marché cryptocurrency de qualité institutionnelle : carnets d'ordres, trades, orderbook depth, données tick-by-tick sur plus de 30 000 paires de trading. Coupler ces flux avec un modèle IA permet de :

Architecture de la Solution

┌─────────────────────────────────────────────────────────────────────┐
│                    ARCHITECTURE RISK MANAGEMENT                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌──────────────┐     ┌──────────────┐     ┌──────────────────┐  │
│   │  Kaiko API   │────▶│   Python     │────▶│  Risk Engine     │  │
│   │  (WebSocket) │     │   Collector  │     │  (Calculations)  │  │
│   └──────────────┘     └──────────────┘     └────────┬─────────┘  │
│                                                       │             │
│   ┌──────────────┐                          ┌────────▼─────────┐  │
│   │  HolySheep   │◀─────────────────────────▶│  AI Analysis     │  │
│   │  AI API      │     DeepSeek V3.2        │  (Claude/GPT)    │  │
│   │  <50ms       │     0,42 $/MTok          └────────┬─────────┘  │
│   └──────────────┘                                   │             │
│                                                       │             │
│                                    ┌─────────────────▼─────────┐   │
│                                    │  Dashboard / Alerting     │   │
│                                    │  Telegram / Slack / Email │   │
│                                    └───────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

Installation et Configuration

# Installation des dépendances
pip install kaiko python-dotenv aiohttp websockets

Structure du projet

mkdir crypto-risk-system cd crypto-risk-system mkdir config data logs models

Connexion à l'API Kaiko

# config/kaiko_config.py
import os
from dotenv import load_dotenv

load_dotenv()

class KaikoConfig:
    API_KEY = os.getenv("KAIKO_API_KEY", "votre_cle_kaiko")
    BASE_URL = "https://exchange-data-rest-api.kaiko.tech"
    WS_URL = "wss://websocket.kaiko.tech/v1/data/直播"
    
    # Endpoints principaux pour le risque
    ENDPOINTS = {
        "orderbook": "/api/v1/data/orderbook_l2",
        "trades": "/api/v1/data/trades",
        "asset_pairs": "/api/v1/data/asset_pairs",
        "price_stats": "/api/v1/data/price_stats",
    }
    
    # Paires de trading surveillées
    MONITORED_PAIRS = [
        "btc-usdt", "eth-usdt", "sol-usdt", 
        "bnb-usdt", "xrp-usdt", "ada-usdt"
    ]
    
    # Seuils de risque (ajustez selon vos besoins)
    RISK_THRESHOLDS = {
        "max_position_size_usd": 1_000_000,
        "max_daily_loss_usd": 50_000,
        "liquidity_ratio_min": 0.15,  # 15% du volume quotidien
        "volatility_alert_7d": 0.08,  # 8% volatilité 7 jours
        "spread_max_bps": 50,  # 50 basis points
    }

Exemple de configuration pour HolySheep AI

class HolySheepConfig: API_KEY = os.getenv("HOLYSHEEP_API_KEY", "votre_cle_holysheep") BASE_URL = "https://api.holysheep.ai/v1" # IMPORTANT: URL officielle MODEL = "deepseek-chat" # Modèle économique pour le risque MAX_TOKENS = 2000 TEMPERATURE = 0.3 # Réponses plus déterministes pour l'analyse # Tarifs 2026 (inclus dans le coût total) COST_PER_MILLION_TOKENS = 0.42 # DeepSeek V3.2 MONTHLY_BUDGET_USD = 100 # Budget maximum

Collecte des Données de Marché en Temps Réel

# data/market_collector.py
import asyncio
import aiohttp
import json
import time
from typing import Dict, List, Optional
from datetime import datetime
from collections import deque
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class MarketDataCollector:
    """
    Collecteur de données de marché via WebSocket Kaiko.
    Gère les connexions, la reconnexion automatique et la mise en buffer.
    """
    
    def __init__(self, config):
        self.config = config
        self.orderbooks = {}  # {pair: deque of snapshots}
        self.trades = {}      # {pair: deque of recent trades}
        self.price_history = deque(maxlen=1000)
        self.connected = False
        self.ws = None
        
    async def connect_websocket(self):
        """Connexion au flux WebSocket Kaiko"""
        headers = {
            "X-API-Key": self.config.API_KEY,
            "Content-Type": "application/json"
        }
        
        # Subscribe aux orderbooks et trades
        subscribe_msg = {
            "type": "subscribe",
            "channels": [
                {"name": "orderbook_l2", "assets": self.config.MONITORED_PAIRS},
                {"name": "trades", "assets": self.config.MONITORED_PAIRS}
            ]
        }
        
        try:
            async with aiohttp.ClientSession() as session:
                self.ws = await session.ws_connect(
                    self.config.WS_URL,
                    headers=headers,
                    timeout=aiohttp.ClientTimeout(total=30)
                )
                await self.ws.send_json(subscribe_msg)
                self.connected = True
                logger.info("✅ Connecté au flux WebSocket Kaiko")
                await self._process_messages()
                
        except aiohttp.ClientError as e:
            logger.error(f"❌ Erreur de connexion WebSocket: {e}")
            await asyncio.sleep(5)
            await self.connect_websocket()  # Reconnexion automatique
    
    async def _process_messages(self):
        """Traitement des messages en temps réel"""
        while True:
            msg = await self.ws.receive()
            
            if msg.type == aiohttp.WSMsgType.TEXT:
                data = json.loads(msg.data)
                await self._handle_message(data)
            elif msg.type == aiohttp.WSMsgType.CLOSED:
                logger.warning("⚠️ WebSocket fermé, reconnexion...")
                self.connected = False
                await self.connect_websocket()
                break
    
    async def _handle_message(self, data: dict):
        """Route les données selon leur type"""
        msg_type = data.get("type", "")
        
        if msg_type == "orderbook_snapshot":
            pair = data.get("asset")
            self._update_orderbook(pair, data)
            
        elif msg_type == "trade":
            pair = data.get("asset")
            self._add_trade(pair, data)
            
        elif msg_type == "price_update":
            self._update_price(data)
    
    def _update_orderbook(self, pair: str, data: dict):
        """Met à jour le carnet d'ordres avec calcul du spread"""
        if pair not in self.orderbooks:
            self.orderbooks[pair] = deque(maxlen=100)
        
        bids = data.get("bids", [])
        asks = data.get("asks", [])
        
        best_bid = float(bids[0]["price"]) if bids else 0
        best_ask = float(asks[0]["price"]) if asks else 0
        
        spread = (best_ask - best_bid) / best_bid * 10000 if best_bid > 0 else 0
        mid_price = (best_bid + best_ask) / 2 if best_bid > 0 and best_ask > 0 else 0
        
        snapshot = {
            "timestamp": datetime.now().isoformat(),
            "pair": pair,
            "best_bid": best_bid,
            "best_ask": best_ask,
            "mid_price": mid_price,
            "spread_bps": spread,
            "bid_depth": sum(float(b["size"]) for b in bids[:10]),
            "ask_depth": sum(float(a["size"]) for a in asks[:10])
        }
        
        self.orderbooks[pair].append(snapshot)
        
        # Vérification du spread (alerte si trop large)
        if spread > self.config.RISK_THRESHOLDS["spread_max_bps"]:
            logger.warning(
                f"🚨 {pair}: Spread anormal {spread:.1f} bps "
                f"(seuil: {self.config.RISK_THRESHOLDS['spread_max_bps']} bps)"
            )
    
    def _add_trade(self, pair: str, data: dict):
        """Enregistre un trade et détecte les anomalies"""
        if pair not in self.trades:
            self.trades[pair] = deque(maxlen=500)
        
        trade = {
            "timestamp": data.get("timestamp", time.time()),
            "pair": pair,
            "price": float(data.get("price", 0)),
            "size": float(data.get("size", 0)),
            "side": data.get("side", "unknown"),
        }
        trade["value_usd"] = trade["price"] * trade["size"]
        
        self.trades[pair].append(trade)
        
        # Détection wash trading (mêmes tailles à intervalles réguliers)
        recent_same_side = [
            t for t in list(self.trades[pair])[-20:] 
            if t["side"] == trade["side"]
        ]
        if len(recent_same_side) > 15:
            sizes = [t["size"] for t in recent_same_side]
            if len(set(sizes)) < 3:  # Très peu de tailles différentes
                logger.critical(
                    f"🚨🚨 {pair}: Wash trading suspect détecté! "
                    f"{len(recent_same_side)} trades similaires"
                )
    
    def _update_price(self, data: dict):
        """Historique des prix pour analyse de volatilité"""
        self.price_history.append({
            "timestamp": time.time(),
            "pair": data.get("asset"),
            "price": float(data.get("price", 0))
        })
    
    def get_liquidity_metrics(self, pair: str) -> dict:
        """Calcule les métriques de liquidité pour une paire"""
        if pair not in self.orderbooks or len(self.orderbooks[pair]) < 2:
            return {"error": "Données insuffisantes"}
        
        recent = list(self.orderbooks[pair])[-1]
        
        # Volume bid/ask sur 10 premiers niveaux
        total_bid_liquidity = recent["bid_depth"] * recent["best_bid"]
        total_ask_liquidity = recent["ask_depth"] * recent["best_ask"]
        
        # Ratio de liquidité (devrait être > 0.15)
        if total_bid_liquidity > 0:
            liquidity_ratio = min(total_ask_liquidity, total_bid_liquidity) / max(total_ask_liquidity, total_bid_liquidity)
        else:
            liquidity_ratio = 0
        
        return {
            "pair": pair,
            "mid_price": recent["mid_price"],
            "total_bid_liquidity_usd": total_bid_liquidity,
            "total_ask_liquidity_usd": total_ask_liquidity,
            "liquidity_ratio": liquidity_ratio,
            "risk_alert": liquidity_ratio < self.config.RISK_THRESHOLDS["liquidity_ratio_min"]
        }


Test du collecteur

if __name__ == "__main__": from config.kaiko_config import KaikoConfig config = KaikoConfig() collector = MarketDataCollector(config) print("🧪 Test du collecteur de données Kaiko") print(f"URL WebSocket: {config.WS_URL}") print(f"Paires surveillées: {config.MONITORED_PAIRS}") print("Démarrage dans 3 secondes...") time.sleep(3)

Analyse IA des Risques avec HolySheep

# models/risk_analyzer.py
import requests
import json
from typing import Dict, List, Optional
from datetime import datetime
import logging

logger = logging.getLogger(__name__)

class HolySheepRiskAnalyzer:
    """
    Analyseur de risques utilisant l'IA via HolySheep API.
    DeepSeek V3.2 pour l'analyse économique et GPT-4.1 pour les rapports détaillés.
    """
    
    def __init__(self, config):
        self.config = config
        self.session_tokens = 0
        self.session_cost = 0.0
    
    def _make_request(self, model: str, messages: List[dict]) -> dict:
        """
        Requête vers l'API HolySheep.
        IMPORTANT: Utilise l'URL officielle https://api.holysheep.ai/v1
        """
        url = f"{self.config.BASE_URL}/chat/completions"
        
        headers = {
            "Authorization": f"Bearer {self.config.API_KEY}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": messages,
            "max_tokens": self.config.MAX_TOKENS,
            "temperature": self.config.TEMPERATURE
        }
        
        try:
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            response.raise_for_status()
            
            result = response.json()
            
            # Tracking des coûts (calculé par HolySheep)
            usage = result.get("usage", {})
            prompt_tokens = usage.get("prompt_tokens", 0)
            completion_tokens = usage.get("completion_tokens", 0)
            total_tokens = usage.get("total_tokens", 0)
            
            self.session_tokens += total_tokens
            
            # DeepSeek: 0.42$/MTok, ratio approximatif output/prompt
            cost = (total_tokens / 1_000_000) * self.config.COST_PER_MILLION_TOKENS
            self.session_cost += cost
            
            logger.info(
                f"💬 {model}: {total_tokens} tokens "
                f"(Coût session: ${self.session_cost:.4f})"
            )
            
            return result
            
        except requests.exceptions.RequestException as e:
            logger.error(f"❌ Erreur API HolySheep: {e}")
            return {"error": str(e)}
    
    def analyze_risk_realtime(self, market_data: dict, position: dict) -> dict:
        """
        Analyse en temps réel des risques d'une position.
        Utilise DeepSeek V3.2 pour la vitesse et le faible coût.
        """
        prompt = f"""Analyse de risque en temps réel pour la position suivante:

DONNÉES DE MARCHÉ:
- Paire: {market_data.get('pair', 'N/A')}
- Prix actuel: ${market_data.get('mid_price', 0):,.2f}
- Spread: {market_data.get('spread_bps', 0):.2f} bps
- Liquidité bid: ${market_data.get('total_bid_liquidity_usd', 0):,.2f}
- Liquidité ask: ${market_data.get('total_ask_liquidity_usd', 0):,.2f}
- Ratio liquidité: {market_data.get('liquidity_ratio', 0):.2%}

POSITION ACTUELLE:
- Direction: {position.get('side', 'N/A')}
- Taille: {position.get('size', 0)} units
- Valeur USD: ${position.get('value_usd', 0):,.2f}
- Entry price: ${position.get('entry_price', 0):,.2f}
- PnL non réalisé: ${position.get('unrealized_pnl', 0):,.2f}

Seuils de risque configurés:
- Position max: ${self.config.RISK_THRESHOLDS['max_position_size_usd']:,.2f}
- Perte max quotidienne: ${self.config.RISK_THRESHOLDS['max_daily_loss_usd']:,.2f}

Réponds en JSON avec:
{{"risk_level": "LOW|MEDIUM|HIGH|CRITICAL", "score": 0-100, 
  "recommendations": ["action1", "action2"], "margin_call_risk": boolean}}"""
        
        messages = [
            {"role": "system", "content": "Tu es un analyste de risques financiers expert en cryptomonnaies. Réponds uniquement en JSON valide."},
            {"role": "user", "content": prompt}
        ]
        
        result = self._make_request("deepseek-chat", messages)
        
        if "error" in result:
            return {"risk_level": "UNKNOWN", "error": result["error"]}
        
        try:
            content = result["choices"][0]["message"]["content"]
            # Nettoyage du JSON (au cas où il y a des backticks)
            if content.startswith("```"):
                content = content.split("```")[1]
                if content.startswith("json"):
                    content = content[4:]
            
            return json.loads(content)
        except (json.JSONDecodeError, KeyError) as e:
            logger.error(f"Erreur parsing réponse IA: {e}")
            return {"risk_level": "PARSE_ERROR", "error": str(e)}
    
    def generate_risk_report(self, all_positions: List[dict], portfolio_metrics: dict) -> str:
        """
        Génère un rapport détaillé des risques du portfolio.
        Utilise GPT-4.1 pour la qualité narrative supérieure.
        Coût: 8$/MTok mais justifié pour les rapports réglementaires.
        """
        positions_summary = "\n".join([
            f"- {p['pair']}: {p['side']} {p['value_usd']:,.2f}$ "
            f"(PnL: {p.get('unrealized_pnl', 0):,.2f}$)"
            for p in all_positions
        ])
        
        prompt = f"""Génère un rapport complet des risques de portfolio pour la direction.

MÉTRIQUES GLOBALES:
- Value at Risk (VaR) 95%: ${portfolio_metrics.get('var_95', 0):,.2f}
- Volatilité portfolio: {portfolio_metrics.get('volatility', 0):.2%}
- Sharpe Ratio: {portfolio_metrics.get('sharpe_ratio', 0):.2f}
- Exposition nette: ${portfolio_metrics.get('net_exposure', 0):,.2f}

POSITIONS:
{positions_summary}

Le rapport doit inclure:
1. Résumé exécutif (3-4 phrases)
2. Principaux facteurs de risque identifiés
3. Recommandations d'action prioritaire
4. Prévisions de liquidité sur 24h
5. Alertes réglementaires potentielles

Style: Professionnel, adapté à un comité de risque."""
        
        messages = [
            {"role": "system", "content": "Tu es un analyste financier senior spécialisé en gestion des risques. Rédige en français, ton professionnel."},
            {"role": "user", "content": prompt}
        ]
        
        result = self._make_request("gpt-4.1", messages)
        
        if "error" in result:
            return f"Erreur génération rapport: {result['error']}"
        
        return result["choices"][0]["message"]["content"]
    
    def detect_market_manipulation(self, trades: List[dict], pair: str) -> dict:
        """
        Détecte les patterns de manipulation de marché via IA.
        """
        # Filtrage des trades suspects
        suspicious_trades = []
        
        for i, trade in enumerate(trades):
            # Vérification des patterns de spoofing
            if i > 0 and trade["size"] > trades[i-1]["size"] * 5:
                suspicious_trades.append({
                    "type": "SPOOFING_SUSPECTED",
                    "trade": trade,
                    "reason": "Taille anormalement grande vs précédent"
                })
            
            # Vérification wash trading
            if i > 10:
                recent_sizes = [t["size"] for t in trades[i-10:i+1]]
                if len(set(recent_sizes)) < 3:  # Beaucoup de tailles identiques
                    suspicious_trades.append({
                        "type": "WASH_TRADING_SUSPECTED",
                        "trade": trade,
                        "reason": f"20 derniers trades avec seulement {len(set(recent_sizes))} tailles différentes"
                    })
        
        if suspicious_trades:
            prompt = f"""Analyse les trades suivants pour {pair} et détermine le risque de manipulation:

{trades[:50]}

Patterns suspects identifiés:
{json.dumps(suspicious_trades[:10], indent=2)}

Réponds en JSON:
{{"manipulation_confirmed": boolean, "confidence": 0-100, 
  "pattern_type": "SPOOFING|WASH_TRADING|FRONTRUNNING|NONE",
  "recommended_action": "string"}}"""
            
            messages = [
                {"role": "system", "content": "Tu es un expert en détection de fraude financière. Réponds en JSON uniquement."},
                {"role": "user", "content": prompt}
            ]
            
            result = self._make_request("deepseek-chat", messages)
            
            if "error" not in result:
                try:
                    return json.loads(result["choices"][0]["message"]["content"])
                except json.JSONDecodeError:
                    pass
        
        return {"manipulation_confirmed": False, "pattern_type": "NONE"}
    
    def get_session_stats(self) -> dict:
        """Retourne les statistiques de la session en cours"""
        return {
            "total_tokens": self.session_tokens,
            "estimated_cost_usd": self.session_cost,
            "cost_vs_openai": self.session_cost / (self.session_tokens / 1_000_000 * 15) if self.session_tokens > 0 else 0,
            "savings_percent": (1 - self.session_cost / (self.session_tokens / 1_000_000 * 15)) * 100 if self.session_tokens > 0 else 0
        }


Test de l'analyseur

if __name__ == "__main__": from config.kaiko_config import HolySheepConfig config = HolySheepConfig() analyzer = HolySheepRiskAnalyzer(config) # Test avec données simulées test_market_data = { "pair": "btc-usdt", "mid_price": 67500.00, "spread_bps": 12.5, "total_bid_liquidity_usd": 2_500_000, "total_ask_liquidity_usd": 2_300_000, "liquidity_ratio": 0.92 } test_position = { "side": "LONG", "size": 1.5, "value_usd": 101_250, "entry_price": 65000, "unrealized_pnl": 3750 } print("🧪 Test de l'analyseur de risques HolySheep") print(f"URL API: {config.BASE_URL}") print(f"Coût DeepSeek V3.2: {config.COST_PER_MILLION_TOKENS}$/MTok") print("\nAnalyse en cours...") result = analyzer.analyze_risk_realtime(test_market_data, test_position) print(f"\n📊 Résultat: {json.dumps(result, indent=2, ensure_ascii=False)}") stats = analyzer.get_session_stats() print(f"\n💰 Stats session: {stats}")

Déclencheur Automatique de Réduction des Risques

# risk_engine/trigger_engine.py
import asyncio
import logging
from typing import Callable, List, Optional
from datetime import datetime
from enum import Enum

logger = logging.getLogger(__name__)

class RiskAction(Enum):
    REDUCE_POSITION = "REDUCE_POSITION"
    CLOSE_POSITION = "CLOSE_POSITION"
    INCREASE_MARGIN = "INCREASE_MARGIN"
    PAUSE_TRADING = "PAUSE_TRADING"
    ALERT_ONLY = "ALERT_ONLY"
    NO_ACTION = "NO_ACTION"

class RiskTriggerEngine:
    """
    Moteur de déclenchement automatique basé sur les seuils de risque.
    Réduit automatiquement les positions quand les limites sont atteinte.
    """
    
    def __init__(self, config, notifier: Optional[Callable] = None):
        self.config = config
        self.notifier = notifier  # Callback pour envoyer les alertes
        self.active_positions = {}
        self.triggered_count = 0
        self.actions_log = []
    
    def check_risk_triggers(self, position: dict, market_data: dict, ai_analysis: dict) -> List[dict]:
        """
        Vérifie tous les déclencheurs de risque pour une position.
        Retourne la liste des actions à prendre.
        """
        actions = []
        
        # 1. Vérification taille position
        if position.get("value_usd", 0) > self.config.RISK_THRESHOLDS["max_position_size_usd"]:
            actions.append({
                "trigger": "MAX_POSITION_SIZE",
                "action": RiskAction.REDUCE_POSITION,
                "priority": "HIGH",
                "reason": f"Position ${position.get('value_usd'):,.2f} dépasse limite ${self.config.RISK_THRESHOLDS['max_position_size_usd']:,.2f}",
                "reduction_percent": min(
                    50,
                    (position.get("value_usd", 0) / self.config.RISK_THRESHOLDS["max_position_size_usd"] - 1) * 100
                )
            })
        
        # 2. Vérification liquidité
        liq_ratio = market_data.get("liquidity_ratio", 1)
        if liq_ratio < self.config.RISK_THRESHOLDS["liquidity_ratio_min"]:
            actions.append({
                "trigger": "LOW_LIQUIDITY",
                "action": RiskAction.REDUCE_POSITION,
                "priority": "CRITICAL",
                "reason": f"Ratio liquidité {liq_ratio:.2%} < {self.config.RISK_THRESHOLDS['liquidity_ratio_min']:.2%}",
                "reduction_percent": 75
            })
        
        # 3. Vérification spread
        spread_bps = market_data.get("spread_bps", 0)
        if spread_bps > self.config.RISK_THRESHOLDS["spread_max_bps"]:
            actions.append({
                "trigger": "HIGH_SPREAD",
                "action": RiskAction.ALERT_ONLY,
                "priority": "MEDIUM",
                "reason": f"Spread {spread_bps:.1f} bps dépasse seuil {self.config.RISK_THRESHOLDS['spread_max_bps']} bps"
            })
        
        # 4. Analyse IA (si disponible)
        if ai_analysis and "risk_level" in ai_analysis:
            risk_level = ai_analysis["risk_level"]
            
            if risk_level == "CRITICAL":
                actions.append({
                    "trigger": "AI_CRITICAL",
                    "action": RiskAction.CLOSE_POSITION,
                    "priority": "CRITICAL",
                    "reason": f"IA signale risque CRITIQUE: {ai_analysis.get('score', 'N/A')}/100",
                    "ai_recommendations": ai_analysis.get("recommendations", [])
                })
                self.triggered_count += 1
                
            elif risk_level == "HIGH":
                actions.append({
                    "trigger": "AI_HIGH",
                    "action": RiskAction.REDUCE_POSITION,
                    "priority": "HIGH",
                    "reason": f"IA signale risque HIGH: {ai_analysis.get('score', 'N/A')}/100",
                    "reduction_percent": 40
                })
        
        # 5. Vérification PnL quotidienne
        daily_loss = position.get("daily_loss", 0)
        if daily_loss > self.config.RISK_THRESHOLDS["max_daily_loss_usd"]:
            actions.append({
                "trigger": "DAILY_LOSS_LIMIT",
                "action": RiskAction.PAUSE_TRADING,
                "priority": "CRITICAL",
                "reason": f"Perte quotidienne ${daily_loss:,.2f} > limite ${self.config.RISK_THRESHOLDS['max_daily_loss_usd']:,.2f}"
            })
        
        # Log et notification
        if actions:
            self._log_and_notify(position, actions)
        
        return actions
    
    def _log_and_notify(self, position: dict, actions: List[dict]):
        """Log les actions et envoie notification si configuré"""
        timestamp = datetime.now().isoformat()
        
        for action in actions:
            log_entry = {
                "timestamp": timestamp,
                "pair": position.get("pair"),
                "position_id": position.get("id"),
                **action
            }
            self.actions_log.append(log_entry)
            
            # Log console
            priority_emoji = {"LOW": "📘", "MEDIUM": "📙", "HIGH": "📕", "CRITICAL": "🚨🚨"}
            emoji = priority_emoji.get(action.get("priority", "LOW"), "📗")
            
            logger.warning(
                f"{emoji} {action['trigger']}: {action['action'].value} "
                f"pour {position.get('pair')} - {action['reason']}"
            )
        
        # Notification externe
        if self.notifier:
            asyncio.create_task(self.notifier(position, actions))
    
    def get_actions_summary(self) -> dict:
        """Résumé des actions de la session"""
        priorities = {}
        for log in self.actions_log:
            p = log.get("priority", "UNKNOWN")
            priorities[p] = priorities.get(p, 0) + 1
        
        return {
            "total_actions": len(self.actions_log),
            "critical_triggers": self.triggered_count,
            "by_priority": priorities,
            "last_action": self.actions_log[-1] if self.actions_log else None
        }


Test du moteur

if __name__ == "__main__": from config.kaiko_config import KaikoConfig from models.risk_analyzer import HolySheepRiskAnalyzer, HolySheepConfig config = KaikoConfig() risk_engine = RiskTriggerEngine(config) test_position = { "id": "POS-001", "pair": "btc-usdt", "side": "LONG", "value_usd": 1_200_000, # Dépasse la limite de 1M "daily_loss": 60_000 # Dépasse la limite de 50k } test_market_data = { "pair": "btc-usdt", "mid_price": 67500, "spread_bps