En tant qu'ingénieur qui a passé plus de 18 mois à intégrer des APIs d'exchanges crypto dans des systèmes de trading haute fréquence, je peux vous dire que l'API OKX représente l'une des interfaces les plus robustes et documentées du marché. Aujourd'hui, je vous propose une plongée technique exhaustive, de l'architecture fondamentale aux patterns de production prêts à l'emploi.

Architecture générale de l'API OKX

L'écosystème OKX propose trois environnements distincts avec des latences mesurées en conditions réelles :

La structure de compte repose sur un système à trois niveaux qui impacte directement vos limites d'API :

NiveauAppels/secondeWebSocket connectionsNécessite
Level 12025Vérification email
Level 260100KYC basique
Level 3300500KYC avancé + VIP request
VIP Enterprise20002000Contrat commercial

Authentification et gestion des clés API

OKX utilise une authentification HMAC-SHA256 pour les endpoints REST et un système de signature pour les WebSockets privés. Voici l'implémentation complète en Python 3.11+ :

import hmac
import hashlib
import time
import base64
from typing import Dict, Optional
from datetime import datetime
import asyncio
import aiohttp

class OKXCredentials:
    """Gestionnaire d'identifiants OKX avec rotation automatique."""
    
    def __init__(
        self,
        api_key: str,
        secret_key: str,
        passphrase: str,
        use_sandbox: bool = False
    ):
        self.api_key = api_key
        self.secret_key = secret_key
        self.passphrase = passphrase
        self.base_url = (
            "https://sim-api.okx.com" if use_sandbox
            else "https://api.okx.com"
        )
    
    def _sign(self, timestamp: str, method: str, path: str, body: str = "") -> str:
        """Génère la signature HMAC-SHA256 pour OKX."""
        message = timestamp + method + path + body
        mac = hmac.new(
            self.secret_key.encode('utf-8'),
            message.encode('utf-8'),
            hashlib.sha256
        )
        return base64.b64encode(mac.digest()).decode('utf-8')
    
    def get_headers(
        self,
        method: str,
        path: str,
        body: str = ""
    ) -> Dict[str, str]:
        """Construit les headers authentifiés pour une requête."""
        timestamp = datetime.utcnow().isoformat() + '.000Z'
        signature = self._sign(timestamp, method, path, body)
        
        return {
            'OK-ACCESS-KEY': self.api_key,
            'OK-ACCESS-SIGN': signature,
            'OK-ACCESS-TIMESTAMP': timestamp,
            'OK-ACCESS-PASSPHRASE': self.passphrase,
            'Content-Type': 'application/json',
            'x-simulated-trading': '1' if 'sim' in self.base_url else '0'
        }
    
    async def request(
        self,
        method: str,
        endpoint: str,
        params: Optional[Dict] = None,
        body: Optional[Dict] = None,
        retries: int = 3
    ) -> Dict:
        """Requête HTTP avec retry automatique et gestion d'erreur."""
        path = endpoint
        if params:
            query = '&'.join(f"{k}={v}" for k, v in params.items())
            path = f"{endpoint}?{query}"
        
        url = f"{self.base_url}{path}"
        body_str = json.dumps(body) if body else ""
        headers = self.get_headers(method, path, body_str)
        
        for attempt in range(retries):
            try:
                async with aiohttp.ClientSession() as session:
                    async with session.request(
                        method,
                        url,
                        headers=headers,
                        json=body if body else None,
                        timeout=aiohttp.ClientTimeout(total=10)
                    ) as response:
                        data = await response.json()
                        
                        if response.status == 200:
                            return data
                        elif response.status == 429:
                            # Rate limit — wait exponentially
                            wait = 2 ** attempt
                            await asyncio.sleep(wait)
                            continue
                        else:
                            raise OKXAPIError(
                                f"HTTP {response.status}: {data}"
                            )
            except aiohttp.ClientError as e:
                if attempt == retries - 1:
                    raise
                await asyncio.sleep(0.5 * (attempt + 1))
        
        raise OKXAPIError("Max retries exceeded")

import json

class OKXAPIError(Exception):
    """Exception personnalisée pour les erreurs API OKX."""
    pass

==== INITIALISATION ====

