Hyperopt runs your strategy's backtest hundreds of times with different parameter values and keeps the set that scores best. Used carefully it can improve a sound strategy. Used carelessly it produces strategies that look brilliant on past data and fail immediately afterwards.
Several strategies in our leaderboard are hyperopt products, such as Diamond and PowerTower. Their rules show what over-fitting looks like in practice.
Before you start
- Hyperopt dependencies are included in the Docker image. For a manual install, run
pip install -r requirements-hyperopt.txt. - You need downloaded data for the pairs and timeframe you will optimise. See the backtesting tutorial.
- Hyperopt is CPU-heavy. It uses all cores by default; limit it with
-j 2on a small VPS.
Make parameters optimisable
Hyperopt only changes values you declare as parameters in your strategy class:
from freqtrade.strategy import IntParameter, DecimalParameter
class MyStrategy(IStrategy):
buy_rsi = IntParameter(10, 40, default=30, space="buy")
sell_rsi = IntParameter(60, 90, default=70, space="sell")
def populate_entry_trend(self, dataframe, metadata):
dataframe.loc[dataframe["rsi"] < self.buy_rsi.value, "enter_long"] = 1
return dataframe
Keep ranges realistic. A range that allows RSI thresholds of 1 to 100 invites the optimiser to find coincidences.
Run hyperopt
freqtrade hyperopt --config user_data/config.json \
--strategy MyStrategy \
--hyperopt-loss SharpeHyperOptLossDaily \
--spaces buy sell \
--timerange 20230101-20240101 \
-e 300
-e sets the number of epochs (test runs). A few hundred is a reasonable start.
Choosing spaces
The --spaces option controls what hyperopt changes:
| Space | Optimises |
|---|---|
buy / enter |
Entry parameters |
sell / exit |
Exit parameters |
roi |
The take-profit table |
stoploss |
The stoploss value |
trailing |
Trailing stop settings |
trades |
Max open trades |
protection |
Protection parameters |
default |
Everything except trailing, trades and protection |
all |
Everything |
Optimising everything at once creates a huge search space. A better order is: entry and exit logic first, then ROI and stoploss, then trailing separately, which is also what the freqtrade docs recommend for the trailing space.
Choosing a loss function
The loss function defines what "best" means. Freqtrade includes several, among them:
| Loss function | Prefers |
|---|---|
SharpeHyperOptLossDaily |
Smooth daily returns relative to volatility |
SortinoHyperOptLossDaily |
Like Sharpe, but only penalises downside volatility |
CalmarHyperOptLoss |
Return relative to max drawdown |
MaxDrawDownRelativeHyperOptLoss |
Low drawdown |
ProfitDrawDownHyperOptLoss |
Profit with a drawdown penalty |
MultiMetricHyperOptLoss |
A balance of profit, drawdown, profit factor, expectancy and win rate, with a penalty for too few trades |
OnlyProfitHyperOptLoss |
Profit only |
Avoid OnlyProfitHyperOptLoss for anything you plan to run. It happily selects strategies with huge drawdowns. Risk-adjusted functions such as Sharpe, Sortino or Calmar usually generalise better.
Apply the results
When hyperopt finishes, it prints the best parameters and writes them to a JSON file next to your strategy (for MyStrategy.py, the file is MyStrategy.json). Freqtrade loads that file automatically next time the strategy runs. You can also paste the printed buy_params and sell_params blocks into the class.
Review other good results with:
freqtrade hyperopt-list --best
freqtrade hyperopt-show -n 25
Check for over-fitting
This is the step most people skip. Do all three:
-
Out-of-sample test. Optimise on one period, then backtest the result on a later period hyperopt never saw. In the command above we optimised on 2023, so test on 2024:
bash freqtrade backtesting --strategy MyStrategy --timerange 20240101-20250101If performance collapses, the parameters fitted noise.
-
Sanity-check the values. If the best RSI entry is 90, or a rule compares price to volume, the optimiser found a coincidence, not a pattern.
-
Look at neighbouring values. Good parameters sit on a plateau: nearby values perform similarly. If changing RSI from 28 to 30 turns profit into loss, the result is fragile.
Signs of an over-fitted strategy
- Very few trades with a very high win rate.
- Oddly precise numbers, such as a stoploss of −34.338%.
- Rules with no market logic behind them.
- Excellent results on one pair and losses on others.
- A smooth in-sample equity curve followed by an immediate drawdown out of sample.
Next steps
- Compare the hand-built and hyperopt-generated strategies in our leaderboard.
- Dry-run any optimised strategy for several weeks before using real money.
Ready to connect an exchange?
Freqtrade needs an exchange account with API access. Bybit supports both spot and futures in freqtrade and offers a demo mode for testing.
Affiliate link: we may earn a commission if you sign up, at no cost to you.
Related guides
- How to control freqtrade from TelegramCreate a Telegram bot with BotFather, find your chat ID, add both to the freqtrade config and use the most useful commands to monitor and control your bot.2 min read
- Freqtrade vs 3Commas vs Pionex vs CryptohopperHow freqtrade compares with 3Commas, Pionex and Cryptohopper on cost, control, strategies, security and effort, and which type of trader each one suits.4 min read
- Best VPS for freqtrade: what you need and how to chooseHow much server you need for freqtrade, where to host it relative to your exchange, which providers people use, and how to secure the server before you trade.4 min read