TickAtlas
Tutorial 12 min read · March 28, 2026

How to Build a Forex Trading Bot with Python in 2026

A complete guide to building a production-ready forex trading bot using Python, the TickAtlas API for real-time data, and proven risk management techniques.

CG
By the TickAtlas team

Why Python for Forex Bots?

Python dominates algorithmic trading for good reason. Its ecosystem of libraries like requests, pandas, and numpy makes data manipulation trivial, and its readable syntax means you can focus on strategy logic instead of fighting with language quirks. In 2026, Python remains the fastest path from idea to live trading bot.

This tutorial walks you through building a forex bot that fetches real-time indicator data from the TickAtlas API, evaluates a multi-indicator strategy, and generates actionable signals.

Prerequisites

  • Python 3.10 or newer
  • A TickAtlas API key (free tier works for development)
  • Basic understanding of forex markets and technical indicators
  • pip install requests pandas

Step 1: Build the API Client

First, create a reusable client class that handles authentication, rate limiting, and error handling. This wrapper will be the foundation of your bot.

python
import requests
import time

class TickAtlasClient:
    BASE_URL = "https://tickatlas.com/v1"

    def __init__(self, api_key: str):
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": api_key,
            "Accept": "application/json"
        })
        self._last_request = 0

    def _rate_limit(self):
        """Enforce minimum 200ms between requests."""
        elapsed = time.time() - self._last_request
        if elapsed < 0.2:
            time.sleep(0.2 - elapsed)
        self._last_request = time.time()

    def get_indicators(self, symbol: str, timeframe: str,
                       indicators: list[str]) -> dict:
        self._rate_limit()
        resp = self.session.get(f"{self.BASE_URL}/indicators", params={
            "symbol": symbol,
            "timeframe": timeframe,
            "indicators": ",".join(indicators)
        })
        resp.raise_for_status()
        return resp.json()

    def get_ohlc(self, symbol: str, timeframe: str,
                 bars: int = 100) -> dict:
        self._rate_limit()
        resp = self.session.get(f"{self.BASE_URL}/ohlc", params={
            "symbol": symbol,
            "timeframe": timeframe,
            "bars": bars
        })
        resp.raise_for_status()
        return resp.json()

Step 2: Define the Strategy

Our strategy uses RSI and MACD confluence. A buy signal fires when RSI exits oversold territory while MACD confirms bullish momentum. This combination filters out a large portion of false signals.

python
class ForexStrategy:
    def __init__(self):
        self.rsi_oversold = 30
        self.rsi_overbought = 70

    def evaluate(self, indicators: dict) -> str:
        rsi = indicators["RSI_14"]["value"]
        macd = indicators["MACD"]["histogram"]

        # Buy: RSI crossing up from oversold + MACD histogram positive
        if rsi > self.rsi_oversold and rsi < 45 and macd > 0:
            return "BUY"

        # Sell: RSI crossing down from overbought + MACD histogram negative
        if rsi < self.rsi_overbought and rsi > 55 and macd < 0:
            return "SELL"

        return "HOLD"

Step 3: Fetch Live Data

Here is what the API returns when you request RSI and MACD for EURUSD on the H1 timeframe:

json
// GET /v1/indicators?symbol=EURUSD&timeframe=H1&indicators=RSI_14,MACD
{
  "success": true,
  "data": {
    "symbol": "EURUSD",
    "timeframe": "H1",
    "indicators": {
      "RSI_14": {
        "value": 34.7,
        "signal": "neutral"
      },
      "MACD": {
        "macd_line": -0.00023,
        "signal_line": -0.00031,
        "histogram": 0.00008
      }
    },
    "timestamp": "2026-03-28T14:00:00Z"
  }
}

Step 4: The Main Trading Loop

The bot runs in a continuous loop, checking for signals every time a new candle closes. For H1, that means one check per hour.

python
import os
from datetime import datetime

def run_bot():
    client = TickAtlasClient(os.environ["CLAW_API_KEY"])
    strategy = ForexStrategy()
    symbols = ["EURUSD", "GBPUSD", "USDJPY", "XAUUSD"]

    print(f"[{datetime.utcnow()}] Bot started. Monitoring {len(symbols)} pairs.")

    while True:
        for symbol in symbols:
            try:
                data = client.get_indicators(
                    symbol=symbol,
                    timeframe="H1",
                    indicators=["RSI_14", "MACD"]
                )
                signal = strategy.evaluate(data["data"]["indicators"])

                if signal != "HOLD":
                    print(f"[{datetime.utcnow()}] {signal} signal on {symbol}")
                    # Execute trade via your broker API here

            except Exception as e:
                print(f"Error fetching {symbol}: {e}")

        time.sleep(3600)  # Wait for next H1 candle

if __name__ == "__main__":
    run_bot()

Step 5: Add Risk Management

No bot is complete without position sizing and stop losses. Use ATR (Average True Range) from the API to set dynamic stops that adapt to market volatility.

python
def calculate_position_size(account_balance: float,
                            risk_percent: float,
                            atr_value: float,
                            stop_multiplier: float = 2.0) -> float:
    """Risk-based position sizing using ATR."""
    risk_amount = account_balance * (risk_percent / 100)
    stop_distance = atr_value * stop_multiplier
    position_size = risk_amount / stop_distance
    return round(position_size, 2)

# Example: $10,000 account, 1% risk, ATR = 0.0012
size = calculate_position_size(10000, 1.0, 0.0012)
# Returns: 41.67 (micro lots)

Step 6: Logging and Monitoring

Every signal and trade should be logged. When something goes wrong at 3 AM, your logs are the only thing that will tell you why.

python
import logging

logging.basicConfig(
    filename="trading_bot.log",
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s"
)

logger = logging.getLogger("forex_bot")
logger.info(f"BUY signal on EURUSD | RSI: 34.7 | MACD hist: 0.00008")
logger.info(f"Position size: 0.42 lots | SL: 1.0823 | TP: 1.0871")

Common Pitfalls

Overfitting to Historical Data

If your strategy has 20 parameters, it is curve-fitted, not robust. Keep it simple.

Ignoring Spreads and Slippage

Use the /v1/spread endpoint to factor real spread data into your backtests.

No Rate Limit Handling

Always respect API rate limits. The client class above handles this automatically.

Next Steps

You now have a working forex bot skeleton. To make it production-ready:

Try this with live data

Every account gets $2.50 in free PAYG credits. No card required — paste your API key and run the code above against live broker data.