Automatisez Votre Stratégie de Trading avec SimpleFX API

Créez des bots de trading puissants en quelques minutes

Accédez à plus de 1 000 instruments à effet de levier incluant crypto, forex, indices, matières premières et actions. SimpleFX fournit une API REST complète et des connexions WebSocket pour les données de marché en temps réel, vous permettant de construire des algorithmes de trading sophistiqués.

Prêt à Commencer le Trading Algorithmique ?

Découvrez comment le trading automatisé peut fonctionner pour votre stratégie avec SimpleFX

Exécution ultra-rapide

Plus de 1 000 instruments

Accès complet à l'API

Spreads serrés

Plateformes mobile et web

Inscription rapide

Pourquoi le Trading Algorithmique ?

Le trading algorithmique transforme la façon dont les traders interagissent avec les marchés, offrant une précision et une efficacité que le trading manuel ne peut égaler. En automatisant vos stratégies, vous éliminez la prise de décision émotionnelle et assurez une exécution cohérente dans toutes les conditions de marché.

Tradez 24/7

Exécutez vos stratégies 24 heures sur 24 sans que les décisions émotionnelles n'affectent vos trades. Votre bot ne dort jamais, n'hésite jamais et ne dévie jamais du plan.

Gestion des Risques Cohérente

Appliquez automatiquement des paramètres de risque prédéfinis incluant stop-losses, take-profits et dimensionnement des positions. Assurez une gestion des risques cohérente sur tous les trades sans intervention manuelle.

Évoluez avec Précision

Exécutez des trades avec un timing parfait et une consistance sur plusieurs instruments. Développez votre trading sans augmenter proportionnellement votre engagement en temps.

Capturez les Opportunités

Profitez automatiquement des opportunités de marché dès qu'elles se présentent en temps réel. Réagissez aux mouvements de prix plus rapidement que tout trader manuel.

Premiers Pas : Obtenez Votre Clé API

Avant de pouvoir exécuter votre premier bot de trading, vous devez générer des identifiants API depuis votre compte SimpleFX. Suivez ces étapes pour configurer votre accès API :

Step 1

Visitez SimpleFX

Naviguez vers simplefx.com et connectez-vous à votre compte

Step 2

Accédez aux Paramètres

Cliquez sur le menu (icône hamburger) et sélectionnez Paramètres

Step 3

Section API

Sélectionnez API dans le menu des paramètres

Step 4

Créer une Clé API

Cliquez sur le bouton "Créer une Clé API"

Step 5

Configurez les Permissions

Nommez votre clé, sélectionnez les permissions de trading et ajoutez optionnellement une liste blanche d'IPs pour une sécurité renforcée

Step 6

Générez et Sauvegardez

Cliquez sur Créer et copiez immédiatement votre secret API (affiché une seule fois !)

Step 7

Confirmez la Clé

Vérifiez via 2FA ou lien de confirmation par email

Step 8

Copiez l'ID de la Clé

Sauvegardez votre ID de Clé API du gestionnaire pour l'utiliser dans votre code

Prêt à commencer ?

Ouvrez votre compte SimpleFX maintenant et générez vos identifiants API pour commencer le trading automatisé.

Ouvrir un Compte Gratuit

Exemples de Stratégies de Trading

Voici deux exemples de stratégies pour vous aider à démarrer avec le trading algorithmique sur SimpleFX. Chaque approche a ses propres caractéristiques et cas d'utilisation.

Croisement de Moyennes Mobiles Statique

Une stratégie basée sur le temps qui analyse les bougies journalières, exécute des trades basés sur le croisement SMA 10/50, et ferme les positions automatiquement. Cette approche fonctionne bien pour les traders qui préfèrent une analyse programmée plutôt qu'une surveillance continue.

Caractéristiques

  • Analyse les données historiques de bougies
  • Utilise la Moyenne Mobile Simple (SMA 10 vs SMA 50)
  • Exécution automatique des trades (ACHAT/VENTE)
  • Take Profit et Stop Loss intégrés
  • Fonctionnalité de fermeture automatique basée sur le temps
  • Utilise uniquement l'API REST (pas de connexion persistante requise)

Comment Ça Fonctionne

  1. Récupère 60 bougies journalières pour l'analyse
  2. Calcule les SMAs de 10 et 50 périodes
  3. Signal ACHAT : Quand SMA10 > SMA50 (croisement haussier)
  4. Signal VENTE : Quand SMA10 < SMA50 (croisement baissier)
  5. Définit TP/SL basé sur la distance de prix définie
  6. Ferme automatiquement après la période définie
