Skip to content

πŸ”’ Close Position (ClosePosition)ΒΆ

Sugar method: Closes an open position completely by ticket number.

API Information:

  • Method: sugar.ClosePosition(ticket)
  • Timeout: 10 seconds
  • Returns: Error if close failed

πŸ“‹ Method SignatureΒΆ

func (s *MT5Sugar) ClosePosition(ticket uint64) error

πŸ”½ Input / ⬆️ OutputΒΆ

Input Type Description
ticket uint64 Position ticket number to close
Output Type Description
error error nil if successful, error if failed

πŸ’¬ Just the EssentialsΒΆ

  • What it is: Closes entire position immediately at current market price.
  • Why you need it: Exit trades manually, cut losses, take profits.
  • Sanity check: Position must exist and be open. Returns error if position not found.

🎯 When to Use¢

βœ… Manual exit - Close position when you want to exit

βœ… Stop loss hit - Manually close after SL triggered

βœ… Take profit - Lock in gains

βœ… Emergency close - Get out of bad trade quickly


πŸ”— Usage ExamplesΒΆ

1) Basic usage - close by ticketΒΆ

ticket := uint64(12345) // Position ticket from opening

err := sugar.ClosePosition(ticket)
if err != nil {
    fmt.Printf("Failed to close: %v\n", err)
    return
}

fmt.Printf("βœ… Position #%d closed successfully\n", ticket)

2) Close and verifyΒΆ

ticket := uint64(12345)

fmt.Printf("Closing position #%d...\n", ticket)

err := sugar.ClosePosition(ticket)
if err != nil {
    fmt.Printf("❌ Close failed: %v\n", err)
    return
}

fmt.Println("βœ… Close successful")

// Verify position no longer exists
time.Sleep(1 * time.Second)
_, err = sugar.GetPositionByTicket(ticket)
if err != nil {
    fmt.Println("βœ… Confirmed - position no longer exists")
} else {
    fmt.Println("⚠️  Warning - position still exists")
}

3) Close with profit checkΒΆ

ticket := uint64(12345)

// Check profit before closing
pos, err := sugar.GetPositionByTicket(ticket)
if err != nil {
    fmt.Printf("Position not found: %v\n", err)
    return
}

fmt.Printf("Position #%d status:\n", ticket)
fmt.Printf("  Symbol: %s\n", pos.Symbol)
fmt.Printf("  Volume: %.2f\n", pos.Volume)
fmt.Printf("  Profit: $%.2f\n", pos.Profit)

// Close position
err = sugar.ClosePosition(ticket)
if err != nil {
    fmt.Printf("Close failed: %v\n", err)
    return
}

if pos.Profit > 0 {
    fmt.Printf("βœ… Profit locked: $%.2f\n", pos.Profit)
} else {
    fmt.Printf("βœ… Loss cut: $%.2f\n", pos.Profit)
}

4) Close at target profitΒΆ

ticket := uint64(12345)
targetProfit := 100.0 // $100

ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()

fmt.Printf("Monitoring position #%d for $%.2f profit...\n", ticket, targetProfit)

for range ticker.C {
    pos, err := sugar.GetPositionByTicket(ticket)
    if err != nil {
        fmt.Println("Position no longer exists")
        return
    }

    fmt.Printf("Current profit: $%.2f\n", pos.Profit)

    if pos.Profit >= targetProfit {
        fmt.Printf("🎯 Target reached! Closing...\n")
        sugar.ClosePosition(ticket)
        fmt.Printf("βœ… Position closed at $%.2f profit\n", pos.Profit)
        return
    }
}

5) Close on stop loss breachΒΆ

ticket := uint64(12345)
maxLoss := -50.0 // Stop at $50 loss

ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()

fmt.Printf("Monitoring position #%d with $%.2f max loss...\n", ticket, maxLoss)

for range ticker.C {
    pos, err := sugar.GetPositionByTicket(ticket)
    if err != nil {
        return
    }

    if pos.Profit <= maxLoss {
        fmt.Printf("πŸ›‘ Stop loss hit: $%.2f\n", pos.Profit)
        err := sugar.ClosePosition(ticket)
        if err != nil {
            fmt.Printf("❌ Emergency close failed: %v\n", err)
        } else {
            fmt.Println("βœ… Position closed - loss limited")
        }
        return
    }

    fmt.Printf("Current P/L: $%.2f (SL: $%.2f)\n", pos.Profit, maxLoss)
}

6) Close all positions for a symbolΒΆ

symbol := "EURUSD"

positions, _ := sugar.GetPositionsBySymbol(symbol)

fmt.Printf("Closing %d %s positions...\n", len(positions), symbol)

closedCount := 0
for _, pos := range positions {
    err := sugar.ClosePosition(pos.Ticket)
    if err != nil {
        fmt.Printf("❌ Failed to close #%d: %v\n", pos.Ticket, err)
        continue
    }

    closedCount++
    fmt.Printf("βœ… Closed #%d (%.2f lots, $%.2f P/L)\n",
        pos.Ticket, pos.Volume, pos.Profit)
}

fmt.Printf("\n%d/%d positions closed\n", closedCount, len(positions))

7) Close oldest position firstΒΆ

positions, _ := sugar.GetOpenPositions()

if len(positions) == 0 {
    fmt.Println("No positions to close")
    return
}

// Find oldest position
var oldest *PositionInfo
for _, pos := range positions {
    if oldest == nil || pos.TimeOpen.Before(oldest.TimeOpen) {
        oldest = pos
    }
}

