Freqtrade
Freqtrade
Freqtrade is a free and open source crypto trading bot written in Python. It is
designed to support all major exchanges and be controlled via Telegram or webUI. It
contains backtesting, plotting and money management tools as well as strategy
optimization by machine learning.
DISCLAIMER
This software is for educational purposes only. Do not risk money which you are
afraid to lose. USE THE SOFTWARE AT YOUR OWN RISK. THE AUTHORS AND ALL AFFILIATES
ASSUME NO RESPONSIBILITY FOR YOUR TRADING RESULTS.
Always start by running a trading bot in Dry-run and do not engage money before you
understand how it works and what profit/loss you should expect.
We strongly recommend you to have basic coding skills and Python knowledge. Do not
hesitate to read the source code and understand the mechanisms of this bot,
algorithms and techniques implemented in it.
freqtrade screenshot
Features
Develop your Strategy: Write your strategy in python, using pandas. Example
strategies to inspire you are available in the strategy repository.
Download market data: Download historical data of the exchange and the markets your
may want to trade with.
Backtest: Test your strategy on downloaded historical data.
Optimize: Find the best parameters for your strategy using hyperoptimization which
employs machining learning methods. You can optimize buy, sell, take profit (ROI),
stop-loss and trailing stop-loss parameters for your strategy.
Select markets: Create your static list or use an automatic one based on top traded
volumes and/or prices (not available during backtesting). You can also explicitly
blacklist markets you don't want to trade.
Run: Test your strategy with simulated money (Dry-Run mode) or deploy it with real
money (Live-Trade mode).
Run using Edge (optional module): The concept is to find the best historical trade
expectancy by markets based on variation of the stop-loss and then allow/reject
markets to trade. The sizing of the trade is based on a risk of a percentage of
your capital.
Control/Monitor: Use Telegram or a WebUI (start/stop the bot, show profit/loss,
daily summary, current open trades results, etc.).
Analyze: Further analysis can be performed on either Backtesting data or Freqtrade
trading history (SQL database), including automated standard plots, and methods to
load the data into interactive environments.
Supported exchange marketplaces
Please read the exchange specific notes to learn about eventual, special
configurations needed for each exchange.
Binance
Bitmart
BingX
[Link]
HTX (Former Huobi)
Kraken
OKX (Former OKEX)
potentially many others through ccxt. (We cannot guarantee they will work)
Supported Futures Exchanges (experimental)
Binance
[Link]
OKX
Bybit
Please make sure to read the exchange specific notes, as well as the trading with
leverage documentation before diving in.
Community tested
Exchanges confirmed working by the community:
Bitvavo
Kucoin
Community showcase
This section will highlight a few projects from members of the community.
Note
The projects below are for the most part not maintained by the freqtrade ,
therefore use your own caution before using them.
2GB RAM
1GB disk space
2vCPU
Software requirements
Docker (Recommended)
Alternatively
Python 3.9+
pip (pip3)
git
TA-Lib
virtualenv (Recommended)
Support
Help / Discord
For any questions not covered by the documentation or for further information about
the bot, or to simply engage with like-minded individuals, we encourage you to join
the Freqtrade discord server.
Ready to try?
Begin by reading the installation guide for docker (recommended), or for
installation without docker.
Freqtrade basics
This page provides you some basic concepts on how Freqtrade works and operates.
Freqtrade terminology
Strategy: Your trading strategy, telling the bot what to do.
Trade: Open position.
Open Order: Order which is currently placed on the exchange, and is not yet
complete.
Pair: Tradable pair, usually in the format of Base/Quote (e.g. XRP/USDT for spot,
XRP/USDT:USDT for futures).
Timeframe: Candle length to use (e.g. "5m", "1h", ...).
Indicators: Technical indicators (SMA, EMA, RSI, ...).
Limit order: Limit orders which execute at the defined limit price or better.
Market order: Guaranteed to fill, may move price depending on the order size.
Current Profit: Currently pending (unrealized) profit for this trade. This is
mainly used throughout the bot and UI.
Realized Profit: Already realized profit. Only relevant in combination with partial
exits - which also explains the calculation logic for this.
Total Profit: Combined realized and unrealized profit. The relative number (%) is
calculated against the total investment in this trade.
Fee handling
All profit calculations of Freqtrade include fees. For Backtesting / Hyperopt /
Dry-run modes, the exchange default fee is used (lowest tier on the exchange). For
live operations, fees are used as applied by the exchange (this includes BNB
rebates etc.).
Pair naming
Freqtrade follows the ccxt naming convention for currencies. Using the wrong naming
convention in the wrong market will usually result in the bot not recognizing the
pair, usually resulting in errors like "this pair is not available".
Both Backtesting and Hyperopt include exchange default Fees in the calculation.
Custom fees can be passed to backtesting / hyperopt by specifying the --fee
argument.
Backtesting will call each callback at max. once per candle (--timeframe-detail
modifies this behavior to once per detailed candle). Most callbacks will be called
once per iteration in live (usually every ~5s) - which can cause backtesting
mismatches.
Per default, the bot loads the configuration from the [Link] file, located in
the current working directory.
You can specify a different configuration file used by the bot with the -c/--config
command-line option.
If you used the Quick start method for installing the bot, the installation script
should have already created the default configuration file ([Link]) for you.
If the default configuration file is not created we recommend to use freqtrade new-
config --config user_data/[Link] to generate a basic configuration file.
Additionally to the standard JSON syntax, you may use one-line // ... and multi-
line /* ... */ comments in your configuration files and trailing commas in the
lists of parameters.
Do not worry if you are not familiar with JSON format -- simply open the
configuration file with an editor of your choice, make some changes to the
parameters you need, save your changes and, finally, restart the bot or, if it was
previously stopped, run it again with the changes you made to the configuration.
The bot validates the syntax of the configuration file at startup and will warn you
if you made any errors editing it, pointing out problematic lines.
Environment variables
Set options in the Freqtrade configuration via environment variables. This takes
priority over the corresponding value in configuration or strategy.
Common example:
FREQTRADE__TELEGRAM__CHAT_ID=<telegramchatid>
FREQTRADE__TELEGRAM__TOKEN=<telegramToken>
FREQTRADE__EXCHANGE__KEY=<yourExchangeKey>
FREQTRADE__EXCHANGE__SECRET=<yourExchangeSecret>
Note
Environment variables detected are logged at startup - so if you can't find why a
value is not what you think it should be based on the configuration, make sure it's
not loaded from an environment variable.
You can use the show-config subcommand to see the final, combined configuration.
Loading sequence
Multiple configuration files
Multiple configuration files can be specified and used by the bot or the bot can
read its configuration parameters from the process standard input stream.
You can use the show-config subcommand to see the final, combined configuration.
You can use a 2nd configuration file containing your secrets. That way you can
share your "primary" configuration file, while still keeping your API keys for
yourself. The 2nd file should only specify what you intend to override. If a key is
in more than one of the configurations, then the "last specified configuration"
wins (in the above example, [Link]).
For one-off commands, you can also use the below syntax by specifying multiple "--
config" parameters.
user_data/[Link]
"add_config_files": [
"[Link]",
"[Link]"
]
{
"$schema": "[Link]
}
Develop version
Configuration parameters
The table below will list all configuration parameters available.
Freqtrade can also load many options via command line (CLI) arguments (check out
the commands --help output for details).
Parameter Description
max_open_trades Required. Number of open trades your bot is allowed to have. Only
one open trade per pair is possible, so the length of your pairlist is another
limitation that can apply. If -1 then it is ignored (i.e. potentially unlimited
open trades, limited by the pairlist). More information below. Strategy Override.
Datatype: Positive integer or -1.
stake_currency Required. Crypto-currency used for trading.
Datatype: String
stake_amount Required. Amount of crypto-currency your bot will use for each
trade. Set it to "unlimited" to allow the bot to use all available balance. More
information below.
Datatype: Positive float or "unlimited".
tradable_balance_ratio Ratio of the total account balance the bot is allowed to
trade. More information below.
Defaults to 0.99 99%).
Datatype: Positive float between 0.1 and 1.0.
available_capital Available starting capital for the bot. Useful when running
multiple bots on the same exchange account. More information below.
Datatype: Positive float.
amend_last_stake_amount Use reduced last stake amount if necessary. More
information below.
Defaults to false.
Datatype: Boolean
last_stake_amount_min_ratio Defines minimum stake amount that has to be left and
executed. Applies only to the last stake amount when it's amended to a reduced
value (i.e. if amend_last_stake_amount is set to true). More information below.
Defaults to 0.5.
Datatype: Float (as ratio)
amount_reserve_percent Reserve some amount in min pair stake amount. The bot will
reserve amount_reserve_percent + stoploss value when calculating min pair stake
amount in order to avoid possible trade refusals.
Defaults to 0.05 (5%).
Datatype: Positive Float as ratio.
timeframe The timeframe to use (e.g 1m, 5m, 15m, 30m, 1h ...). Usually missing in
configuration, and specified in the strategy. Strategy Override.
Datatype: String
fiat_display_currency Fiat currency used to show your profits. More information
below.
Datatype: String
dry_run Required. Define if the bot must be in Dry Run or production mode.
Defaults to true.
Datatype: Boolean
dry_run_wallet Define the starting amount in stake currency for the simulated
wallet used by the bot running in Dry Run mode.
Defaults to 1000.
Datatype: Float
cancel_open_orders_on_exit Cancel open orders when the /stop RPC command is
issued, Ctrl+C is pressed or the bot dies unexpectedly. When set to true, this
allows you to use /stop to cancel unfilled and partially filled orders in the event
of a market crash. It does not impact open positions.
Defaults to false.
Datatype: Boolean
process_only_new_candles Enable processing of indicators only when new candles
arrive. If false each loop populates the indicators, this will mean the same candle
is processed many times creating system load but can be useful of your strategy
depends on tick data not only candle. Strategy Override.
Defaults to true.
Datatype: Boolean
minimal_roi Required. Set the threshold as ratio the bot will use to exit a trade.
More information below. Strategy Override.
Datatype: Dict
stoploss Required. Value as ratio of the stoploss used by the bot. More details
in the stoploss documentation. Strategy Override.
Datatype: Float (as ratio)
trailing_stop Enables trailing stoploss (based on stoploss in either
configuration or strategy file). More details in the stoploss documentation.
Strategy Override.
Datatype: Boolean
trailing_stop_positive Changes stoploss once profit has been reached. More details
in the stoploss documentation. Strategy Override.
Datatype: Float
trailing_stop_positive_offset Offset on when to apply trailing_stop_positive.
Percentage value which should be positive. More details in the stoploss
documentation. Strategy Override.
Defaults to 0.0 (no offset).
Datatype: Float
trailing_only_offset_is_reached Only apply trailing stoploss when the offset is
reached. stoploss documentation. Strategy Override.
Defaults to false.
Datatype: Boolean
fee Fee used during backtesting / dry-runs. Should normally not be configured,
which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001
= 0.1%). Fee is applied twice for each trade, once when buying, once when selling.
Datatype: Float (as ratio)
futures_funding_rate User-specified funding rate to be used when historical
funding rates are not available from the exchange. This does not overwrite real
historical rates. It is recommended that this be set to 0 unless you are testing a
specific coin and you understand how the funding rate will affect freqtrade's
profit calculations. More information here
Defaults to None.
Datatype: Float
trading_mode Specifies if you want to trade regularly, trade with leverage, or
trade contracts whose prices are derived from matching cryptocurrency prices.
leverage documentation.
Defaults to "spot".
Datatype: String
margin_mode When trading with leverage, this determines if the collateral owned by
the trader will be shared or isolated to each trading pair leverage documentation.
Datatype: String
liquidation_buffer A ratio specifying how large of a safety net to place
between the liquidation price and the stoploss to prevent a position from reaching
the liquidation price leverage documentation.
Defaults to 0.05.
Datatype: Float
Unfilled timeout
[Link] Required. How long (in minutes or seconds) the bot will
wait for an unfilled entry order to complete, after which the order will be
cancelled and repeated at current (new) price, as long as there is a signal.
Strategy Override.
Datatype: Integer
[Link] Required. How long (in minutes or seconds) the bot will
wait for an unfilled exit order to complete, after which the order will be
cancelled and repeated at current (new) price, as long as there is a signal.
Strategy Override.
Datatype: Integer
[Link] Unit to use in unfilledtimeout setting. Note: If you set
[Link] to "seconds", "internals.process_throttle_secs" must be
inferior or equal to timeout Strategy Override.
Defaults to "minutes".
Datatype: String
unfilledtimeout.exit_timeout_count How many times can exit orders time out. Once
this number of timeouts is reached, an emergency exit is triggered. 0 to disable
and allow unlimited order cancels. Strategy Override.
Defaults to 0.
Datatype: Integer
Pricing
entry_pricing.price_side Select the side of the spread the bot should look at
to get the entry rate. More information below.
Defaults to "same".
Datatype: String (either ask, bid, same or other).
entry_pricing.price_last_balance Required. Interpolate the bidding price. More
information below.
entry_pricing.use_order_book Enable entering using the rates in Order Book Entry.
Defaults to true.
Datatype: Boolean
entry_pricing.order_book_top Bot will use the top N rate in Order Book
"price_side" to enter a trade. I.e. a value of 2 will allow the bot to pick the 2nd
entry in Order Book Entry.
Defaults to 1.
Datatype: Positive Integer
entry_pricing. check_depth_of_market.enabled Do not enter if the difference of
buy orders and sell orders is met in Order Book. Check market depth.
Defaults to false.
Datatype: Boolean
entry_pricing. check_depth_of_market.bids_to_ask_delta The difference ratio of
buy orders and sell orders found in Order Book. A value below 1 means sell order
size is greater, while value greater than 1 means buy order size is higher. Check
market depth
Defaults to 0.
Datatype: Float (as ratio)
exit_pricing.price_side Select the side of the spread the bot should look at to get
the exit rate. More information below.
Defaults to "same".
Datatype: String (either ask, bid, same or other).
exit_pricing.price_last_balance Interpolate the exiting price. More information
below.
exit_pricing.use_order_book Enable exiting of open trades using Order Book Exit.
Defaults to true.
Datatype: Boolean
exit_pricing.order_book_top Bot will use the top N rate in Order Book
"price_side" to exit. I.e. a value of 2 will allow the bot to pick the 2nd ask rate
in Order Book Exit
Defaults to 1.
Datatype: Positive Integer
custom_price_max_distance_ratio Configure maximum distance ratio between
current and custom entry or exit price.
Defaults to 0.02 2%).
Datatype: Positive float
TODO
use_exit_signal Use exit signals produced by the strategy in addition to the
minimal_roi.
Setting this to false disables the usage of "exit_long" and "exit_short" columns.
Has no influence on other exit methods (Stoploss, ROI, callbacks). Strategy
Override.
Defaults to true.
Datatype: Boolean
exit_profit_only Wait until the bot reaches exit_profit_offset before taking an
exit decision. Strategy Override.
Defaults to false.
Datatype: Boolean
exit_profit_offset Exit-signal is only active above this value. Only active in
combination with exit_profit_only=True. Strategy Override.
Defaults to 0.0.
Datatype: Float (as ratio)
ignore_roi_if_entry_signal Do not exit if the entry signal is still active. This
setting takes preference over minimal_roi and use_exit_signal. Strategy Override.
Defaults to false.
Datatype: Boolean
ignore_buying_expired_candle_after Specifies the number of seconds until a buy
signal is no longer used.
Datatype: Integer
order_types Configure order-types depending on the action ("entry", "exit",
"stoploss", "stoploss_on_exchange"). More information below. Strategy Override.
Datatype: Dict
order_time_in_force Configure time in force for entry and exit orders. More
information below. Strategy Override.
Datatype: Dict
position_adjustment_enable Enables the strategy to use position adjustments
(additional buys or sells). More information here.
Strategy Override.
Defaults to false.
Datatype: Boolean
max_entry_position_adjustment Maximum additional order(s) for each open trade on
top of the first entry Order. Set it to -1 for unlimited additional orders. More
information here.
Strategy Override.
Defaults to -1.
Datatype: Positive Integer or -1
Exchange
[Link] Required. Name of the exchange class to use.
Datatype: String
[Link] API key to use for the exchange. Only required when you are in
production mode.
Keep it in secret, do not disclose publicly.
Datatype: String
[Link] API secret to use for the exchange. Only required when you are in
production mode.
Keep it in secret, do not disclose publicly.
Datatype: String
[Link] API password to use for the exchange. Only required when you are
in production mode and for exchanges that use password for API requests.
Keep it in secret, do not disclose publicly.
Datatype: String
[Link] API uid to use for the exchange. Only required when you are in
production mode and for exchanges that use uid for API requests.
Keep it in secret, do not disclose publicly.
Datatype: String
exchange.pair_whitelist List of pairs to use by the bot for trading and to check
for potential trades during backtesting. Supports regex pairs as .*/BTC. Not used
by VolumePairList. More information.
Datatype: List
exchange.pair_blacklist List of pairs the bot must absolutely avoid for trading and
backtesting. More information.
Datatype: List
exchange.ccxt_config Additional CCXT parameters passed to both ccxt instances
(sync and async). This is usually the correct place for additional ccxt
configurations. Parameters may differ from exchange to exchange and are documented
in the ccxt documentation. Please avoid adding exchange secrets here (use the
dedicated fields instead), as they may be contained in logs.
Datatype: Dict
exchange.ccxt_sync_config Additional CCXT parameters passed to the regular
(sync) ccxt instance. Parameters may differ from exchange to exchange and are
documented in the ccxt documentation
Datatype: Dict
exchange.ccxt_async_config Additional CCXT parameters passed to the async ccxt
instance. Parameters may differ from exchange to exchange and are documented in the
ccxt documentation
Datatype: Dict
exchange.enable_ws Enable the usage of Websockets for the exchange.
More information.
Defaults to true.
Datatype: Boolean
exchange.markets_refresh_interval The interval in minutes in which markets are
reloaded.
Defaults to 60 minutes.
Datatype: Positive Integer
exchange.skip_pair_validation Skip pairlist validation on startup.
Defaults to false
Datatype: Boolean
exchange.skip_open_order_update Skips open order updates on startup should the
exchange cause problems. Only relevant in live conditions.
Defaults to false
Datatype: Boolean
exchange.unknown_fee_rate Fallback value to use when calculating trading fees.
This can be useful for exchanges which have fees in non-tradable currencies. The
value provided here will be multiplied with the "fee cost".
Defaults to None
Datatype:* float
exchange.log_responses Log relevant exchange responses. For debug mode only - use
with care.
Defaults to false
Datatype: Boolean
experimental.block_bad_exchanges Block exchanges known to not work with
freqtrade. Leave on default unless you want to test if that exchange works now.
Defaults to true.
Datatype: Boolean
Plugins
edge.* Please refer to edge configuration document for detailed explanation of
all possible configuration options.
pairlists Define one or more pairlists to be used. More information.
Defaults to StaticPairList.
Datatype: List of Dicts
protections Define one or more protections to be used. More information.
Datatype: List of Dicts
Telegram
[Link] Enable the usage of Telegram.
Datatype: Boolean
[Link] Your Telegram bot token. Only required if [Link] is
true.
Keep it in secret, do not disclose publicly.
Datatype: String
telegram.chat_id Your personal Telegram account id. Only required if
[Link] is true.
Keep it in secret, do not disclose publicly.
Datatype: String
telegram.balance_dust_level Dust-level (in stake currency) - currencies with a
balance below this will not be shown by /balance.
Datatype: float
[Link] Allow "reload" buttons on telegram messages.
Defaults to true.
Datatype:* boolean
telegram.notification_settings.* Detailed notification settings. Refer to the
telegram documentation for details.
Datatype: dictionary
telegram.allow_custom_messages Enable the sending of Telegram messages from
strategies via the dataprovider.send_msg() function.
Datatype: Boolean
Webhook
[Link] Enable usage of Webhook notifications
Datatype: Boolean
[Link] URL for the webhook. Only required if [Link] is true. See the
webhook documentation for more details.
Datatype: String
[Link] Payload to send on entry. Only required if [Link] is
true. See the webhook documentation for more details.
Datatype: String
webhook.entry_cancel Payload to send on entry order cancel. Only required if
[Link] is true. See the webhook documentation for more details.
Datatype: String
webhook.entry_fill Payload to send on entry order filled. Only required if
[Link] is true. See the webhook documentation for more details.
Datatype: String
[Link] Payload to send on exit. Only required if [Link] is
true. See the webhook documentation for more details.
Datatype: String
webhook.exit_cancel Payload to send on exit order cancel. Only required if
[Link] is true. See the webhook documentation for more details.
Datatype: String
webhook.exit_fill Payload to send on exit order filled. Only required if
[Link] is true. See the webhook documentation for more details.
Datatype: String
[Link] Payload to send on status calls. Only required if [Link]
is true. See the webhook documentation for more details.
Datatype: String
webhook.allow_custom_messages Enable the sending of Webhook messages from
strategies via the dataprovider.send_msg() function.
Datatype: Boolean
Rest API / FreqUI / Producer-Consumer
api_server.enabled Enable usage of API Server. See the API Server
documentation for more details.
Datatype: Boolean
api_server.listen_ip_address Bind IP address. See the API Server documentation for
more details.
Datatype: IPv4
api_server.listen_port Bind Port. See the API Server documentation for more
details.
Datatype: Integer between 1024 and 65535
api_server.verbosity Logging verbosity. info will print all RPC Calls, while
"error" will only display errors.
Datatype: Enum, either info or error. Defaults to info.
api_server.username Username for API server. See the API Server documentation
for more details.
Keep it in secret, do not disclose publicly.
Datatype: String
api_server.password Password for API server. See the API Server documentation
for more details.
Keep it in secret, do not disclose publicly.
Datatype: String
api_server.ws_token API token for the Message WebSocket. See the API Server
documentation for more details.
Keep it in secret, do not disclose publicly.
Datatype: String
bot_name Name of the bot. Passed via API to a client - can be shown to
distinguish / name bots.
Defaults to freqtrade
Datatype: String
external_message_consumer Enable Producer/Consumer mode for more details.
Datatype: Dict
Other
initial_state Defines the initial application state. If set to stopped, then
the bot has to be explicitly started via /start RPC command.
Defaults to stopped.
Datatype: Enum, either stopped or running
force_entry_enable Enables the RPC Commands to force a Trade entry. More
information below.
Datatype: Boolean
disable_dataframe_checks Disable checking the OHLCV dataframe returned from
the strategy methods for correctness. Only use when intentionally changing the
dataframe and understand what you are doing. Strategy Override.
Defaults to False.
Datatype: Boolean
internals.process_throttle_secs Set the process throttle, or minimum loop
duration for one bot iteration loop. Value in second.
Defaults to 5 seconds.
Datatype: Positive Integer
internals.heartbeat_interval Print heartbeat message every N seconds. Set to 0 to
disable heartbeat messages.
Defaults to 60 seconds.
Datatype: Positive Integer or 0
internals.sd_notify Enables use of the sd_notify protocol to tell systemd
service manager about changes in the bot state and issue keep-alive pings. See here
for more details.
Datatype: Boolean
strategy Required Defines Strategy class to use. Recommended to be set via --
strategy NAME.
Datatype: ClassName
strategy_path Adds an additional strategy lookup path (must be a directory).
Datatype: String
recursive_strategy_search Set to true to recursively search sub-directories
inside user_data/strategies for a strategy.
Datatype: Boolean
user_data_dir Directory containing user data.
Defaults to ./user_data/.
Datatype: String
db_url Declares database URL to use. NOTE: This defaults to
sqlite:///[Link] if dry_run is true, and to
sqlite:///[Link] for production instances.
Datatype: String, SQLAlchemy connect string
logfile Specifies logfile name. Uses a rolling strategy for log file rotation
for 10 files with the 1MB limit per file.
Datatype: String
add_config_files Additional config files. These files will be loaded and merged
with the current config file. The files are resolved relative to the initial file.
Defaults to [].
Datatype: List of strings
dataformat_ohlcv Data format to use to store historical candle (OHLCV) data.
Defaults to feather.
Datatype: String
dataformat_trades Data format to use to store historical trades data.
Defaults to feather.
Datatype: String
reduce_df_footprint Recast all numeric columns to float32/int32, with the
objective of reducing ram/disk usage (and decreasing train/inference timing in
FreqAI). (Currently only affects FreqAI use-cases)
Datatype: Boolean.
Default: False.
Parameters in the strategy
The following parameters can be set in the configuration file or strategy. Values
set in the configuration file always overwrite values set in the strategy.
minimal_roi
timeframe
stoploss
max_open_trades
trailing_stop
trailing_stop_positive
trailing_stop_positive_offset
trailing_only_offset_is_reached
use_custom_stoploss
process_only_new_candles
order_types
order_time_in_force
unfilledtimeout
disable_dataframe_checks
use_exit_signal
exit_profit_only
exit_profit_offset
ignore_roi_if_entry_signal
ignore_buying_expired_candle_after
position_adjustment_enable
max_entry_position_adjustment
Configuring amount per trade
There are several methods to configure how much of the stake currency the bot will
use to enter a trade. All methods respect the available balance configuration as
explained below.
Assuming the minimum tradable amount for XRP/USD is 20 XRP (given by the exchange),
and the price is 0.6\(, the minimum stake amount to buy this pair is 20 * 0.6 ~=
12. This exchange has also a limit on USD - where all orders must be > 10\) - which
however does not apply in this case.
To guarantee safe execution, freqtrade will not allow buying with a stake-amount of
10.1$, instead, it'll make sure that there's enough space to place a stoploss below
the pair (+ an offset, defined by amount_reserve_percent, which defaults to 5%).
With a reserve of 5%, the minimum stake amount would be ~12.6$ (12 * (1 + 0.05)).
If we take into account a stoploss of 10% on top of that - we'd end up with a value
of ~14$ (12.6 / (1 - 0.1)).
To limit this calculation in case of large stoploss values, the calculated minimum
stake-limit will never be more than 50% above the real limit.
Warning
Since the limits on exchanges are usually stable and are not updated often, some
pairs can show pretty high minimum limits, simply because the price increased a lot
since the last limit adjustment by the exchange. Freqtrade adjusts the stake-amount
to this value, unless it's > 30% more than the calculated/desired stake-amount - in
which case the trade is rejected.
Tradable balance
By default, the bot assumes that the complete amount - 1% is at it's disposal, and
when using dynamic stake amount, it will split the complete balance into
max_open_trades buckets per trade. Freqtrade will reserve 1% for eventual fees when
entering a trade and will therefore not touch that by default.
For example, if you have 10 ETH available in your wallet on the exchange and
tradable_balance_ratio=0.5 (which is 50%), then the bot will use a maximum amount
of 5 ETH for trading and considers this as an available balance. The rest of the
wallet is untouched by the trades.
Danger
This setting should not be used when running multiple bots on the same account.
Please look at Available Capital to the bot instead.
Warning
Assuming your account has 10000 USDT and you want to run 2 different strategies on
this exchange. You'd set available_capital=5000 - granting each bot an initial
capital of 5000 USDT. The bot will then split this starting balance equally into
max_open_trades buckets. Profitable trades will result in increased stake-sizes for
this bot - without affecting the stake-sizes of the other bot.
To overcome this, the option amend_last_stake_amount can be set to True, which will
enable the bot to reduce stake_amount to the available balance to fill the last
trade slot.
This option only applies with Static stake amount - since Dynamic stake amount
divides the balances evenly.
Note
The minimal configuration value is 0.0001, however, please check your exchange's
trading minimums for the stake currency you're using to avoid problems.
This setting works in combination with max_open_trades. The maximum capital engaged
in trades is stake_amount * max_open_trades. For example, the bot will at most use
(0.05 BTC x 3) = 0.15 BTC, assuming a configuration of max_open_trades=3 and
stake_amount=0.05.
Note
"stake_amount" : "unlimited",
"tradable_balance_ratio": 0.99,
Compounding profits
For example if your position adjustment assumes it can do 2 additional buys with
the same stake amounts then your buffer should be 66.6667% of the initially
proposed unlimited stake amount.
Note
Orderbook data used by Freqtrade are the data retrieved from exchange by the ccxt's
function fetch_order_book(), i.e. are usually data from the L2-aggregated
orderbook, while the ticker data are the structures returned by the ccxt's
fetch_ticker()/fetch_tickers() functions. Refer to the ccxt library documentation
for more details.
Please read the section Market order pricing section when using market orders.
Entry price
Enter price side
The configuration setting entry_pricing.price_side defines the side of the
orderbook the bot looks for when buying.
...
103
102
101 # ask
-------------Current spread
99 # bid
98
97
...
If entry_pricing.price_side is set to "bid", then the bot will use 99 as entry
price.
In line with that, if entry_pricing.price_side is set to "ask", then the bot will
use 101 as entry price.
Depending on the order direction (long/short), this will lead to different results.
Therefore we recommend to use "same" or "other" for this configuration instead.
This would result in the following pricing matrix:
Orderbook bid (buy) side depth is then divided by the orderbook ask (sell) side
depth and the resulting delta is compared to the value of the
entry_pricing.check_depth_of_market.bids_to_ask_delta parameter. The entry order is
only executed if the orderbook delta is greater than or equal to the configured
delta value.
Note
A delta value below 1 means that ask (sell) orderbook side depth is greater than
the depth of the bid (buy) orderbook side, while a value greater than 1 means
opposite (depth of the buy side is higher than the depth of the sell side).
Exit price
Exit price side
The configuration setting exit_pricing.price_side defines the side of the spread
the bot looks for when exiting a trade.
...
103
102
101 # ask
-------------Current spread
99 # bid
98
97
...
If exit_pricing.price_side is set to "ask", then the bot will use 101 as exiting
price.
In line with that, if exit_pricing.price_side is set to "bid", then the bot will
use 99 as exiting price.
Depending on the order direction (long/short), this will lead to different results.
Therefore we recommend to use "same" or "other" for this configuration instead.
This would result in the following pricing matrix:
1 specifies the topmost entry in the orderbook, while 2 would use the 2nd entry in
the orderbook, and so on.
"order_types": {
"entry": "market",
"exit": "market"
// ...
},
"entry_pricing": {
"price_side": "other",
// ...
},
"exit_pricing":{
"price_side": "other",
// ...
},
Obviously, if only one side is using limit orders, different pricing combinations
can be used.
"minimal_roi": {
"40": 0.0, # Exit after 40 minutes if the profit is not negative
"30": 0.01, # Exit after 30 minutes if there is at least 1% profit
"20": 0.02, # Exit after 20 minutes if there is at least 2% profit
"0": 0.04 # Exit immediately if there is at least 4% profit
},
Most of the strategy files already include the optimal minimal_roi value. This
parameter can be set in either Strategy or Configuration file. If you use it in the
configuration file, it will override the minimal_roi value from the strategy file.
If it is not set in either Strategy or Configuration, a default of 1000% {"0": 10}
is used, and minimal ROI is disabled unless your trade generates 1000% profit.
A special case presents using "<N>": -1 as ROI. This forces the bot to exit a trade
after N Minutes, no matter if it's positive or negative, so represents a time-
limited force-exit.
Understand force_entry_enable
The force_entry_enable configuration parameter enables the usage of force-enter
(/forcelong, /forceshort) commands via Telegram and REST API. For security reasons,
it's disabled by default, and freqtrade will show a warning message on startup if
enabled. For example, you can send /forceenter ETH/BTC to the bot, which will
result in freqtrade buying the pair and holds it until a regular exit-signal (ROI,
stoploss, /forceexit) appears.
In these situations, you can enable the functionality to ignore candles that are
beyond a specified period by setting ignore_buying_expired_candle_after to a
positive number, indicating the number of seconds after which the buy signal
becomes expired.
For example, if your strategy is using a 1h timeframe, and you only want to buy
within the first 5 minutes when a new candle comes in, you can add the following
configuration to your strategy:
{
//...
"ignore_buying_expired_candle_after": 300,
// ...
}
Note
This setting resets with each new candle, so it will not prevent sticking-signals
from executing on the 2nd or 3rd candle they're active. Best use a "trigger"
selector for buy signals, which are only active for one candle.
Understand order_types
The order_types configuration parameter maps actions (entry, exit, stoploss,
emergency_exit, force_exit, force_entry) to order-types (market, limit, ...) as
well as configures stoploss to be on the exchange and defines stoploss on exchange
update interval in seconds.
This allows to enter using limit orders, exit using limit-orders, and create
stoplosses using market orders. It also allows to set the stoploss "on exchange"
which means stoploss order would be placed immediately once the buy order is
fulfilled.
order_types set in the configuration file overwrites values set in the strategy as
a whole, so you need to configure the whole order_types dictionary in one place.
order_types = {
"entry": "limit",
"exit": "limit",
"emergency_exit": "market",
"force_entry": "market",
"force_exit": "market",
"stoploss": "market",
"stoploss_on_exchange": False,
"stoploss_on_exchange_interval": 60,
"stoploss_on_exchange_limit_ratio": 0.99,
}
Configuration:
"order_types": {
"entry": "limit",
"exit": "limit",
"emergency_exit": "market",
"force_entry": "market",
"force_exit": "market",
"stoploss": "market",
"stoploss_on_exchange": false,
"stoploss_on_exchange_interval": 60
}
Market order support
Not all exchanges support "market" orders. The following message will be shown if
your exchange does not support market orders: "Exchange <yourexchange> does not
support market orders." and the bot will refuse to start.
Using market orders
Please carefully read the section Market order pricing section when using market
orders.
Stoploss on exchange
If stoploss on exchange creation fails for some reason, then an "emergency exit" is
initiated. By default, this will exit the trade using a market order. The order-
type for the emergency-exit can be changed by setting the emergency_exit value in
the order_types dictionary - however, this is not advised.
Understand order_time_in_force
The order_time_in_force configuration parameter defines the policy by which the
order is executed on the exchange. Three commonly used time in force are:
This is most of the time the default time in force. It means the order will remain
on exchange till it is cancelled by the user. It can be fully or partially
fulfilled. If partially fulfilled, the remaining will stay on the exchange till
cancelled.
It means if the order is not executed immediately AND fully then it is cancelled by
the exchange.
It is the same as FOK (above) except it can be partially fulfilled. The remaining
part is automatically cancelled by the exchange.
PO (Post only):
Post only order. The order is either placed as a maker order, or it is canceled.
This means the order must be placed on orderbook for at least time in an unfilled
state.
time_in_force config
The order_time_in_force parameter contains a dict with entry and exit time in force
policy values. This can be set in the configuration file or in the strategy. Values
set in the configuration file overwrites values set in the strategy.
"order_time_in_force": {
"entry": "GTC",
"exit": "GTC"
},
Warning
This is ongoing work. For now, it is supported only for binance, gate and kucoin.
Please don't change the default value unless you know what you are doing and have
researched the impact of using different values for your particular exchange.
Fiat conversion
Freqtrade uses the Coingecko API to convert the coin value to it's corresponding
fiat value for the Telegram reports. The FIAT currency can be set in the
configuration file as fiat_display_currency.
"AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF",
"IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
"RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD"
In addition to fiat currencies, a range of crypto currencies is supported.
{
"fiat_display_currency": "USD",
"coingecko": {
"api_key": "your-api",
"is_demo": true
}
}
Freqtrade supports both Demo and Pro coingecko API keys.
The Coingecko API key is NOT required for the bot to function correctly. It is only
used for the conversion of coin to fiat in the Telegram reports, which usually also
work without API key.
Freqtrade aims ensure data is available at all times. Should the websocket
connection fail (or be disabled), the bot will fall back to REST API calls.
Should you experience problems you suspect are caused by websockets, you can
disable these via the setting exchange.enable_ws, which defaults to true.
"exchange": {
// ...
"enable_ws": false,
// ...
}
Should you be required to use a proxy, please refer to the proxy section for more
information.
Rollout
We're implementing this out slowly, ensuring stability of your bots. Currently,
usage is limited to ohlcv data streams. It's also limited to a few exchanges, with
new exchanges being added on an ongoing basis.
"dry_run": true,
"db_url": "sqlite:///[Link]",
Remove your Exchange API key and secret (change them by empty values or fake
credentials):
"exchange": {
"name": "binance",
"key": "key",
"secret": "secret",
...
}
Once you will be happy with your bot performance running in the Dry-run mode, you
can switch it to production mode.
Note
A simulated wallet is available during dry-run mode and will assume a starting
capital of dry_run_wallet (defaults to 1000).
When switching to Production mode, please make sure to use a different / fresh
database to avoid dry-run trades messing with your exchange money and eventually
tainting your statistics.
Switch dry-run to false and don't forget to adapt your database URL if set:
"dry_run": false,
Insert your Exchange API key (change them by fake API keys):
{
"exchange": {
"name": "binance",
"key": "af8ddd35195e9dc500b9a6f799f6f5c93d89193b",
"secret": "08a9dc6db3d7b53e1acebd9275677f4b0a04f1a5",
//"password": "", // Optional, not needed by all exchanges)
// ...
}
//...
}
You should also make sure to read the Exchanges section of the documentation to be
aware of potential configuration details specific to your exchange.
To keep your secrets secret, we recommend using a 2nd configuration for your API
keys. Simply use the above snippet in a new configuration file (e.g. config-
[Link]) and keep your settings in this file. You can then start the bot with
freqtrade trade --config user_data/[Link] --config user_data/config-
[Link] <...> to have your keys loaded.
NEVER share your private configuration file or your exchange keys with anyone!
{
"exchange": {
"ccxt_config": {
"httpsProxy": "[Link]
"wsProxy": "[Link]
}
}
}
For more information on available proxy types, please consult the ccxt proxy
documentation.
Next step
Now you have configured your [Link], the next step is to start your bot.
Strategy Customization
This page explains how to customize your strategies, add new indicators and set up
trading rules.
Please familiarize yourself with Freqtrade basics first, which provides overall
info on how the bot operates.
You will however most likely have your own idea for a strategy. This document
intends to help you convert your strategy idea into your own strategy.
Note
This is just a template file, which will most likely not be profitable out of the
box.
Indicators
Entry strategy rules
Exit strategy rules
Minimal ROI recommended
Stoploss strongly recommended
The bot also include a sample strategy called SampleStrategy you can update:
user_data/strategies/sample_strategy.py. You can test it with the parameter: --
strategy SampleStrategy
Additionally, there is an attribute called INTERFACE_VERSION, which defines the
version of the strategy interface the bot should use. The current version is 3 -
which is also the default when it's not set explicitly in the strategy.
Since backtesting passes the full time range to the populate_*() methods, the
strategy author needs to take care to avoid having the strategy utilize data from
the future. Some common patterns for this are listed in the Common Mistakes section
of this document.
Dataframe
Freqtrade uses pandas to store/provide the candlestick (OHLCV) data. Pandas is a
great library developed for processing large amounts of data.
Each row in a dataframe corresponds to one candle on a chart, with the latest
candle always being the last in the dataframe (sorted by date).
> [Link]()
date open high low close volume
0 2021-11-09 [Link]+00:00 67279.67 67321.84 67255.01 67300.97 44.62253
1 2021-11-09 [Link]+00:00 67300.97 67301.34 67183.03 67187.01 61.38076
2 2021-11-09 [Link]+00:00 67187.02 67187.02 67031.93 67123.81 113.42728
3 2021-11-09 [Link]+00:00 67123.80 67222.40 67080.33 67160.48 78.96008
4 2021-11-09 [Link]+00:00 67160.48 67160.48 66901.26 66943.37 111.39292
Pandas provides fast ways to calculate metrics. To benefit from this speed, it's
advised to not use loops, but use vectorized methods instead.
Vectorized operations perform calculations across the whole range of data and are
therefore, compared to looping through each row, a lot faster when calculating
indicators.
As a dataframe is a table, simple python comparisons like the following will not
work
Customize Indicators
Buy and sell signals need indicators. You can add more indicators by extending the
list contained in the method populate_indicators() from your strategy file.
Sample:
Indicator libraries
Out of the box, freqtrade installs the following technical libraries:
ta-lib
pandas-ta
technical
Additional technical libraries can be installed as necessary, or custom indicators
may be written / invented by the strategy author.
You can use recursive-analysis to check and find the correct startup_candle_count
to be used.
If you receive a warning like WARNING - Using 3 calls to get OHLCV. This can result
in slower operations for the bot. Please check if you really need 1500 candles for
your strategy - you should consider if you really need this much historic data for
your signals. Having this will cause Freqtrade to make multiple calls for the same
pair, which will obviously be slower than one network request. As a consequence,
Freqtrade will take longer to refresh candles - and should therefore be avoided if
possible. This is capped to 5 total calls to avoid overloading the exchange, or
make freqtrade too slow.
Warning
Example
Let's try to backtest 1 month (January 2019) of 5m candles using an example
strategy with EMA100, as above.
Note
If data for the startup period is not available, then the timerange will be
adjusted to account for this startup period - so Backtesting would start at 2019-
01-02 [Link].
This method will also define a new column, "enter_long" ("enter_short" for shorts),
which needs to contain 1 for entries, and 0 for "no action". enter_long is a
mandatory column that must be set even if the strategy is shorting only.
return dataframe
Enter short trades
Note
This method will also define a new column, "exit_long" ("exit_short" for shorts),
which needs to contain 1 for exits, and 0 for "no action".
It is of the following format, with the dict key (left side of the colon) being the
minutes passed since the trade opened, and the value (right side of the colon)
being the percentage.
minimal_roi = {
"40": 0.0,
"30": 0.01,
"20": 0.02,
"0": 0.04
}
The above configuration would therefore mean:
minimal_roi = {}
To use times based on candle duration (timeframe), the following snippet can be
handy. This will allow you to change the timeframe for the strategy, and ROI times
will still be set as candles (e.g. after 3 candles ...)
class AwesomeStrategy(IStrategy):
timeframe = "1d"
timeframe_mins = timeframe_to_minutes(timeframe)
minimal_roi = {
"0": 0.05, # 5% for the first 3 candles
str(timeframe_mins * 3): 0.02, # 2% after 3 candles
str(timeframe_mins * 6): 0.01, # 1% After 6 candles
}
Orders that don't fill immediately
Stoploss
Setting a stoploss is highly recommended to protect your capital from strong moves
against you.
stoploss = -0.10
For the full documentation on stoploss features, look at the dedicated stoploss
page.
Timeframe
This is the set of candles the bot should download and use for the analysis. Common
values are "1m", "5m", "15m", "1h", however all values supported by your exchange
should work.
Please note that the same entry/exit signals may work well with one timeframe, but
not with the others.
Can short
To use short signals in futures markets, you will have to let us know to do so by
setting can_short=True. Strategies which enable this will fail to load on spot
markets. Disabling of this will have short signals ignored (also in futures
markets).
Metadata dict
The metadata-dict (available for populate_entry_trend, populate_exit_trend,
populate_indicators) contains additional information. Currently this is pair, which
can be accessed using metadata['pair'] - and will return a pair in the format
XRP/BTC.
The Metadata-dict should not be modified and does not persist information across
multiple calls. Instead, have a look at the Storing information section.
By default, we recommend the following imports as a base line for your strategy:
This will cover all imports necessary for freqtrade functions to work. Obviously
you can add more imports as needed for your strategy.
# --------------------------------
# Add your lib to import here
import [Link] as ta
from technical import qtpylib
Strategy file loading
By default, freqtrade will attempt to load strategies from all .py files within
user_data/strategies.
You can use freqtrade list-strategies to see a list of all strategies Freqtrade is
able to load (all strategies in the correct folder). It will also include a
"status" field, highlighting potential problems.
The pairs need to be specified as tuples in the format ("pair", "timeframe"), with
pair as the first and timeframe as the second argument.
Sample:
def informative_pairs(self):
return [("ETH/USDT", "5m"),
("BTC/TUSD", "15m"),
]
A full sample can be found in the DataProvider section.
Warning
As these pairs will be refreshed as part of the regular whitelist refresh, it's
best to keep this list short. All timeframes and all pairs can be specified as long
as they are available (and active) on the used exchange. It is however better to
use resampling to longer timeframes whenever possible to avoid hammering the
exchange with too many requests and risk being blocked.
Full documentation
Fast and easy way to define informative pairs
Note
Do not use @informative decorator if you need to use data of one informative pair
when generating another informative pair. Instead, define informative pairs
manually as described in the DataProvider section.
Note
Use string formatting when accessing informative dataframes of other pairs. This
will allow easily changing stake currency in config without having to adjust
strategy code.
return dataframe
Alternatively column renaming may be used to remove stake currency from column
names: @informative('1h', 'BTC/{stake}', fmt='{base}_{column}_{timeframe}').
Duplicate method names
Methods tagged with @informative() decorator must always have unique names! Re-
using same name (for example when copy-pasting already defined informative method)
will overwrite previously defined method and not produce any errors due to
limitations of Python programming language. In such cases you will find that
indicators created in earlier-defined methods are not available in the dataframe.
Carefully review method names and make sure they are unique!
merge_informative_pair()
This method helps you merge an informative pair to a regular dataframe without
lookahead bias. It's there to help you merge the dataframe in a safe and consistent
way.
Options:
Column renaming
All methods return None in case of failure (do not raise an exception).
Please always check the mode of operation to select the correct method to get data
(samples see below).
Hyperopt
Scan through the top 10 pairs by volume using the VolumePairList every 5 minutes
and use a 14 day RSI to buy and sell.
Due to the limited available data, it's very difficult to resample 5m candles into
daily candles for use in a 14 day RSI. Most exchanges limit us to just 500-1000
candles which effectively gives us around 1.74 daily candles. We need 14 days at
least!
Since we can't resample the data we will have to use an informative pair; and since
the whitelist will be dynamic we don't know which pair(s) to use.
def informative_pairs(self):
# fetch live / historical candle (OHLCV) data for the first informative pair
inf_pair, inf_timeframe = self.informative_pairs()[0]
informative = [Link].get_pair_dataframe(pair=inf_pair,
timeframe=inf_timeframe)
Warning about backtesting
get_analyzed_dataframe(pair, timeframe)
This method is used by freqtrade internally to determine the last signal. It can
also be used in specific callbacks to get the signal that caused the action (see
Advanced Strategy Documentation for more details on available callbacks).
Returns an empty dataframe if the requested pair was not cached. You can check for
this with if [Link]: and handle this case accordingly. This should not
happen when using whitelisted pairs.
orderbook(pair, maximum)
{
'bids': [
[ price, amount ], // [ float, float ]
[ price, amount ],
...
],
'asks': [
[ price, amount ],
[ price, amount ],
//...
],
//...
}
Therefore, using ob['bids'][0][0] as demonstrated above will result in using the
best bid price. ob['bids'][0][1] would look at the amount at this orderbook
position.
The order book is not part of the historic data which means backtesting and
hyperopt will not work correctly if this method is used, as the method will return
up-to-date values.
ticker(pair)
if [Link] in ('live', 'dry_run'):
ticker = [Link](metadata['pair'])
dataframe['last_price'] = ticker['last']
dataframe['volume24h'] = ticker['quoteVolume']
dataframe['vwap'] = ticker['vwap']
Warning
Although the ticker data structure is a part of the ccxt Unified Interface, the
values returned by this method can vary for different exchanges. For instance, many
exchanges do not return vwap values, some exchanges does not always fills in the
last field (so it can be None), etc. So you need to carefully verify the ticker
data returned from the exchange and add appropriate error handling / defaults.
This method will always return up-to-date values - so usage during backtesting /
hyperopt without runmode checks will lead to wrong results.
Send Notification
The dataprovider .send_msg() function allows you to send custom notifications from
your strategy. Identical notifications will only be sent once per candle, unless
the 2nd argument (always_send) is set to True.
# Force send this notification, avoid caching (Please read warning below!)
[Link].send_msg(f"{metadata['pair']} just got hot!", always_send=True)
Notifications will only be sent in trading modes (Live/Dry-run) - so this method
can be called without conditions for backtesting.
Spamming
You can spam yourself pretty good by setting always_send=True in this method. Use
this with great care and only in conditions you know will not happen throughout a
candle to avoid a message every 5 seconds.
class SampleStrategy(IStrategy):
# strategy init stuff...
timeframe = '5m'
def informative_pairs(self):
inf_tf = '1d'
# Get the informative pair
informative = [Link].get_pair_dataframe(pair=metadata['pair'],
timeframe=inf_tf)
# Get the 14 day rsi
informative['rsi'] = [Link](informative, timeperiod=14)
# Do other stuff
# ...
return dataframe
[Link][
(
(qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI
crosses above 30
(dataframe['rsi_1d'] < 30) & # Ensure daily RSI
is < 30
(dataframe['volume'] > 0) # Ensure this
candle had volume (important for backtesting)
),
['enter_long', 'enter_tag']] = (1, 'rsi_cross')
Additional data (Wallets)
The strategy provides access to the wallets object. This contains the current
balances on the exchange.
Backtesting / Hyperopt
trades = Trade.get_trades_proxy(pair=metadata['pair'],
open_date=[Link]([Link]) -
timedelta(days=1),
is_open=False,
]).order_by(Trade.close_date).all()
# Summarize profit for this pair.
curdayprofit = sum(trade.close_profit for trade in trades)
For a full list of available methods, please consult the Trade object
documentation.
Warning
Locked pairs will show the message Pair <pair> is currently locked..
Freqtrade has an easy method to do this from within the strategy, by calling
self.lock_pair(pair, until, [reason]). until must be a datetime object in the
future, after which trading will be re-enabled for that pair, while reason is an
optional string detailing why the pair was locked.
Note
Locked pairs will always be rounded up to the next candle. So assuming a 5m
timeframe, a lock with until set to 10:18 will lock the pair until the candle from
10:15-10:20 will be finished.
Warning
Manually locking pairs is not available during backtesting, only locks via
Protections are allowed.
return dataframe
Printing more than a few rows is also possible (simply use print(dataframe) instead
of print([Link]())), however not recommended, as that will be very verbose
(~500 lines per pair every 5 seconds).
The following lists some common patterns which should be avoided to prevent
frustration:
don't use shift(-1) or other negative values. This uses data from the future in
backtesting, which is not available in dry or live modes.
don't use .iloc[-1] or any other absolute position in the dataframe within
populate_ functions, as this will be different between dry-run and backtesting.
Absolute iloc indexing is safe to use in callbacks however - see Strategy
Callbacks.
don't use dataframe['volume'].mean(). This uses the full DataFrame for backtesting,
including data from the future. Use dataframe['volume'].rolling(<window>).mean()
instead
don't use .resample('1h'). This uses the left border of the interval, so moves data
from an hour to the start of the hour. Use .resample('1h', label='right') instead.
Identifying problems
You may also want to check the 2 helper commands lookahead-analysis and recursive-
analysis, which can each help you figure out problems with your strategy in
different ways. Please treat them as what they are - helpers to identify most
common problems. A negative result of each does not guarantee that there's none of
the above errors included.
Colliding signals
When conflicting signals collide (e.g. both 'enter_long' and 'exit_long' are 1),
freqtrade will do nothing and ignore the entry signal. This will avoid trades that
enter, and exit immediately. Obviously, this can potentially lead to missed
entries.
The following rules apply, and entry signals will be ignored if more than one of
the 3 signals is set:
Next step
Now you have a perfect strategy you probably want to backtest it. Your next step is
to learn How to use the Backtesting.
Strategy Callbacks
While the main strategy functions (populate_indicators(), populate_entry_trend(),
populate_exit_trend()) should be used in a vectorized way, and are only called once
during backtesting, callbacks are called "whenever needed".
As such, you should avoid doing heavy calculations in callbacks to avoid delays
during operations. Depending on the callback used, they may be called when entering
/ exiting a trade, or throughout the duration of a trade.
By default, we recommend the following imports as a base line for your strategy:
This will cover all imports necessary for freqtrade functions to work. Obviously
you can add more imports as needed for your strategy.
# --------------------------------
# Add your lib to import here
import [Link] as ta
from technical import qtpylib
Bot start
A simple callback which is called once when the strategy is loaded. This can be
used to perform actions that must only be performed once and runs after
dataprovider and wallet are set
import requests
class AwesomeStrategy(IStrategy):
# Default imports
import requests
class AwesomeStrategy(IStrategy):
# Default imports
class AwesomeStrategy(IStrategy):
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate:
float,
proposed_stake: float, min_stake: Optional[float],
max_stake: float,
leverage: float, entry_tag: Optional[str], side: str,
**kwargs) -> float:
dataframe, _ = [Link].get_analyzed_dataframe(pair=pair,
timeframe=[Link])
current_candle = [Link][-1].squeeze()
Tip
You do not have to ensure that min_stake <= returned_value <= max_stake. Trades
will succeed as the returned value will be clamped to supported range and this
action will be logged.
Tip
Allows to define custom exit signals, indicating that specified position should be
sold. This is very useful when we need to customize exit conditions for each
individual trade, or if you need trade data to make an exit decision.
For example you could implement a 1:2 risk-reward ROI with custom_exit().
Note
Returning a (none-empty) string or True from this method is equal to setting exit
signal on a candle at specified time. This method is not called when exit signal is
set already, or if exit signals are disabled (use_exit_signal=False). string max
length is 64 characters. Exceeding this limit will cause the message to be
truncated to 64 characters. custom_exit() will ignore exit_profit_only, and will
always be called unless use_exit_signal=False, even if there is a new enter signal.
An example of how we can use different indicators depending on the current profit
and also exit trades that were open longer than one day:
# Default imports
class AwesomeStrategy(IStrategy):
def custom_exit(self, pair: str, trade: Trade, current_time: datetime,
current_rate: float,
current_profit: float, **kwargs):
dataframe, _ = [Link].get_analyzed_dataframe(pair, [Link])
last_candle = [Link][-1].squeeze()
# Sell any positions at a loss if they are held for more than one day.
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
return "unclog"
See Dataframe access for more information about dataframe use in strategy
callbacks.
Custom stoploss
Called for open trade every iteration (roughly every 5 seconds) until a trade is
closed.
The stoploss price can only ever move upwards - if the stoploss value returned from
custom_stoploss would result in a lower stoploss price than was previously set, it
will be ignored. The traditional stoploss value serves as an absolute lower level
and will be instated as the initial stoploss (before this method is called for the
first time for a trade), and is still mandatory.
The method must return a stoploss value (float / number) as a percentage of the
current price. E.g. If the current_rate is 200 USD, then returning 0.02 will set
the stoploss price 2% lower, at 196 USD. During backtesting, current_rate (and
current_profit) are provided against the candle's high (or low for short trades) -
while the resulting stoploss is evaluated against the candle's low (or high for
short trades).
The absolute value of the return value is used (the sign is ignored), so returning
0.05 or -0.05 have the same result, a stoploss 5% below the current price.
Returning None will be interpreted as "no desire to change", and is the only safe
way to return when you'd like to not modify the stoploss. NaN and inf values are
considered invalid and will be ignored (identical to None).
Use of dates
Trailing stoploss
It's recommended to disable trailing_stop when using custom stoploss values. Both
can work in tandem, but you might encounter the trailing stop to move the price
higher while your custom function would not want this, causing conflicting
behavior.
backwards compatibility
This call will only be made if the after_fill parameter is part of the function
definition of your custom_stoploss function. As such, this will not impact (and
with that, surprise) existing, running strategies.
# Default imports
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
# Default imports
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
# Make sure you have the longest interval first - these conditions are
evaluated from top to bottom.
if current_time - timedelta(minutes=120) > trade.open_date_utc:
return -0.05
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
return -0.10
return None
Time based trailing stop with after-fill adjustments
Use the initial stoploss for the first 60 minutes, after this change to 10%
trailing stoploss, and after 2 hours (120 minutes) we use a 5% trailing stoploss.
If an additional order fills, set stoploss to -10% below the new open_rate
(Averaged across all entries).
# Default imports
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
if after_fill:
# After an additional order, start with a stoploss of 10% below the new
open rate
return stoploss_from_open(0.10, current_profit,
is_short=trade.is_short, leverage=[Link])
# Make sure you have the longest interval first - these conditions are
evaluated from top to bottom.
if current_time - timedelta(minutes=120) > trade.open_date_utc:
return -0.05
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
return -0.10
return None
Different stoploss per pair
Use a different stoploss depending on the pair. In this example, we'll trail the
highest price with 10% trailing stoploss for ETH/BTC and XRP/BTC, with 5% trailing
stoploss for LTC/BTC and with 15% for all other pairs.
# Default imports
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
Please note that the stoploss can only increase, values lower than the current
stoploss are ignored.
# Default imports
class AwesomeStrategy(IStrategy):
# After reaching the desired offset, allow the stoploss to trail by half
the profit
desired_stoploss = current_profit / 2
# Default imports
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
# Default imports
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
Returning a stoploss relative to the open price from the custom stoploss function
Note
Each of these methods are called right before placing an order on the exchange.
Note
If your custom pricing function return None or an invalid value, price will fall
back to proposed_rate, which is based on the regular pricing configuration.
Note
Using custom_entry_price, the Trade object will be available as soon as the first
entry order associated with the trade is created, for the first entry, trade
parameter value will be None.
# Default imports
class AwesomeStrategy(IStrategy):
timeframe=[Link])
new_entryprice = dataframe["bollinger_10_lowerband"].iat[-1]
return new_entryprice
timeframe=[Link])
new_exitprice = dataframe["bollinger_10_upperband"].iat[-1]
return new_exitprice
Warning
Modifying entry and exit prices will only work for limit orders. Depending on the
price chosen, this can result in a lot of unfilled orders. By default the maximum
allowed distance between the current price and the custom price is 2%, this value
can be changed in config with the custom_price_max_distance_ratio parameter.
Example: If the new_entryprice is 97, the proposed_rate is 100 and the
custom_price_max_distance_ratio is set to 2%, The retained valid custom entry price
will be 98, which is 2% below the current (proposed) rate.
Backtesting
Custom prices are supported in backtesting (starting with 2021.12), and orders will
fill if the price falls within the candle's low/high range. Orders that don't fill
immediately are subject to regular timeout handling, which happens once per
(detail) candle. custom_exit_price() is only called for sells of type exit_signal,
Custom exit and partial exits. All other exit-types will use regular backtesting
prices.
However, freqtrade also offers a custom callback for both order types, which allows
you to decide based on custom criteria if an order did time out or not.
Note
Backtesting fills orders if their price falls within the candle's low/high range.
The below callbacks will be called once per (detail) candle for orders that don't
fill immediately (which use custom pricing).
The function must return either True (cancel order) or False (keep order alive).
# Default imports
class AwesomeStrategy(IStrategy):
For the above example, unfilledtimeout must be set to something bigger than 24h,
otherwise that type of timeout will apply first.
# Default imports
class AwesomeStrategy(IStrategy):
# Default imports
class AwesomeStrategy(IStrategy):
confirm_trade_exit() may be called multiple times within one iteration for the same
trade if different exit-reasons apply. The exit-reasons (if applicable) will be in
the following sequence:
exit_signal / custom_exit
stop_loss
roi
trailing_stop_loss
# Default imports
class AwesomeStrategy(IStrategy):
This callback is not called when there is an open order (either buy or sell)
waiting for execution.
Increase position
The strategy is expected to return a positive stake_amount (in stake currency)
between min_stake and max_stake if and when an additional entry order should be
made (position is increased -> buy order for long trades, sell order for short
trades).
If there are not enough funds in the wallet (the return value is above max_stake)
then the signal will be ignored. max_entry_position_adjustment property is used to
limit the number of additional entries per trade (on top of the first entry order)
that the bot can execute. By default, the value is -1 which means the bot have no
limit on number of adjustment entries.
Additional entries are ignored once you have reached the maximum amount of extra
entries that you have set on max_entry_position_adjustment, but the callback is
called anyway looking for partial exits.
Decrease position
The strategy is expected to return a negative stake_amount (in stake currency) for
a partial exit. Returning the full owned stake at that point (-trade.stake_amount)
results in a full exit.
Returning a value more than the above (so remaining stake_amount would become
negative) will result in the bot ignoring the signal.
Using fixed stake size means it will be the amount used for the first order, just
like without position adjustment. If you wish to buy additional orders with DCA,
then make sure to leave enough funds in the wallet for that. Using "unlimited"
stake amount with DCA orders requires you to also implement the
custom_stake_amount() callback to avoid allocating all funds to the initial order.
Stoploss calculation
Stoploss is still calculated from the initial opening price, not averaged price.
Regular stoploss rules still apply (cannot move down).
While /stopentry command stops the bot from entering new trades, the position
adjustment feature will continue buying new orders on existing trades.
Backtesting
# Default imports
class DigDeeperStrategy(IStrategy):
position_adjustment_enable = True
# We need to leave most of the funds for possible further DCA orders
# This also applies to fixed stakes
return proposed_stake / self.max_dca_multiplier
filled_entries = trade.select_filled_orders(trade.entry_side)
count_of_entries = trade.nr_of_successful_entries
# Allow up to 3 additional increasingly larger buys (4 in total)
# Initial buy is 1x
# If that falls to -5% profit, we buy 1.25x more, average profit should
increase to roughly -2.2%
# If that falls down to -5% again, we buy 1.5x more
# If that falls once again down to -5%, we buy 1.75x more
# Total stake for this trade would be 1 + 1.25 + 1.5 + 1.75 = 5.5x of the
initial allowed stake.
# That is why max_dca_multiplier is 5.5
# Hope you have a deep wallet!
try:
# This returns first order stake size
stake_amount = filled_entries[0].stake_amount
# This then calculates current safety order size
stake_amount = stake_amount * (1 + (count_of_entries * 0.25))
return stake_amount, "1/3rd_increase"
except Exception as exception:
return None
return None
Position adjust calculations
Entry rates are calculated using weighted averages.
Exits will not influence the average entry rate.
Partial exit relative profit is relative to the average entry price at this point.
Final exit relative profit is calculated based on the total invested capital. (See
example below)
Calculation example
Adjust Entry Price
The adjust_entry_price() callback may be used by strategy developer to
refresh/replace limit orders upon arrival of new candles. Be aware that
custom_entry_price() is still the one dictating initial entry limit order price
target at the time of entry trigger.
Returning current_order_rate will keep the order on the exchange "as is". Returning
any other price will cancel the existing order, and replace it with a new order.
The trade open-date (trade.open_date_utc) will remain at the time of the very first
order placed. Please make sure to be aware of this - and eventually adjust your
logic in other callbacks to account for this, and use the date of the first filled
order instead.
If the cancellation of the original order fails, then the order will not be
replaced - though the order will most likely have been canceled on exchange. Having
this happen on initial entries will result in the deletion of the order, while on
position adjustment orders, it'll result in the trade size remaining as is.
Regular timeout
# Default imports
class AwesomeStrategy(IStrategy):
"""
# Limit orders to use and follow SMA200 as price target for the first 10
minutes since entry trigger for BTC/USDT pair.
if (
pair == "BTC/USDT"
and entry_tag == "long_sma200"
and side == "long"
and (current_time - timedelta(minutes=10)) > trade.open_date_utc
):
# just cancel the order if it has been filled more than half of the
amount
if [Link] > [Link]:
return None
else:
dataframe, _ = [Link].get_analyzed_dataframe(pair=pair,
timeframe=[Link])
current_candle = [Link][-1].squeeze()
# desired price
return current_candle["sma_200"]
# default: maintain existing order
return current_order_rate
Leverage Callback
When trading in markets that allow leverage, this method must return the desired
Leverage (Defaults to 1 -> No leverage).
Values that are above max_leverage will be adjusted to max_leverage. For markets /
exchanges that don't support leverage, this method is ignored.
# Default imports
class AwesomeStrategy(IStrategy):
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, entry_tag:
Optional[str], side: str,
**kwargs) -> float:
"""
Customize leverage for each new trade. This method is only called in
futures mode.
Assuming that your strategy needs to store the high value of the candle at trade
entry, this is possible with this callback as the following example show.
# Default imports
class AwesomeStrategy(IStrategy):
def order_filled(self, pair: str, trade: Trade, order: Order, current_time:
datetime, **kwargs) -> None:
"""
Called right after an order fills.
Will be called for all order types (entry, exit, stoploss, position
adjustment).
:param pair: Pair for trade
:param trade: trade object.
:param order: Order object.
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break
your strategy.
"""
# Obtain pair dataframe (just to show how to access it)
dataframe, _ = [Link].get_analyzed_dataframe([Link], [Link])
last_candle = [Link][-1].squeeze()
return None
Stop Loss
The stoploss configuration parameter is loss as ratio that should trigger a sale.
For example, value -0.10 will cause immediate sell if the profit dips below -10%
for a given trade. This parameter is optional. Stoploss calculations do include
fees, so a stoploss of -10% is placed exactly 10% below the entry point.
Most of the strategy files already include the optimal stoploss value.
Info
All stoploss properties mentioned in this file can be set in the Strategy, or in
the configuration.
Configuration values will override the strategy values.
'emergency_exit': 'market',
'stoploss_on_exchange': False
'stoploss_on_exchange_interval': 60,
'stoploss_on_exchange_limit_ratio': 0.99
Stoploss on exchange is only supported for the following exchanges, and not all
exchanges support both stop-limit and stop-market. The Order-type will be ignored
if only one mode is available.
Do not set too low/tight stoploss value when using stop loss on exchange!
If set to low/tight you will have greater risk of missing fill on the order and
stoploss will not work.
Note
stoploss_on_exchange_interval
In case of stoploss on exchange there is another parameter called
stoploss_on_exchange_interval. This configures the interval in seconds at which the
bot will check the stoploss and update it if necessary.
The bot cannot do these every 5 seconds (at each iteration), otherwise it would get
banned by the exchange. So this parameter will tell the bot how often it should
update the stoploss order. The default value is 60 (1 minute). This same logic will
reapply a stoploss order on the exchange should you cancel it accidentally.
stoploss_price_type
Only applies to futures
Stoploss on exchange on futures markets can trigger on different price types. The
naming for these prices in exchange terminology often varies, but is usually
something around "last" (or "contract price" ), "mark" and "index".
Acceptable values for this setting are "last", "mark" and "index" - which freqtrade
will transfer automatically to the corresponding API type, and place the stoploss
on exchange order correspondingly.
force_exit
force_exit is an optional value, which defaults to the same value as exit and is
used when sending a /forceexit command from Telegram or from the Rest API.
force_entry
force_entry is an optional value, which defaults to the same value as entry and is
used when sending a /forceentry command from Telegram or from the Rest API.
emergency_exit
emergency_exit is an optional value, which defaults to market and is used when
creating stop loss on exchange orders fails. The below is the default which is used
if not changed in strategy or configuration file.
order_types = {
"entry": "limit",
"exit": "limit",
"emergency_exit": "market",
"stoploss": "market",
"stoploss_on_exchange": True,
"stoploss_on_exchange_interval": 60,
"stoploss_on_exchange_limit_ratio": 0.99
}
Stop Loss Types
At this stage the bot contains the following stoploss support modes:
stoploss = -0.10
For example, simplified math:
stoploss = -0.10
trailing_stop = True
This will now activate an algorithm, which automatically moves the stop loss up
every time the price of your asset increases.
Note
If you want the stoploss to only be changed when you break even of making a profit
(what most users want) please refer to next section with offset enabled.
stoploss = -0.10
trailing_stop = True
trailing_stop_positive = 0.02
trailing_stop_positive_offset = 0.0
trailing_only_offset_is_reached = False # Default - not necessary for this
example
For example, simplified math:
stoploss = -0.10
trailing_stop = True
trailing_stop_positive = 0.02
trailing_stop_positive_offset = 0.03
the bot buys an asset at a price of 100$
the stop loss is defined at -10%, so the stop loss would get triggered once the
asset drops below 90$
assuming the asset now increases to 102$
the stoploss will now be at 91.8$ - 10% below the highest observed rate
assuming the asset now increases to 103.5$ (above the offset configured)
the stop loss will now be -2% of 103.5$ = 101.43$
now the asset drops in value to 102$, the stop loss will still be 101.43$ and would
trigger once price breaks below 101.43$
Trailing stop loss only once the trade has reached a certain offset
You can also keep a static stoploss until the offset is reached, and then trail the
trade to take profits once the market turns.
stoploss = -0.10
trailing_stop = True
trailing_stop_positive = 0.02
trailing_stop_positive_offset = 0.03
trailing_only_offset_is_reached = True
For example, simplified math:
When using leverage, the same principle is applied - with stoploss defining the
risk on the trade (the amount you are willing to lose).
Make sure to be aware of this, and avoid using too tight stoploss (at 10x leverage,
10% risk may be too little to allow the trade to "breath" a little).
The new stoploss value will be applied to open trades (and corresponding log-
messages will be generated).
Limitations
Stoploss values cannot be changed if trailing_stop is enabled and the stoploss has
already been adjusted, or if Edge is enabled (since Edge would recalculate stoploss
based on the current market situation).
Plugins
Pairlists and Pairlist Handlers
Pairlist Handlers define the list of pairs (pairlist) that the bot should trade.
They are configured in the pairlists section of the configuration settings.
In your configuration, you can use Static Pairlist (defined by the StaticPairList
Pairlist Handler) and Dynamic Pairlist (defined by the VolumePairList and
PercentChangePairList Pairlist Handlers).
If multiple Pairlist Handlers are used, they are chained and a combination of all
Pairlist Handlers forms the resulting pairlist the bot uses for trading and
backtesting. Pairlist Handlers are executed in the sequence they are configured.
You can define either StaticPairList, VolumePairList, ProducerPairList,
RemotePairList, MarketCapPairList or PercentChangePairList as the starting Pairlist
Handler.
Inactive markets are always removed from the resulting pairlist. Explicitly
blacklisted pairs (those in the pair_blacklist configuration setting) are also
always removed from the resulting pairlist.
Pair blacklist
The pair blacklist (configured via exchange.pair_blacklist in the configuration)
disallows certain pairs from trading. This can be as simple as excluding DOGE/BTC -
which will remove exactly this pair.
The pair-blacklist does also support wildcards (in regex-style) - so BNB/.* will
exclude ALL pairs that start with BNB. You may also use something like .*DOWN/BTC
or .*UP/BTC to exclude leveraged tokens (check Pair naming conventions for your
exchange!)
Pairlist configurations can be quite tricky to get right. Best use the test-
pairlist utility sub-command to test your configuration quickly.
"pairlists": [
{"method": "StaticPairList"}
],
By default, only currently enabled pairs are allowed. To skip pair validation
against active markets, set "allow_inactive": true within the StaticPairList
configuration. This can be useful for backtesting expired pairs (like quarterly
spot-markets). This option must be configured along with
exchange.skip_pair_validation in the exchange configuration.
When used in the leading position of the chain of Pairlist Handlers, the
pair_whitelist configuration setting is ignored. Instead, VolumePairList selects
the top assets from all available markets with matching stake-currency on the
exchange.
The refresh_period setting allows to define the period (in seconds), at which the
pairlist will be refreshed. Defaults to 1800s (30 minutes). The pairlist cache
(refresh_period) on VolumePairList is only applicable to generating pairlists.
Filtering instances (not the first position in the list) will not apply any cache
(beyond caching candles for the duration of the candle in advanced mode) and will
always use up-to-date data.
VolumePairList is per default based on the ticker data from exchange, as reported
by the ccxt library:
The quoteVolume is the amount of quote (stake) currency traded (bought or sold) in
last 24 hours.
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume",
"min_value": 0,
"max_value": 8000000,
"refresh_period": 1800
}
],
You can define a minimum volume with min_value - which will filter out pairs with a
volume lower than the specified value in the specified timerange. In addition to
that, you can also define a maximum volume with max_value - which will filter out
pairs with a volume higher than the specified value in the specified timerange.
For convenience lookback_days can be specified, which will imply that 1d candles
will be used for the lookback. In the example below the pairlist would be created
based on the last 7 days:
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 86400,
"lookback_days": 7
}
],
Range look back and refresh period
Unsupported exchanges
More sophisticated approach can be used, by using lookback_timeframe for candle
size and lookback_period which specifies the amount of candles. This example will
build the volume pairs based on a rolling period of 3 days of 1h candles:
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 3600,
"lookback_timeframe": "1h",
"lookback_period": 72
}
],
Note
Configuration Options
number_assets: Specifies the number of top pairs to select based on the 24-hour
percentage change.
min_value: Sets a minimum percentage change threshold. Pairs with a percentage
change below this value will be filtered out.
max_value: Sets a maximum percentage change threshold. Pairs with a percentage
change above this value will be filtered out.
sort_direction: Specifies the order in which pairs are sorted based on their
percentage change. Accepts two values: asc for ascending order and desc for
descending order.
refresh_period: Defines the interval (in seconds) at which the pairlist will be
refreshed. The default is 1800 seconds (30 minutes).
lookback_days: Number of days to look back. When lookback_days is selected, the
lookback_timeframe is defaulted to 1 day.
lookback_timeframe: Timeframe to use for the lookback period.
lookback_period: Number of periods to look back at.
When PercentChangePairList is used after other Pairlist Handlers, it will operate
on the outputs of those handlers. If it is the leading Pairlist Handler, it will
select pairs from all available markets with the specified stake currency.
PercentChangePairList uses ticker data from the exchange, provided via the ccxt
library: The percentage change is calculated as the change in price over the last
24 hours.
Unsupported exchanges
Example Configuration to Read from Ticker
"pairlists": [
{
"method": "PercentChangePairList",
"number_assets": 15,
"min_value": -10,
"max_value": 50
}
],
In this configuration:
The top 15 pairs are selected based on the highest percentage change in price over
the last 24 hours.
Only pairs with a percentage change between -10% and 50% are considered.
Example Configuration to Read from Candles
"pairlists": [
{
"method": "PercentChangePairList",
"number_assets": 15,
"sort_key": "percentage",
"min_value": 0,
"refresh_period": 3600,
"lookback_timeframe": "1h",
"lookback_period": 72
}
],
This example builds the percent change pairs based on a rolling period of 3 days of
1-hour candles by using lookback_timeframe for candle size and lookback_period
which specifies the number of candles.
The percent change in price is calculated using the following formula, which
expresses the percentage difference between the current candle's close price and
the previous candle's close price, as defined by the specified timeframe and
lookback period:
Range look back and refresh period
Backtesting
ProducerPairList
With ProducerPairList, you can reuse the pairlist from a Producer without
explicitly defining the pairlist on each consumer.
The pairlist will perform a check on active pairs against the current exchange
configuration to avoid attempting to trade on invalid markets.
You can limit the length of the pairlist with the optional parameter number_assets.
Using "number_assets"=0 or omitting this key will result in the reuse of all
producer pairs valid for the current setup.
"pairlists": [
{
"method": "ProducerPairList",
"number_assets": 5,
"producer_name": "default",
}
],
Combining pairlists
This pairlist can be combined with all other pairlists and filters for further
pairlist reduction, and can also act as an "additional" pairlist, on top of already
defined pairs. ProducerPairList can also be used multiple times in sequence,
combining the pairs from multiple producers. Obviously in complex such
configurations, the Producer may not provide data for all pairs, so the strategy
must be fit for this.
RemotePairList
It allows the user to fetch a pairlist from a remote server or a locally stored
json file within the freqtrade directory, enabling dynamic updates and
customization of the trading pairlist.
In "filter" mode, the retrieved pairlist is used as a filter. Only the pairs
present in both the original pairlist and the retrieved pairlist are included in
the final pairlist. Other pairs are filtered out.
In "append" mode, the retrieved pairlist is added to the original pairlist. All
pairs from both lists are included in the final pairlist without any filtering.
The pairlist_url option specifies the URL of the remote server where the pairlist
is located, or the path to a local file (if [Link] is prepended). This allows the
user to use either a remote server or a local file as the source for the pairlist.
The save_to_file option, when provided with a valid filename, saves the processed
pairlist to that file in JSON format. This option is optional, and by default, the
pairlist is not saved to a file.
{
"pairs": ["XRP/USDT", "ETH/USDT", "LTC/USDT"],
"refresh_period": 1800
}
The pairs property should contain a list of strings with the trading pairs to be
used by the bot. The refresh_period property is optional and specifies the number
of seconds that the pairlist should be cached before being refreshed.
The optional read_timeout specifies the maximum amount of time (in seconds) to wait
for a response from the remote source, The default value is 60.
Note
In case of a server error the last received pairlist will be kept if
keep_pairlist_on_failure is set to true, when set to false a empty pairlist is
returned.
MarketCapPairList
MarketCapPairList employs sorting/filtering of pairs by their marketcap rank based
of CoinGecko. It will only recognize coins up to the coin placed at rank 250. The
returned pairlist will be sorted based of their marketcap ranks.
"pairlists": [
{
"method": "MarketCapPairList",
"number_assets": 20,
"max_rank": 50,
"refresh_period": 86400
}
]
number_assets defines the maximum number of pairs returned by the pairlist.
max_rank will determine the maximum rank used in creating/filtering the pairlist.
It's expected that some coins within the top max_rank marketcap will not be
included in the resulting pairlist since not all pairs will have active trading
pairs in your preferred market/stake/exchange combination.
refresh_period setting defines the period (in seconds) at which the marketcap rank
data will be refreshed. Defaults to 86,400s (1 day). The pairlist cache
(refresh_period) is applicable on both generating pairlists (first position in the
list) and filtering instances (not the first position in the list).
AgeFilter
Removes pairs that have been listed on the exchange for less than min_days_listed
days (defaults to 10) or more than max_days_listed days (defaults None mean
infinity).
When pairs are first listed on an exchange they can suffer huge price drops and
volatility in the first few days while the pair goes through its price-discovery
period. Bots can often be caught out buying before the pair has finished dropping
in price.
This filter allows freqtrade to ignore pairs until they have been listed for at
least min_days_listed days and listed before max_days_listed.
FullTradesFilter
Shrink whitelist to consist only in-trade pairs when the trade slots are full (when
max_open_trades isn't being set to -1 in the config).
When the trade slots are full, there is no need to calculate indicators of the rest
of the pairs (except informative pairs) since no new trade can be opened. By
shrinking the whitelist to just the in-trade pairs, you can improve calculation
speeds and reduce CPU usage. When a trade slot is free (either a trade is closed or
max_open_trades value in config is increased), then the whitelist will return to
normal state.
When multiple pairlist filters are being used, it's recommended to put this filter
at second position directly below the primary pairlist, so when the trade slots are
full, the bot doesn't have to download data for the rest of the filters.
Backtesting
FullTradesFilter does not support backtesting mode.
OffsetFilter
Offsets an incoming pairlist by a given offset value.
Example to remove the first 10 pairs from the pairlist, and takes the next 20
(taking items 10-30 of the initial list):
"pairlists": [
// ...
{
"method": "OffsetFilter",
"offset": 10,
"number_assets": 20
}
],
Warning
Note
An offset larger than the total length of the incoming pairlist will result in an
empty pairlist.
PerformanceFilter
Sorts pairs by past trade performance, as follows:
Positive performance.
No closed trades yet.
Negative performance.
Trade count is used as a tie breaker.
You can use the minutes parameter to only consider performance of the past X
minutes (rolling window). Not defining this parameter (or setting it to 0) will use
all-time performance.
The optional min_profit (as ratio -> a setting of 0.01 corresponds to 1%) parameter
defines the minimum profit a pair must have to be considered. Pairs below this
level will be filtered out. Using this parameter without minutes is highly
discouraged, as it can lead to an empty pairlist without a way to recover.
"pairlists": [
// ...
{
"method": "PerformanceFilter",
"minutes": 1440, // rolling 24h
"min_profit": 0.01 // minimal profit 1%
}
],
As this Filter uses past performance of the bot, it'll have some startup-period -
and should only be used after the bot has a few 100 trades in the database.
Backtesting
PrecisionFilter
Filters low-value coins which would not allow setting stoplosses.
Namely, pairs are blacklisted if a variance of one percent or more in the stop
price would be caused by precision rounding on the exchange, i.e.
rounded(stop_price) <= rounded(stop_price * 0.99). The idea is to avoid coins with
a value VERY close to their lower trading boundary, not allowing setting of proper
stoploss.
The above does not apply to shorts. And for longs, in theory the trade will be
liquidated first.
Backtesting
PriceFilter
The PriceFilter allows filtering of pairs by price. Currently the following price
filters are supported:
min_price
max_price
max_value
low_price_ratio
The min_price setting removes pairs where the price is below the specified price.
This is useful if you wish to avoid trading very low-priced pairs. This option is
disabled by default, and will only apply if set to > 0.
The max_price setting removes pairs where the price is above the specified price.
This is useful if you wish to trade only low-priced pairs. This option is disabled
by default, and will only apply if set to > 0.
The max_value setting removes pairs where the minimum value change is above a
specified value. This is useful when an exchange has unbalanced limits. For
example, if step-size = 1 (so you can only buy 1, or 2, or 3, but not 1.1 Coins) -
and the price is pretty high (like 20$) as the coin has risen sharply since the
last limit adaption. As a result of the above, you can only buy for 20$, or 40$ -
but not for 25$. On exchanges that deduct fees from the receiving currency (e.g.
binance) - this can result in high value coins / amounts that are unsellable as the
amount is slightly below the limit.
The low_price_ratio setting removes pairs where a raise of 1 price unit (pip) is
above the low_price_ratio ratio. This option is disabled by default, and will only
apply if set to > 0.
Calculation example:
Low priced pairs with high "1 pip movements" are dangerous since they are often
illiquid and it may also be impossible to place the desired stoploss, which can
often result in high losses since price needs to be rounded to the next tradable
price - so instead of having a stoploss of -5%, you could end up with a stoploss of
-9% simply due to price rounding.
ShuffleFilter
Shuffles (randomizes) pairs in the pairlist. It can be used for preventing the bot
from trading some of the pairs more frequently then others when you want all pairs
be treated with the same priority.
By default, ShuffleFilter will shuffle pairs once per candle. To shuffle on every
iteration, set "shuffle_frequency" to "iteration" instead of the default of
"candle".
{
"method": "ShuffleFilter",
"shuffle_frequency": "candle",
"seed": 42
}
Tip
You may set the seed value for this Pairlist to obtain reproducible results, which
can be useful for repeated backtesting sessions. If seed is not set, the pairs are
shuffled in the non-repeatable random order. ShuffleFilter will automatically
detect runmodes and apply the seed only for backtesting modes - if a seed value is
set.
SpreadFilter
Removes pairs that have a difference between asks and bids above the specified
ratio, max_spread_ratio (defaults to 0.005).
Example:
If DOGE/BTC maximum bid is 0.00000026 and minimum ask is 0.00000027, the ratio is
calculated as: 1 - bid/ask ~= 0.037 which is > 0.005 and this pair will be filtered
out.
RangeStabilityFilter
Removes pairs where the difference between lowest low and highest high over
lookback_days days is below min_rate_of_change or above max_rate_of_change. Since
this is a filter that requires additional data, the results are cached for
refresh_period.
In the below example: If the trading range over the last 10 days is <1% or >99%,
remove the pair from the whitelist.
"pairlists": [
{
"method": "RangeStabilityFilter",
"lookback_days": 10,
"min_rate_of_change": 0.01,
"max_rate_of_change": 0.99,
"refresh_period": 86400
}
]
Adding "sort_direction": "asc" or "sort_direction": "desc" enables sorting for this
pairlist.
Tip
This Filter can be used to automatically remove stable coin pairs, which have a
very low trading range, and are therefore extremely difficult to trade with profit.
Additionally, it can also be used to automatically remove pairs with extreme
high/low variance over a given amount of time.
VolatilityFilter
Volatility is the degree of historical variation of a pairs over time, it is
measured by the standard deviation of logarithmic daily returns. Returns are
assumed to be normally distributed, although actual distribution might be
different. In a normal distribution, 68% of observations fall within one standard
deviation and 95% of observations fall within two standard deviations. Assuming a
volatility of 0.05 means that the expected returns for 20 out of 30 days is
expected to be less than 5% (one standard deviation). Volatility is a positive
ratio of the expected deviation of return and can be greater than 1.00. Please
refer to the wikipedia definition of volatility.
This filter removes pairs if the average volatility over a lookback_days days is
below min_volatility or above max_volatility. Since this is a filter that requires
additional data, the results are cached for refresh_period.
This filter can be used to narrow down your pairs to a certain volatility or avoid
very volatile pairs.
In the below example: If the volatility over the last 10 days is not in the range
of 0.05-0.50, remove the pair from the whitelist. The filter is applied every 24h.
"pairlists": [
{
"method": "VolatilityFilter",
"lookback_days": 10,
"min_volatility": 0.05,
"max_volatility": 0.50,
"refresh_period": 86400
}
]
Adding "sort_direction": "asc" or "sort_direction": "desc" enables sorting mode for
this pairlist.
"exchange": {
"pair_whitelist": [],
"pair_blacklist": ["BNB/BTC"]
},
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume"
},
{"method": "AgeFilter", "min_days_listed": 10},
{"method": "PrecisionFilter"},
{"method": "PriceFilter", "low_price_ratio": 0.01},
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
{
"method": "RangeStabilityFilter",
"lookback_days": 10,
"min_rate_of_change": 0.01,
"refresh_period": 86400
},
{
"method": "VolatilityFilter",
"lookback_days": 10,
"min_volatility": 0.05,
"max_volatility": 0.50,
"refresh_period": 86400
},
{"method": "ShuffleFilter", "seed": 42}
],
Protections
Beta feature
This feature is still in it's testing phase. Should you notice something you think
is wrong please let us know via Discord or via Github Issue.
Protections will protect your strategy from unexpected events and market conditions
by temporarily stop trading for either one pair, or for all pairs. All protection
end times are rounded up to the next candle to avoid sudden, unexpected intra-
candle buys.
Note
Not all Protections will work for all strategies, and parameters will need to be
tuned for your strategy to improve performance.
Tip
Backtesting
Setting protections from the configuration via "protections": [], key should be
considered deprecated and will be removed in a future version. It is also no longer
guaranteed that your protections apply to the strategy in cases where the strategy
defines protections as property.
Available Protections
StoplossGuard Stop trading if a certain amount of stoploss occurred within a
certain time window.
MaxDrawdown Stop trading if max-drawdown is reached.
LowProfitPairs Lock pairs with low profits
CooldownPeriod Don't enter a trade right after selling a trade.
Common settings to all Protections
Parameter Description
method Protection name to use.
Datatype: String, selected from available Protections
stop_duration_candles For how many candles should the lock be set?
Datatype: Positive integer (in candles)
stop_duration how many minutes should protections be locked.
Cannot be used together with stop_duration_candles.
Datatype: Float (in minutes)
lookback_period_candles Only trades that completed within the last
lookback_period_candles candles will be considered. This setting may be ignored by
some Protections.
Datatype: Positive integer (in candles).
lookback_period Only trades that completed after current_time - lookback_period
will be considered.
Cannot be used together with lookback_period_candles.
This setting may be ignored by some Protections.
Datatype: Float (in minutes)
trade_limit Number of trades required at minimum (not used by all Protections).
Datatype: Positive integer
unlock_at Time when trading will be unlocked regularly (not used by all
Protections).
Datatype: string
Input Format: "HH:MM" (24-hours)
Durations
Stoploss Guard
StoplossGuard selects all trades within lookback_period in minutes (or in candles
when using lookback_period_candles). If trade_limit or more trades resulted in
stoploss, trading will stop for stop_duration in minutes (or in candles when using
stop_duration_candles, or until the set time when using unlock_at).
This applies across all pairs, unless only_per_pair is set to true, which will then
only look at one pair at a time.
Similarly, this protection will by default look at all trades (long and short). For
futures bots, setting only_per_side will make the bot only consider one side, and
will then only lock this one side, allowing for example shorts to continue after a
series of long stoplosses.
required_profit will determine the required relative profit (or loss) for
stoplosses to consider. This should normally not be set and defaults to 0.0 - which
means all losing stoplosses will be triggering a block.
The below example stops trading for all pairs for 4 candles after the last trade if
the bot hit stoploss 4 times within the last 24 candles.
@property
def protections(self):
return [
{
"method": "StoplossGuard",
"lookback_period_candles": 24,
"trade_limit": 4,
"stop_duration_candles": 4,
"required_profit": 0.0,
"only_per_pair": False,
"only_per_side": False
}
]
Note
MaxDrawdown
MaxDrawdown uses all trades within lookback_period in minutes (or in candles when
using lookback_period_candles) to determine the maximum drawdown. If the drawdown
is below max_allowed_drawdown, trading will stop for stop_duration in minutes (or
in candles when using stop_duration_candles) after the last trade - assuming that
the bot needs some time to let markets recover.
The below sample stops trading for 12 candles if max-drawdown is > 20% considering
all pairs - with a minimum of trade_limit trades - within the last 48 candles. If
desired, lookback_period and/or stop_duration can be used.
@property
def protections(self):
return [
{
"method": "MaxDrawdown",
"lookback_period_candles": 48,
"trade_limit": 20,
"stop_duration_candles": 12,
"max_allowed_drawdown": 0.2
},
]
Low Profit Pairs
LowProfitPairs uses all trades for a pair within lookback_period in minutes (or in
candles when using lookback_period_candles) to determine the overall profit ratio.
If that ratio is below required_profit, that pair will be locked for stop_duration
in minutes (or in candles when using stop_duration_candles, or until the set time
when using unlock_at).
For futures bots, setting only_per_side will make the bot only consider one side,
and will then only lock this one side, allowing for example shorts to continue
after a series of long losses.
The below example will stop trading a pair for 60 minutes if the pair does not have
a required profit of 2% (and a minimum of 2 trades) within the last 6 candles.
@property
def protections(self):
return [
{
"method": "LowProfitPairs",
"lookback_period_candles": 6,
"trade_limit": 2,
"stop_duration": 60,
"required_profit": 0.02,
"only_per_pair": False,
}
]
Cooldown Period
CooldownPeriod locks a pair for stop_duration in minutes (or in candles when using
stop_duration_candles, or until the set time when using unlock_at) after exiting,
avoiding a re-entry for this pair for stop_duration minutes.
The below example will stop trading a pair for 2 candles after closing a trade,
allowing this pair to "cool down".
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration_candles": 2
}
]
Note
This Protection applies only at pair-level, and will never lock all pairs globally.
This Protection does not consider lookback_period as it only looks at the latest
trade.
Locks each pair after selling for an additional 5 candles (CooldownPeriod), giving
other pairs a chance to get filled.
Stops trading for 4 hours (4 * 1h candles) if the last 2 days (48 * 1h candles) had
20 trades, which caused a max-drawdown of more than 20%. (MaxDrawdown).
Stops trading if more than 4 stoploss occur for all pairs within a 1 day (24 * 1h
candles) limit (StoplossGuard).
Locks all pairs that had 2 Trades within the last 6 hours (6 * 1h candles) with a
combined profit ratio of below 0.02 (<2%) (LowProfitPairs).
Locks all pairs for 2 candles that had a profit of below 0.01 (<1%) within the last
24h (24 * 1h candles), a minimum of 4 trades.
class AwesomeStrategy(IStrategy)
timeframe = '1h'
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration_candles": 5
},
{
"method": "MaxDrawdown",
"lookback_period_candles": 48,
"trade_limit": 20,
"stop_duration_candles": 4,
"max_allowed_drawdown": 0.2
},
{
"method": "StoplossGuard",
"lookback_period_candles": 24,
"trade_limit": 4,
"stop_duration_candles": 2,
"only_per_pair": False
},
{
"method": "LowProfitPairs",
"lookback_period_candles": 6,
"trade_limit": 2,
"stop_duration_candles": 60,
"required_profit": 0.02
},
{
"method": "LowProfitPairs",
"lookback_period_candles": 24,
"trade_limit": 4,
"stop_duration_candles": 2,
"required_profit": 0.01
}
]
# ...
Note
Up-to-date clock
The clock on the system running the bot must be accurate, synchronized to a NTP
server frequently enough to avoid problems with communication to the exchanges.
Bot commands
positional arguments:
{trade,create-userdir,new-config,show-config,new-strategy,download-data,convert-
data,convert-trade-data,trades-to-ohlcv,list-data,backtesting,backtesting-
show,backtesting-analysis,edge,hyperopt,hyperopt-list,hyperopt-show,list-
exchanges,list-markets,list-pairs,list-strategies,list-freqaimodels,list-
timeframes,show-trades,test-pairlist,convert-db,install-ui,plot-dataframe,plot-
profit,webserver,strategy-updater,lookahead-analysis,recursive-analysis}
trade Trade module.
create-userdir Create user-data directory.
new-config Create new config
show-config Show resolved config
new-strategy Create new strategy
download-data Download backtesting data.
convert-data Convert candle (OHLCV) data from one format to
another.
convert-trade-data Convert trade data from one format to another.
trades-to-ohlcv Convert trade data to OHLCV data.
list-data List downloaded data.
backtesting Backtesting module.
backtesting-show Show past Backtest results
backtesting-analysis
Backtest Analysis module.
edge Edge module.
hyperopt Hyperopt module.
hyperopt-list List Hyperopt results
hyperopt-show Show details of Hyperopt results
list-exchanges Print available exchanges.
list-markets Print markets on exchange.
list-pairs Print pairs on exchange.
list-strategies Print available strategies.
list-freqaimodels Print available freqAI models.
list-timeframes Print available timeframes for the exchange.
show-trades Show trades.
test-pairlist Test your pairlist configuration.
convert-db Migrate database to different system
install-ui Install FreqUI
plot-dataframe Plot candles with indicators.
plot-profit Generate plot showing profits.
webserver Webserver module.
strategy-updater updates outdated strategy files to the current version
lookahead-analysis Check for potential look ahead bias.
recursive-analysis Check for potential recursive formula issue.
options:
-h, --help show this help message and exit
-V, --version show program's version number and exit
Bot trading commands
usage: freqtrade trade [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
[--userdir PATH] [-s NAME] [--strategy-path PATH]
[--db-url PATH] [--sd-notify] [--dry-run]
[--dry-run-wallet DRY_RUN_WALLET]
optional arguments:
-h, --help show this help message and exit
--db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///[Link]` for
Live Run mode, `sqlite:///[Link]` for
Dry Run).
--sd-notify Notify systemd service manager.
--dry-run Enforce dry-run for trading (removes Exchange secrets
and simulates trades).
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
Starting balance, used for backtesting / hyperopt and
dry-runs.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Strategy arguments:
-s NAME, --strategy NAME
Specify strategy class name which will be used by the
bot.
--strategy-path PATH Specify additional strategy lookup path.
How to specify which configuration file be used?
The bot allows you to select which configuration file you want to use by means of
the -c/--config command line option:
For example, you can make a separate configuration file with your key and secret
for the Exchange you use for trading, specify default configuration file with empty
key and secret values while running in the Dry Mode (which does not actually
require them):
See more details on this technique with examples in the documentation page on
configuration.
user_data/
├── backtest_results
├── data
├── hyperopts
├── hyperopt_results
├── plot
└── strategies
You can add the entry "user_data_dir" setting to your configuration, to always
point your bot to this directory. Alternatively, pass in --userdir to every
command. The bot will fail to start if the directory does not exist, but will
create necessary subdirectories.
This directory should contain your custom strategies, custom hyperopts and hyperopt
loss functions, backtesting historical data (downloaded using either backtesting
command or the download script) and plot outputs.
The bot will search your strategy file within user_data/strategies. To use other
directories, please read the next section about --strategy-path.
To load a strategy, simply pass the class name (e.g.: CustomStrategy) in this
parameter.
Data Downloading
Getting data for backtesting and hyperopt
To download data (candles / OHLCV) needed for backtesting and hyperoptimization use
the freqtrade download-data command.
If no additional parameter is specified, freqtrade will download data for "1m" and
"5m" timeframes for the last 30 days. Exchange and pairs will come from [Link]
(if specified using -c/--config). Without provided configuration, --exchange
becomes mandatory.
You can use a relative timerange (--days 20) or an absolute starting point (--
timerange 20200101-). For incremental downloads, the relative approach should be
used.
If you already have backtesting data available in your data-directory and would
like to refresh this data up to today, freqtrade will automatically calculate the
data missing for the existing pairs and the download will occur from the latest
available point until "now", neither --days or --timerange parameters are required.
Freqtrade will keep the available data and only download the missing data. If you
are updating existing data after inserting new pairs that you have no data for, use
--new-pairs-days xx parameter. Specified number of days will be downloaded for new
pairs while old pairs will be updated with missing data only. If you use --days xx
parameter alone - data for specified number of days will be downloaded for all
pairs. Be careful, if specified number of days is smaller than gap between now and
last downloaded candle - freqtrade will delete all existing data to avoid gaps in
candle data.
Usage
usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]] [--pairs-file FILE]
[--days INT] [--new-pairs-days INT]
[--include-inactive-pairs]
[--timerange TIMERANGE] [--dl-trades]
[--convert] [--exchange EXCHANGE]
[-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]
[--data-format-ohlcv
{json,jsongz,hdf5,feather,parquet}]
[--data-format-trades
{json,jsongz,hdf5,feather,parquet}]
[--trading-mode {spot,margin,futures}]
[--prepend]
options:
-h, --help show this help message and exit
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--pairs-file FILE File containing a list of pairs. Takes precedence over
--pairs or pairs configured in the configuration.
--days INT Download data for given number of days.
--new-pairs-days INT Download data of new pairs for given number of days.
Default: `None`.
--include-inactive-pairs
Also download data from inactive pairs.
--timerange TIMERANGE
Specify what timerange of data to use.
--dl-trades Download trades instead of OHLCV data. The bot will
resample trades to the desired timeframe as specified
as --timeframes/-t.
--convert Convert downloaded trades to OHLCV data. Only
applicable in combination with `--dl-trades`. Will be
automatic for exchanges which don't have historic
OHLCV (e.g. Kraken). If not provided, use `trades-to-
ohlcv` to convert trades data to OHLCV data.
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
-t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...]
Specify which tickers to download. Space-separated
list. Default: `1m 5m`.
--erase Clean all existing data for the selected
exchange/pairs/timeframes.
--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded candle (OHLCV) data.
(default: `feather`).
--data-format-trades {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded trades data. (default:
`feather`).
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
Select Trading mode
--prepend Allow data prepending. (Data-appending is disabled)
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Downloading all data for one quote currency
Often, you'll want to download data for all pairs of a specific quote-currency. In
such cases, you can use the following shorthand: freqtrade download-data --exchange
binance --pairs .*/USDT <...>. The provided "pairs" string will be expanded to
contain all active pairs on the exchange. To also download data for inactive
(delisted) pairs, add --include-inactive-pairs to the command.
Startup period
For that reason, download-data does not care about the "startup-period" defined in
a strategy. It's up to the user to download additional days if the backtest should
start at a specific point in time (while respecting startup period).
Start download
A very simple command (assuming an available [Link] file) can look as follows.
Freqtrade will ignore the end-date in this mode if data is available, updating the
end-date to the existing data start point.
Data format
Freqtrade currently supports the following data-formats:
// ...
"dataformat_ohlcv": "hdf5",
"dataformat_trades": "hdf5",
// ...
If the default data-format has been changed during download, then the keys
dataformat_ohlcv and dataformat_trades in the configuration file need to be
adjusted to the selected dataformat as well.
Note
You can convert between data-formats using the convert-data and convert-trade-data
methods.
Dataformat comparison
The following comparisons have been made with the following data, and by using the
linux time command.
To have a best performance/size mix, we recommend using the default feather format,
or parquet.
Pairs file
In alternative to the whitelist from [Link], a [Link] file can be used. If
you are using Binance for example:
mkdir -p user_data/data/binance
touch user_data/data/binance/[Link]
The format of the [Link] file is a simple json list. Mixing different stake-
currencies is allowed for this file, since it's only used for downloading.
[
"ETH/BTC",
"ETH/USDT",
"BTC/USDT",
"XRP/ETH"
]
Note
usage: freqtrade convert-data [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]] --format-from
{json,jsongz,hdf5,feather,parquet} --format-to
{json,jsongz,hdf5,feather,parquet} [--erase]
[--exchange EXCHANGE]
[-t TIMEFRAMES [TIMEFRAMES ...]]
[--trading-mode {spot,margin,futures}]
[--candle-types
{spot,futures,mark,index,premiumIndex,funding_rate}
[{spot,futures,mark,index,premiumIndex,funding_rate} ...]]
options:
-h, --help show this help message and exit
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--format-from {json,jsongz,hdf5,feather,parquet}
Source format for data conversion.
--format-to {json,jsongz,hdf5,feather,parquet}
Destination format for data conversion.
--erase Clean all existing data for the selected
exchange/pairs/timeframes.
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
-t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...]
Specify which tickers to download. Space-separated
list. Default: `1m 5m`.
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
Select Trading mode
--candle-types {spot,futures,mark,index,premiumIndex,funding_rate}
[{spot,futures,mark,index,premiumIndex,funding_rate} ...]
Select candle type to convert. Defaults to all
available types.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Example converting data
The following command will convert all candle (OHLCV) data available in
~/.freqtrade/data/binance from json to jsongz, saving diskspace in the process.
It'll also remove original json data files (--erase parameter).
usage: freqtrade convert-trade-data [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]] --format-from
{json,jsongz,hdf5,feather,parquet}
--format-to
{json,jsongz,hdf5,feather,parquet}
[--erase] [--exchange EXCHANGE]
options:
-h, --help show this help message and exit
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--format-from {json,jsongz,hdf5,feather,parquet}
Source format for data conversion.
--format-to {json,jsongz,hdf5,feather,parquet}
Destination format for data conversion.
--erase Clean all existing data for the selected
exchange/pairs/timeframes.
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Example converting trades
The following command will convert all available trade-data in
~/.freqtrade/data/kraken from jsongz to json. It'll also remove original jsongz
data files (--erase parameter).
usage: freqtrade trades-to-ohlcv [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]]
[-t TIMEFRAMES [TIMEFRAMES ...]]
[--exchange EXCHANGE]
[--data-format-ohlcv
{json,jsongz,hdf5,feather,parquet}]
[--data-format-trades {json,jsongz,hdf5,feather}]
options:
-h, --help show this help message and exit
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
-t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...]
Specify which tickers to download. Space-separated
list. Default: `1m 5m`.
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded candle (OHLCV) data.
(default: `feather`).
--data-format-trades {json,jsongz,hdf5,feather}
Storage format for downloaded trades data. (default:
`feather`).
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Example trade-to-ohlcv conversion
usage: freqtrade list-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
[--userdir PATH] [--exchange EXCHANGE]
[--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}]
[--data-format-trades
{json,jsongz,hdf5,feather,parquet}]
[--trades] [-p PAIRS [PAIRS ...]]
[--trading-mode {spot,margin,futures}]
[--show-timerange]
options:
-h, --help show this help message and exit
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded candle (OHLCV) data.
(default: `feather`).
--data-format-trades {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded trades data. (default:
`feather`).
--trades Work on trades data instead of OHLCV data.
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
Select Trading mode
--show-timerange Show timerange available for available data. (May take
a while to calculate).
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Example list-data
Since this data is large by default, the files use the feather file format by
default. They are stored in your data-directory with the naming convention of
<pair>-[Link] (ETH_BTC-[Link]). Incremental mode is also supported,
as for historic OHLCV data, so downloading the data once per week with --days 8
will create an incremental data-repository.
To use this mode, simply add --dl-trades to your call. This will swap the download
method to download trades. If --convert is also provided, the resample step will
happen automatically and overwrite eventually existing OHLCV data for the given
pair/timeframe combinations.
Do not use
You should not use this unless you're a kraken user (Kraken does not provide
historic OHLCV data).
Most other exchanges provide OHLCV data with sufficient history, so downloading
multiple timeframes through that method will still proof to be a lot faster than
downloading trades data.
Kraken user
Example call:
Next step
Great, you now have some data downloaded, so you can now start backtesting your
strategy.
Backtesting
This page explains how to validate your strategy performance by using Backtesting.
Backtesting requires historic data to be available. To learn how to get data for
the pairs and exchange you're interested in, head over to the Data Downloading
section of the documentation.
usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [-s NAME]
[--strategy-path PATH] [-i TIMEFRAME]
[--timerange TIMERANGE]
[--data-format-ohlcv {json,jsongz,hdf5}]
[--max-open-trades INT]
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
[-p PAIRS [PAIRS ...]] [--eps] [--dmmp]
[--enable-protections]
[--dry-run-wallet DRY_RUN_WALLET]
[--timeframe-detail TIMEFRAME_DETAIL]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades,signals}]
[--export-filename PATH]
[--breakdown {day,week,month} [{day,week,month} ...]]
[--cache {none,day,week,month}]
optional arguments:
-h, --help show this help message and exit
-i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--timerange TIMERANGE
Specify what timerange of data to use.
--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}
Storage format for downloaded candle (OHLCV) data.
(default: `feather`).
--max-open-trades INT
Override the value of the `max_open_trades`
configuration setting.
--stake-amount STAKE_AMOUNT
Override the value of the `stake_amount` configuration
setting.
--fee FLOAT Specify fee ratio. Will be applied twice (on trade
entry and exit).
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--eps, --enable-position-stacking
Allow buying the same pair multiple times (position
stacking).
--dmmp, --disable-max-market-positions
Disable applying `max_open_trades` during backtest
(same as setting `max_open_trades` to a very high
number).
--enable-protections, --enableprotections
Enable protections for [Link] slow
backtesting down by a considerable amount, but will
include configured protections
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
Starting balance, used for backtesting / hyperopt and
dry-runs.
--timeframe-detail TIMEFRAME_DETAIL
Specify detail timeframe for backtesting (`1m`, `5m`,
`30m`, `1h`, `1d`).
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
Provide a space-separated list of strategies to
backtest. Please note that timeframe needs to be set
either in config or via command line. When using this
together with `--export trades`, the strategy-name is
injected into the filename (so `[Link]`
becomes `[Link]`
--export {none,trades,signals}
Export backtest results (default: trades).
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest [Link]
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--breakdown {day,week,month} [{day,week,month} ...]
Show backtesting breakdown per [day, week, month].
--cache {none,day,week,month}
Load a cached backtest result no older than specified
age (default: day).
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Strategy arguments:
-s NAME, --strategy NAME
Specify strategy class name which will be used by the
bot.
--strategy-path PATH Specify additional strategy lookup path.
Test your strategy with Backtesting
Now you have good Entry and exit strategies and some historic data, you want to
test it against real data. This is what we call backtesting.
Backtesting will use the crypto-currencies (pairs) from your config file and load
historical candle (OHLCV) data from user_data/data/<exchange> by default. If no
data is available for the exchange / pair / timeframe combination, backtesting will
ask you to download them first using freqtrade download-data. For details on
downloading, please refer to the Data Downloading section in the documentation.
The result of backtesting will confirm if your bot has better odds of making a
profit than a loss.
All profit calculations include fees, and freqtrade will use the exchange's default
fees for the calculation.
Using dynamic pairlists is possible (not all of the handlers are allowed to be used
in backtest mode), however it relies on the current market conditions - which will
not reflect the historic status of the pairlist. Also, when using pairlists other
than StaticPairlist, reproducibility of backtesting-results cannot be guaranteed.
Please read the pairlists documentation for more information.
Note
Starting balance
Backtesting will require a starting balance, which can be provided as --dry-run-
wallet <balance> or --starting-balance <balance> command line argument, or via
dry_run_wallet configuration setting. This amount must be higher than stake_amount,
otherwise the bot will not be able to simulate any trade.
Assume you downloaded the history data from the Binance exchange and kept it in the
user_data/data/binance-20180101 directory. You can then use this data for
backtesting as follows:
Sometimes your account has certain fee rebates (fee reductions starting with a
certain account size or monthly volume), which are not visible to ccxt. To account
for this in backtesting, you can use the --fee command line option to supply this
value to backtesting. This fee must be a ratio, and will be applied twice (once for
trade entry, and once for trade exit).
For example, if the commission fee per order is 0.1% (i.e., 0.001 written as
ratio), then you would run backtesting as the following:
Only supply this option (or the corresponding configuration parameter) if you want
to experiment with different fee values. By default, Backtesting fetches the
default fee from the exchange pair/market info.
Use the --timerange argument to change how much of the test-set you want to use.
For example, running backtesting with the --timerange=20190501- option will use all
available data starting with May 1st, 2019 from your input data.
The last line will give you the overall performance of your strategy, here:
The column Avg Profit % shows the average profit for all trades made. The column
Tot Profit % shows instead the total profit % in relation to the starting balance.
In the above results, we have a starting balance of 0.01 BTC and an absolute profit
of 0.00762792 BTC - so the Tot Profit % will be (0.00762792 / 0.01) * 100 ~= 76.2%.
Your strategy performance is influenced by your entry strategy, your exit strategy,
and also by the minimal_roi and stop_loss you have set.
For example, if your minimal_roi is only "0": 0.01 you cannot expect the bot to
make more profit than 1% (because it will exit every time a trade reaches 1%).
"minimal_roi": {
"0": 0.01
},
On the other hand, if you set a too high minimal_roi like "0": 0.55 (55%), there is
almost no chance that the bot will ever reach this profit. Hence, keep in mind that
your performance is an integral mix of all different elements of the strategy, your
configuration, and the crypto-currency pairs you have set up.
Summary metrics
The last element of the backtest report is the summary metrics table. It contains
some useful key metrics about performance of your strategy on backtesting data.
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2019-01-01 [Link] |
| Backtesting to | 2019-05-01 [Link] |
| Max open trades | 3 |
| | |
| Total/Daily Avg Trades | 429 / 3.575 |
| Starting balance | 0.01000000 BTC |
| Final balance | 0.01762792 BTC |
| Absolute profit | 0.00762792 BTC |
| Total profit % | 76.2% |
| CAGR % | 460.87% |
| Sortino | 1.88 |
| Sharpe | 2.97 |
| Calmar | 6.29 |
| Profit factor | 1.11 |
| Expectancy (Ratio) | -0.15 (-0.05) |
| Avg. stake amount | 0.001 BTC |
| Total trade volume | 0.429 BTC |
| | |
| Long / Short | 352 / 77 |
| Total profit Long % | 1250.58% |
| Total profit Short % | -15.02% |
| Absolute profit Long | 0.00838792 BTC |
| Absolute profit Short | -0.00076 BTC |
| | |
| Best Pair | LSK/BTC 26.26% |
| Worst Pair | ZEC/BTC -10.18% |
| Best Trade | LSK/BTC 4.25% |
| Worst Trade | ZEC/BTC -10.25% |
| Best day | 0.00076 BTC |
| Worst day | -0.00036 BTC |
| Days win/draw/lose | 12 / 82 / 25 |
| Avg. Duration Winners | [Link] |
| Avg. Duration Loser | [Link] |
| Max Consecutive Wins / Loss | 3 / 4 |
| Rejected Entry signals | 3089 |
| Entry/Exit Timeouts | 0 / 0 |
| Canceled Trade Entries | 34 |
| Canceled Entry Orders | 123 |
| Replaced Entry Orders | 89 |
| | |
| Min balance | 0.00945123 BTC |
| Max balance | 0.01846651 BTC |
| Max % of account underwater | 25.19% |
| Absolute Drawdown (Account) | 13.33% |
| Drawdown | 0.0015 BTC |
| Drawdown high | 0.0013 BTC |
| Drawdown low | -0.0002 BTC |
| Drawdown Start | 2019-02-15 [Link] |
| Drawdown End | 2019-04-11 [Link] |
| Market change | -5.88% |
=====================================================
Backtesting from / Backtesting to: Backtesting range (usually defined with the --
timerange option).
Max open trades: Setting of max_open_trades (or --max-open-trades) - or number of
pairs in the pairlist (whatever is lower).
Total/Daily Avg Trades: Identical to the total trades of the backtest output
table / Total trades divided by the backtesting duration in days (this will give
you information about how many trades to expect from the strategy).
Starting balance: Start balance - as given by dry-run-wallet (config or command
line).
Final balance: Final balance - starting balance + absolute profit.
Absolute profit: Profit made in stake currency.
Total profit %: Total profit. Aligned to the TOTAL row's Tot Profit % from the
first table. Calculated as (End capital − Starting capital) / Starting capital.
CAGR %: Compound annual growth rate.
Sortino: Annualized Sortino ratio.
Sharpe: Annualized Sharpe ratio.
Calmar: Annualized Calmar ratio.
Profit factor: profit / loss.
Avg. stake amount: Average stake amount, either stake_amount or the average when
using dynamic stake amount.
Total trade volume: Volume generated on the exchange to reach the above profit.
Best Pair / Worst Pair: Best and worst performing pair, and it's corresponding Tot
Profit %.
Best Trade / Worst Trade: Biggest single winning trade and biggest single losing
trade.
Best day / Worst day: Best and worst day based on daily profit.
Days win/draw/lose: Winning / Losing days (draws are usually days without closed
trade).
Avg. Duration Winners / Avg. Duration Loser: Average durations for winning and
losing trades.
Max Consecutive Wins / Loss: Maximum consecutive wins/losses in a row.
Rejected Entry signals: Trade entry signals that could not be acted upon due to
max_open_trades being reached.
Entry/Exit Timeouts: Entry/exit orders which did not fill (only applicable if
custom pricing is used).
Canceled Trade Entries: Number of trades that have been canceled by user request
via adjust_entry_price.
Canceled Entry Orders: Number of entry orders that have been canceled by user
request via adjust_entry_price.
Replaced Entry Orders: Number of entry orders that have been replaced by user
request via adjust_entry_price.
Min balance / Max balance: Lowest and Highest Wallet balance during the backtest
period.
Max % of account underwater: Maximum percentage your account has decreased from the
top since the simulation started. Calculated as the maximum of (Max Balance -
Current Balance) / (Max Balance).
Absolute Drawdown (Account): Maximum Account Drawdown experienced. Calculated as
(Absolute Drawdown) / (DrawdownHigh + startingBalance).
Drawdown: Maximum, absolute drawdown experienced. Difference between Drawdown High
and Subsequent Low point.
Drawdown high / Drawdown low: Profit at the beginning and end of the largest
drawdown period. A negative low value means initial capital lost.
Drawdown Start / Drawdown End: Start and end datetime for this largest drawdown
(can also be visualized via the plot-dataframe sub-command).
Market change: Change of the market during the backtest period. Calculated as
average of all pairs changes from the first to the last candle using the "close"
column.
Long / Short: Split long/short values (Only shown when short trades were made).
Total profit Long % / Absolute profit Long: Profit long trades only (Only shown
when short trades were made).
Total profit Short % / Absolute profit Short: Profit short trades only (Only shown
when short trades were made).
Daily / Weekly / Monthly breakdown
You can get an overview over daily / weekly or monthly results by using the --
breakdown <> switch.
To visualize daily and weekly breakdowns, you can use the following:
Warning
In addition to the above assumptions, strategy authors should carefully read the
Common Mistakes section, to avoid using data in backtesting which is not available
in real market conditions.
Backtesting (as well as live and dry-run) does honor these limits, and will ensure
that a stoploss can be placed below this value - so the value will be slightly
higher than what the exchange specifies. Freqtrade has however no information about
historic limits.
This can lead to situations where trading-limits are inflated by using a historic
price, resulting in minimum amounts > 50$.
For example:
BTC minimum tradable amount is 0.001. BTC trades at 22.000$ today (0.001 BTC is
related to this) - but the backtesting period includes prices as high as 50.000$.
Today's minimum would be 0.001 * 22_000 - or 22$.
However the limit could also be 50$ - based on 0.001 * 50_000 in some historic
setting.
Trading precision limits
Most exchanges pose precision limits on both price and amounts, so you cannot buy
1.0020401 of a pair, or at a price of 1.24567123123.
Instead, these prices and amounts will be rounded or truncated (based on the
exchange definition) to the defined trading precision. The above values may for
example be rounded to an amount of 1.002, and a price of 1.24567.
These precision values are based on current exchange limits (as described in the
above section), as historic precision limits are not available.
While backtesting does take some assumptions (read above) about this - this can
never be perfect, and will always be biased in one way or the other. To mitigate
this, freqtrade can use a lower (faster) timeframe to simulate intra-candle
movements.
Obviously this will require more memory (5m data is bigger than 1h data), and will
also impact runtime (depending on the amount of trades and trade durations). Also,
data must be available / downloaded already.
Tip
You can use this function as the last part of strategy development, to ensure your
strategy is not exploiting one of the backtesting assumptions. Strategies that
perform similarly well with this mode have a good chance to perform well in
dry/live modes too (although only forward-testing (dry-mode) can really confirm a
strategy).
This is limited to 1 timeframe value per run. However, data is only loaded once
from disk so if you have multiple strategies you'd like to compare, this will give
a nice runtime boost.
All listed Strategies need to be in the same directory, unless also --recursive-
strategy-search is specified, where sub-directories within the strategy directory
are also considered.
Hyperopt
This page explains how to tune your strategy by finding the optimal parameters, a
process called hyperparameter optimization. The bot uses algorithms included in the
scikit-optimize package to accomplish this. The search will burn all your CPU
cores, make your laptop sound like a fighter jet and still take a long time.
In general, the search for best parameters starts with a few random combinations
(see below for more details) and then uses Bayesian search with a ML regressor
algorithm (currently ExtraTreesRegressor) to quickly find a combination of
parameters in the search hyperspace that minimizes the value of the loss function.
Bug
Hyperopt can crash when used with only 1 CPU Core as found out in Issue #1133
Note
Since 2021.4 release you no longer have to write a separate hyperopt class, but can
configure the parameters directly in the strategy. The legacy method was supported
up to 2021.8 and has been removed in 2021.9.
Note
Docker
The docker-image includes hyperopt dependencies, no further action needed.
source .venv/bin/activate
pip install -r [Link]
Hyperopt command reference
usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
[--userdir PATH] [-s NAME] [--strategy-path PATH]
[--recursive-strategy-search] [--freqaimodel NAME]
[--freqaimodel-path PATH] [-i TIMEFRAME]
[--timerange TIMERANGE]
[--data-format-ohlcv {json,jsongz,hdf5}]
[--max-open-trades INT]
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
[-p PAIRS [PAIRS ...]] [--hyperopt-path PATH]
[--eps] [--dmmp] [--enable-protections]
[--dry-run-wallet DRY_RUN_WALLET]
[--timeframe-detail TIMEFRAME_DETAIL] [-e INT]
[--spaces
{all,buy,sell,roi,stoploss,trailing,protection,trades,default}
[{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]]
[--print-all] [--no-color] [--print-json] [-j JOBS]
[--random-state INT] [--min-trades INT]
[--hyperopt-loss NAME] [--disable-param-export]
[--ignore-missing-spaces] [--analyze-per-epoch]
optional arguments:
-h, --help show this help message and exit
-i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--timerange TIMERANGE
Specify what timerange of data to use.
--data-format-ohlcv {json,jsongz,hdf5}
Storage format for downloaded candle (OHLCV) data.
(default: `json`).
--max-open-trades INT
Override the value of the `max_open_trades`
configuration setting.
--stake-amount STAKE_AMOUNT
Override the value of the `stake_amount` configuration
setting.
--fee FLOAT Specify fee ratio. Will be applied twice (on trade
entry and exit).
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
--hyperopt-path PATH Specify additional lookup path for Hyperopt Loss
functions.
--eps, --enable-position-stacking
Allow buying the same pair multiple times (position
stacking).
--dmmp, --disable-max-market-positions
Disable applying `max_open_trades` during backtest
(same as setting `max_open_trades` to a very high
number).
--enable-protections, --enableprotections
Enable protections for [Link] slow
backtesting down by a considerable amount, but will
include configured protections
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
Starting balance, used for backtesting / hyperopt and
dry-runs.
--timeframe-detail TIMEFRAME_DETAIL
Specify detail timeframe for backtesting (`1m`, `5m`,
`30m`, `1h`, `1d`).
-e INT, --epochs INT Specify number of epochs (default: 100).
--spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default}
[{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]
Specify which parameters to hyperopt. Space-separated
list.
--print-all Print all results, not only the best ones.
--no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file.
--print-json Print output in JSON format.
-j JOBS, --job-workers JOBS
The number of concurrently running jobs for
hyperoptimization (hyperopt worker processes). If -1
(default), all CPUs are used, for -2, all CPUs but one
are used, etc. If 1 is given, no parallel computing
code is used at all.
--random-state INT Set random state to some positive integer for
reproducible hyperopt results.
--min-trades INT Set minimal desired number of trades for evaluations
in the hyperopt optimization path (default: 1).
--hyperopt-loss NAME, --hyperoptloss NAME
Specify the class name of the hyperopt loss function
class (IHyperOptLoss). Different functions can
generate completely different results, since the
target for optimization is different. Built-in
Hyperopt-loss-functions are:
ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss,
SharpeHyperOptLoss, SharpeHyperOptLossDaily,
SortinoHyperOptLoss, SortinoHyperOptLossDaily,
CalmarHyperOptLoss, MaxDrawDownHyperOptLoss,
MaxDrawDownRelativeHyperOptLoss,
ProfitDrawDownHyperOptLoss
--disable-param-export
Disable automatic hyperopt parameter export.
--ignore-missing-spaces, --ignore-unparameterized-spaces
Suppress errors for any requested Hyperopt spaces that
do not contain any parameters.
--analyze-per-epoch Run populate_indicators once per epoch.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Strategy arguments:
-s NAME, --strategy NAME
Specify strategy class name which will be used by the
bot.
--strategy-path PATH Specify additional strategy lookup path.
--recursive-strategy-search
Recursively search for a strategy in the strategies
folder.
--freqaimodel NAME Specify a custom freqaimodels.
--freqaimodel-path PATH
Specify additional lookup path for freqaimodels.
Hyperopt checklist
Checklist on all tasks / possibilities in hyperopt
Depending on the space you want to optimize, only some of the below are required:
populate_indicators needs to create all indicators any of the spaces may use,
otherwise hyperopt will not work.
Rarely you may also need to create a nested class named HyperOpt and implement
roi_space - for custom ROI optimization (if you need the ranges for the ROI
parameters in the optimization hyperspace that differ from default)
generate_roi_table - for custom ROI optimization (if you need the ranges for the
values in the ROI table that differ from default or the number of entries (steps)
in the ROI table which differs from the default 4 steps)
stoploss_space - for custom stoploss optimization (if you need the range for the
stoploss parameter in the optimization hyperspace that differs from default)
trailing_space - for custom trailing stop optimization (if you need the ranges for
the trailing stop parameters in the optimization hyperspace that differ from
default)
max_open_trades_space - for custom max_open_trades optimization (if you need the
ranges for the max_open_trades parameter in the optimization hyperspace that differ
from default)
Quickly optimize ROI, stoploss and trailing stoploss
You can quickly optimize the spaces roi, stoploss and trailing without changing
anything in your strategy.
For every new set of parameters, freqtrade will run first populate_entry_trend()
followed by populate_exit_trend(), and then run the regular backtesting process to
simulate trades.
After backtesting, the results are passed into the loss function, which will
evaluate if this result was better or worse than previous results.
Based on the loss function result, hyperopt will determine the next set of
parameters to try in the next round of backtesting.
Guards are conditions like "never buy if ADX < 10", or never buy if current price
is over EMA10.
Triggers are ones that actually trigger buy in specific moment, like "buy when EMA5
crosses over EMA10" or "buy when close price touches lower Bollinger band".
Guards and Triggers
Hyper-optimization will, for each epoch round, pick one trigger and possibly
multiple guards.
Define the parameters at the class level hyperopt shall be optimizing, either
naming them sell_*, or by explicitly defining space='sell'.
Within populate_exit_trend() - use defined parameter values instead of raw
constants.
The configuration and rules are the same than for buy signals.
Solving a Mystery
Let's say you are curious: should you use MACD crossings or lower Bollinger Bands
to trigger your long entries. And you also wonder should you use RSI or ADX to help
with those decisions. If you decide to use RSI or ADX, which values should I use
for them?
So let's use hyperparameter optimization to solve this mystery.
class MyAwesomeStrategy(IStrategy):
class MyAwesomeStrategy(IStrategy):
buy_adx = DecimalParameter(20, 40, decimals=1, default=30.1, space="buy")
buy_rsi = IntParameter(20, 40, default=30, space="buy")
buy_adx_enabled = BooleanParameter(default=True, space="buy")
buy_rsi_enabled = CategoricalParameter([True, False], default=False,
space="buy")
buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"],
default="bb_lower", space="buy")
The above definition says: I have five parameters I want to randomly combine to
find the best combination.
buy_rsi is an integer parameter, which will be tested between 20 and 40. This space
has a size of 20.
buy_adx is a decimal parameter, which will be evaluated between 20 and 40 with 1
decimal place (so values are 20.1, 20.2, ...). This space has a size of 200.
Then we have three category variables. First two are either True or False. We use
these to either enable or disable the ADX and RSI guards. The last one we call
trigger and use it to decide which buy trigger we want to use.
# TRIGGERS
if self.buy_trigger.value == 'bb_lower':
[Link](dataframe['close'] < dataframe['bb_lowerband'])
if self.buy_trigger.value == 'macd_cross_signal':
[Link](qtpylib.crossed_above(
dataframe['macd'], dataframe['macdsignal']
))
if conditions:
[Link][
reduce(lambda x, y: x & y, conditions),
'enter_long'] = 1
return dataframe
Hyperopt will now call populate_entry_trend() many times (epochs) with different
value combinations.
It will use the given historical data and simulate buys based on the buy signals
generated with the above function.
Based on the results, hyperopt will tell you which parameter combination produced
the best results (based on the configured loss function).
Note
The above setup expects to find ADX, RSI and Bollinger Bands in the populated
indicators. When you want to test an indicator that isn't used by the bot
currently, remember to add it to the populate_indicators() method in your strategy
or hyperopt file.
Parameter types
There are four parameter types each suited for different purposes.
optimize - when set to False, the parameter will not be included in optimization
process. (Default: True)
load - when set to False, results of a previous hyperopt run (in buy_params and
sell_params either in your strategy or the JSON output file) will not be used as
the starting value for subsequent hyperopts. The default value specified in the
parameter will be used instead. (Default: True)
Effects of load=False on backtesting
Be aware that setting the load option to False will mean backtesting will also use
the default value specified in the parameter and not the value found through
hyperoptimisation.
Warning
import [Link] as ta
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
minimal_roi = {
"0": 0.10
}
# Define the parameter spaces
buy_ema_short = IntParameter(3, 50, default=5)
buy_ema_long = IntParameter(15, 200, default=50)
return dataframe
if conditions:
[Link][
reduce(lambda x, y: x & y, conditions),
'enter_long'] = 1
return dataframe
if conditions:
[Link][
reduce(lambda x, y: x & y, conditions),
'exit_long'] = 1
return dataframe
Breaking it down:
Hyperopt itself will then use the selected value to create the buy and sell
signals.
While this strategy is most likely too simple to provide consistent profit, it
should serve as an example how optimize indicator parameters.
Note
self.buy_ema_short.range will act differently between hyperopt and other modes. For
hyperopt, the above example may generate 48 new columns, however for all other
modes (backtesting, dry/live), it will only generate the column for the selected
value. You should therefore avoid using the resulting column with explicit values
(values other than self.buy_ema_short.value).
Note
Performance tip
Optimizing protections
Freqtrade can also optimize protections. How you optimize protections is up to you,
and the following should be considered as example only.
The strategy will simply need to define the "protections" entry as property
returning a list of protection configurations.
import [Link] as ta
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
# Define the parameter spaces
cooldown_lookback = IntParameter(2, 48, default=5, space="protection",
optimize=True)
stop_duration = IntParameter(12, 200, default=5, space="protection",
optimize=True)
use_stop_protection = BooleanParameter(default=True, space="protection",
optimize=True)
@property
def protections(self):
prot = []
[Link]({
"method": "CooldownPeriod",
"stop_duration_candles": self.cooldown_lookback.value
})
if self.use_stop_protection.value:
[Link]({
"method": "StoplossGuard",
"lookback_period_candles": 24 * 3,
"trade_limit": 4,
"stop_duration_candles": self.stop_duration.value,
"only_per_pair": False
})
return prot
Note
The protection space is not part of the default space, and is only available with
the Parameters Hyperopt interface, not with the legacy hyperopt interface (which
required separate hyperopt files). Freqtrade will also automatically change the "--
enable-protections" flag if the protection space is selected.
Warning
class MyAwesomeStrategy(IStrategy):
protections = [
{
"method": "CooldownPeriod",
"stop_duration_candles": 4
}
]
Result
class MyAwesomeStrategy(IStrategy):
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration_candles": 4
}
]
You will then obviously also change potential interesting entries to parameters to
allow hyper-optimization.
Optimizing max_entry_position_adjustment
While max_entry_position_adjustment is not a separate space, it can still be used
in hyperopt by using the property approach shown above.
import [Link] as ta
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
@property
def max_entry_position_adjustment(self):
return self.max_epa.value
A loss function must be specified via the --hyperopt-loss <Class-name> argument (or
optionally via the configuration under the "hyperopt_loss" key). This class should
be in its own file within the user_data/hyperopts/ directory.
Execute Hyperopt
Once you have updated your hyperopt configuration you can run it. Because hyperopt
tries a lot of combinations to find the best parameters it will take time to get a
good result.
The --spaces all option determines that all possible parameters should be
optimized. Possibilities are listed below.
Note
Hyperopt will store hyperopt results with the timestamp of the hyperopt start time.
Reading commands (hyperopt-list, hyperopt-show) can use --hyperopt-filename
<filename> to read and display older hyperopt results. You can find a list of
filenames with ls -l user_data/hyperopt_results/.
Full command:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC
(0.7722%). Avg duration 180.4 mins. Objective: 1.94367
# Buy hyperspace params:
buy_params = {
'buy_adx': 44,
'buy_rsi': 29,
'buy_adx_enabled': False,
'buy_rsi_enabled': True,
'buy_trigger': 'bb_lower'
}
You should understand this result like:
Your strategy class can also contain these results explicitly. Simply copy hyperopt
results block and paste them at class level, replacing old parameters (if any). New
parameters will automatically be loaded next time strategy is executed.
Transferring your whole hyperopt result to your strategy would then look like:
class MyAwesomeStrategy(IStrategy):
# Buy hyperspace params:
buy_params = {
'buy_adx': 44,
'buy_rsi': 29,
'buy_adx_enabled': False,
'buy_rsi_enabled': True,
'buy_trigger': 'bb_lower'
}
Note
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC
(0.7722%). Avg duration 180.4 mins. Objective: 1.94367
# ROI table:
minimal_roi = {
0: 0.10674,
21: 0.09158,
78: 0.03634,
118: 0
}
In order to use this best ROI table found by Hyperopt in backtesting and for live
trades/dry-run, copy-paste it as the value of the minimal_roi attribute of your
custom strategy:
# step 1m 5m 1h 1d
1 0 0.011...0.119 0 0.03...0.31 0 0.068...0.711 0
0.121...1.258
2 2...8 0.007...0.042 10...40 0.02...0.11 120...480 0.045...0.252
2880...11520 0.081...0.446
3 4...20 0.003...0.015 20...100 0.01...0.04 240...1200
0.022...0.091 5760...28800 0.040...0.162
4 6...44 0.0 30...220 0.0 360...2640 0.0 8640...63360 0.0
These ranges should be sufficient in most cases. The minutes in the steps (ROI dict
keys) are scaled linearly depending on the timeframe used. The ROI values in the
steps (ROI dict values) are scaled logarithmically depending on the timeframe used.
Override the roi_space() method if you need components of the ROI tables to vary in
other ranges. Override the generate_roi_table() and roi_space() methods and
implement your own custom approach for generation of the ROI tables during
hyperoptimization if you need a different structure of the ROI tables or other
amount of rows (steps).
A sample for these methods can be found in the overriding pre-defined spaces
section.
To limit the search space further, Decimals are limited to 3 decimal places (a
precision of 0.001). This is usually sufficient, every value more precise than this
will usually result in overfitted results. You can however overriding pre-defined
spaces to change this to your needs.
Understand Hyperopt Stoploss results
If you are optimizing stoploss values (i.e. if optimization search-space contains
'all', 'default' or 'stoploss'), your result will look as follows and include
stoploss:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC
(0.7722%). Avg duration 180.4 mins. Objective: 1.94367
stoploss: -0.27996
In order to use this best stoploss value found by Hyperopt in backtesting and for
live trades/dry-run, copy-paste it as the value of the stoploss attribute of your
custom strategy:
If you have the stoploss_space() method in your custom hyperopt file, remove it in
order to utilize Stoploss hyperoptimization space generated by Freqtrade by
default.
Override the stoploss_space() method and define the desired range in it if you need
stoploss values to vary in other range during hyperoptimization. A sample for this
method can be found in the overriding pre-defined spaces section.
To limit the search space further, Decimals are limited to 3 decimal places (a
precision of 0.001). This is usually sufficient, every value more precise than this
will usually result in overfitted results. You can however overriding pre-defined
spaces to change this to your needs.
Best result:
45/100: 606 trades. Avg profit 1.04%. Total profit 0.31555614 BTC
( 630.48%). Avg duration 150.3 mins. Objective: -1.10161
# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.02001
trailing_stop_positive_offset = 0.06038
trailing_only_offset_is_reached = True
In order to use these best trailing stop parameters found by Hyperopt in
backtesting and for live trades/dry-run, copy-paste them as the values of the
corresponding attributes of your custom strategy:
# Trailing stop
# These attributes will be overridden if the config file contains corresponding
values.
trailing_stop = True
trailing_stop_positive = 0.02001
trailing_stop_positive_offset = 0.06038
trailing_only_offset_is_reached = True
As stated in the comment, you can also use it as the values of the corresponding
settings in the configuration file.
Override the trailing_space() method and define the desired range in it if you need
values of the trailing stop parameters to vary in other ranges during
hyperoptimization. A sample for this method can be found in the overriding pre-
defined spaces section.
To limit the search space further, Decimals are limited to 3 decimal places (a
precision of 0.001). This is usually sufficient, every value more precise than this
will usually result in overfitted results. You can however overriding pre-defined
spaces to change this to your needs.
Reproducible results
The search for optimal parameters starts with a few (currently 30) random
combinations in the hyperspace of parameters, random Hyperopt epochs. These random
epochs are marked with an asterisk character (*) in the first column in the
Hyperopt output.
The initial state for generation of these random values (random state) is
controlled by the value of the --random-state command line option. You can set it
to some arbitrary value of your choice to obtain reproducible results.
If you have not set this value explicitly in the command line options, Hyperopt
seeds the random state with some random value for you. The random state value for
each Hyperopt run is shown in the log, so you can copy and paste it into the --
random-state command line option to repeat the set of the initial random epochs
used.
If you have not changed anything in the command line options, configuration,
timerange, Strategy and Hyperopt classes, historical data and the Loss Function --
you should obtain same hyper-optimization results with same random state value
used.
Output formatting
By default, hyperopt prints colorized results -- epochs with positive profit are
printed in the green color. This highlighting helps you find epochs that can be
interesting for later analysis. Epochs with zero total profit or with negative
profits (losses) are printed in the normal color. If you do not need colorization
of results (for instance, when you are redirecting hyperopt output to a file) you
can switch colorization off by specifying the --no-color option in the command
line.
You can use the --print-all command line option if you would like to see all
results in the hyperopt output, not only the best ones. When --print-all is used,
current best results are also colorized by default -- they are printed in bold
(bright) style. This can also be switched off with the --no-color command line
option.
By default, hyperopt emulates the behavior of the Freqtrade Live Run/Dry Run, where
only one open trade is allowed for every traded pair. The total number of trades
open for all pairs is also limited by the max_open_trades setting. During
Hyperopt/Backtesting this may lead to some potential trades to be hidden (or
masked) by previously open trades.
Note
Dry/live runs will NOT use position stacking - therefore it does make sense to also
validate the strategy without this as it's closer to reality.
You can also enable position stacking in the configuration file by explicitly
setting "position_stacking"=true.
Example:
To achieve same the results (number of trades, their durations, profit, etc.) as
during Hyperopt, please use the same configuration and parameters (timerange,
timeframe, ...) used for hyperopt --dmmp/--disable-max-market-positions and --
eps/--enable-position-stacking for Backtesting.
You may have added parameters to hyperopt in populate_indicators() where they will
be calculated only once for all epochs. If you are, for example, trying to optimise
multiple SMA timeperiod values, the hyperoptable timeperiod parameter should be
placed in populate_entry_trend() which is calculated every epoch. See Optimizing an
indicator parameter.
If you have disabled the auto-export of hyperopt parameters into the JSON
parameters file, double-check to make sure you transferred all hyperopted values
into your strategy correctly.
Check the logs to verify what parameters are being set and what values are being
used.
Pay special care to the stoploss, max_open_trades and trailing stoploss parameters,
as these are often set in configuration files, which override changes to the
strategy. Check the logs of your backtest to ensure that there were no parameters
inadvertently set by the configuration (like stoploss, max_open_trades or
trailing_stop).
Verify that you do not have an unexpected parameters JSON file overriding the
parameters or the default hyperopt settings in your strategy.
Verify that any protections that are enabled in backtesting are also enabled when
hyperopting, and vice versa. When using --space protection, protections are auto-
enabled for hyperopting.
Advanced Strategies
This page explains some advanced concepts available for strategies. If you're just
getting started, please familiarize yourself with the Freqtrade basics and methods
described in Strategy Customization first.
The call sequence of the methods described here is covered under bot execution
logic. Those docs are also helpful in deciding which method is most suitable for
your customisation needs.
Note
Tip
Start off with a strategy template containing all available callback methods by
running freqtrade new-strategy --strategy MyAwesomeStrategy --template advanced
For the data to be able to be stored within the database, freqtrade must serialized
the data. This is done by converting the data to a JSON formatted string. Freqtrade
will attempt to reverse this action on retrieval, so from a strategy perspective,
this should not be relevant.
class AwesomeStrategy(IStrategy):
entry_adjustment_count = trade.get_custom_data(key='num_entry_adjustments')
trade_entry_type = trade.get_custom_data(key='entry_type')
if entry_adjustment_count is None:
if current_profit > 0.01 and (current_time - timedelta(minutes=100) >
trade.open_date_utc):
return True, 'exit_1'
else
if entry_adjustment_count > 0 and if current_profit > 0.05:
return True, 'exit_2'
if trade_entry_type == 'breakout' and current_profit > 0.1:
return True, 'exit_3
Note
It is recommended that simple data types are used [bool, int, float, str] to ensure
no issues when serializing the data that needs to be stored. Storing big junks of
data may lead to unintended side-effects, like a database becoming big (and as a
consequence, also slow).
Non-serializable data
If supplied data cannot be serialized a warning is logged and the entry for the
specified key will contain None as data.
All attributes
Storing information (Non-Persistent)
Deprecated
Storing information
Dataframe access
You may access dataframe in various strategy functions by querying it from
dataprovider.
class AwesomeStrategy(IStrategy):
def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str,
amount: float,
rate: float, time_in_force: str, exit_reason: str,
current_time: 'datetime', **kwargs) -> bool:
# Obtain pair dataframe.
dataframe, _ = [Link].get_analyzed_dataframe(pair, [Link])
# In dry/live runs trade open date will not match candle open date
therefore it must be
# rounded.
trade_date = timeframe_to_prev_date([Link], trade.open_date_utc)
# Look up trade candle.
trade_candle = [Link][dataframe['date'] == trade_date]
# trade_candle may be empty for trades that just opened as it is still
incomplete.
if not trade_candle.empty:
trade_candle = trade_candle.squeeze()
# <...>
Using .iloc[-1]
You can use .iloc[-1] here because get_analyzed_dataframe() only returns candles
that backtesting is allowed to see. This will not work in populate_* methods, so
make sure to not use .iloc[] in that area. Also, this will only work starting with
version 2021.5.
Enter Tag
When your strategy has multiple buy signals, you can name the signal that
triggered. Then you can access your buy signal on custom_exit
return dataframe
Warning
There is only one enter_tag column, which is used for both long and short trades.
As a consequence, this column must be treated as "last write wins" (it's just a
dataframe column after all). In fancy situations, where multiple signals collide
(or if signals are deactivated again based on different conditions), this can lead
to odd results with the wrong tag applied to an entry signal. These results are a
consequence of the strategy overwriting prior tags - where the last tag will
"stick" and will be the one freqtrade will use.
Exit tag
Similar to Entry Tagging, you can also specify an exit tag.
return dataframe
The provided exit-tag is then used as sell-reason - and shown as such in backtest
results.
Note
Strategy version
You can implement custom strategy versioning by using the "version" method, and
returning the version you would like this strategy to have.
You should make sure to implement proper version control (like a git repository)
alongside this, as freqtrade will not keep historic versions of your strategy, so
it's up to the user to be able to eventually roll back to a prior version of the
strategy.
Derived strategies
The strategies can be derived from other strategies. This avoids duplication of
your custom strategy code. You can use this technique to override small parts of
your main strategy, leaving the rest untouched:
user_data/strategies/[Link]
class MyAwesomeStrategy(IStrategy):
...
stoploss = 0.13
trailing_stop = False
# All other attributes and methods are here as they
# should be in any custom strategy...
...
user_data/strategies/[Link]
While keeping the subclass in the same file is technically possible, it can lead to
some problems with hyperopt parameter files, we therefore recommend to use separate
strategy files, and import the parent strategy as shown above.
Embedding Strategies
Freqtrade provides you with an easy way to embed the strategy into your
configuration file. This is done by utilizing BASE64 encoding and providing this
string at the strategy configuration field, in your chosen config file.
"strategy": "NameOfStrategy:BASE64String"
Please ensure that 'NameOfStrategy' is identical to the strategy name!
Performance warning
When executing a strategy, one can sometimes be greeted by the following in the
logs
PerformanceWarning: DataFrame is highly fragmented.
This is a warning from pandas and as the warning continues to say: use
[Link](axis=1). This can have slight performance implications, which are usually
only visible during hyperopt (when optimizing an indicator).
For example:
frames = [dataframe]
for val in self.buy_ema_short.range:
[Link](DataFrame({
f'ema_short_{val}': [Link](dataframe, timeperiod=val)
}))
Advanced Hyperopt
This page explains some advanced Hyperopt topics that may require higher coding
skills and Python knowledge than creation of an ordinal hyperoptimization class.
A sample of this can be found below, which is identical to the Default Hyperopt
loss implementation. A full sample can be found in userdata/hyperopts.
TARGET_TRADES = 600
EXPECTED_MAX_PROFIT = 3.0
MAX_ACCEPTED_TRADE_DURATION = 300
class SuperDuperHyperOptLoss(IHyperOptLoss):
"""
Defines the default loss function for hyperopt
"""
@staticmethod
def hyperopt_loss_function(
*,
results: DataFrame,
trade_count: int,
min_date: datetime,
max_date: datetime,
config: Config,
processed: Dict[str, DataFrame],
backtest_stats: Dict[str, Any],
**kwargs,
) -> float:
"""
Objective function, returns smaller number for better results
This is the legacy algorithm (used until now in freqtrade).
Weights are distributed as follows:
* 0.4 to trade duration
* 0.25: Avoiding trade loss
* 1.0 to total profit, compared to the expected value
(`EXPECTED_MAX_PROFIT`) defined above
"""
total_profit = results['profit_ratio'].sum()
trade_duration = results['trade_duration'].mean()
results: DataFrame containing the resulting trades. The following columns are
available in results (corresponds to the output-file of backtesting when used with
--export trades):
pair, profit_ratio, profit_abs, open_date, open_rate, fee_open, close_date,
close_rate, fee_close, amount, trade_duration, is_open, exit_reason, stake_amount,
min_rate, max_rate, stop_loss_ratio, stop_loss_abs
trade_count: Amount of trades (identical to len(results))
min_date: Start date of the timerange used
min_date: End date of the timerange used
config: Config object used (Note: Not all strategy-related parameters will be
updated here if they are part of a hyperopt space).
processed: Dict of Dataframes with the pair as keys containing the data used for
backtesting.
backtest_stats: Backtesting statistics using the same format as the backtesting
file "strategy" substructure. Available fields can be seen in
generate_strategy_stats() in optimize_reports.py.
This function needs to return a floating point number (float). Smaller numbers will
be interpreted as better results. The parameters and balancing for this is up to
you.
Note
This function is called once per epoch - so please make sure to have this as
optimized as possible to not slow hyperopt down unnecessarily.
Please keep the arguments *args and **kwargs in the interface to allow us to extend
this interface in the future.
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
# Define a custom stoploss space.
def stoploss_space():
return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')]
roi_table = {}
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
return roi_table
Dynamic parameters
Parameters can also be defined dynamically, but must be available to the instance
once the bot_start() callback has been called.
class MyAwesomeStrategy(IStrategy):
# ...
Warning
Parameters created this way will not show up in the list-strategies parameter
count.
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
def generate_estimator(dimensions: List['Dimension'], **kwargs):
return "RF"
Possible values are either one of "GP", "RF", "ET", "GBRT" (Details can be found in
the scikit-optimize documentation), or "an instance of a class that inherits from
RegressorMixin (from sklearn) and where the predict method has an optional
return_std argument, which returns std(Y | x) along with E[Y | x]".
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
def generate_estimator(dimensions: List['Dimension'], **kwargs):
from [Link] import ExtraTreesRegressor
# Corresponds to "ET" - but allows additional parameters.
return ExtraTreesRegressor(n_estimators=100)
The dimensions parameter is the list of [Link] objects corresponding
to the parameters to be optimized. It can be used to create isotropic kernels for
the [Link] estimator. Here's an example:
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
def generate_estimator(dimensions: List['Dimension'], **kwargs):
from [Link] import cook_estimator
from [Link].gaussian_process.kernels import (Matern,
ConstantKernel)
kernel_bounds = (0.0001, 10000)
kernel = (
ConstantKernel(1.0, kernel_bounds) *
Matern(length_scale=[Link](len(dimensions)),
length_scale_bounds=[kernel_bounds for d in dimensions], nu=2.5)
)
kernel += (
ConstantKernel(1.0, kernel_bounds) *
Matern(length_scale=[Link](len(dimensions)),
length_scale_bounds=[kernel_bounds for d in dimensions], nu=1.5)
)
Space options
For the additional spaces, scikit-optimize (in combination with Freqtrade) provides
the following space types:
We recommend to use SKDecimal instead of the Real space in almost all cases. While
the Real space provides full accuracy (up to ~16 decimal places) - this precision
is rarely needed, and leads to unnecessary long hyperopt times.
A corresponding real space Real(0.10, 0.15 name='xxx') on the other hand has an
almost unlimited number of possibilities ([0.10, 0.010000000001,
0.010000000002, ... 0.014999999999, 0.01500000000]).
Trade Object
Trade
A position freqtrade enters is stored in a Trade object - which is persisted to the
database. It's a core concept of freqtrade - and something you'll come across in
many sections of the documentation, which will most likely point you to this
location.
It will be passed to the strategy in many strategy callbacks. The object passed to
the strategy cannot be modified directly. Indirect modifications may occur based on
callback results.
Backtesting/hyperopt
Most methods will work in both backtesting / hyperopt and live/dry modes. During
backtesting, it's limited to usage in strategy callbacks. Usage in populate_*()
methods is not supported and will result in wrong results.
get_trades_proxy
When your strategy needs some information on existing (open or close) trades - it's
best to use Trade.get_trades_proxy().
Usage:
from [Link] import Trade
from datetime import timedelta
# ...
trade_hist = Trade.get_trades_proxy(pair='ETH/USDT', is_open=False,
open_date=current_date - timedelta(days=2))
get_trades_proxy() supports the following keyword arguments. All arguments are
optional - calling get_trades_proxy() without arguments will return a list of all
trades in the database.
# ...
profit = Trade.get_total_closed_profit()
total_open_trades_stakes
Retrieve the total stake_amount that's currently in trades.
# ...
profit = Trade.total_open_trades_stakes()
get_overall_performance
Retrieve the overall performance - similar to the /performance telegram command.
# ...
if [Link]['runmode'].value in ('live', 'dry_run'):
performance = Trade.get_overall_performance()
Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of
0.015).
Utility Subcommands
Besides the Live-Trade and Dry-Run run modes, the backtesting, edge and hyperopt
optimization subcommands, and the download-data subcommand which prepares
historical data, the bot contains a number of utility subcommands. They are
described in this section.
Create userdir
Creates the directory structure to hold your files for freqtrade. Will also create
strategy and hyperopt examples for you to get started. Can be used multiple times -
using --reset will reset the sample strategy and hyperopt files to their default
state.
optional arguments:
-h, --help show this help message and exit
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
--reset Reset sample files to their original state.
Warning
Using --reset may result in loss of data, since this will overwrite all sample
files without asking again.
├── backtest_results
├── data
├── hyperopt_results
├── hyperopts
│ ├── sample_hyperopt_loss.py
├── notebooks
│ └── strategy_analysis_example.ipynb
├── plot
└── strategies
└── sample_strategy.py
Create new config
Creates a new configuration file, asking some questions which are important
selections for a configuration.
optional arguments:
-h, --help show this help message and exit
-c PATH, --config PATH
Specify configuration file (default: `[Link]`).
Multiple --config options may be used. Can be set to `-`
to read config from stdin.
Warning
Only vital questions are asked. Freqtrade offers a lot more configuration
possibilities, which are listed in the Configuration documentation
options:
-h, --help show this help message and exit
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
--show-sensitive Show secrets in the output.
We try to remove all known sensitive information from the default output (without
--show-sensitive). Yet, please do double-check for sensitive values in your output
to make sure you're not accidentally exposing some private info.
optional arguments:
-h, --help show this help message and exit
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
-s NAME, --strategy NAME
Specify strategy class name which will be used by the
bot.
--template {full,minimal,advanced}
Use a template which is either `minimal`, `full`
(containing multiple sample indicators) or `advanced`.
Default: `full`.
Sample usage of new-strategy
This subcommand is useful for finding problems in your environment with loading
strategies: modules with strategies that contain errors and failed to load are
printed in red (LOAD FAILED), while strategies with duplicate names are printed in
yellow (DUPLICATE NAME).
usage: freqtrade list-strategies [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--strategy-path PATH] [-1] [--no-color]
[--recursive-strategy-search]
optional arguments:
-h, --help show this help message and exit
--strategy-path PATH Specify additional strategy lookup path.
-1, --one-column Print output in one column.
--no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file.
--recursive-strategy-search
Recursively search for a strategy in the strategies
folder.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Warning
Using these commands will try to load all python files from a directory. This can
be a security risk if untrusted files reside in this directory, since all module-
level code is executed.
freqtrade list-strategies
Example: Search strategies directory within the userdir.
This subcommand is useful for finding problems in your environment with loading
freqAI models: modules with models that contain errors and failed to load are
printed in red (LOAD FAILED), while models with duplicate names are printed in
yellow (DUPLICATE NAME).
usage: freqtrade list-freqaimodels [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--freqaimodel-path PATH] [-1] [--no-color]
optional arguments:
-h, --help show this help message and exit
--freqaimodel-path PATH
Specify additional lookup path for freqaimodels.
-1, --one-column Print output in one column.
--no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
List Exchanges
Use the list-exchanges subcommand to see the exchanges available for the bot.
optional arguments:
-h, --help show this help message and exit
-1, --one-column Print output in one column.
-a, --all Print all exchanges known to the ccxt library.
Example: see exchanges available for the bot:
$ freqtrade list-exchanges
Exchanges available for Freqtrade:
Exchange name Supported Markets Reason
------------------ ----------- ----------------------
------------------------------------------------------------------------
binance Official spot, isolated futures
bitmart Official spot
bybit spot, isolated futures
gate Official spot, isolated futures
htx Official spot
huobi spot
kraken Official spot
okx Official spot, isolated futures
Output reduced for clarity - supported and available exchanges may change over
time.
Values with "missing opt:" might need special configuration (e.g. using orderbook
if fetchTickers is missing) - but should in theory work (although we cannot
guarantee they will).
Example: see all exchanges supported by the ccxt library (including 'bad' ones,
i.e. those that are known to not work with Freqtrade)
$ freqtrade list-exchanges -a
All exchanges supported by the ccxt library:
Exchange name Valid Supported Markets Reason
------------------ ------- ----------- ----------------------
---------------------------------------------------------------------------------
binance True Official spot, isolated futures
bitflyer False spot missing:
fetchOrder. missing opt: fetchTickers.
bitmart True Official spot
bybit True spot, isolated futures
gate True Official spot, isolated futures
htx True Official spot
kraken True Official spot
okx True Official spot, isolated futures
Reduced output - supported and available exchanges may change over time.
List Timeframes
Use the list-timeframes subcommand to see the list of timeframes available for the
exchange.
usage: freqtrade list-timeframes [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--exchange EXCHANGE] [-1]
options:
-h, --help show this help message and exit
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
-1, --one-column Print output in one column.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Example: see the timeframes for the 'binance' exchange, set in the configuration
file:
Pairs are markets with the '/' character between the base currency part and the
quote currency part in the market symbol. For example, in the 'ETH/BTC' pair 'ETH'
is the base currency, while 'BTC' is the quote currency.
For pairs traded by Freqtrade the pair quote currency is defined by the value of
the stake_currency configuration setting.
You can print info about any pair/market with these subcommands - and you can
filter output by quote-currency using --quote BTC, or by base-currency using --base
ETH options correspondingly.
These subcommands have same usage and same set of available options:
usage: freqtrade list-markets [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [--exchange EXCHANGE]
[--print-list] [--print-json] [-1] [--print-csv]
[--base BASE_CURRENCY [BASE_CURRENCY ...]]
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]]
[-a] [--trading-mode {spot,margin,futures}]
usage: freqtrade list-pairs [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [--exchange EXCHANGE]
[--print-list] [--print-json] [-1] [--print-csv]
[--base BASE_CURRENCY [BASE_CURRENCY ...]]
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-a]
[--trading-mode {spot,margin,futures}]
options:
-h, --help show this help message and exit
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
--print-list Print list of pairs or market symbols. By default data
is printed in the tabular format.
--print-json Print list of pairs or market symbols in JSON format.
-1, --one-column Print output in one column.
--print-csv Print exchange pair or market data in the csv format.
--base BASE_CURRENCY [BASE_CURRENCY ...]
Specify base currency(-ies). Space-separated list.
--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]
Specify quote currency(-ies). Space-separated list.
-a, --all Print all pairs or market symbols. By default only
active ones are shown.
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
Select Trading mode
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
By default, only active pairs/markets are shown. Active pairs/markets are those
that can currently be traded on the exchange. You can use the -a/-all option to see
the list of all pairs/markets, including the inactive ones. Pairs may be listed as
untradeable if the smallest tradeable price for the market is very small, i.e. less
than 1e-11 (0.00000000001)
Examples
Print the list of active pairs with quote currency USD on exchange, specified in
the default configuration file (i.e. pairs on the "Binance" exchange) in JSON
format:
$ freqtrade list-pairs -c config_binance.json --all --base BTC ETH --quote USDT USD
--print-list
Print all markets on exchange "Kraken", in the tabular format:
options:
-h, --help show this help message and exit
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]
Specify quote currency(-ies). Space-separated list.
-1, --one-column Print output in one column.
--print-json Print list of pairs or market symbols in JSON format.
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
Examples
Show whitelist when using a dynamic pairlist.
optional arguments:
-h, --help show this help message and exit
--db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///[Link]` for
Live Run mode, `sqlite:///[Link]` for
Dry Run).
--db-url-from PATH Source db url to use when migrating a database.
Warning
Please ensure to only use this on an empty target database. Freqtrade will perform
a regular migration, but may fail if entries already existed.
Webserver mode
Experimental
Run freqtrade in webserver mode. Freqtrade will start the webserver and allow
FreqUI to start and control backtesting processes. This has the advantage that data
will not be reloaded between backtesting runs (as long as timeframe and timerange
remain identical). FreqUI will also show the backtesting results.
usage: freqtrade webserver [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
[--userdir PATH]
optional arguments:
-h, --help show this help message and exit
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Webserver mode - docker
You can also use webserver mode via docker. Starting a one-off container requires
the configuration of the port explicitly, as ports are not exposed by default. You
can use docker compose run --rm -p [Link]:8080:8080 freqtrade webserver to start
a one-off container that'll be removed once you stop it. This assumes that port
8080 is still available and no other bot is running on that port.
Alternatively, you can reconfigure the docker-compose file to have the command
updated:
command: >
webserver
--config /freqtrade/user_data/[Link]
You can now use docker compose up to start the webserver. This assumes that the
configuration has a webserver enabled and configured for docker (listening port =
[Link]).
Tip
Don't forget to reset the command back to the trade command if you want to start a
live or dry-run bot.
Strategy overfitting
usage: freqtrade backtesting-show [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--export-filename PATH] [--show-pair-list]
optional arguments:
-h, --help show this help message and exit
--export-filename PATH
Save backtest results to the file with this filename.
Requires `--export` to be set as well. Example:
`--export-filename=user_data/backtest_results/backtest
_today.json`
--show-pair-list Show backtesting pairlist sorted by profit.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Detailed backtest analysis
Advanced backtest result analysis.
optional arguments:
-h, --help show this help message and exit
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest [Link]
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--analysis-groups {0,1,2,3,4} [{0,1,2,3,4} ...]
grouping output - 0: simple wins/losses by enter tag,
1: by enter_tag, 2: by enter_tag and exit_tag, 3: by
pair and enter_tag, 4: by pair, enter_ and exit_tag
(this can get quite large)
--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]
Space separated list of entry signals to analyse.
Default: all. e.g. 'entry_tag_a entry_tag_b'
--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]
Space separated list of exit signals to analyse.
Default: all. e.g.
'exit_tag_a roi stop_loss trailing_stop_loss'
--indicator-list INDICATOR_LIST [INDICATOR_LIST ...]
Space separated list of indicators to analyse. e.g.
'close rsi bb_lowerband profit_abs'
--timerange YYYYMMDD-[YYYYMMDD]
Timerange to filter trades for analysis,
start inclusive, end exclusive. e.g.
20220101-20220201
--rejected
Print out rejected trades table
--analysis-to-csv
Write out tables to individual CSVs, by default to
'user_data/backtest_results' unless '--analysis-csv-path'
is given.
--analysis-csv-path [PATH]
Optional path where individual CSVs will be written. If not
used,
CSVs will be written to 'user_data/backtest_results'.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
List Hyperopt results
You can list the hyperoptimization epochs the Hyperopt module evaluated previously
with the hyperopt-list sub-command.
usage: freqtrade hyperopt-list [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [--best]
[--profitable] [--min-trades INT]
[--max-trades INT] [--min-avg-time FLOAT]
[--max-avg-time FLOAT] [--min-avg-profit FLOAT]
[--max-avg-profit FLOAT]
[--min-total-profit FLOAT]
[--max-total-profit FLOAT]
[--min-objective FLOAT] [--max-objective FLOAT]
[--no-color] [--print-json] [--no-details]
[--hyperopt-filename PATH] [--export-csv FILE]
optional arguments:
-h, --help show this help message and exit
--best Select only best epochs.
--profitable Select only profitable epochs.
--min-trades INT Select epochs with more than INT trades.
--max-trades INT Select epochs with less than INT trades.
--min-avg-time FLOAT Select epochs above average time.
--max-avg-time FLOAT Select epochs below average time.
--min-avg-profit FLOAT
Select epochs above average profit.
--max-avg-profit FLOAT
Select epochs below average profit.
--min-total-profit FLOAT
Select epochs above total profit.
--max-total-profit FLOAT
Select epochs below total profit.
--min-objective FLOAT
Select epochs above objective.
--max-objective FLOAT
Select epochs below objective.
--no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file.
--print-json Print output in JSON format.
--no-details Do not print best epoch details.
--hyperopt-filename FILENAME
Hyperopt result [Link]: `--hyperopt-
filename=hyperopt_results_2020-09-27_16-[Link]`
--export-csv FILE Export to CSV-File. This will disable table print.
Example: --export-csv [Link]
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Note
hyperopt-list will automatically use the latest available hyperopt results file.
You can override this using the --hyperopt-filename argument, and specify another,
available filename (without path!).
Examples
List all results, print details of the best result at the end:
freqtrade hyperopt-list
List only epochs with positive profit. Do not print the details of the best epoch,
so that the list can be iterated in a script:
usage: freqtrade hyperopt-show [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [--best]
[--profitable] [-n INT] [--print-json]
[--hyperopt-filename FILENAME] [--no-header]
[--disable-param-export]
[--breakdown {day,week,month}
[{day,week,month} ...]]
optional arguments:
-h, --help show this help message and exit
--best Select only best epochs.
--profitable Select only profitable epochs.
-n INT, --index INT Specify the index of the epoch to print details for.
--print-json Print output in JSON format.
--hyperopt-filename FILENAME
Hyperopt result [Link]: `--hyperopt-
filename=hyperopt_results_2020-09-27_16-[Link]`
--no-header Do not print epoch details header.
--disable-param-export
Disable automatic hyperopt parameter export.
--breakdown {day,week,month} [{day,week,month} ...]
Show backtesting breakdown per [day, week, month].
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Note
hyperopt-show will automatically use the latest available hyperopt results file.
You can override this using the --hyperopt-filename argument, and specify another,
available filename (without path!).
Examples
Print details for the epoch 168 (the number of the epoch is shown by the hyperopt-
list subcommand or by Hyperopt itself during hyperoptimization run):
usage: freqtrade show-trades [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [--db-url PATH]
[--trade-ids TRADE_IDS [TRADE_IDS ...]]
[--print-json]
optional arguments:
-h, --help show this help message and exit
--db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///[Link]` for
Live Run mode, `sqlite:///[Link]` for
Dry Run).
--trade-ids TRADE_IDS [TRADE_IDS ...]
Specify the list of trade ids.
--print-json Print output in JSON format.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
Examples
Print trades with id 2 and 3 as json
Conversion results
Strategy updater will work on a "best effort" approach. Please do your due
diligence and verify the results of the conversion. We also recommend to run a
python formatter (e.g. black) to format results in a sane manner.
usage: freqtrade strategy-updater [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--strategy-list STRATEGY_LIST
[STRATEGY_LIST ...]]
options:
-h, --help show this help message and exit
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
Provide a space-separated list of strategies to
be converted.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/[Link]` or `[Link]` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
This feature is still in it's testing phase. Should you notice something you think
is wrong please let us know via Discord or via Github Issue.
You can't run 2 bots on the same account with leverage. For leveraged / margin
trading, freqtrade assumes it's the only user of the account, and all liquidation
levels are calculated based on this assumption.
Do not trade with a leverage > 1 using a strategy that hasn't shown positive
results in a live run using the spot market. Check the stoploss of your strategy.
With a leverage of 2, a stoploss of 0.5 (50%) would be too low, and these trades
would be liquidated before reaching that stoploss. We do not assume any
responsibility for eventual losses that occur from using this software or this
mode.
Please only use advanced trading modes when you know how freqtrade (and your
strategy) works. Also, never risk more than what you can afford to lose.
If you already have an existing strategy, please read the strategy migration guide
to migrate your strategy from a freqtrade v2 strategy, to strategy of version 3
which can short and trade futures.
Shorting
Shorting is not possible when trading with trading_mode set to spot. To short
trade, trading_mode must be set to margin(currently unavailable) or futures, with
margin_mode set to cross(currently unavailable) or isolated
For a strategy to short, the strategy class must set the class variable can_short =
True
Please read strategy customization for instructions on how to set signals to enter
and exit short trades.
Understand trading_mode
The possible values are: spot (default), margin(Currently unavailable) or futures.
Spot
Regular trading mode (low risk)
Because the capital must always be re-payed, exchanges will liquidate (forcefully
sell the traders assets) a trade made using borrowed capital when the total value
of assets in the leverage account drops to a certain point (a point where the total
value of losses is less than the value of the collateral that the trader actually
owns in the leverage account), in order to ensure that the trader has enough
capital to pay the borrowed assets back to the exchange. The exchange will also
charge a liquidation fee, adding to the traders losses.
For this reason, DO NOT TRADE WITH LEVERAGE IF YOU DON'T KNOW EXACTLY WHAT YOUR
DOING. LEVERAGE TRADING IS HIGH RISK, AND CAN RESULT IN THE VALUE OF YOUR ASSETS
DROPPING TO 0 VERY QUICKLY, WITH NO CHANCE OF INCREASING IN VALUE AGAIN.
Futures
Perpetual swaps (also known as Perpetual Futures) are contracts traded at a price
that is closely tied to the underlying asset they are based off of (ex.). You are
not trading the actual asset but instead are trading a derivative contract.
Perpetual swap contracts can last indefinitely, in contrast to futures or option
contracts.
In addition to the gains/losses from the change in price of the futures contract,
traders also exchange funding fees, which are gains/losses worth an amount that is
derived from the difference in price between the futures contract and the
underlying asset. The difference in price between a futures contract and the
underlying asset varies between exchanges.
To trade in futures markets, you'll have to set trading_mode to "futures". You will
also have to pick a "margin mode" (explanation below) - with freqtrade currently
only supporting isolated margin.
"trading_mode": "futures",
"margin_mode": "isolated"
Pair namings
Freqtrade follows the ccxt naming conventions for futures. A futures pair will
therefore have the naming of base/quote:settle (e.g. ETH/USDT:USDT).
Margin mode
On top of trading_mode - you will also have to configure your margin_mode. While
freqtrade currently only supports one margin mode, this will change, and by
configuring it now you're all set for future updates.
"margin_mode": "isolated"
Cross margin mode (currently unavailable)
One account is used to share collateral between markets (trading pairs). Margin is
taken from total account balance to avoid liquidation when needed.
"margin_mode": "cross"
Please read the exchange specific notes for exchanges that support this mode and
how they differ.
Warning
Higher leverage also equals higher risk - be sure you fully understand the
implications of using leverage!
Understand liquidation_buffer
Defaults to 0.05
A ratio specifying how large of a safety net to place between the liquidation price
and the stoploss to prevent a position from reaching the liquidation price. This
artificial liquidation price is calculated as:
Currently Freqtrade is able to calculate liquidation prices, but does not calculate
liquidation fees. Setting your liquidation_buffer to 0.0, or using a low
liquidation_buffer could result in your positions being liquidated. Freqtrade does
not track liquidation fees, so liquidations will result in inaccurate profit/loss
results for your bot. If you use a low liquidation_buffer, it is recommended to use
stoploss_on_exchange if your exchange supports this.
This will not overwrite funding rates that are available from the exchange, but
bear in mind that setting a false funding rate will mean backtesting results will
be inaccurate for historical timeranges where funding rates are not available.
Developer
Margin mode
For shorts, the currency which pays the interest fee for the borrowed currency is
purchased at the same time of the closing trade (This means that the amount
purchased in short closing trades is greater than the amount sold in short opening
trades).
For longs, the currency which pays the interest fee for the borrowed will already
be owned by the user and does not need to be purchased. The interest is subtracted
from the close_value of the trade.
Futures mode
Funding fees are either added or subtracted from the total amount of a trade