Skip to main content

État CLOSED - Fermeture de Position

📊 Statut des Tests

Tests Frontend (Checkly)

Tests Backend (Vitest)


🎯 Vue d’ensemble

L’état CLOSED correspond à une position fermée. Une position peut être fermée pour deux raisons principales : changement de tendance ou Stop Loss touché.

🔄 Transition RUNNING → CLOSED

Conditions de fermeture

  1. Changement de tendance :
    • LONG : candle.wma50 < wma50_htf
    • SHORT : candle.wma50 > wma50_htf
  2. Stop Loss touché :
    • SL de BUY2 touché (BUY2 fermé) → Fermeture complète
    • Note : SL de BUY1 touché (BUY2 non fermé) → Position reste en RUNNING
Note : Le Stop Loss est désormais géré par sharkModeCron.ts qui surveille les bougies 1m et met à jour le SL de manière agressive basé sur le Heikin Ashi. La fermeture par SL est gérée directement via processClose() qui crée l’ordre Close, puis la position passe en CLOSED après l’exécution de l’ordre.

Actions lors de la fermeture

  • Annulation des ordres TP1/TP2 ouverts
  • Création d’un ordre de fermeture (market)
  • Après l’exécution de l’ordre Close : status = CLOSED
  • Calcul des coûts finaux (finalBuyCost, finalSellCost)
  • Calcul des frais finaux (finalBuyFee, finalSellFee)
  • Notification envoyée

Ordre de fermeture (processClose)

Calcul du montant à fermer selon le contexte :
  1. SL touché + BUY2 non fermé :
    amountToClose = relativeAmount  // Pas de soustraction des fees pour SL
    
  2. SL touché + BUY2 fermé :
    amountToClose = relativeAmount + reserveAmount  // Pas de soustraction des fees pour SL
    
  3. Fermeture normale (changement de tendance) :
    amountToClose = relativeAmount + reserveAmount - totalBaseAssetFees
    
Vérification préalable :
  • Si relativeAmount <= 0 : Ne pas créer d’ordre Close, passer directement en CLOSED
Note : Pour les fermetures par SL (touché ou sécurité), les frais ne sont pas soustraits du montant à fermer car ils sont gérés séparément lors de l’exécution de l’ordre.

📋 Variantes de Fermeture

Variante 1 : Fermeture par changement de tendance

Séquence :
Position RUNNING → Nouvelle bougie → Changement tendance détecté → Annulation TP1/TP2 → Ordre Close → CLOSED
Comportement attendu :
  • Détection du changement de tendance (WMA50)
  • Annulation des ordres TP1/TP2 ouverts
  • Création d’un ordre Close (market) pour vendre relativeAmount + reserveAmount - totalBaseAssetFees
  • Après exécution de l’ordre Close : status = CLOSED, closedReason = TREND_CHANGED
  • Calcul des coûts et frais finaux
  • Notification envoyée

Variante 2 : Fermeture par Stop Loss (SL_BUY2)

Séquence :
Position RUNNING → BUY2 fermé → SL touché (SL_BUY2) → Ordre Close → CLOSED
Comportement attendu :
  • SL de BUY2 touché (BUY2 fermé)
  • slMode = SL_BUY2 défini
  • Création d’un ordre Close pour vendre relativeAmount + reserveAmount
  • Après exécution de l’ordre Close : status = CLOSED, closedReason = REACHED_STOP_LOSS
  • Fermeture complète de la position
  • Calcul des coûts et frais finaux
  • Notification envoyée

Variante 3 : SL de BUY1 touché (position reste RUNNING)

Séquence :
Position RUNNING → BUY2 non fermé → SL de BUY1 touché → Ordre Close → Position reste RUNNING
Comportement attendu :
  • SL de BUY1 touché (BUY2 non fermé)
  • slMode = SL_BUY1 défini
  • Création d’un ordre Close pour vendre seulement relativeAmount (pas reserveAmount)
  • Après exécution de l’ordre Close : Position reste en RUNNING (pas CLOSED)
  • relativeAmount mis à jour à 0
  • La position continue d’être traitée pour permettre l’exécution future de BUY2
  • La position ne sera fermée que si :
    • BUY2 est exécuté puis son SL est touché (passage en SL_BUY2)
    • La tendance change (création d’un ordre Close)
Note importante : Cette variante ne ferme PAS la position, elle vend seulement le montant de BUY1. La position reste active pour permettre l’exécution de BUY2.

🔍 Logique de Fermeture Détaillée

Après exécution de l’ordre Close

La fermeture de la position après l’exécution de l’ordre Close est déterminée par slMode et le status, pas par calculatedRelativeAmount.

Cas 1 : SL_BUY2 (SL de BUY2 touché)

  • Condition : slMode === 'SL_BUY2' ET closeOrder.status === 'closed'
  • Comportement :
    • Fermeture complète de la position (l’ordre Close a vendu relativeAmount + reserveAmount)
    • status = CLOSED
    • closedReason = REACHED_STOP_LOSS
    • closedAt = new Date()
    • relativeAmount = 0
    • ✅ Calcul des coûts finaux (finalBuyCost, finalSellCost)
    • ✅ Calcul des frais finaux (finalBuyFee, finalSellFee)
    • ✅ Notification envoyée

Cas 2 : SL_BUY1 (SL de BUY1 touché, BUY2 non fermé)

  • Condition : slMode === 'SL_BUY1' ET buy2IsClosed === false ET closeOrder.status === 'closed'
  • Comportement :
    • La position reste en RUNNING même après l’exécution de l’ordre Close
    • ✅ L’ordre Close a vendu seulement relativeAmount (pas reserveAmount)
    • relativeAmount est mis à jour à 0
    • ✅ La position continue d’être traitée par swingPositions pour permettre l’exécution future de BUY2
    • ✅ La position ne sera fermée que si :
      • BUY2 est exécuté puis son SL est touché (passage en SL_BUY2)
      • La tendance change (création d’un ordre Close)

Cas 3 : Fermeture normale (changement de tendance)

  • Condition : closeOrder.status === 'closed' ET slMode !== 'SL_BUY1' (ou slMode === null)
  • Comportement :
    • status = CLOSED
    • closedReason = TREND_CHANGED
    • closedAt = new Date()
    • ✅ Calcul des coûts finaux (finalBuyCost, finalSellCost)
    • ✅ Calcul des frais finaux (finalBuyFee, finalSellFee)
    • ✅ Notification envoyée

📊 Calculs Finaux

Coûts finaux

finalBuyCost = (buy1Amount * buy1Price) + (buy2Amount * buy2Price)
finalSellCost = (tp1Amount * tp1Price) + (tp2Amount * tp2Price) + (closeAmount * closePrice)

Frais finaux

finalBuyFee = (buy1Order.fee?.cost || 0) + (buy2Order.fee?.cost || 0)
finalSellFee = totalTpFees + (closeOrder.fee?.cost || 0)

PnL final

pnl = finalSellCost - finalBuyCost - finalBuyFee - finalSellFee

🧪 Tests

Tests Frontend

Les tests frontend vérifient l’affichage des positions fermées et l’historique. Fichiers de tests : features/positions/closed-position.spec.ts Configuration Checkly :
// @checkly frequency: 10min
// @checkly locations: paris, new-york
// @checkly alertChannels: linear
// @checkly tags: production, positions

Tests Backend

Les tests backend valident la logique de fermeture et les différents scénarios. Fichiers de tests : packages/functions/src/tests/positions/closed-state.test.ts Exécution :
npm run test -- closed-state

🔗 Navigation