FreqAI Machine Learning Strategy Template.
Timeframe
5m
Direction
Long Only
Stoploss
-10.0%
Trailing Stop
Yes
ROI
0m: 4.0%, 30m: 2.0%, 60m: 1.0%
Interface Version
3
Startup Candles
N/A
Indicators
6
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
import logging
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
logger = logging.getLogger(__name__)
class FreqAIStrategy(IStrategy):
"""
FreqAI Machine Learning Strategy Template.
Uses Freqtrade's built-in FreqAI module to train a classifier
that predicts price direction using technical indicators as features.
Model: LightGBMClassifier (default) or RandomForest
Target: Predict if price will rise > 1% in next 24 candles (2 hours)
Features used:
- RSI (14)
- MACD histogram
- Bollinger Band position (%)
- EMA slopes (fast/slow)
- Volume ratio
- ATR (normalized)
- ADX
REQUIRES: freqai config section in config.json
See: freqai/freqai_config.json for full setup
Paper trade for minimum 2 weeks before going live.
Model needs 500+ candles to train initially.
"""
INTERFACE_VERSION = 3
freqai_info: dict = {}
# Entry/exit thresholds (model outputs probability 0-1)
entry_threshold = DecimalParameter(0.5, 0.9, default=0.6, space="buy", decimals=2)
exit_threshold = DecimalParameter(0.1, 0.5, default=0.4, space="sell", decimals=2)
minimal_roi = {"60": 0.01, "30": 0.02, "0": 0.04}
stoploss = -0.10
trailing_stop = True
trailing_stop_positive = 0.02
trailing_stop_positive_offset = 0.04
trailing_only_offset_is_reached = True
timeframe = "5m"
process_only_new_candles = True
startup_candle_count: int = 40
can_short = False
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int,
metadata: dict, **kwargs) -> DataFrame:
"""
FreqAI feature engineering — called for each period in indicator_periods_candles.
Features prefixed with %% are used as ML inputs.
"""
dataframe[f"%rsi-period_{period}"] = ta.RSI(dataframe, timeperiod=period)
macd = ta.MACD(dataframe, fastperiod=period, slowperiod=period * 2, signalperiod=period // 2)
dataframe[f"%macd-period_{period}"] = macd["macdhist"]
dataframe[f"%ema_fast-period_{period}"] = ta.EMA(dataframe, timeperiod=period)
dataframe[f"%ema_slow-period_{period}"] = ta.EMA(dataframe, timeperiod=period * 2)
dataframe[f"%atr-period_{period}"] = ta.ATR(dataframe, timeperiod=period) / dataframe["close"]
bollinger = qtpylib.bollinger_bands(
qtpylib.typical_price(dataframe), window=period, stds=2
)
dataframe[f"%bb_percent-period_{period}"] = (
(dataframe["close"] - bollinger["lower"]) /
(bollinger["upper"] - bollinger["lower"] + 1e-6)
)
return dataframe
def feature_engineering_standard(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
"""Standard features added once (not per period)."""
dataframe["%adx"] = ta.ADX(dataframe, timeperiod=14)
dataframe["%volume_ratio"] = dataframe["volume"] / dataframe["volume"].rolling(20).mean()
dataframe["%day_of_week"] = pd.to_datetime(dataframe["date"]).dt.dayofweek
dataframe["%hour_of_day"] = pd.to_datetime(dataframe["date"]).dt.hour
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
"""
Define the target variable for training.
&target_roi = 1 if price rises > 1% in next 24 candles, else 0.
"""
dataframe["&target_roi"] = (
dataframe["close"].shift(-24) > dataframe["close"] * 1.01
).astype(int)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Standard indicators (non-FreqAI, for entry/exit logic)."""
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["volume_mean"] = dataframe["volume"].rolling(window=20).mean()
# FreqAI prediction columns are added automatically after this
dataframe = self.freqai.start(dataframe, metadata, self)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# FreqAI outputs: do_predict (1=trade, 0=skip), &target_roi_mean (probability)
enter_long_conditions = [
dataframe["do_predict"] == 1,
dataframe["&target_roi_mean"] > self.entry_threshold.value,
dataframe["volume"] > 0.8 * dataframe["volume_mean"],
]
if enter_long_conditions:
dataframe.loc[
pd.concat([c.to_frame() for c in enter_long_conditions], axis=1).all(axis=1),
"enter_long",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
dataframe["do_predict"] == 1,
dataframe["&target_roi_mean"] < self.exit_threshold.value,
]
if exit_long_conditions:
dataframe.loc[
pd.concat([c.to_frame() for c in exit_long_conditions], axis=1).all(axis=1),
"exit_long",
] = 1
return dataframe