How to Build a Regime-Aware Trading Bot with Freqtrade

Most Freqtrade strategies treat every market condition the same. An EMA crossover fires in a bull market? Buy. Same crossover in a grinding bear? Also buy. Then you wonder why your backtest looked great but live trading bled out over three months.

The fix isn't a better indicator. It's knowing when to trade and when to sit out.

This tutorial shows you how to plug market regime detection into a Freqtrade strategy so your bot automatically adapts — aggressive in bull markets, defensive in chop, and sidelined in bear conditions.

What You'll Build

A Freqtrade strategy that:

Prerequisites

Step 1: Get Your API Key

``bash

curl -X POST https://getregime.com/api/v1/auth/register \

-H 'Content-Type: application/json' \

-d '{"email":"[email protected]","name":"freqtrade-bot"}'

`

Save the apiKey from the response. Add it to your Freqtrade config:

`json

{

"regime_api_key": "cse_free_abc123...",

"regime_api_url": "https://getregime.com"

}

`

Step 2: The Regime Client

Add this to your strategy file — it handles API calls, caching, and fallback:

`python

import requests

from datetime import datetime, timedelta, timezone

class RegimeClient:

def __init__(self, api_key: str, base_url: str = "https://getregime.com"):

self.api_key = api_key

self.base_url = base_url

self._cache = None

self._cache_time = None

self._cache_ttl = timedelta(minutes=5)

def get_regime(self) -> dict:

now = datetime.now(timezone.utc)

if self._cache and self._cache_time and (now - self._cache_time) < self._cache_ttl:

return self._cache

try:

resp = requests.get(

f"{self.base_url}/api/v1/market/regime",

headers={"X-API-Key": self.api_key},

timeout=10

)

resp.raise_for_status()

self._cache = resp.json()

self._cache_time = now

return self._cache

except Exception:

return self._cache or {"regime": "unknown", "confidence": 0}

`

The 5-minute cache matches the API's data refresh rate. If the API is unreachable, the last known regime is used — your bot doesn't crash because of a network blip.

Step 3: Regime-Aware Entry Logic

Here's the core idea: different market conditions call for different entry strategies.

`python

from freqtrade.strategy import IStrategy

import talib.abstract as ta

class RegimeAwareStrategy(IStrategy):

INTERFACE_VERSION = 3

timeframe = '5m'

stoploss = -0.05

can_short = False

def __init__(self, config: dict) -> None:

super().__init__(config)

self.regime_client = RegimeClient(

api_key=config.get('regime_api_key', ''),

base_url=config.get('regime_api_url', 'https://getregime.com')

)

def populate_indicators(self, dataframe, metadata):

dataframe['ema_8'] = ta.EMA(dataframe, timeperiod=8)

dataframe['ema_21'] = ta.EMA(dataframe, timeperiod=21)

dataframe['bb_upper'] = ta.BBANDS(dataframe, timeperiod=20)[0]

dataframe['bb_lower'] = ta.BBANDS(dataframe, timeperiod=20)[2]

dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

return dataframe

def populate_entry_trend(self, dataframe, metadata):

regime_data = self.regime_client.get_regime()

regime = regime_data.get('regime', 'unknown')

confidence = regime_data.get('confidence', 0)

if regime == 'bull' and confidence > 0.6:

# Trend-following: EMA crossover

dataframe.loc[

(dataframe['ema_8'] > dataframe['ema_21']) &

(dataframe['rsi'] < 70),

'enter_long'

] = 1

elif regime == 'chop':

# Mean-reversion: Bollinger bounce

dataframe.loc[

(dataframe['close'] < dataframe['bb_lower']) &

(dataframe['rsi'] < 35),

'enter_long'

] = 1

# Bear regime: no entries. Bot sits out.

return dataframe

`

Step 4: Regime-Based Position Sizing

Don't just change your signals — change your conviction:

`python

def custom_stake_amount(self, current_time, current_rate, proposed_stake,

min_stake, max_stake, leverage, entry_tag, side, **kwargs):

regime_data = self.regime_client.get_regime()

regime = regime_data.get('regime', 'unknown')

confidence = regime_data.get('confidence', 0)

multiplier = {

'bull': 1.0, # Full size

'chop': 0.5, # Half size

'bear': 0.0, # No new positions

}.get(regime, 0.25)

# Scale by confidence: 74% confidence = 74% of multiplier

adjusted = proposed_stake multiplier min(confidence, 1.0)

return max(min_stake, min(adjusted, max_stake))

`

Step 5: Dynamic Stop-Loss

Tighten stops in choppy markets, let winners run in trends:

`python

def custom_stoploss(self, current_time, current_rate, current_profit,

after_fill, **kwargs):

regime_data = self.regime_client.get_regime()

regime = regime_data.get('regime', 'unknown')

if regime == 'bull':

return -0.08 # Wide stop for trending markets

elif regime == 'chop':

return -0.03 # Tight stop for ranging markets

else:

return -0.02 # Very tight in bear — protect capital

`

Running It

`bash

freqtrade trade --strategy RegimeAwareStrategy \

--config user_data/config.json

`

Check your logs for regime state:

`

2026-04-12 08:00:05 - RegimeAwareStrategy - Regime: bear (74% confidence, grinding)

2026-04-12 08:00:05 - RegimeAwareStrategy - Position multiplier: 0.0 — sitting out

`

Free vs Pro Tier

The free tier gives you regime classification with a 15-minute delay — fine for backtesting and development. For live trading where you need real-time regime shifts and signal breakdowns, Pro at $49/mo removes the delay and adds the /signals/all endpoint for individual signal weights.

The dedicated Freqtrade endpoint (/api/v1/freqtrade/regime`) returns a simplified response optimized for bot consumption.

What the Data Actually Looks Like

As of today, Regime has classified 9,285 market snapshots across 266 regime transitions. The current bear phase has been grinding for 59 hours at 74% confidence. That's the kind of sustained directional read that keeps your bot from buying dips in a downtrend.

The regime detector uses 10 signals: funding rates, open interest changes, Fear & Greed, DeFi TVL flows, stablecoin supply, macro divergences (DXY, VIX), and volume-weighted price action. It's not a single indicator — it's a composite classifier.

Full Strategy Template

A complete, production-ready strategy file is available in the Regime GitHub repo. It includes all the code above plus logging, error handling, and a configuration guide.


Building something with Regime data? Reply on Twitter/X or drop a comment in the Freqtrade Discord. We're actively helping builders integrate.