Add a Regime Filter to Any Freqtrade Strategy in 10 Minutes
A regime filter is a single gate you add on top of your existing Freqtrade entry logic: before a trade opens, the bot checks whether the current market regime — bull, bear, or chop — matches the conditions your strategy is built for, and skips the entry if it doesn't. Your Freqtrade bot otherwise runs the same entry logic in every market, which is why strategies that backtest brilliantly blow up live: the backtest period was one regime, and the live period is another.
This guide shows you how to add Regime's market-condition API to any Freqtrade strategy. No complicated setup. No new dependencies beyond requests. Ten minutes of work for a permanent improvement to your bot's risk management — and there's a free, complete strategy file at the end.
Why Your Freqtrade Bot Needs a Regime Filter
Freqtrade's populate_entry_trend function generates buy signals based on technical indicators — RSI, MACD, Bollinger Bands, moving averages, whatever your strategy uses. The problem: those indicators don't know context.
An RSI of 30 means something completely different in a bull market (buying opportunity) versus a bear market (could drop to 15). A MACD crossover in a trending market leads to a profitable trade. The same crossover in chop leads to a whipsaw loss.
Without regime awareness, your bot makes two systematic errors:
- Enters trades in hostile regimes — buying breakouts in bear markets, selling dips in bull markets
- Uses uniform sizing — risking the same amount in high-confidence trends as in uncertain chop
Both errors compound. Gating entries on regime doesn't change your edge — it just stops your edge from firing when the environment is wrong for it.
The placement trap: don't call the API in populate_*
The mistake almost everyone makes first: putting the regime fetch in populate_indicators or populate_entry_trend. Those run vectorized over your whole history — thousands of candles per call, expected to be pure and fast. An HTTP request there either hammers the API thousands of times in a backtest or blocks the bot loop.
The correct place for an external call is confirm_trade_entry — it runs once, on the live bot, at the moment a trade is about to open. Cache the answer for a few minutes so a busy multi-pair bot makes a handful of calls per hour.
The Regime API Endpoint for Freqtrade
Regime provides a dedicated endpoint optimized for Freqtrade bots:
curl -s https://getregime.com/api/v1/freqtrade/regime \
-H "Authorization: Bearer YOUR_API_KEY" | jq
Response:
{
"regime": "bear",
"confidence": 0.72,
"action": "exit_or_hedge",
"fear_greed": 31,
"btc_price": 61240,
"updated_at": "2026-06-08T14:00:00.000Z"
}
The action field maps directly to Freqtrade behavior:
| Action | Regime | What Your Bot Should Do |
|---|---|---|
full_position |
Bull | Normal operation, full position sizes |
reduce_position |
Chop | Smaller positions, skip marginal setups |
exit_or_hedge |
Bear | Cut risk, tighten stops, sit out longs |
This endpoint works with any tier: a free key returns a 15-minute-delayed read (enough to gate a bot trading majors); a Pro key makes it real-time. Grab a key (no card) at getregime.com and set it in your environment — never hard-code it:
export REGIME_API_KEY="your_key_here"
Step 1: Add the Regime Fetcher
Add this to your strategy file. It fetches the current regime and caches it for 5 minutes to stay within rate limits:
import os
import requests
import time
from freqtrade.strategy import IStrategy, DecimalParameter
from freqtrade.persistence import Trade
class MyRegimeFilteredStrategy(IStrategy):
# --- Regime filter settings ---
regime_enabled = True
regime_min_confidence = 0.6
_regime_cache = None
_regime_cache_time = 0
_regime_cache_ttl = 300 # 5 minutes
def get_regime(self) -> dict:
"""Fetch current market regime with caching."""
now = time.time()
if self._regime_cache and (now - self._regime_cache_time) < self._regime_cache_ttl:
return self._regime_cache
try:
resp = requests.get(
'https://getregime.com/api/v1/freqtrade/regime',
headers={'Authorization': f"Bearer {os.environ['REGIME_API_KEY']}"},
timeout=5
)
resp.raise_for_status()
self._regime_cache = resp.json()
self._regime_cache_time = now
except Exception as e:
# On failure, return the last known regime so the bot doesn't freeze
if self._regime_cache:
return self._regime_cache
return {
'regime': 'unknown',
'confidence': 0.5,
'action': 'reduce_position'
}
return self._regime_cache
Key design decisions:
- 5-minute cache — The regime doesn't change every second. Caching avoids burning through rate limits and adds resilience against network blips.
-
Graceful degradation — If the API is down, the bot uses the last known regime. If there's no cache at all, it defaults to
reduce_position(conservative, not frozen). - Timeout — a 5-second timeout prevents the bot from hanging if the API is slow.
Step 2: Filter Entries by Regime
Override confirm_trade_entry to check the regime before every trade:
def confirm_trade_entry(
self, pair: str, order_type: str, amount: float,
rate: float, time_in_force: str, current_time, entry_tag, side, **kwargs
) -> bool:
if not self.regime_enabled:
return True
regime = self.get_regime()
action = regime.get('action', 'reduce_position')
confidence = regime.get('confidence', 0.5)
# Block all entries in a bear regime
if action == 'exit_or_hedge':
self.log(f"REGIME FILTER: Blocking entry on {pair} — "
f"regime={regime['regime']}, action=exit_or_hedge")
return False
# Block low-confidence entries
if confidence < self.regime_min_confidence:
self.log(f"REGIME FILTER: Blocking entry on {pair} — "
f"confidence={confidence:.0%} < {self.regime_min_confidence:.0%}")
return False
return True
def log(self, msg):
"""Simple logger — replace with your logging setup."""
print(f"[RegimeFilter] {msg}")
That's it. Every entry signal your strategy generates now passes through a regime gate. In bear or low-confidence regimes, the bot sits on its hands instead of churning through losing trades.
Step 3: Scale Position Size by Confidence
For more sophisticated risk management, adjust position size based on regime confidence. Override custom_stake_amount:
def custom_stake_amount(
self, current_time, current_rate, proposed_stake,
min_stake, max_stake, leverage, entry_tag, side, **kwargs
) -> float:
if not self.regime_enabled:
return proposed_stake
regime = self.get_regime()
confidence = regime.get('confidence', 0.5)
action = regime.get('action', 'reduce_position')
# Scale stake by confidence
if action == 'full_position' and confidence >= 0.75:
scale = 1.0 # Full size in high-confidence bull
elif action == 'full_position':
scale = 0.75 # Slightly reduced in moderate bull
elif action == 'reduce_position':
scale = 0.5 # Half size in chop
else:
scale = 0.25 # Quarter size (shouldn't reach here due to entry filter)
adjusted = proposed_stake * scale
adjusted = max(adjusted, min_stake)
adjusted = min(adjusted, max_stake)
self.log(f"REGIME SIZE: stake {proposed_stake:.4f} -> "
f"{adjusted:.4f} (scale={scale}, regime={regime['regime']}, "
f"confidence={confidence:.0%})")
return adjusted
This creates a smooth risk curve: full size in confident bull markets, half size in chop, quarter size in uncertain conditions. Your bot's equity curve becomes dramatically smoother.
Step 4: Add Regime-Aware Exit Logic (Optional)
You can also use the regime to manage exits. For example, tighten trailing stops when the regime shifts bearish:
def custom_stoploss(
self, pair: str, trade: Trade, current_time,
current_rate: float, current_profit: float, after_fill, **kwargs
) -> float:
regime = self.get_regime()
action = regime.get('action', 'full_position')
if action == 'exit_or_hedge' and current_profit > 0.02:
# In bear regime with profit, tighten stop to lock gains
return -0.03 # 3% trailing stop
elif action == 'full_position' and current_profit > 0.05:
# In bull regime with good profit, give room to run
return -0.08 # 8% trailing stop
return -0.10 # Default 10% stop
In bear markets, you lock in profits quickly. In bull markets, you let winners run. Simple logic, massive impact on returns.
Get the complete strategy file
Rather than copy snippets, take the full, runs-out-of-the-box version. Download the free Regime Filter Freqtrade strategy — a complete RegimeFilterStrategy you drop into user_data/strategies/, with the cache, the fail-mode switch, the confidence gate, and a placeholder entry signal you replace with your own. Inherit from it and your existing strategy keeps the regime gate for free.
Pro Tier: Webhook Alerts on Regime Transitions
The endpoint above is enough for filtering. But if you want to be notified the instant the regime changes — so you can manually review positions or trigger automation — the Pro tier ($49/mo) adds webhook support:
# Register a webhook for regime transitions
curl -X POST https://getregime.com/api/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-server.com/regime-change", "event": "regime_transition"}'
You'll receive a POST whenever the regime shifts (e.g., bull to chop, chop to bear). This is useful for triggering Freqtrade's /forcesell command via its REST API when the market turns hostile.
FAQ
Where do I call the regime API in Freqtrade?
In confirm_trade_entry, not in populate_indicators or populate_entry_trend. Those are vectorized over history and must stay pure and fast; confirm_trade_entry runs once at trade time, which is the right place for an external call.
Does the endpoint need an API key?
Yes — pass Authorization: Bearer YOUR_KEY. A free key works (15-minute-delayed read), and a Pro key makes it real-time. Get one with no card at getregime.com.
Won't this use up my API rate limit?
No, if you cache. One regime read covers every pair for the cache window (default 5 minutes), so a busy bot makes only a few calls per hour — well within the free tier.
What happens if the Regime API is down?
The fetcher returns the last known regime, or a conservative reduce_position default if there's no cache yet — so the bot degrades gracefully instead of freezing.
Does the filter place trades for me?
No. It only blocks entries that don't match the regimes you allow. Your own entry logic still decides what to trade. It's a filter, not a signal generator — and it's informational, not financial advice.
Get the free strategy file and a Regime API key at getregime.com/freqtrade-strategy. Informational tool, not financial advice; regime classification is probabilistic, not a guarantee.
Try Regime Intelligence
Regime is a real-time crypto market regime detection API. One endpoint tells you if the market is bull, bear, or chop — so your bot only trades when conditions match your strategy.
Top comments (0)