fmt.Printf("Closing oldest position #%d (opened: %s)\n",
    oldest.Ticket, oldest.TimeOpen.Format("2006-01-02 15:04:05"))

err := sugar.ClosePosition(oldest.Ticket)
if err != nil {
    fmt.Printf("Close failed: %v\n", err)
} else {
    fmt.Printf("βœ… Closed - held for %v\n", time.Since(oldest.TimeOpen).Round(time.Minute))
}

8) Close losing positions onlyΒΆ

positions, _ := sugar.GetOpenPositions()

fmt.Println("Closing losing positions...")

for _, pos := range positions {
    if pos.Profit < 0 {
        fmt.Printf("Closing #%d: %s (loss: $%.2f)\n",
            pos.Ticket, pos.Symbol, pos.Profit)

        err := sugar.ClosePosition(pos.Ticket)
        if err != nil {
            fmt.Printf("  ❌ Failed: %v\n", err)
        } else {
            fmt.Printf("  βœ… Closed\n")
        }
    }
}

9) Close with retry logicΒΆ

func ClosePositionWithRetry(sugar *mt5.MT5Sugar, ticket uint64, maxRetries int) error {
    for attempt := 1; attempt <= maxRetries; attempt++ {
        err := sugar.ClosePosition(ticket)
        if err == nil {
            fmt.Printf("βœ… Position #%d closed (attempt %d)\n", ticket, attempt)
            return nil
        }

        fmt.Printf("❌ Attempt %d failed: %v\n", attempt, err)

        if attempt < maxRetries {
            fmt.Printf("   Retrying in 2 seconds...\n")
            time.Sleep(2 * time.Second)
        }
    }

    return fmt.Errorf("failed to close after %d attempts", maxRetries)
}

// Usage:
err := ClosePositionWithRetry(sugar, 12345, 3)

10) Advanced close with analysisΒΆ

func ClosePositionWithAnalysis(sugar *mt5.MT5Sugar, ticket uint64) error {
    fmt.Println("╔═══════════════════════════════════════╗")
    fmt.Println("β•‘      CLOSING POSITION                 β•‘")
    fmt.Println("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•")

    // Get position details before closing
    pos, err := sugar.GetPositionByTicket(ticket)
    if err != nil {
        return fmt.Errorf("position not found: %w", err)
    }

    fmt.Printf("Position #%d:\n", ticket)
    fmt.Printf("  Symbol:    %s\n", pos.Symbol)
    fmt.Printf("  Type:      %s\n", pos.Type)
    fmt.Printf("  Volume:    %.2f lots\n", pos.Volume)
    fmt.Printf("  Open:      %.5f\n", pos.PriceOpen)
    fmt.Printf("  Current:   %.5f\n", pos.PriceCurrent)
    fmt.Printf("  Profit:    $%.2f\n", pos.Profit)
    fmt.Printf("  Duration:  %v\n", time.Since(pos.TimeOpen).Round(time.Minute))

    // Calculate metrics
    var pips float64
    if pos.Type == "BUY" {
        pips = (pos.PriceCurrent - pos.PriceOpen) / 0.00001
    } else {
        pips = (pos.PriceOpen - pos.PriceCurrent) / 0.00001
    }

    fmt.Printf("  Pips:      %.1f\n", pips)

    // Close position
    fmt.Println("\nClosing...")
    err = sugar.ClosePosition(ticket)
    if err != nil {
        return fmt.Errorf("close failed: %w", err)
    }

    fmt.Println("\nβœ… Position closed successfully")
    fmt.Printf("   Final P/L: $%.2f (%.1f pips)\n", pos.Profit, pips)

    return nil
}

// Usage:
ClosePositionWithAnalysis(sugar, 12345)

🍬 Other close methods:

  • ClosePositionPartial() - Close only part of position
  • CloseAllPositions() - Close all positions at once

🍬 Position info:

  • GetPositionByTicket() - Get position details before closing
  • GetOpenPositions() - List all positions

⚠️ Common Pitfalls¢

1) Not checking if position existsΒΆ

// ❌ WRONG - blindly closing
sugar.ClosePosition(12345) // Might not exist!

// βœ… CORRECT - check first
pos, err := sugar.GetPositionByTicket(12345)
if err != nil {
    fmt.Println("Position doesn't exist")
    return
}
sugar.ClosePosition(12345)

2) Ignoring close errorsΒΆ

// ❌ WRONG - ignoring errors
sugar.ClosePosition(ticket)
fmt.Println("Closed!") // Maybe not!

// βœ… CORRECT - handle errors
err := sugar.ClosePosition(ticket)
if err != nil {
    fmt.Printf("Failed: %v\n", err)
    return
}

3) Closing during high spreadΒΆ

// ❌ WRONG - close regardless of spread
sugar.ClosePosition(ticket)

// βœ… BETTER - check spread first
spread, _ := sugar.GetSpread("EURUSD")
if spread > 20 {
    fmt.Printf("⚠️  High spread: %.0f - wait for better conditions?\n", spread)
}
// Then decide whether to close

πŸ’Ž Pro TipsΒΆ

  1. Check profit first - Know what you're closing

  2. Verify close - Check position no longer exists after

  3. Handle errors - Market might be closed, position might not exist

  4. Be patient - Sometimes close takes a few seconds to execute

  5. Consider spread - Closing during wide spread = worse exit price


See also: ClosePositionPartial.md, CloseAllPositions.md, GetPositionByTicket.md