credentials = OKXCredentials( api_key="YOUR_OKX_API_KEY", # Remplacez par votre clé secret_key="YOUR_OKX_SECRET_KEY", passphrase="YOUR_PASSPHRASE", use_sandbox=False # True pour tester sans risque )

Structure des endpoints REST — Guide de référence

Gestion de compte et soldes

class OKXAccount:
    """Classe complète pour la gestion de compte OKX."""
    
    def __init__(self, credentials: OKXCredentials):
        self.cred = credentials
    
    async def get_account_config(self) -> Dict:
        """Récupère la configuration du compte (niveau, etc.)."""
        return await self.cred.request(
            "GET",
            "/api/v5/account/config"
        )
    
    async def get_balances(self, ccy: str = "") -> Dict:
        """Soldes de tous les actifs ou d'une devise spécifique.
        
        Exemple de réponse:
        {
            "data": [{
                "uTime": "1699900000000",
                "totalEq": "85000.50",
                "adjEq": "84000.25",
                "imr": "5000.00",      # Marge initiale
                "mmr": "500.00",        # Marge minimum
                "mgnRatio": "15.50",
                "details": [{
                    "ccy": "USDT",
                    "cashBal": "75000.00",
                    "availBal": "72000.00",
                    "frozenBal": "3000.00"
                }]
            }]
        }
        """
        params = {"ccy": ccy} if ccy else {}
        return await self.cred.request(
            "GET",
            "/api/v5/account/balance",
            params=params
        )
    
    async def get_positions(
        self,
        instType: str = "SWAP",
        instId: str = ""
    ) -> Dict:
        """Récupère les positions ouvertes.
        
        Args:
            instType: SPOT, SWAP, FUTURES, OPTION
            instId: Filter par instrument (ex: "BTC-USDT-SWAP")
        """
        params = {
            "instType": instType,
            "instId": instId
        }
        return await self.cred.request(
            "GET",
            "/api/v5/account/positions",
            params=params
        )

Placement d'ordres avec gestion avancée

class OKXTrading:
    """Moteur de trading avec contrôle de concurrence."""
    
    def __init__(self, credentials: OKXCredentials):
        self.cred = credentials
        self._order_semaphore = asyncio.Semaphore(50)
        self._pending_orders: Dict[str, asyncio.Future] = {}
    
    async def place_order(
        self,
        instId: str,
        tdMode: str,
        side: str,
        ordType: str,
        sz: str,
        px: Optional[str] = None,
        slTriggerPx: Optional[str] = None,
        slOrdPx: Optional[str] = None,
        tpTriggerPx: Optional[str] = None,
        tpOrdPx: Optional[str] = None
    ) -> Dict:
        """Place un ordre avec support stop-loss et take-profit.
        
        Args:
            instId: Exemple "BTC-USDT-SWAP"
            tdMode: cross (marge croisée) ou isolated
            side: buy ou sell
            ordType: market, limit, post_only, fok, ioc
            sz: Quantité en contrat ou en montant
            slTriggerPx: Prix trigger stop-loss
            slOrdPx: Prix ordre stop-loss (-1 = marché)
        """
        async with self._order_semaphore:
            order_data = {
                "instId": instId,
                "tdMode": tdMode,
                "side": side,
                "ordType": ordType,
                "sz": sz,
            }
            
            if px:
                order_data["px"] = px
            
            # Stop-Loss
            if slTriggerPx:
                order_data["slTriggerPx"] = slTriggerPx
                order_data["slOrdPx"] = slOrdPx or "-1"
            
            # Take-Profit
            if tpTriggerPx:
                order_data["tpTriggerPx"] = tpTriggerPx
                order_data["tpOrdPx"] = tpOrdPx or "-1"
            
            result = await self.cred.request(
                "POST",
                "/api/v5/trade/order",
                body=order_data
            )
            
            # Stocker pour tracking async
            if result.get('data'):
                order_id = result['data'][0]['ordId']
                self._pending_orders[order_id] = asyncio.get_event_loop().create_future()
            
            return result
    
    async def cancel_order(
        self,
        instId: str,
        ordId: str
    ) -> Dict:
        """Annule un ordre en attente."""
        return await self.cred.request(
            "POST",
            "/api/v5/trade/cancel-order",
            body={
                "instId": instId,
                "ordId": ordId
            }
        )
    
    async def get_order(
        self,
        instId: str,
        ordId: str
    ) -> Dict:
        """Récupère le statut d'un ordre."""
        return await self.cred.request(
            "GET",
            "/api/v5/trade/order",
            params={"instId": instId, "ordId": ordId}
        )
    
    async def get_filled_orders(
        self,
        instId: str,
        after: Optional[str] = None,
        before: Optional[str] = None,
        limit: int = 100
    ) -> Dict:
        """Récupère l'historique des ordres remplis pour analyse."""
        params = {
            "instId": instId,
            "uly": instId.split("-")[0] + "-" + instId.split("-")[1],
            "ordType": "market,limit",
            "state": "filled",
            "limit": str(limit)
        }
        if after:
            params["after"] = after
        if before:
            params["before"] = before
        
        return await self.cred.request(
            "GET",
            "/api/v5/trade/orders-history",
            params=params
        )

WebSocket temps réel — Abonnements multiples

import websockets
import asyncio
import json
from typing import Callable, Dict, Set

class OKXWebSocket:
    """Client WebSocket pour données temps réel."""
    
    def __init__(
        self,
        api_key: str,
        secret_key: str,
        passphrase: str,
        use_sandbox: bool = False
    ):
        self.api_key = api_key
        self.secret_key = secret_key
        self.passphrase = passphrase
        
        self.url = (
            "wss://wss-sandbox.okx.com:8443/ws/v5/private"
            if use_sandbox
            else "wss://ws.okx.com:8443/ws/v5/private"
        )
        
        self._handlers: Dict[str, Set[Callable]] = {}
        self._running = False
        self._ws = None
    
    async def connect(self):
        """Établit la connexion WebSocket authentifiée."""
        timestamp = datetime.utcnow().isoformat() + '.000Z'
        sign = self._sign(timestamp, "GET", "/users/self/verify")
        
        self._ws = await websockets.connect(
            self.url,
            extra_headers={
                'OK-ACCESS-KEY': self.api_key,
                'OK-ACCESS-SIGN': sign,
                'OK-ACCESS-TIMESTAMP': timestamp,
                'OK-ACCESS-PASSPHRASE': self.passphrase
            }
        )
        self._running = True
    
    def _sign(self, timestamp: str, method: str, path: str) -> str:
        message = timestamp + method + path
        mac = hmac.new(
            self.secret_key.encode('utf-8'),
            message.encode('utf-8'),
            hashlib.sha256
        )
        return base64.b64encode(mac.digest()).decode('utf-8')
    
    async def subscribe(self, channels: list):
        """S'abonne à plusieurs channels simultanément.
        
        Channels supportés:
        - candles1m, candles3M, ..., candles1W
        - trades
        - books50 (50 niveaux)
        - books400 (400 niveaux)
        - ticker
        - positions
        - orders
        """
        subscribe_msg = {
            "op": "subscribe",
            "args": channels
        }
        await self._ws.send(json.dumps(subscribe_msg))
    
    async def listen(self, callback: Callable[[Dict], None]):
        """Boucle principale d'écoute des messages."""
        while self._running:
            try:
                message = await self._ws.recv()
                data = json.loads(message)
                
                if data.get('event') == 'subscribe':
                    print(f"Subscribed: {data.get('arg', {}).get('channel')}")
                    continue
                
                if data.get('data'):
                    channel = data.get('arg', {}).get('channel')
                    
                    # Dispatch vers les handlers appropriés
                    if channel in self._handlers:
                        for handler in self._handlers[channel]:
                            await handler(data['data'])
                    
                    if callback:
                        await callback(data)
                        
            except websockets.ConnectionClosed:
                print("Connection closed, reconnecting...")
                await self.reconnect()
    
    def register_handler(
        self,
        channel: str,
        handler: Callable[[Dict], None]
    ):
        """Enregistre un handler pour un channel."""
        if channel not in self._handlers:
            self._handlers[channel] = set()
        self._handlers[channel].add(handler)
    
    async def reconnect(self):
        """Reconnexion automatique avec backoff exponentiel."""
        max_retries = 5
        for attempt in range(max_retries):
            try:
                await self.connect()
                print("Reconnected successfully")
                return
            except Exception as e:
                wait = 2 ** attempt
                print(f"Reconnect failed, retry in {wait}s: {e}")
                await asyncio.sleep(wait)
        raise ConnectionError("Max reconnection attempts exceeded")

==== EXEMPLE D'UTILISATION ====

async def handle_ticker(data): """Traitement des données ticker temps réel.""" for ticker in data: symbol = ticker['instId'] last_price = float(ticker['last']) volume_24h = float(ticker['vol24h']) # Logique de trading ici print(f"{symbol}: ${last_price} | Vol: {volume_24h}") async def handle_orderbook(data): """Traitement du carnet d'ordres.""" for book in data: bids = [(float(p), float(s)) for p, s in book.get('bids', [])] asks = [(float(p), float(s)) for p, s in book.get('asks', [])] print(f"Bids: {len(bids)} | Asks: {len(asks)}") async def main(): ws = OKXWebSocket( api_key="YOUR_API_KEY", secret_key="YOUR_SECRET_KEY", passphrase="YOUR_PASSPHRASE" ) # Enregistrement des handlers ws.register_handler('ticker', handle_ticker) ws.register_handler('books50', handle_orderbook) await ws.connect() # Abonnement aux channels await ws.subscribe([ {"channel": "ticker", "instId": "BTC-USDT-SWAP"}, {"channel": "ticker", "instId": "ETH-USDT-SWAP"}, {"channel": "books50", "instId": "BTC-USDT-SWAP"}, ]) await ws.listen(None)

Lancement

asyncio.run(main())

Stratégie de market making — Code production

Voici une stratégie de market making simplifiée avec gestion du spread et contrôle des risques :

class MarketMaker:
    """Stratégie de market making avec gestion des risques."""
    
    def __init__(
        self,
        trading: OKXTrading,
        inst_id: str,
        base_spread_pct: float = 0.001,
        order_size: float = 0.01,
        max_position: float = 1.0,
        inventory_target: float = 0.0
    ):
        self.trading = trading
        self.inst_id = inst_id
        self.base_spread_pct = base_spread_pct
        self.order_size = order_size
        self.max_position = max_position
        self.inventory_target = inventory_target
        
        self.current_position = 0.0
        self.bid_order_id = None
        self.ask_order_id = None
        self.last_mid_price = None
    
    async def get_mid_price(self) -> float:
        """Récupère le prix médian du marché."""
        result = await self.trading.cred.request(
            "GET",
            "/api/v5/market/ticker",
            params={"instId": self.inst_id}
        )
        data = result['data'][0]
        bid = float(data['bidPx'])
        ask = float(data['askPx'])
        return (bid + ask) / 2
    
    def calculate_spread(self) -> tuple[float, float]:
        """Calcule les prix bid et ask avec spread ajusté.
        
        Ajuste le spread en fonction de la position:
        - Position longue → spread plus large pour vendre
        - Position courte → spread plus large pour acheter
        """
        if self.last_mid_price is None:
            return None, None
        
        # Ajustement du spread selon position
        inventory_skew = (
            self.current_position - self.inventory_target
        ) / self.max_position
        
        # Spread asymétrique pour gérer l'inventaire
        bid_spread = self.base_spread_pct * (1 + inventory_skew)
        ask_spread = self.base_spread_pct * (1 - inventory_skew)
        
        bid_price = self.last_mid_price * (1 - bid_spread)
        ask_price = self.last_mid_price * (1 + ask_spread)
        
        return bid_price, ask_price
    
    async def refresh_orders(self):
        """Rafraîchit les ordres de market making."""
        mid = await self.get_mid_price()
        self.last_mid_price = mid
        
        bid_price, ask_price = self.calculate_spread()
        
        # Annuler les ordres existants
        if self.bid_order_id:
            try:
                await self.trading.cancel_order(self.inst_id, self.bid_order_id)
            except:
                pass
        
        if self.ask_order_id:
            try:
                await self.trading.cancel_order(self.inst_id, self.ask_order_id)
            except:
                pass
        
        # Placer nouveaux ordres
        bid_result = await self.trading.place_order(
            instId=self.inst_id,
            tdMode="cross",
            side="buy",
            ordType="post_only",
            sz=str(self.order_size),
            px=str(bid_price)
        )
        
        ask_result = await self.trading.place_order(
            instId=self.inst_id,
            tdMode="cross",
            side="sell",
            ordType="post_only",
            sz=str(self.order_size),
            px=str(ask_price)
        )
        
        if bid_result.get('data'):
            self.bid_order_id = bid_result['data'][0]['ordId']
        if ask_result.get('data'):
            self.ask_order_id = ask_result['data'][0]['ordId']
    
    async def sync_position(self):
        """Synchronise la position avec l'API."""
        positions = await self.trading.get_positions(
            instId=self.inst_id
        )
        if positions.get('data'):
            for pos in positions['data']:
                self.current_position = float(pos.get('pos', 0))
        else:
            self.current_position = 0.0

Boucle principale

async def run_market_maker(): credentials = OKXCredentials( api_key="YOUR_API_KEY", secret_key="YOUR_SECRET_KEY", passphrase="YOUR_PASSPHRASE" ) trading = OKXTrading(credentials) mm = MarketMaker( trading=trading, inst_id="BTC-USDT-SWAP", base_spread_pct=0.001, order_size=0.01, max_position=1.0 ) while True: try: await mm.sync_position() await mm.refresh_orders() await asyncio.sleep(1) # Refresh toutes les secondes except Exception as e: print(f"Error: {e}") await asyncio.sleep(5)

asyncio.run(run_market_maker())

Optimisation des coûts et latence

Comparatif des approches d'optimisation

TechniqueLatenceCoût CPUCas d'usage
REST synchrone25-80msFaibleTrading basse fréquence
REST async (aiohttp)15-40msMoyenMulti-positions
WebSocket uniquement5-15msÉlevéMarket making, scalping
Co-location Tokyo2-8msN/AHFT professionnel

Pool de connexions et caching

import asyncio
import aiohttp
from functools import lru_cache
import redis.asyncio as redis

class OptimizedOKXClient:
    """Client optimisé avec cache et connection pooling."""
    
    def __init__(
        self,
        credentials: OKXCredentials,
        redis_url: str = "redis://localhost:6379"
    ):
        self.cred = credentials
        self._session = None
        self._redis = None
        self._cache_ttl = 1  # 1 seconde pour données market
    
    async def __aenter__(self):
        """Initialise les pools de connexions."""
        connector = aiohttp.TCPConnector(
            limit=100,          # Max connexions
            limit_per_host=20,  # Max par host
            ttl_dns_cache=300,  # Cache DNS 5 minutes
            enable_cleanup_closed=True
        )
        self._session = aiohttp.ClientSession(
            connector=connector,
            timeout=aiohttp.ClientTimeout(total=10)
        )
        self._redis = await redis.from_url(redis_url)
        return self
    
    async def __aexit__(self, *args):
        """Ferme proprement les connexions."""
        if self._session:
            await self._session.close()
        if self._redis:
            await self._redis.close()
    
    async def get_ticker_cached(self, inst_id: str) -> Dict:
        """Récupère le ticker avec cache Redis."""
        cache_key = f"ticker:{inst_id}"
        
        # Vérifie le cache
        cached = await self._redis.get(cache_key)
        if cached:
            return json.loads(cached)
        
        # Fetch depuis API
        result = await self._fetch_ticker(inst_id)
        
        # Met en cache
        await self._redis.setex(
            cache_key,
            self._cache_ttl,
            json.dumps(result)
        )
        
        return result
    
    async def _fetch_ticker(self, inst_id: str) -> Dict:
        """Appel API effectif pour ticker."""
        url = f"{self.cred.base_url}/api/v5/market/ticker"
        params = {"instId": inst_id}
        
        async with self._session.get(url, params=params) as resp:
            return await resp.json()

Utilisation

async def main(): async with OptimizedOKXClient(credentials) as client: ticker = await client.get_ticker_cached("BTC-USDT-SWAP") print(ticker)

Pour qui / pour qui ce n'est pas fait

✅ Idéal pour❌ Déconseillé pour
Développeurs Python/Node/Java Go connaîtissant le tradingDébutants sans expérience en API REST
Stratégies automatisées (grid, DCA, arbitrage)Trading manuel fréquence ultra-haute (>1000 orders/sec)
Backtesting et paper trading préalablesStratégies nécessitant des données on-chain
Portfolios multi-chaînes avec API OKXApplications financières régulées (nécessite licence)

Tarification et ROI

L'API OKX elle-même est gratuite, mais les coûts indirects sont à considérer :

ÉlémentCoûtOptimisation possible
Frais trading maker0.02% (Level 1) → 0.008% (VIP)Volume progressif
Frais trading taker0.05% (Level 1) → 0.02% (VIP)Ordres limit avec post_only
Infrastructure (VPS)20-100€/moisCo-location Tokyo si HFT
Développement initial40-100h selon complexitéFrameworks existants

Break-even estimation : Pour un trader actif, les frais maker réduits peuvent représenter 60-70% d'économie vs taker sur 100K$ de volume mensuel.

Pourquoi choisir HolySheep pour vos intégrations IA

Dans un pipeline de trading moderne, l'analyse de sentiment, la détection de patterns et les modèles prédictifs nécessitent des appels API IA. S'inscrire ici pour accéder à des APIs IA optimisées :

CaractéristiqueHolySheep AIConcurrents majeurs
Prix DeepSeek V3.2$0.42/MTok$0.55-0.70/MTok
Latence médiane<50ms (Paris)80-150ms
PaiementWeChat/Alipay ¥Carte internationale uniquement
Crédits gratuitsOui, dès l'inscriptionRare

Pour un système de trading exécutant 500K appels IA/mois en analyse de données on-chain et sentiment :

Erreurs courantes et solutions

Erreur 1 : Rate Limit 429 sur les ordres

# ❌ CAUSE : Trop d'ordres envoyés simultanément

Exemple d'erreur reçue:

{"msg":"Too many requests","code":"50004","data":[]}

✅ SOLUTION : Implémenter un rate limiter avec token bucket

import asyncio from collections import deque class RateLimiter: """Token bucket algorithm pour OKX API.""" def __init__(self, max_calls: int, time_window: float): self.max_calls = max_calls self.time_window = time_window self.calls = deque() async def acquire(self): """Bloque jusqu'à ce qu'un token soit disponible.""" now = asyncio.get_event_loop().time() # Supprime les appels hors fenêtre while self.calls and self.calls[0] < now - self.time_window: self.calls.popleft() if len(self.calls) >= self.max_calls: # Attend le prochain slot libre sleep_time = self.calls[0] + self.time_window - now await asyncio.sleep(sleep_time) return await self.acquire() self.calls.append(now)

Utilisation

rate_limiter = RateLimiter(max_calls=20, time_window=1.0) # 20 req/sec max async def safe_order(...): await rate_limiter.acquire() return await trading.place_order(...)

Erreur 2 : Signature invalide (401 Unauthorized)

# ❌ CAUSE : Mauvais format de timestamp ou de calcul de signature

Erreur type:

{"msg":"Illegal request","code":"50102"}

✅ SOLUTION : Vérifier le format exact requis par OKX

Le timestamp DOIT être en ISO 8601 avec millisecondes

from datetime import datetime, timezone def get_okx_timestamp() -> str: """Génère le timestamp au format exact OKX.""" utc_now = datetime.now(timezone.utc) # Format: 2024-01-15T10:30:45.123Z return utc_now.strftime('%Y-%m-%dT%H:%M:%S.') + \ f"{utc_now.microsecond // 1000:03d}Z"

Vérification de la signature:

1. timestamp = OK-ACCESS-TIMESTAMP

2. method = POST ou GET (MAJUSCULES)

3. request_path = /api/v5/trade/order (sans base_url)

4. body = "" pour GET, JSON string pour POST

5. message = timestamp + method + request_path + body

❌ ERREUR COURANTE : Inclure les query params dans requestPath

✅ CORRECT : requestPath = "/api/v5/trade/order" sans "?sz=1"

Code corrigé pour POST avec body:

body = {"instId": "BTC-USDT-SWAP", "sz": "0.01"} body_str = json.dumps(body, separators=(',', ':')) # Pas d'espace!

Signature: timestamp + "POST" + "/api/v5/trade/order" + body_str

Erreur 3 : Position non trouvée ou incohérence de balance

# ❌ CAUSE : Mauvais paramètre instType ou ccy pour les positions

Erreur type:

{"data": [], "msg": ""} mais position existe réellement

✅ SOLUTION : Vérifier les paramètres exacts de l'endpoint

async def get_all_positions(trading: OKXTrading) -> list: """Récupère TOUTES les positions avec les bons paramètres.""" all_positions = [] # Pour les perpetual swaps : # - instType = "SWAP" # - instId doit inclure le suffix "-SWAP" for inst_type in ["SWAP", "FUTURES", "OPTION"]: result = await trading.cred.request( "GET", "/api/v5/account/positions", params={"instType": inst_type} ) if result.get('data'): all_positions.extend(result['data']) return all_positions

Vérification de la position spécifique

async def get_position_detail(trading: OKXTrading, inst_id: str): """Récupère les détails d'une position spécifique. Note: Pour les SWAP, le paramètre est instId complet comme "BTC-USDT-SWAP", pas seulement "BTC-USDT" """ return await trading.cred.request( "GET", "/api/v5