Avant-propos : Pourquoi ne pas trader des cryptos, mais plutôt du TradFi ?
Tous ceux qui ont déjà fait du grid trading sur des cryptos en ont fait le même cauchemar : à peine le grid mis en place, le prix s’effondre, les positions sont bloquées, il faut ajouter de la marge ou c’est le liquidation. L’attrait des cryptos réside dans l’absence de limite de variation, mais c’est précisément le pire ennemi du grid trading – le grid est conçu pour les marchés oscillants, un mouvement unidirectionnel le mène à la ruine.
Existe-t-il une classe d’actifs qui conserve suffisamment de volatilité intraday pour que le grid soit fréquemment déclenché, sans subir des poussées ou des dégringolades brutales de 30 % ou 50 % ? La réponse se trouve dans les instruments TradFi.
Les produits dérivés TradFi (finance traditionnelle), notamment les contrats perpétuels sur des actifs traditionnels comme le S&P 500, le Nasdaq, l’or, le pétrole brut, les devises, sont ancrés par un fondamental réel. Les indices boursiers sont contraints par les bénéfices des entreprises et les politiques de la Fed, les matières premières par l’offre et la demande, les taux de change par les relations entre deux économies souveraines. Ces actifs ne peuvent pas multiplier par 5 en une nuit sans raison, ni s’effondrer de 80 % à cause d’un tweet. Leur prix a une « gravité » – ils peuvent osciller à court terme, mais à long terme, ils reviennent vers les fondamentaux.
Cette caractéristique fait du grid trading et de ces actifs un duo presque parfait : une volatilité intraday normale de 1 à 3 %, suffisante pour déclencher fréquemment les grilles ; en cas de mouvement extrême, le grid n’est pas totalement anéanti, laissant une marge de manœuvre suffisante pour les stop-loss et la gestion du capital. Cette stratégie est construite sur ce principe – scanner automatiquement tous les instruments TradFi, identifier ceux qui sont les plus volatils actuellement, y construire un grid cyclique, et effectuer une rotation automatique lorsque la structure de volatilité change.
Contexte : Les bourses crypto ont discrètement listé un nouveau type de produits
Ces deux dernières années, les grandes bourses crypto comme OKX, Bitget ont discrètement listé un grand nombre de contrats perpétuels TradFi, couvrant des indices boursiers américains (S&P 500, Nasdaq 100), des actions individuelles (Apple, NVIDIA, Tesla), des matières premières (or, pétrole brut, gaz naturel), et des devises (EUR, JPY). En bref, vous pouvez désormais trader des actions américaines, de l’or, des devises directement sur une bourse crypto, 24 h/24 et 7 j/7, avec un effet de levier en prime.
Cela a une importance majeure pour le trading quantitatif. D’un côté, ces instruments héritent des propriétés fondamentales des actifs financiers traditionnels – leur prix ne fait pas de bonds ou de chutes sans raison. De l’autre, ils sont listés sur des bourses crypto avec la structure des contrats perpétuels, une liquidité suffisante, des frais transparents, et des API identiques à celles des cryptos, permettant une intégration fluide des stratégies quantitatives.
Autrement dit, cette catégorie ouvre un nouvel espace d’arbitrage : utiliser l’infrastructure crypto pour faire de l’arbitrage de range sur des actifs financiers traditionnels. Cette stratégie est taillée sur mesure pour ce scénario : utiliser un programme pour filtrer automatiquement les instruments les plus volatils, y placer des grids, et capturer les profits des oscillations.
I. Logique de sélection : ne retenir que les instruments les plus volatils
La rentabilité d’un grid dépend à 60 % du choix de l’instrument. Un bon instrument déclenche la grille des dizaines de fois par jour, engrangeant des profits naturels. Un mauvais instrument laisse la grille inactive toute une semaine, immobilisant le capital.
Le seul critère de sélection de cette stratégie est l’amplitude quotidienne moyenne des N dernières bougies journalières.
Score de volatilité = Σ [ (High_i − Low_i) / Close_i × 100 ] / N
Voici le code, la logique est claire :
python
def score_symbol(info):
bars = exchange.GetRecords(info["sym"], PERIOD_D1, KLINE_COUNT + 2)
if not bars or len(bars) < 3:
return None
bars = bars[-KLINE_COUNT:]
atr_pcts = [(b["High"] - b["Low"]) / b["Close"] * 100 for b in bars if b["Close"] > 0]
avg_atr = sum(atr_pcts) / len(atr_pcts)
# L'amplitude quotidienne moyenne doit être au moins 1,5 fois l'espacement des grilles, sinon élimination
if avg_atr < GRID_RATIO * 100 * 1.5:
return None
return {"sym": info["sym"], "atr": round(avg_atr, 3), "price": bars[-1]["Close"]}
La stratégie scanne régulièrement tous les instruments TradFi et les classe, en sélectionnant les TOP_N les plus volatils pour les détenir. Le seuil d’entrée est crucial : l’amplitude quotidienne moyenne doit être au moins 1,5 fois l’espacement des grilles, sinon le prix pourrait même ne pas traverser une seule grille en une journée, donc élimination directe pour éviter de bloquer des fonds sur des instruments inefficaces.
L’identification des instruments TradFi nécessite un traitement spécial. Sur la plateforme FMZ, les instruments TradFi sont distingués des cryptos classiques par le champ instCategory :
python
def scan_tradfi():
markets = exchange.GetMarkets()
for sym, mkt in markets.items():
if not sym.endswith("USDT.swap"):
continue
info = mkt.get("Info") or {}
# instCategory != 1 correspond aux instruments TradFi
if int(info.get("instCategory", 1)) == 1:
continue
result.append({"sym": sym, "base": base, "cat": cat})
II. Structure du grid : acheter bas, vendre haut, arbitrage cyclique
Sur l’instrument sélectionné, on prend le prix actuel comme centre, on étend de part et d’autre selon un certain pourcentage, on découpe en grilles équidistantes (échelle géométrique). Chaque grille située sous le prix actuel reçoit un ordre d’achat, en attente que le prix descende pour être exécuté.
Le code principal pour construire le grid :
python
def build_grid(sym, price):
low = price * (1 - LOWER_RANGE)
high = price * (1 + LOWER_RANGE)
# Découpage géométrique
grids, p = [], low
while p <= high * 1.001:
grids.append(round(p, g_states[sym]["pp"]))
p = p * (1 + GRID_RATIO)
for i in range(len(grids) - 1):
buy_p, sell_p = grids[i], grids[i + 1]
if buy_p < price:
oid = buy_open(sym, buy_p, GRID_VALUE) # prix sous le marché : ordre d'achat immédiat
g["status"] = "pending_buy" if oid else "skip"
else:
g["status"] = "above" # prix au-dessus du marché : pas d'ordre pour l'instant, attendre que le prix baisse
La synchronisation du grid est la boucle centrale de la stratégie, qui vérifie l’état de chaque ordre de grille et réagit :
python
def sync(sym):
for g in grids:
if g["status"] == "pending_buy":
s, deal, avgp = check_order(g["buy_oid"])
if s == "filled":
# Ordre d'achat exécuté → placer immédiatement un ordre de prise de profit
oid = sell_close(sym, g["sp"], ct)
g["status"] = "pending_sell"
elif g["status"] == "pending_sell":
s, deal, avgp = check_order(g["sell_oid"])
if s == "filled":
# Prise de profit exécutée → calcul du profit, replacer un ordre d'achat, cycle
profit = g["ct"] * cv * (avgp - g["fp"])
g_total_profit += profit
oid = buy_open(sym, g["bp"], GRID_VALUE)
g["status"] = "pending_buy"
La logique est claire : quand le prix traverse une grille à la baisse, déclenche un achat ; quand il remonte au-dessus de la grille suivante, déclenche une prise de profit ; après la prise de profit, replace un ordre d’achat au même niveau, et ainsi de suite. En cas d’annulation d’ordre, d’anomalie de take-profit, etc., des mécanismes de détection et de replacement sont en place, la stratégie ne s’arrête pas à cause d’incidents ponctuels.
III. Rotation intelligente : garder le capital toujours sur les instruments les plus actifs
Le rythme de volatilité des instruments TradFi se déplace en fonction des événements macro, des saisons de résultats, des changements de politique. Parfois l’or est le plus actif, puis une période plus tard ce peut être le pétrole brut ou le S&P futures. Rester fixé sur un seul instrument, on finira tôt ou tard par tomber sur une phase de faible volatilité où la grille ne bouge pas pendant une semaine.
La stratégie réévalue et classe tous les instruments TradFi toutes les N heures (par défaut 48 heures), en décidant s’il faut remplacer les instruments actuellement détenus. Pour éviter les frais de rotation excessifs dus à des écarts minimes, un mécanisme d’hystérésis est introduit :
python
def needs_rebalance(new_selected):
cur_scores = {s["sym"]: s["atr"] for s in g_score_log if s["sym"] in g_active}
for s in new_selected:
if s["sym"] in g_active:
continue
weakest_atr = min(cur_scores.values())
threshold = weakest_atr * (1 + HYSTERESIS) # Doit être 20% plus élevé pour déclencher le changement
if s["atr"] >= threshold:
Log(f"{s['base']} ATR={s['atr']:.2f}% > seuil={threshold:.2f}%, changement déclenché")
else:
Log(f"{s['base']} ATR={s['atr']:.2f}% < seuil={threshold:.2f}%, hystérésis maintenue")
Ce n'est que lorsque l'amplitude quotidienne moyenne du nouveau candidat dépasse de plus de 20 % celle de la position la plus faible actuelle que le changement de portefeuille est réellement déclenché. Le processus de changement est le suivant : d'abord annuler tous les ordres en attente de l'ancien actif, clôturer toutes les positions, puis reconstruire une grille complète sur le nouvel actif. L'ensemble du processus est automatisé.
IV. Description des paramètres clés
-- TOP_N contrôle le nombre d'actifs détenus simultanément, par défaut 3, ce qui signifie que le capital est réparti sur les 3 actifs les plus volatils.
-- GRID_RATIO est le ratio d'espacement de la grille, par défaut 1,5 %, représentant le niveau de take-profit de chaque cellule.
-- GRID_VALUE est le montant fixe en USDT investi par cellule, par défaut 50, non ajusté en fonction du prix.
-- LOWER_RANGE détermine la plage de prix couverte par la grille, par défaut ±10 % autour du prix actuel.
-- REBALANCE_HOURS est la période d'évaluation du rééquilibrage, par défaut 48 heures.
-- HYSTERESIS est le seuil d'hystérésis, par défaut 20 %, pour éviter des changements trop fréquents.
-- LEVERAGE est le niveau de levier, recommandé pas plus de 3x.
-- STOP_LOSS_RATIO est la ligne de stop-loss globale ; lorsque la perte du compte dépasse ce ratio, toutes les positions sont fermées automatiquement, par défaut 30 %.
-- KLINE_COUNT est le nombre de bougies journalières utilisées pour l'évaluation, par défaut les 20 dernières.
-- EXCLUDE_SYMBOLS est une liste noire dans laquelle on peut inscrire les codes des actifs à ne pas toucher ; plusieurs codes séparés par des virgules.
V. Contrôle des risques
Le stop-loss global est la dernière ligne de défense de la stratégie. Lorsque la perte de capitaux propres du compte dépasse un certain pourcentage de la valeur initiale, la stratégie annule automatiquement les ordres, ferme toutes les positions et arrête toutes les opérations suivantes :
python
def check_stop():
acc = exchange.GetAccount()
loss = (g_init_equity - acc.Equity) / g_init_equity
if loss >= STOP_LOSS_RATIO:
Log(f"Stop-loss déclenché ! Perte={loss*100:.1f}% → fermeture complète")
for sym in list(g_active):
close_all(sym)
g_state = "STOP"
Le filtre d'admission lors de la sélection des actifs élimine ceux dont la volatilité est insuffisante, garantissant que chaque actif entrant dans la stratégie dispose d'une amplitude intraday suffisante pour faire fonctionner la grille. Le mécanisme de liste noire permet d'exclure manuellement les actifs à faible liquidité, présentant des spreads anormaux ou un comportement instable. Tous les prix et quantités des ordres sont strictement alignés sur les exigences de précision de l'échange, éliminant à la source les rejets d'ordres dus à des erreurs de précision. Le capital est réparti également entre les actifs, de sorte qu'une perte sur un seul actif n'affecte pas la structure globale du portefeuille.
VI. Conditions de marché favorables et points d'attention
Cette stratégie donne les meilleurs résultats dans un marché en range. Lorsque l'actif cible oscille entre deux bornes, les cellules de la grille sont fréquemment déclenchées, les gains s'accumulent linéairement dans le temps, et la stratégie ne nécessite pratiquement aucune intervention manuelle.
Il faut toutefois noter que si le prix évolue durablement dans une direction unique et franchit la borne inférieure de la grille, tous les ordres d'achat seront piégés, et il faudra attendre que le prix revienne ou que le stop-loss global se déclenche. Pour certains actifs TradFi, en dehors des heures de négociation (par exemple pendant la fermeture des marchés américains), la liquidité chute fortement et les ordres en attente peuvent ne pas être exécutés pendant longtemps ; cela est normal. Le paramètre GRID_RATIO doit être défini en fonction de l'amplitude quotidienne moyenne de l'actif cible : il est recommandé de le fixer entre 1/3 et 1/2 de cette amplitude. Trop grand, la fréquence de déclenchement est faible ; trop petit, les frais de transaction grignotent les bénéfices. Le levier est recommandé en dessous de 3x ; un levier excessif dans des conditions de marché extrêmes aggrave les pertes et rend le contrôle difficile avant même que le stop-loss ne se déclenche.
Conclusion
Le principe fondamental de cette stratégie peut se résumer en une phrase : placer en permanence le capital sur les actifs TradFi les plus volatils, et laisser la grille faire son travail avec le temps. Les quatre modules — sélection des actifs, construction de la grille, rééquilibrage et contrôle des risques — sont interconnectés et fonctionnent entièrement en automatique. La nature fondamentale des actifs TradFi offre une garantie sous-jacente que le prix ne dérivera pas indéfiniment, tandis que le filtrage programmatique de la volatilité garantit que le capital est toujours alloué aux actifs les plus efficaces. Avec des paramètres bien choisis, la stratégie peut générer des gains de grille stables dans la plupart des environnements de marché, tout en maintenant le risque de baisse dans des limites acceptables grâce au stop-loss et au mécanisme d'hystérésis.
Ce document est une description de la stratégie originale de la plateforme FMZ Quant, fournie à titre éducatif et informatif uniquement, et ne constitue en aucun cas un conseil en investissement.
- 1


