Code Mode
Code Mode lets you write full Python trading strategies using the Freqtrade strategy API. This gives you complete control over every aspect of your strategy — custom indicators, advanced callbacks, hyperopt parameters, and any logic that fits inside the Freqtrade contract.
Code Mode is available on Pro and Team plans.
Getting Started
- Navigate to Strategies → New Strategy
- Select Code Mode
- Write your strategy in the Monaco code editor
- Click Save Strategy
Strategy Structure
A VolatiCloud strategy is a standard Freqtrade strategy class.
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
from pandas import DataFrame
import talib.abstract as ta
class MyStrategy(IStrategy):
# Required: candle timeframe
timeframe = '1h'
# Required: stop-loss (-10%)
stoploss = -0.10
# Optional: ROI table
minimal_roi = {
"60": 0.01, # 1% profit after 60 minutes
"30": 0.02, # 2% profit after 30 minutes
"0": 0.04 # 4% profit immediately
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Add indicators to dataframe
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2, nbdevdn=2)
dataframe['bb_upper'] = bollinger['upperband']
dataframe['bb_lower'] = bollinger['lowerband']
dataframe['bb_mid'] = bollinger['middleband']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Define entry conditions
dataframe.loc[
(dataframe['rsi'] < 30) &
(dataframe['close'] > dataframe['ema_200']),
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Define exit conditions
dataframe.loc[
dataframe['rsi'] > 70,
'exit_long'
] = 1
return dataframe
Key Methods
populate_indicators
Calculate technical indicators and add them to the dataframe. This runs once per new candle.
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# metadata['pair'] contains the current pair, e.g., 'BTC/USDT'
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
populate_entry_trend
Set enter_long = 1 rows where you want to open long positions. Set enter_short = 1 for shorts.
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['rsi'] < 30) &
(dataframe['volume'] > 0),
'enter_long'
] = 1
return dataframe
populate_exit_trend
Set exit_long = 1 where you want to close long positions. Use exit_short = 1 for shorts.
custom_stoploss (optional)
Define dynamic stop-loss based on current trade data:
def custom_stoploss(self, pair: str, trade, current_time, current_rate,
current_profit: float, **kwargs) -> float:
# Trail stop-loss at 1% below the 20-candle high
if current_profit > 0.02:
return -0.01 # Tight stop after 2% profit
return self.stoploss # Use default otherwise
Hyperparameters
Use IntParameter and DecimalParameter to define tunable parameters for hyperopt.
class MyStrategy(IStrategy):
# Define tunable parameters
buy_rsi = IntParameter(20, 40, default=30, space='buy')
sell_rsi = IntParameter(60, 80, default=70, space='sell')
ema_period = IntParameter(50, 300, default=200, space='buy')
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
dataframe['rsi'] < self.buy_rsi.value,
'enter_long'
] = 1
return dataframe
VolatiCloud's strategy analyzer automatically discovers these declarations and pre-populates them in the hyperopt UI — no manual entry required.
Long/Short Strategies
For futures trading with both long and short positions:
class LongShortStrategy(IStrategy):
can_short = True
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Long entry
dataframe.loc[dataframe['rsi'] < 30, 'enter_long'] = 1
# Short entry
dataframe.loc[dataframe['rsi'] > 70, 'enter_short'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Close longs
dataframe.loc[dataframe['rsi'] > 70, 'exit_long'] = 1
# Close shorts
dataframe.loc[dataframe['rsi'] < 30, 'exit_short'] = 1
return dataframe
Available Libraries
The following Python libraries are available in Code Mode.
| Library | Purpose |
|---|---|
ta-lib | Technical analysis (via talib) |
pandas | Data manipulation |
numpy | Numerical computing |
pandas_ta | Additional technical indicators |
freqtrade.strategy | Strategy base classes and utilities |
Code Editor Features
The integrated Monaco editor provides:
- Syntax highlighting for Python
- Auto-completion for common patterns
- Inline lint markers from the strategy analyzer (errors, warnings, info — see Insights tab)
- Line numbers and code folding

Saving and Versioning
Every time you click Save Strategy:
- A new immutable version is created
- The previous version is preserved
- Backtests linked to old versions remain valid
- Bots continue running the version they were configured with
See the versioning guide for the full lifecycle.
Testing Your Strategy
Before deploying live:
- Save your strategy and review the Insights tab for lint errors
- Run a Backtest to validate historical performance
- Deploy as Dry Run bot to test real-time behavior
- Only then switch to Live mode
Common Patterns
Moving Average Crossover
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=9)
dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=21)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['ema_fast'] > dataframe['ema_slow']) &
(dataframe['ema_fast'].shift(1) <= dataframe['ema_slow'].shift(1)),
'enter_long'
] = 1
return dataframe
Bollinger Band Bounce
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
dataframe['close'] < dataframe['bb_lower'],
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
dataframe['close'] > dataframe['bb_mid'],
'exit_long'
] = 1
return dataframe
Related guides
- Strategies Overview — Trading modes, position direction, and strategy concepts.
- UI Builder — Build strategies visually without writing Python.
- Strategy Versioning — How immutable versions protect your live bots.
- Backtesting Overview — Validate your code-mode strategy against historical data.
- Blog: Strategy Analysis & Insights — Live lint, risk profile, and hyperopt parameter discovery for code-mode strategies.
- Blog: Multi-Timeframe Strategies —
informative_pairsand@informativedecorator patterns.