Building a Multi-Timeframe Trading Bot
Design and implement a trading bot that analyzes multiple timeframes simultaneously. Use higher timeframes for trend and lower timeframes for entry timing.
The Multi-Timeframe Edge
Single-timeframe strategies have a fundamental weakness: they cannot distinguish between a pullback in a trend and a full reversal. A multi-timeframe approach solves this by using a higher timeframe for trend direction and a lower timeframe for entry timing.
Trend direction
Signal confirmation
Entry timing
The Three-Timeframe Framework
import requests
from dataclasses import dataclass
from typing import Optional
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://tickatlas.com/v1"
@dataclass
class TimeframeAnalysis:
timeframe: str
trend: str # "bullish", "bearish", "neutral"
rsi: float
macd_signal: str
ema_trend: str # price vs EMA relationship
@dataclass
class MultiTFSignal:
symbol: str
trend_tf: TimeframeAnalysis
signal_tf: TimeframeAnalysis
entry_tf: TimeframeAnalysis
trade_direction: Optional[str]
confidence: str
def analyze_timeframe(symbol: str, timeframe: str) -> TimeframeAnalysis:
"""Analyze a single timeframe."""
headers = {"X-API-Key": API_KEY}
# Fetch RSI
rsi_resp = requests.get(f"{BASE_URL}/indicator", headers=headers,
params={"symbol": symbol, "indicator": "RSI_14", "timeframe": timeframe})
rsi_data = rsi_resp.json()["data"]
# Fetch MACD
macd_resp = requests.get(f"{BASE_URL}/indicator", headers=headers,
params={"symbol": symbol, "indicator": "MACD", "timeframe": timeframe})
macd_data = macd_resp.json()["data"]
# Fetch EMA 50
ema_resp = requests.get(f"{BASE_URL}/indicator", headers=headers,
params={"symbol": symbol, "indicator": "EMA_50", "timeframe": timeframe})
ema_data = ema_resp.json()["data"]
close = rsi_data["ohlcv"]["close"]
rsi = rsi_data["values"]["rsi"]
macd_hist = macd_data["values"]["histogram"]
ema = ema_data["values"]["value"]
ema_trend = "above" if close > ema else "below"
trend = "bullish" if ema_trend == "above" and macd_hist > 0 else \
"bearish" if ema_trend == "below" and macd_hist < 0 else "neutral"
return TimeframeAnalysis(
timeframe=timeframe, trend=trend, rsi=rsi,
macd_signal=macd_data.get("signal", "neutral"), ema_trend=ema_trend,
) The Decision Engine
def multi_tf_analysis(symbol: str) -> MultiTFSignal:
"""Run the three-timeframe analysis."""
trend = analyze_timeframe(symbol, "D1")
signal = analyze_timeframe(symbol, "H4")
entry = analyze_timeframe(symbol, "H1")
direction = None
confidence = "low"
# Rule 1: All three timeframes must agree on direction
if trend.trend == "bullish" and signal.trend == "bullish":
if entry.rsi < 40: # Entry TF showing a pullback
direction = "long"
confidence = "high"
elif entry.rsi < 55:
direction = "long"
confidence = "medium"
elif trend.trend == "bearish" and signal.trend == "bearish":
if entry.rsi > 60: # Entry TF showing a pullback
direction = "short"
confidence = "high"
elif entry.rsi > 45:
direction = "short"
confidence = "medium"
return MultiTFSignal(
symbol=symbol, trend_tf=trend, signal_tf=signal,
entry_tf=entry, trade_direction=direction, confidence=confidence,
)
# Scan the watchlist
for symbol in ["EURUSD", "GBPUSD", "USDJPY", "XAUUSD"]:
result = multi_tf_analysis(symbol)
if result.trade_direction:
print(f"{symbol}: {result.trade_direction} ({result.confidence})")
print(f" D1: {result.trend_tf.trend}, H4: {result.signal_tf.trend}")
print(f" H1 RSI: {result.entry_tf.rsi:.1f}") Adding Risk Management
def calculate_trade(signal: MultiTFSignal) -> Optional[dict]:
"""Calculate entry, stop, and target using ATR."""
if not signal.trade_direction:
return None
# Get ATR from the signal timeframe (H4)
atr_resp = requests.get(f"{BASE_URL}/indicator",
headers={"X-API-Key": API_KEY},
params={"symbol": signal.symbol, "indicator": "ATR_14", "timeframe": "H4"})
atr = atr_resp.json()["data"]["values"]["atr"]
# Get current price from entry timeframe
price_resp = requests.get(f"{BASE_URL}/indicator",
headers={"X-API-Key": API_KEY},
params={"symbol": signal.symbol, "indicator": "RSI_14", "timeframe": "H1"})
close = price_resp.json()["data"]["ohlcv"]["close"]
multiplier = 1.5 if signal.confidence == "high" else 2.0
rr_ratio = 2.0 if signal.confidence == "high" else 1.5
if signal.trade_direction == "long":
stop = close - (atr * multiplier)
target = close + (atr * multiplier * rr_ratio)
else:
stop = close + (atr * multiplier)
target = close - (atr * multiplier * rr_ratio)
return {
"symbol": signal.symbol,
"direction": signal.trade_direction,
"entry": round(close, 5),
"stop_loss": round(stop, 5),
"take_profit": round(target, 5),
"confidence": signal.confidence,
} Key Principles
Trade in the direction of the highest timeframe
If D1 is bullish, only look for longs on H4 and H1. Fighting the major trend is the fastest way to blow up.
Use pullbacks on the entry timeframe
The best entries come when the entry timeframe shows a temporary pullback against the higher-timeframe trend. This gives you a better entry price and tighter stop.
Timeframe ratio of 4-6x between levels
D1/H4/H1 is a 6x and 4x ratio. This gives enough separation that each level provides unique information without too much overlap.
Related Reading
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.
Keep reading
All articles- Tutorial 11 min read
24/7 Crypto Monitoring: Building Always-On Analysis Systems
Build a monitoring system that watches crypto markets around the clock, detects significant moves, and sends alerts when conditions match your criteria.
March 28, 2026
- Tutorial 12 min read
How to Build an AI Market Analyst That Runs 24/7
Build a production-ready AI market analyst that monitors forex and crypto markets around the clock, generates daily briefings, and alerts you to opportunities via Telegram.
March 28, 2026
- Tutorial 10 min read
Using ATR for Dynamic Stop-Loss Placement
Learn how to use Average True Range (ATR) to set volatility-adjusted stop losses that adapt to market conditions, with full code examples.
March 28, 2026