TickAtlas
Analysis 10 min read · March 28, 2026

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.

CG
By the TickAtlas team

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.

> +100

Above average -- look for shorts

-100 to +100

Normal range -- no signal

< -100

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:

json
{
  "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

python
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:

python
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.