Aperçu du Code
import json
import requests
import time
import threading
from datetime import datetime, timedelta

class SimpleFXBot:
    def __init__(self, client_id, client_secret, symbol="ETHUSD", amount=0.01, account_login=None, tp_distance=None, sl_distance=None):
        self.client_id = client_id
        self.client_secret = client_secret
        self.symbol = symbol
        self.amount = amount
        self.base_url = "https://rest.simplefx.com"
        self.candles_url = "https://candles-core.simplefx.com"
        self.token = None
        self.account_login = account_login
        self.account_reality = "DEMO"
        self.account_currency = "USD"
        self.accounts = []
        self.close_completed = False
        self.tp_distance = tp_distance
        self.sl_distance = sl_distance
        self.symbol_digits = None
        
    def authenticate(self):
        """Authenticate and get token"""
        url = f"{self.base_url}/api/v3/auth/key"
        payload = {"clientId": self.client_id, "clientSecret": self.client_secret}
        headers = {"Content-Type": "application/json", "Accept": "application/json"}
        
        print(f"Authenticating...")
        
        try:
            response = requests.post(url, json=payload, headers=headers)
            if response.status_code == 200:
                self.token = response.json()['data']['token']
                print(f"✓ Authentication successful!")
                return True
            else:
                print(f"✗ Authentication failed: {response.status_code}")
                return False
        except Exception as e:
            print(f"✗ Error: {e}")
            return False
    
    def get_symbol_digits(self):
        """Get symbol digits from SimpleFX instruments JSON"""
        print(f"\nFetching symbol information for {self.symbol}...")
        
        try:
            url = "https://simplefx.com/utils/instruments.json"
            response = requests.get(url, timeout=10)
            
            if response.status_code == 200:
                instruments_dict = response.json()
                
                for key, instrument_data in instruments_dict.items():
                    if not isinstance(instrument_data, dict):
                        continue
                    
                    if instrument_data.get('symbol') == self.symbol:
                        self.symbol_digits = instrument_data.get('digits', 2)
                        print(f"✓ Found {self.symbol}: digits = {self.symbol_digits}")
                        return self.symbol_digits
                
                print(f"⚠ Symbol {self.symbol} not found, using default digits = 2")
                self.symbol_digits = 2
                return self.symbol_digits
            else:
                print(f"✗ Failed to fetch instruments: {response.status_code}")
                self.symbol_digits = 2
                return self.symbol_digits
                
        except Exception as e:
            print(f"✗ Error fetching symbol digits: {e}")
            self.symbol_digits = 2
            return self.symbol_digits
    
    def round_price(self, price):
        """Round price to symbol's digits"""
        if self.symbol_digits is None:
            return price
        try:
            return round(float(price), self.symbol_digits)
        except (ValueError, TypeError):
            return price
    
    def get_headers(self):
        return {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
    
    def get_accounts(self):
        """Get account information"""
        url = f"{self.base_url}/api/v3/accounts"
        print(f"\nFetching accounts...")
        
        try:
            response = requests.get(url, headers=self.get_headers())
            if response.status_code == 200:
                self.accounts = response.json()['data']
                print(f"✓ Found {len(self.accounts)} account(s)")
                
                if not self.account_login:
                    for account in self.accounts:
                        if account['balance'] > 0:
                            self.account_login = account['login']
                            self.account_reality = account['reality']
                            self.account_currency = account['currency']
                            print(f"  ➜ Auto-selected account: {self.account_login}")
                            break
                else:
                    for account in self.accounts:
                        if account['login'] == self.account_login:
                            self.account_reality = account['reality']
                            self.account_currency = account['currency']
                            break
                
                return self.accounts
            else:
                print(f"✗ Failed: {response.status_code}")
                return None
        except Exception as e:
            print(f"✗ Error: {e}")
            return None
    
    def get_candles(self, num_candles=60):
        """Get daily candles for moving average calculation"""
        print(f"\nFetching {num_candles} daily candles for {self.symbol}...")
        
        try:
            url = f"{self.candles_url}/api/v3/candles"
            now = datetime.utcnow()
            time_to = int(now.timestamp())
            time_from = time_to - ((num_candles + 10) * 24 * 60 * 60)
            
            params = {
                "symbol": self.symbol,
                "cPeriod": 86400,
                "timeFrom": time_from,
                "timeTo": time_to
            }
            
            response = requests.get(url, params=params, headers=self.get_headers(), timeout=10)
            
            if response.status_code == 200:
                data = response.json()
                if 'data' in data and len(data['data']) > 0:
                    candles = data['data']
                    print(f"  ✓ Received {len(candles)} candle(s)")
                    return candles
                else:
                    print(f"✗ No candle data returned")
                    return None
            else:
                print(f"✗ HTTP error: {response.status_code}")
                return None
                
        except Exception as e:
            print(f"✗ Error fetching candle data: {e}")
            return None
    
    def calculate_sma(self, candles, period):
        """Calculate Simple Moving Average"""
        if len(candles) < period:
            return None
        recent_candles = candles[-period:]
        close_prices = [candle['close'] for candle in recent_candles]
        return sum(close_prices) / len(close_prices)
    
    def analyze_moving_averages(self):
        """Analyze moving averages and determine trade direction"""
        print(f"\n{'='*50}")
        print("MOVING AVERAGE ANALYSIS")
        print("="*50)
        
        candles = self.get_candles(num_candles=60)
        
        if not candles or len(candles) < 50:
            print(f"✗ Not enough candle data for analysis")
            return None, None
        
        print(f"\nCalculating Moving Averages...")
        sma_10 = self.calculate_sma(candles, 10)
        sma_50 = self.calculate_sma(candles, 50)
        
        if sma_10 is None or sma_50 is None:
            return None, None
        
        current_price = candles[-1]['close']
        
        print(f"  Current Price: ${current_price:,.2f}")
        print(f"  SMA 10 (Fast): ${sma_10:,.2f}")
        print(f"  SMA 50 (Slow): ${sma_50:,.2f}")
        
        if sma_10 > sma_50:
            print(f"\n✓ BULLISH SIGNAL → Opening BUY position")
            return "BUY", current_price
        else:
            print(f"\n✓ BEARISH SIGNAL → Opening SELL position")
            return "SELL", current_price
    
    def calculate_tp_sl_prices(self, side, current_price):
        """Calculate TP and SL prices based on distance"""
        tp_price = None
        sl_price = None
        
        if self.tp_distance and self.tp_distance > 0:
            if side.upper() == "BUY":
                tp_price = current_price + self.tp_distance
            else:
                tp_price = current_price - self.tp_distance
            tp_price = self.round_price(tp_price)
        
        if self.sl_distance and self.sl_distance > 0:
            if side.upper() == "BUY":
                sl_price = current_price - self.sl_distance
            else:
                sl_price = current_price + self.sl_distance
            sl_price = self.round_price(sl_price)
        
        return tp_price, sl_price
    
    def open_market_order(self, side="BUY", current_price=None):
        """Open a market order with TP and SL"""
        url = f"{self.base_url}/api/v3/trading/orders/market"
        
        order_data = {
            "Reality": self.account_reality,
            "Login": self.account_login,
            "Symbol": self.symbol,
            "Side": side.upper(),
            "Volume": self.amount,
            "IsFIFO": True
        }
        
        if current_price:
            tp_price, sl_price = self.calculate_tp_sl_prices(side, current_price)
            if tp_price:
                order_data["TakeProfit"] = tp_price
            if sl_price:
                order_data["StopLoss"] = sl_price
        
        print(f"\nOpening {side.upper()} Market Order...")
        
        try:
            response = requests.post(url, json=order_data, headers=self.get_headers())
            
            if response.status_code in [200, 201]:
                response_data = response.json()
                print(f"✓ SUCCESS! Order placed")
                
                market_orders = response_data.get('data', {}).get('marketOrders', [])
                if market_orders:
                    order = market_orders[0].get('order', {})
                    return {
                        "id": order.get('id'),
                        "volume": order.get('volume'),
                        "side": order.get('side'),
                        "symbol": order.get('symbol')
                    }
                return None
            else:
                print(f"✗ FAILED to place order: {response.status_code}")
                return None
                
        except Exception as e:
            print(f"✗ ERROR: {e}")
            return None
    
    def close_order(self, order_info):
        """Close a market order"""
        url = f"{self.base_url}/api/v3/trading/orders/market"
        opposite_side = "SELL" if order_info['side'].upper() == "BUY" else "BUY"
        
        close_data = {
            "Reality": self.account_reality,
            "Login": self.account_login,
            "Symbol": order_info['symbol'],
            "Side": opposite_side,
            "Volume": order_info['volume'],
            "CloseBy": order_info['id'],
            "IsFIFO": True
        }
        
        print(f"\nClosing Order {order_info['id']}...")
        
        try:
            response = requests.post(url, json=close_data, headers=self.get_headers())
            
            if response.status_code in [200, 201]:
                print(f"✓ SUCCESS! Order closed")
                self.close_completed = True
                return True
            else:
                print(f"✗ FAILED to close order")
                self.close_completed = True
                return False
                
        except Exception as e:
            print(f"✗ ERROR: {e}")
            self.close_completed = True
            return False
    
    def schedule_close_order(self, order_info, delay_seconds=60):
        """Schedule order closure after delay"""
        def close_after_delay():
            print(f"\n⏱ Order will close in {delay_seconds} seconds")
            time.sleep(delay_seconds)
            print(f"\n⏰ Time's up! Closing order now...")
            self.close_order(order_info)
        
        thread = threading.Thread(target=close_after_delay)
        thread.daemon = False
        thread.start()
        return thread
    
    def run_strategy(self):
        """Execute the moving average crossover strategy"""
        print("\n" + "="*50)
        print("SimpleFX Moving Average Crossover Bot")
        print("="*50)
        print(f"Symbol: {self.symbol}")
        print(f"Amount: {self.amount} lots")
        print(f"Strategy: SMA 10/50 Crossover")
        
        # Step 1: Authenticate
        if not self.authenticate():
            return False
        
        # Step 2: Get symbol digits
        self.get_symbol_digits()
        
        # Step 3: Get accounts
        if not self.get_accounts() or not self.account_login:
            return False
        
        # Step 4: Analyze moving averages
        trade_side, current_price = self.analyze_moving_averages()
        
        if trade_side is None:
            print("\n⚠ Could not analyze moving averages. Aborting.")
            return False
        
        # Step 5: Open trade
        order_info = self.open_market_order(side=trade_side, current_price=current_price)
        
        if order_info:
            # Step 6: Schedule auto-close
            close_thread = self.schedule_close_order(order_info, delay_seconds=60)
            close_thread.join()
            return True
        else:
            print("\n✗ Trade execution failed")
            return False

def main():
    print("SimpleFX Moving Average Crossover Bot")
    print("="*50)
    
    CLIENT_ID = input("Enter your Client ID: ").strip()
    CLIENT_SECRET = input("Enter your Client Secret: ").strip()
    
    if not CLIENT_ID or not CLIENT_SECRET:
        print("\n⚠ ERROR: Client ID and Client Secret are required!")
        return
    
    SYMBOL = input("Enter Trading Symbol [default: BTCUSD]: ").strip().upper() or "BTCUSD"
    VOLUME = float(input("Enter Trade Volume [default: 0.01]: ").strip() or "0.01")
    
    tp_input = input("Take Profit distance in $ (or Enter to skip): ").strip()
    tp_distance = float(tp_input) if tp_input else None
    
    sl_input = input("Stop Loss distance in $ (or Enter to skip): ").strip()
    sl_distance = float(sl_input) if sl_input else None
    
    bot = SimpleFXBot(CLIENT_ID, CLIENT_SECRET, SYMBOL, VOLUME, None, tp_distance, sl_distance)
    bot.run_strategy()

if __name__ == "__main__":
    main()

Bot de Trading par Seuil de Prix

Une stratégie basée sur WebSocket qui surveille les prix XAUUSD (Or) en temps réel et exécute automatiquement un ordre d'ACHAT lorsque le prix passe sous votre seuil cible. Parfait pour les traders qui veulent entrer en position à des niveaux de prix spécifiques sans surveillance manuelle constante.

Caractéristiques

  • Streaming de prix en temps réel via WebSocket
  • Déclenchement automatique ACHAT au prix cible
  • Take Profit et Stop Loss configurables
  • Focalisé sur le trading XAUUSD (Or)
  • Gestion automatique des reconnexions
  • Configuration interactive via CLI

Comment Ça Fonctionne

  1. S'authentifie avec l'API SimpleFX via vos identifiants
  2. Se connecte via WebSocket pour les cotations XAUUSD en direct
  3. Surveille le prix Ask en temps réel
  4. Déclenche ACHAT quand le prix passe sous votre cible
  5. Place un ordre au marché avec TP/SL configuré
  6. Ferme la connexion après exécution réussie
Aperçu du Code
import asyncio
import websockets
import json
from datetime import datetime
import logging
import sys
import nest_asyncio
from websockets.exceptions import ConnectionClosed
import requests

# Apply nest_asyncio to allow nested event loops
nest_asyncio.apply()

# Set up logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

class SimpleFXTrader:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = "https://rest.simplefx.com"
        self.token = None
        self.account_login = None
        self.account_reality = "DEMO"
        self.account_currency = "USD"
        self.price_precision = None
        
    def authenticate(self):
        """Authenticate and get token"""
        url = f"{self.base_url}/api/v3/auth/key"
        payload = {"clientId": self.client_id, "clientSecret": self.client_secret}
        headers = {"Content-Type": "application/json", "Accept": "application/json"}
        
        logger.info("Authenticating...")
        
        try:
            response = requests.post(url, json=payload, headers=headers)
            if response.status_code == 200:
                self.token = response.json()['data']['token']
                logger.info("✓ Authentication successful!")
                return True
            else:
                logger.error(f"✗ Authentication failed: {response.status_code}")
                logger.error(f"Response: {response.text}")
                return False
        except Exception as e:
            logger.error(f"✗ Error: {e}")
            return False
    
    def get_headers(self):
        return {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
    
    def get_accounts(self):
        """Get account information"""
        url = f"{self.base_url}/api/v3/accounts"
        logger.info("Fetching accounts...")
        
        try:
            response = requests.get(url, headers=self.get_headers())
            if response.status_code == 200:
                accounts = response.json()['data']
                logger.info(f"✓ Found {len(accounts)} account(s)")
                
                for i, account in enumerate(accounts, 1):
                    logger.info(f"\n  [{i}] Login: {account['login']}")
                    logger.info(f"      Currency: {account['currency']}")
                    logger.info(f"      Balance: {account['balance']}")
                    logger.info(f"      Type: {account['reality']}")
                
                for account in accounts:
                    if account['balance'] > 0:
                        self.account_login = account['login']
                        self.account_reality = account['reality']
                        self.account_currency = account['currency']
                        logger.info(f"\n  ➜ Selected account: {self.account_login} ({self.account_reality})")
                        logger.info(f"     Balance: {account['balance']} {account['currency']}")
                        return True
                
                logger.error("✗ No account with balance found")
                return False
            else:
                logger.error(f"✗ Failed: {response.status_code}")
                logger.error(f"Response: {response.text}")
                return False
        except Exception as e:
            logger.error(f"✗ Error: {e}")
            return False
    
    def get_instrument_precision(self, symbol):
        """Get price precision for the symbol"""
        logger.info(f"Fetching instrument precision for {symbol}...")
        
        try:
            url = "https://simplefx.com/utils/instruments.json"
            response = requests.get(url, timeout=10)
            
            if response.status_code == 200:
                data = response.json()
                
                if isinstance(data, dict):
                    for key, instrument in data.items():
                        if isinstance(instrument, dict):
                            if instrument.get('symbol') == symbol or key == symbol:
                                digits = instrument.get('digits')
                                if digits is not None:
                                    self.price_precision = digits
                                    logger.info(f"  ✓ Precision: {digits} digits")
                                    return digits
                
                elif isinstance(data, list):
                    for instrument in data:
                        if isinstance(instrument, dict):
                            if instrument.get('symbol') == symbol:
                                digits = instrument.get('digits')
                                if digits is not None:
                                    self.price_precision = digits
                                    logger.info(f"  ✓ Precision: {digits} digits")
                                    return digits
                
                logger.warning(f"  ⚠ Symbol not found, using default: 2 digits")
                self.price_precision = 2
                return 2
            else:
                logger.warning(f"  Using default precision: 2 digits")
                self.price_precision = 2
                return 2
                
        except Exception as e:
            logger.error(f"  ✗ Error: {e}")
            self.price_precision = 2
            return 2
    
    def round_price(self, price):
        """Round price to instrument's precision"""
        if self.price_precision is None:
            self.price_precision = 2
        return round(price, self.price_precision)
    
    def open_market_order(self, symbol, side, amount, tp_price=None, sl_price=None):
        """Open a market order"""
        url = f"{self.base_url}/api/v3/trading/orders/market"
        
        order_data = {
            "Reality": self.account_reality,
            "Login": self.account_login,
            "Symbol": symbol,
            "Side": side.upper(),
            "Volume": amount,
            "IsFIFO": True
        }
        
        if tp_price:
            order_data["TakeProfit"] = tp_price
        if sl_price:
            order_data["StopLoss"] = sl_price
        
        logger.info(f"\n{'='*60}")
        logger.info(f"Placing {side.upper()} Market Order")
        logger.info(f"{'='*60}")
        logger.info(f"  Symbol: {symbol}")
        logger.info(f"  Volume: {amount} lots")
        logger.info(f"  Account: {self.account_login} ({self.account_reality})")
        if tp_price:
            logger.info(f"  Take Profit: ${tp_price:,.{self.price_precision}f}")
        if sl_price:
            logger.info(f"  Stop Loss: ${sl_price:,.{self.price_precision}f}")
        
        try:
            response = requests.post(url, json=order_data, headers=self.get_headers(), timeout=10)
            
            if response.status_code in [200, 201]:
                response_data = response.json()
                logger.info(f"\n✓ SUCCESS! Market order placed")
                
                market_orders = response_data.get('data', {}).get('marketOrders', [])
                if market_orders:
                    order = market_orders[0].get('order', {})
                    order_id = order.get('id')
                    open_price = order.get('openPrice')
                    
                    logger.info(f"\n✓ Order Details:")
                    logger.info(f"  Order ID: {order_id}")
                    logger.info(f"  Symbol: {order.get('symbol')}")
                    logger.info(f"  Side: {order.get('side')}")
                    logger.info(f"  Volume: {order.get('volume')}")
                    if open_price:
                        logger.info(f"  Open Price: ${open_price:,.{self.price_precision}f}")
                    
                    return {
                        "id": order_id,
                        "open_price": open_price,
                        "volume": order.get('volume'),
                        "side": order.get('side'),
                        "symbol": order.get('symbol')
                    }
                return response_data
            else:
                logger.error(f"\n✗ FAILED to place order")
                logger.error(f"Status Code: {response.status_code}")
                return None
                
        except Exception as e:
            logger.error(f"\n✗ ERROR: {e}")
            return None

class GoldPriceMonitor:
    def __init__(self, trader, target_price, amount=0.01, tp_distance=None, sl_distance=None):
        self.trader = trader
        self.target_price = target_price
        self.amount = amount
        self.tp_distance = tp_distance
        self.sl_distance = sl_distance
        self.symbol = "XAUUSD"
        self.running = True
        self.order_placed = False
        self.ws = None
        self.subscription_id = 0
        self.last_log_time = None
        self.trigger_ask = None
        
    async def connect_and_monitor(self):
        """Connect to WebSocket and monitor XAUUSD prices"""
        uri = "wss://web-quotes-core.simplefx.com/websocket/quotes"
        
        logger.info(f"\n{'='*60}")
        logger.info("Starting Price Monitor")
        logger.info(f"{'='*60}")
        logger.info(f"  Symbol: {self.symbol}")
        logger.info(f"  Target Price: ${self.target_price:,.2f}")
        logger.info(f"  Action: Waiting for price to drop BELOW target")
        logger.info(f"  Trade Size: {self.amount} lots")
        if self.tp_distance:
            logger.info(f"  Take Profit: ${self.tp_distance} above entry")
        if self.sl_distance:
            logger.info(f"  Stop Loss: ${self.sl_distance} below entry")
        logger.info(f"{'='*60}\n")
        
        while self.running and not self.order_placed:
            try:
                async with websockets.connect(uri) as ws:
                    self.ws = ws
                    logger.info("✓ Connected to WebSocket")
                    
                    # Subscribe to XAUUSD
                    self.subscription_id += 1
                    subscription_message = json.dumps({
                        "p": "/subscribe/addList",
                        "i": self.subscription_id,
                        "d": [self.symbol]
                    })
                    await ws.send(subscription_message)
                    logger.info(f"✓ Subscribed to {self.symbol} prices")
                    logger.info(f"\n⏳ Monitoring prices... (Press Ctrl+C to stop)\n")
                    
                    # Start heartbeat
                    heartbeat_task = asyncio.create_task(self._send_heartbeat(ws))
                    
                    try:
                        while self.running and not self.order_placed:
                            response = await ws.recv()
                            await self.process_quote(response)
                    except ConnectionClosed:
                        if not self.order_placed:
                            logger.warning("WebSocket closed, reconnecting...")
                    finally:
                        heartbeat_task.cancel()
                        
            except Exception as e:
                if self.running and not self.order_placed:
                    logger.error(f"Connection error: {str(e)}")
                    logger.info("Reconnecting in 5 seconds...")
                    await asyncio.sleep(5)
                else:
                    break
    
    async def _send_heartbeat(self, ws):
        """Send periodic heartbeat"""
        while self.running and not self.order_placed:
            try:
                await asyncio.sleep(30)
                await ws.send(json.dumps({"type": "ping"}))
            except Exception as e:
                logger.error(f"Heartbeat error: {str(e)}")
                break
    
    async def process_quote(self, quote_data):
        """Process incoming quote and check if we should trade"""
        try:
            data = json.loads(quote_data)
            
            if data.get("p") == "/quotes/subscribed":
                quotes_data = data.get("d", [])
                for quote in quotes_data:
                    symbol = quote.get("s")
                    if symbol == self.symbol:
                        bid = quote.get("b")
                        ask = quote.get("a")
                        
                        if bid and ask:
                            current_time = datetime.now()
                            
                            # Log every 2 seconds
                            if self.last_log_time is None or (current_time - self.last_log_time).total_seconds() >= 2:
                                time_str = current_time.strftime('%H:%M:%S')
                                logger.info(f"[{time_str}] {symbol} - Bid: ${bid:,.2f} | Ask: ${ask:,.2f} | Target: ${self.target_price:,.2f}")
                                self.last_log_time = current_time
                            
                            # Check if ask price is below target
                            if ask <= self.target_price and not self.order_placed:
                                self.order_placed = True
                                self.trigger_ask = ask
                                
                                logger.info(f"\n{'='*60}")
                                logger.info(f"🎯 TARGET REACHED!")
                                logger.info(f"{'='*60}")
                                logger.info(f"  Current Ask: ${ask:,.2f}")
                                logger.info(f"  Target Price: ${self.target_price:,.2f}")
                                logger.info(f"{'='*60}\n")
                                
                                # Close WebSocket before placing order
                                self.running = False
                                if self.ws:
                                    await self.ws.close()
                                
                                await asyncio.sleep(1)
                                self.place_order_sync()
                        
        except json.JSONDecodeError as e:
            logger.error(f"Error decoding JSON: {e}")
        except Exception as e:
            logger.error(f"Error processing quote: {str(e)}")
    
    def place_order_sync(self):
        """Place order after WebSocket is closed"""
        tp_price = None
        sl_price = None
        
        if self.tp_distance:
            tp_price = self.trader.round_price(self.trigger_ask + self.tp_distance)
        if self.sl_distance:
            sl_price = self.trader.round_price(self.trigger_ask - self.sl_distance)
        
        order = self.trader.open_market_order(
            self.symbol, 
            "BUY", 
            self.amount,
            tp_price,
            sl_price
        )
        
        if order:
            logger.info(f"\n✓✓✓ Order placed successfully!")
        else:
            logger.error(f"\n✗ Failed to place order")
    
    def stop(self):
        """Stop monitoring"""
        self.running = False

async def main():
    print("""
╔══════════════════════════════════════════════════════════╗
║         XAUUSD Price Threshold Trading Bot              ║
║     Automatically opens BUY when price drops below       ║
║              your specified target price                 ║
╚══════════════════════════════════════════════════════════╝
    """)
    
    # Configuration
    CLIENT_ID = input("\n🔑 Enter your SimpleFX Client ID: ").strip()
    CLIENT_SECRET = input("🔑 Enter your SimpleFX Client Secret: ").strip()
    
    if not CLIENT_ID or not CLIENT_SECRET:
        print("\n✗ Error: Client ID and Secret are required")
        return
    
    # Get target price
    while True:
        try:
            target_price_input = input("\n💰 Enter target price for XAUUSD: $").strip()
            target_price = float(target_price_input)
            if target_price > 0:
                break
            else:
                print("  ✗ Please enter a positive number")
        except ValueError:
            print("  ✗ Invalid input. Please enter a valid price")
    
    # Get trade size
    while True:
        try:
            amount_input = input("\n📊 Enter trade size in lots (e.g., 0.01): ").strip() or "0.01"
            amount = float(amount_input)
            if amount > 0:
                break
            else:
                print("  ✗ Please enter a positive number")
        except ValueError:
            print("  ✗ Invalid input")
    
    # Get TP and SL
    print(f"\n{'='*60}")
    print("TAKE PROFIT & STOP LOSS (Optional)")
    print("="*60)
    
    tp_distance = None
    sl_distance = None
    
    tp_input = input("\n💰 Take Profit distance in $ (e.g., 10): $").strip()
    if tp_input:
        try:
            tp_distance = float(tp_input)
            if tp_distance > 0:
                print(f"  ➜ Take Profit set to ${tp_distance}")
            else:
                tp_distance = None
        except ValueError:
            print("  ✗ Invalid input, skipping Take Profit")
    
    sl_input = input("\n🛡️  Stop Loss distance in $ (e.g., 5): $").strip()
    if sl_input:
        try:
            sl_distance = float(sl_input)
            if sl_distance > 0:
                print(f"  ➜ Stop Loss set to ${sl_distance}")
            else:
                sl_distance = None
        except ValueError:
            print("  ✗ Invalid input, skipping Stop Loss")
    
    # Summary
    print(f"\n{'='*60}")
    print("CONFIGURATION SUMMARY")
    print("="*60)
    print(f"  Symbol: XAUUSD (Gold)")
    print(f"  Target Price: ${target_price:,.2f}")
    print(f"  Trade Size: {amount} lots")
    print(f"  Action: BUY when Ask price ≤ ${target_price:,.2f}")
    if tp_distance:
        print(f"  Take Profit: ${tp_distance} above entry")
    if sl_distance:
        print(f"  Stop Loss: ${sl_distance} below entry")
    print("="*60)
    
    user_input = input(f"\n⚠  Start monitoring? (yes/no): ").strip().lower()
    
    if user_input != 'yes':
        print("\n👋 Cancelled.")
        return
    
    # Initialize trader
    trader = SimpleFXTrader(CLIENT_ID, CLIENT_SECRET)
    
    if not trader.authenticate():
        print("\n✗ Authentication failed. Exiting.")
        return
    
    if not trader.get_accounts():
        print("\n✗ Failed to get accounts. Exiting.")
        return
    
    trader.get_instrument_precision("XAUUSD")
    
    # Start monitoring
    monitor = GoldPriceMonitor(trader, target_price, amount, tp_distance, sl_distance)
    
    try:
        await monitor.connect_and_monitor()
        
        if monitor.order_placed:
            print(f"\n{'='*60}")
            print("🎉 TRADE COMPLETED!")
            print("="*60)
        else:
            print(f"\n⚠  Monitor stopped without placing order")
            
    except KeyboardInterrupt:
        print("\n\n⚠ Interrupted by user!")
        monitor.stop()
        print("👋 Goodbye!")
    except Exception as e:
        logger.error(f"\n✗ Unexpected error: {e}")

if __name__ == "__main__":
    if sys.platform == 'win32':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n\n👋 Goodbye!")

Astuce

Lorsque vous utilisez des LLMs (comme ChatGPT, Claude ou Copilot) pour écrire du code de trading, référencez la spécification OpenAPI dans vos prompts pour des résultats plus précis :

https://simplefx.com/docs/api/oas3-3.1.json

Pourquoi Trader avec SimpleFX ?

SimpleFX fournit l'environnement idéal pour les traders algorithmiques. Avec une API robuste, une exécution rapide et un accès à plus de 1 000 instruments, vous avez tout ce dont vous avez besoin pour construire et exécuter des stratégies de trading sophistiquées.

Avantages de la Plateforme

  • ✓Exécution ultra-rapide avec traitement des ordres en moins d'une seconde optimisé pour le trading algorithmique
  • ✓Accès à plus de 1 000 instruments incluant cryptomonnaies, forex, indices, matières premières et CFDs actions
  • ✓Accès complet à l'API REST avec support WebSocket pour les données en temps réel et documentation complète
  • ✓Spreads compétitifs avec tarification transparente et sans frais cachés
  • ✓Plateforme web professionnelle et apps mobiles avec graphiques avancés et outils de gestion des risques
  • ✓Ouverture de compte rapide sans dépôt minimum requis et compte démo disponible

Que vous construisiez votre premier bot de trading ou que vous développiez une stratégie complexe multi-instruments, SimpleFX fournit les outils et l'infrastructure dont vous avez besoin pour réussir.

Avertissement

Les exemples de code fournis sur cette page sont uniquement à des fins éducatives. Ils peuvent contenir des erreurs ou des bugs et ne sont pas destinés à une utilisation en production sans tests et modifications approfondis. SimpleFX n'est pas responsable des pertes de trading, des problèmes techniques ou d'autres dommages résultant de l'utilisation de ces exemples de code. Testez toujours minutieusement dans un environnement de démonstration avant d'utiliser des stratégies de trading automatisées avec des fonds réels.

Commencez à Trader Aujourd'hui