CCI Trading Strategy: Mean Reversion with Commodity Channel Index
Build a mean reversion trading strategy using the Commodity Channel Index. Includes API integration, Python code, and signal filtering techniques.
What Is the CCI?
The Commodity Channel Index, developed by Donald Lambert in 1980, measures the deviation of the current price from its statistical mean. Despite the name, it works on any instrument -- forex, indices, crypto, and of course commodities.
CCI oscillates around zero with no fixed upper or lower bound. Readings above +100 suggest the price is well above its average (potentially overbought), while readings below -100 suggest the price is well below its average (potentially oversold).
Typical Price = (High + Low + Close) / 3
SMA = Simple Moving Average of Typical Price over N periods
Mean Deviation = Average absolute deviation from SMA
CCI = (Typical Price - SMA) / (0.015 * Mean Deviation)
The 0.015 constant scales CCI so that approximately 75% of values fall between -100 and +100.
The Mean Reversion Thesis
Mean reversion is the idea that prices tend to return to their average after extreme moves. CCI quantifies "extreme" in statistical terms. When CCI reaches -150 or lower, the price has moved significantly below its rolling average, and the probability of a bounce increases.
Above average -- look for shorts
Normal range -- no signal
Below average -- look for longs
Fetching CCI via API
curl -H "X-API-Key: YOUR_API_KEY" \
"https://tickatlas.com/v1/indicator?symbol=EURUSD&indicator=CCI_20&timeframe=H4"
Response:
{
"success": true,
"data": {
"symbol": "EURUSD",
"timeframe": "H4",
"indicator": "CCI_20",
"values": {
"cci": -142.87
},
"signal": "oversold",
"ohlcv": {
"open": 1.0851,
"high": 1.0858,
"low": 1.0822,
"close": 1.0829,
"volume": 15230
},
"timestamp": "2026-03-28T08:00:00Z"
}
} Python: CCI Mean Reversion Strategy
import requests
from dataclasses import dataclass
from typing import Optional
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://tickatlas.com/v1"
@dataclass
class CCISignal:
symbol: str
cci_value: float
signal_type: Optional[str] # "LONG", "SHORT", or None
entry_price: float
confidence: str # "standard", "high", "extreme"
def cci_mean_reversion(
symbol: str,
timeframe: str,
entry_threshold: float = 100,
high_threshold: float = 150,
extreme_threshold: float = 200,
) -> CCISignal:
"""Generate mean reversion signals based on CCI levels."""
resp = requests.get(
f"{BASE_URL}/indicator",
headers={"X-API-Key": API_KEY},
params={
"symbol": symbol,
"indicator": "CCI_20",
"timeframe": timeframe,
},
)
resp.raise_for_status()
data = resp.json()["data"]
cci = data["values"]["cci"]
close = data["ohlcv"]["close"]
signal_type = None
confidence = "standard"
if cci <= -extreme_threshold:
signal_type = "LONG"
confidence = "extreme"
elif cci <= -high_threshold:
signal_type = "LONG"
confidence = "high"
elif cci <= -entry_threshold:
signal_type = "LONG"
confidence = "standard"
elif cci >= extreme_threshold:
signal_type = "SHORT"
confidence = "extreme"
elif cci >= high_threshold:
signal_type = "SHORT"
confidence = "high"
elif cci >= entry_threshold:
signal_type = "SHORT"
confidence = "standard"
return CCISignal(
symbol=symbol,
cci_value=round(cci, 2),
signal_type=signal_type,
entry_price=close,
confidence=confidence,
)
# Scan multiple symbols
symbols = ["EURUSD", "GBPUSD", "USDJPY", "AUDUSD", "XAUUSD"]
for sym in symbols:
signal = cci_mean_reversion(sym, "H4")
if signal.signal_type:
print(f"{sym}: {signal.signal_type} (CCI={signal.cci_value}, {signal.confidence})")
else:
print(f"{sym}: No signal (CCI={signal.cci_value})") Adding a Trend Filter
Pure mean reversion without trend context is dangerous. A strong downtrend can keep CCI below -100 for weeks. Add a higher-timeframe trend filter:
def filtered_cci_signal(symbol: str) -> dict:
"""CCI mean reversion with EMA trend filter."""
# H4 CCI for the signal
cci_resp = requests.get(
f"{BASE_URL}/indicator",
headers={"X-API-Key": API_KEY},
params={"symbol": symbol, "indicator": "CCI_20", "timeframe": "H4"},
).json()["data"]
# D1 EMA for the trend
ema_resp = requests.get(
f"{BASE_URL}/indicator",
headers={"X-API-Key": API_KEY},
params={"symbol": symbol, "indicator": "EMA_50", "timeframe": "D1"},
).json()["data"]
cci = cci_resp["values"]["cci"]
close = cci_resp["ohlcv"]["close"]
ema = ema_resp["values"]["value"]
daily_trend = "UP" if close > ema else "DOWN"
signal = None
# Only take longs when daily trend is up
if cci < -100 and daily_trend == "UP":
signal = "LONG"
# Only take shorts when daily trend is down
elif cci > 100 and daily_trend == "DOWN":
signal = "SHORT"
return {
"symbol": symbol,
"cci": round(cci, 2),
"daily_trend": daily_trend,
"signal": signal,
"reason": f"CCI={cci:.0f}, trend={daily_trend}",
} Exit Strategy
For a mean reversion strategy, the exit is when price returns to the mean:
CCI crosses back through zero
The most conservative exit. Price has returned to its average. Close the full position.
CCI reaches the opposite extreme
If you entered long at CCI -150, exit when CCI reaches +100. This captures the full mean reversion move.
Time-based exit
If CCI has not returned to zero within 10 bars, exit at market. The mean reversion thesis has failed.
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- Analysis 9 min read
ADX: How to Measure Trend Strength in Your Trading Bot
Learn how the ADX indicator measures trend strength, not direction, and how to use it as a filter to dramatically improve your bot's signal quality.
March 28, 2026
- Analysis 13 min read
Crypto Trading API Comparison: 2026 Developer's Guide
A detailed comparison of crypto and multi-asset trading APIs for developers. Features, pricing, reliability, and code examples for the top platforms.
March 28, 2026
- Analysis 10 min read
Currency Strength Analysis: Finding the Best Pairs to Trade
Build a currency strength meter using the TickAtlas API. Compare relative strength across all major currencies to find the highest-probability forex trades.
March 28, 2026