Why Spreads Matter
The spread is the hidden cost of every trade. A 1.2-pip spread on EURUSD might seem trivial, but if you trade 10 times a day, that is 12 pips of pure cost. Over a month, it adds up to hundreds of pips -- often the difference between a profitable and unprofitable strategy.
Spreads are not fixed. They widen during news events, low-liquidity sessions, and weekends. Monitoring spreads in real-time tells you when conditions favor your strategy and when to sit out.
EURUSD typical spread (London)
EURUSD during NFP release
Sunday night rollover
Fetching Spread Data
curl -H "X-API-Key: YOUR_API_KEY" \
"https://tickatlas.com/v1/spread?symbol=EURUSD" Response:
// GET /v1/spread?symbol=EURUSD
{
"success": true,
"data": {
"symbol": "EURUSD",
"current": {
"spread_pips": 0.9,
"spread_points": 9
},
"statistics": {
"period": "24h",
"avg_spread": 1.1,
"min_spread": 0.6,
"max_spread": 4.8,
"std_deviation": 0.42
},
"by_session": {
"asian": 1.4,
"london": 0.8,
"new_york": 1.0
}
}
} Python: Spread Monitor
import requests
import time
import logging
from collections import deque
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("spread_monitor")
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://tickatlas.com/v1"
class SpreadMonitor:
def __init__(self, symbols: list[str], alert_multiplier: float = 2.0):
self.symbols = symbols
self.alert_multiplier = alert_multiplier
# Track recent spreads for each symbol (rolling window)
self.history: dict[str, deque] = {
sym: deque(maxlen=100) for sym in symbols
}
def fetch_spread(self, symbol: str) -> dict:
resp = requests.get(
f"{BASE_URL}/spread",
headers={"X-API-Key": API_KEY},
params={"symbol": symbol},
)
resp.raise_for_status()
return resp.json()["data"]
def check_all(self) -> list[dict]:
"""Check spreads for all symbols. Return any alerts."""
alerts = []
for symbol in self.symbols:
data = self.fetch_spread(symbol)
spread = data["current"]["spread_pips"]
self.history[symbol].append(spread)
# Calculate rolling average
history = list(self.history[symbol])
if len(history) < 10:
continue # Need enough data
avg_spread = sum(history) / len(history)
threshold = avg_spread * self.alert_multiplier
if spread > threshold:
alert = {
"symbol": symbol,
"current_spread": spread,
"average_spread": round(avg_spread, 2),
"multiplier": round(spread / avg_spread, 1),
"timestamp": datetime.utcnow().isoformat(),
}
alerts.append(alert)
logger.warning(
f"SPREAD ALERT: {symbol} at {spread} pips "
f"({alert['multiplier']}x average)"
)
return alerts
# Usage
monitor = SpreadMonitor(
["EURUSD", "GBPUSD", "USDJPY", "XAUUSD"],
alert_multiplier=2.0,
)
while True:
alerts = monitor.check_all()
for a in alerts:
print(f"WARNING: {a['symbol']} spread {a['current_spread']} pips")
time.sleep(30) # Check every 30 seconds Trading Condition Signals
Beyond alerts, use spread data to control your bot's behavior:
def should_trade(symbol: str, max_spread_pips: float) -> bool:
"""Check if spread conditions allow trading."""
resp = requests.get(
f"{BASE_URL}/spread",
headers={"X-API-Key": API_KEY},
params={"symbol": symbol},
)
spread = resp.json()["data"]["current"]["spread_pips"]
if spread > max_spread_pips:
logger.info(f"Skipping {symbol}: spread {spread} > {max_spread_pips}")
return False
return True
# In your trading bot:
if should_trade("EURUSD", max_spread_pips=2.0):
execute_strategy("EURUSD")
else:
logger.info("Waiting for better spread conditions") When Spreads Typically Widen
High-impact news events
NFP, FOMC, ECB rate decisions. Spreads can blow out to 5-10x normal levels seconds before the release. Use the /sessions endpoint to check for upcoming events.
Low-liquidity sessions
Sunday night rollover (17:00 EST), Asian session for European pairs, holidays. Plan your bot's schedule around liquidity.
Flash crashes and volatility spikes
Sudden spread widening can indicate a liquidity vacuum. If spreads spike without a scheduled event, reduce exposure immediately.
Run this against live data.
Every account starts pay-as-you-go with $2.50 of credit and no card. Paste the key into the samples above and the requests work unchanged.