Deployed 7e7e475 to develop in en with MkDocs 1.6.1 and mike 2.1.4
This commit is contained in:
@@ -2091,8 +2091,8 @@ determine indicator values on the signal candle that resulted in a trade opening
|
||||
</div>
|
||||
<p>We need to run backtesting with the <code>--export</code> option set to <code>signals</code> to enable the exporting of
|
||||
signals <strong>and</strong> trades:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange=<timerange> --export=signals</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--timeframe<span class="w"> </span><tf><span class="w"> </span>--strategy<span class="w"> </span><strategy_name><span class="w"> </span>--timerange<span class="o">=</span><timerange><span class="w"> </span>--export<span class="o">=</span>signals
|
||||
</code></pre></div>
|
||||
<p>This will tell freqtrade to output a pickled dictionary of strategy, pairs and corresponding
|
||||
DataFrame of the candles that resulted in entry and exit signals.
|
||||
Depending on how many entries your strategy makes, this file may get quite large, so periodically check your <code>user_data/backtest_results</code> folder to delete old exports.</p>
|
||||
@@ -2101,8 +2101,8 @@ backtesting with the <code>--cache none</code> option to make sure no cached res
|
||||
<p>If all goes well, you should now see a <code>backtest-result-{timestamp}_signals.pkl</code> and <code>backtest-result-{timestamp}_exited.pkl</code> files in the <code>user_data/backtest_results</code> folder.</p>
|
||||
<p>To analyze the entry/exit tags, we now need to use the <code>freqtrade backtesting-analysis</code> command
|
||||
with <code>--analysis-groups</code> option provided with space-separated arguments:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-groups 0 1 2 3 4 5</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">5</span>
|
||||
</code></pre></div>
|
||||
<p>This command will read from the last backtesting results. The <code>--analysis-groups</code> option is
|
||||
used to specify the various tabular outputs showing the profit of each group or trade,
|
||||
ranging from the simplest (0) to the most detailed per pair, per buy and per sell tag (4):</p>
|
||||
@@ -2118,30 +2118,32 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel
|
||||
<h3 id="using-backtest-filename">Using backtest-filename<a class="headerlink" href="#using-backtest-filename" title="Permanent link">¶</a></h3>
|
||||
<p>By default, <code>backtesting-analysis</code> processes the most recent backtest results in the <code>user_data/backtest_results</code> directory.
|
||||
If you want to analyze results from an earlier backtest, use the <code>--backtest-filename</code> option to specify the desired file. This lets you revisit and re-analyze historical backtest outputs at any time by providing the filename of the relevant backtest result:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting -c <config.json> --strategy <strategy_name> --timerange <timerange> --export signals --backtest-filename backtest-result-2025-03-05_20-38-34.zip</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--strategy<span class="w"> </span><strategy_name><span class="w"> </span>--timerange<span class="w"> </span><timerange><span class="w"> </span>--export<span class="w"> </span>signals<span class="w"> </span>--backtest-filename<span class="w"> </span>backtest-result-2025-03-05_20-38-34.zip
|
||||
</code></pre></div>
|
||||
<p>You should see some output similar to below in the logs with the name of the timestamped filename that was exported:</p>
|
||||
<p><code>2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "mystrat_backtest-2022-06-14_16-28-32.json"</code></p>
|
||||
<div class="highlight"><pre><span></span><code>2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "mystrat_backtest-2022-06-14_16-28-32.json"
|
||||
</code></pre></div>
|
||||
<p>You can then use that filename in <code>backtesting-analysis</code>:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --backtest-filename=backtest-result-2025-03-05_20-38-34.zip</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--backtest-filename<span class="o">=</span>backtest-result-2025-03-05_20-38-34.zip
|
||||
</code></pre></div>
|
||||
<p>To use a result from a different results directory, you can use <code>--backtest-directory</code> to specify the directory</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --backtest-directory custom_results/ --backtest-filename backtest-result-2025-03-05_20-38-34.zip</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--backtest-directory<span class="w"> </span>custom_results/<span class="w"> </span>--backtest-filename<span class="w"> </span>backtest-result-2025-03-05_20-38-34.zip
|
||||
</code></pre></div>
|
||||
<h3 id="tuning-the-buy-tags-and-sell-tags-to-display">Tuning the buy tags and sell tags to display<a class="headerlink" href="#tuning-the-buy-tags-and-sell-tags-to-display" title="Permanent link">¶</a></h3>
|
||||
<p>To show only certain buy and sell tags in the displayed output, use the following two options:</p>
|
||||
<p><code>--enter-reason-list : Space-separated list of enter signals to analyse. Default: "all"
|
||||
--exit-reason-list : Space-separated list of exit signals to analyse. Default: "all"</code></p>
|
||||
<div class="highlight"><pre><span></span><code>--enter-reason-list : Space-separated list of enter signals to analyse. Default: "all"
|
||||
--exit-reason-list : Space-separated list of exit signals to analyse. Default: "all"
|
||||
</code></pre></div>
|
||||
<p>For example:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-groups 0 2 --enter-reason-list enter_tag_a enter_tag_b --exit-reason-list roi custom_exit_tag_a stop_loss</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>--enter-reason-list<span class="w"> </span>enter_tag_a<span class="w"> </span>enter_tag_b<span class="w"> </span>--exit-reason-list<span class="w"> </span>roi<span class="w"> </span>custom_exit_tag_a<span class="w"> </span>stop_loss
|
||||
</code></pre></div>
|
||||
<h3 id="outputting-signal-candle-indicators">Outputting signal candle indicators<a class="headerlink" href="#outputting-signal-candle-indicators" title="Permanent link">¶</a></h3>
|
||||
<p>The real power of <code>freqtrade backtesting-analysis</code> comes from the ability to print out the indicator
|
||||
values present on signal candles to allow fine-grained investigation and tuning of buy signal
|
||||
indicators. To print out a column for a given set of indicators, use the <code>--indicator-list</code>
|
||||
option:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-groups 0 2 --enter-reason-list enter_tag_a enter_tag_b --exit-reason-list roi custom_exit_tag_a stop_loss --indicator-list rsi rsi_1h bb_lowerband ema_9 macd macdsignal</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>--enter-reason-list<span class="w"> </span>enter_tag_a<span class="w"> </span>enter_tag_b<span class="w"> </span>--exit-reason-list<span class="w"> </span>roi<span class="w"> </span>custom_exit_tag_a<span class="w"> </span>stop_loss<span class="w"> </span>--indicator-list<span class="w"> </span>rsi<span class="w"> </span>rsi_1h<span class="w"> </span>bb_lowerband<span class="w"> </span>ema_9<span class="w"> </span>macd<span class="w"> </span>macdsignal
|
||||
</code></pre></div>
|
||||
<p>The indicators have to be present in your strategy's main DataFrame (either for your main
|
||||
timeframe or for informative timeframes) otherwise they will simply be ignored in the script
|
||||
output.</p>
|
||||
@@ -2166,8 +2168,8 @@ automatically accessible by including them on the indicator-list, and these incl
|
||||
<li><strong>profit_abs :</strong> absolute profit return of the trade </li>
|
||||
</ul>
|
||||
<h4 id="sample-output-for-indicator-values">Sample Output for Indicator Values<a class="headerlink" href="#sample-output-for-indicator-values" title="Permanent link">¶</a></h4>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c user_data/config.json --analysis-groups 0 --indicator-list chikou_span tenkan_sen</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span>user_data/config.json<span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span>--indicator-list<span class="w"> </span>chikou_span<span class="w"> </span>tenkan_sen<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<p>In this example,
|
||||
we aim to display the <code>chikou_span</code> and <code>tenkan_sen</code> indicator values at both the entry and exit points of trades.</p>
|
||||
<p>A sample output for indicators might look like this:</p>
|
||||
@@ -2222,33 +2224,34 @@ to distinguish the values at the entry and exit points of the trade.</p>
|
||||
<h4 id="filtering-indicators-based-on-entry-or-exit-signals">Filtering Indicators Based on Entry or Exit Signals<a class="headerlink" href="#filtering-indicators-based-on-entry-or-exit-signals" title="Permanent link">¶</a></h4>
|
||||
<p>The <code>--indicator-list</code> option, by default, displays indicator values for both entry and exit signals. To filter the indicator values exclusively for entry signals, you can use the <code>--entry-only</code> argument. Similarly, to display indicator values only at exit signals, use the <code>--exit-only</code> argument.</p>
|
||||
<p>Example: Display indicator values at entry signals:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c user_data/config.json --analysis-groups 0 --indicator-list chikou_span tenkan_sen --entry-only</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span>user_data/config.json<span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span>--indicator-list<span class="w"> </span>chikou_span<span class="w"> </span>tenkan_sen<span class="w"> </span>--entry-only
|
||||
</code></pre></div>
|
||||
<p>Example: Display indicator values at exit signals:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c user_data/config.json --analysis-groups 0 --indicator-list chikou_span tenkan_sen --exit-only</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span>user_data/config.json<span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span>--indicator-list<span class="w"> </span>chikou_span<span class="w"> </span>tenkan_sen<span class="w"> </span>--exit-only
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>When using these filters, the indicator names will not be suffixed with <code>(entry)</code> or <code>(exit)</code>.</p>
|
||||
</div>
|
||||
<h3 id="filtering-the-trade-output-by-date">Filtering the trade output by date<a class="headerlink" href="#filtering-the-trade-output-by-date" title="Permanent link">¶</a></h3>
|
||||
<p>To show only trades between dates within your backtested timerange, supply the usual <code>timerange</code> option in <code>YYYYMMDD-[YYYYMMDD]</code> format:</p>
|
||||
<p><code>--timerange : Timerange to filter output trades, start date inclusive, end date exclusive. e.g. 20220101-20221231</code></p>
|
||||
<div class="highlight"><pre><span></span><code>--timerange : Timerange to filter output trades, start date inclusive, end date exclusive. e.g. 20220101-20221231
|
||||
</code></pre></div>
|
||||
<p>For example, if your backtest timerange was <code>20220101-20221231</code> but you only want to output trades in January:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --timerange 20220101-20220201</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--timerange<span class="w"> </span><span class="m">20220101</span>-20220201
|
||||
</code></pre></div>
|
||||
<h3 id="printing-out-rejected-signals">Printing out rejected signals<a class="headerlink" href="#printing-out-rejected-signals" title="Permanent link">¶</a></h3>
|
||||
<p>Use the <code>--rejected-signals</code> option to print out rejected signals.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --rejected-signals</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--rejected-signals
|
||||
</code></pre></div>
|
||||
<h3 id="writing-tables-to-csv">Writing tables to CSV<a class="headerlink" href="#writing-tables-to-csv" title="Permanent link">¶</a></h3>
|
||||
<p>Some of the tabular outputs can become large, so printing them out to the terminal is not preferable.
|
||||
Use the <code>--analysis-to-csv</code> option to disable printing out of tables to standard out and write them to CSV files.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-to-csv</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-to-csv
|
||||
</code></pre></div>
|
||||
<p>By default this will write one file per output table you specified in the <code>backtesting-analysis</code> command, e.g.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-to-csv --rejected-signals --analysis-groups 0 1</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-to-csv<span class="w"> </span>--rejected-signals<span class="w"> </span>--analysis-groups<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">1</span>
|
||||
</code></pre></div>
|
||||
<p>This will write to <code>user_data/backtest_results</code>:</p>
|
||||
<ul>
|
||||
<li>rejected_signals.csv</li>
|
||||
@@ -2256,8 +2259,8 @@ freqtrade backtesting-analysis -c <config.json> --analysis-to-csv --reject
|
||||
<li>group_1.csv</li>
|
||||
</ul>
|
||||
<p>To override where the files will be written, also specify the <code>--analysis-csv-path</code> option.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting-analysis -c <config.json> --analysis-to-csv --analysis-csv-path another/data/path/</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting-analysis<span class="w"> </span>-c<span class="w"> </span><config.json><span class="w"> </span>--analysis-to-csv<span class="w"> </span>--analysis-csv-path<span class="w"> </span>another/data/path/
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1611,6 +1611,17 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#space-options" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Space options
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1918,6 +1929,17 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#space-options" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Space options
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1953,51 +1975,53 @@ class.</p>
|
||||
<p>To use a custom loss function class, make sure that the function <code>hyperopt_loss_function</code> is defined in your custom hyperopt loss class.
|
||||
For the sample below, you then need to add the command line parameter <code>--hyperopt-loss SuperDuperHyperOptLoss</code> to your hyperopt call so this function is being used.</p>
|
||||
<p>A sample of this can be found below, which is identical to the Default Hyperopt loss implementation. A full sample can be found in <a href="https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_loss.py">userdata/hyperopts</a>.</p>
|
||||
<p>``` python
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict</p>
|
||||
<p>from pandas import DataFrame</p>
|
||||
<p>from freqtrade.constants import Config
|
||||
from freqtrade.optimize.hyperopt import IHyperOptLoss</p>
|
||||
<p>TARGET_TRADES = 600
|
||||
EXPECTED_MAX_PROFIT = 3.0
|
||||
MAX_ACCEPTED_TRADE_DURATION = 300</p>
|
||||
<p>class SuperDuperHyperOptLoss(IHyperOptLoss):
|
||||
"""
|
||||
Defines the default loss function for hyperopt
|
||||
"""</p>
|
||||
<div class="codehilite"><pre><span></span><code>@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],
|
||||
starting_balance: float,
|
||||
**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()
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Dict</span>
|
||||
|
||||
trade_loss = 1 - 0.25 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.8)
|
||||
profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT)
|
||||
duration_loss = 0.4 * min(trade_duration / MAX_ACCEPTED_TRADE_DURATION, 1)
|
||||
result = trade_loss + profit_loss + duration_loss
|
||||
return result
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">pandas</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataFrame</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.constants</span><span class="w"> </span><span class="kn">import</span> <span class="n">Config</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.optimize.hyperopt</span><span class="w"> </span><span class="kn">import</span> <span class="n">IHyperOptLoss</span>
|
||||
|
||||
<span class="n">TARGET_TRADES</span> <span class="o">=</span> <span class="mi">600</span>
|
||||
<span class="n">EXPECTED_MAX_PROFIT</span> <span class="o">=</span> <span class="mf">3.0</span>
|
||||
<span class="n">MAX_ACCEPTED_TRADE_DURATION</span> <span class="o">=</span> <span class="mi">300</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">SuperDuperHyperOptLoss</span><span class="p">(</span><span class="n">IHyperOptLoss</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Defines the default loss function for hyperopt</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">hyperopt_loss_function</span><span class="p">(</span>
|
||||
<span class="o">*</span><span class="p">,</span>
|
||||
<span class="n">results</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span>
|
||||
<span class="n">trade_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">min_date</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span>
|
||||
<span class="n">max_date</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span>
|
||||
<span class="n">config</span><span class="p">:</span> <span class="n">Config</span><span class="p">,</span>
|
||||
<span class="n">processed</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">DataFrame</span><span class="p">],</span>
|
||||
<span class="n">backtest_stats</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span>
|
||||
<span class="n">starting_balance</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
|
||||
<span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
|
||||
<span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Objective function, returns smaller number for better results</span>
|
||||
<span class="sd"> This is the legacy algorithm (used until now in freqtrade).</span>
|
||||
<span class="sd"> Weights are distributed as follows:</span>
|
||||
<span class="sd"> * 0.4 to trade duration</span>
|
||||
<span class="sd"> * 0.25: Avoiding trade loss</span>
|
||||
<span class="sd"> * 1.0 to total profit, compared to the expected value (`EXPECTED_MAX_PROFIT`) defined above</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">total_profit</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s1">'profit_ratio'</span><span class="p">]</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span>
|
||||
<span class="n">trade_duration</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s1">'trade_duration'</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
|
||||
|
||||
<span class="n">trade_loss</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="mf">0.25</span> <span class="o">*</span> <span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">trade_count</span> <span class="o">-</span> <span class="n">TARGET_TRADES</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="mi">10</span> <span class="o">**</span> <span class="mf">5.8</span><span class="p">)</span>
|
||||
<span class="n">profit_loss</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">total_profit</span> <span class="o">/</span> <span class="n">EXPECTED_MAX_PROFIT</span><span class="p">)</span>
|
||||
<span class="n">duration_loss</span> <span class="o">=</span> <span class="mf">0.4</span> <span class="o">*</span> <span class="nb">min</span><span class="p">(</span><span class="n">trade_duration</span> <span class="o">/</span> <span class="n">MAX_ACCEPTED_TRADE_DURATION</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">trade_loss</span> <span class="o">+</span> <span class="n">profit_loss</span> <span class="o">+</span> <span class="n">duration_loss</span>
|
||||
<span class="k">return</span> <span class="n">result</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>Currently, the arguments are:</p>
|
||||
<ul>
|
||||
<li><code>results</code>: DataFrame containing the resulting trades.
|
||||
@@ -2022,86 +2046,82 @@ def hyperopt_loss_function(
|
||||
</div>
|
||||
<h2 id="overriding-pre-defined-spaces">Overriding pre-defined spaces<a class="headerlink" href="#overriding-pre-defined-spaces" title="Permanent link">¶</a></h2>
|
||||
<p>To override a pre-defined space (<code>roi_space</code>, <code>generate_roi_table</code>, <code>stoploss_space</code>, <code>trailing_space</code>, <code>max_open_trades_space</code>), define a nested class called Hyperopt and define the required spaces as follows:</p>
|
||||
<p>```python
|
||||
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal</p>
|
||||
<p>class MyAwesomeStrategy(IStrategy):
|
||||
class HyperOpt:
|
||||
# Define a custom stoploss space.
|
||||
def stoploss_space():
|
||||
return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')]</p>
|
||||
<div class="codehilite"><pre><span></span><code> # Define custom ROI space
|
||||
def roi_space() -> List[Dimension]:
|
||||
return [
|
||||
Integer(10, 120, name='roi_t1'),
|
||||
Integer(10, 60, name='roi_t2'),
|
||||
Integer(10, 40, name='roi_t3'),
|
||||
SKDecimal(0.01, 0.04, decimals=3, name='roi_p1'),
|
||||
SKDecimal(0.01, 0.07, decimals=3, name='roi_p2'),
|
||||
SKDecimal(0.01, 0.20, decimals=3, name='roi_p3'),
|
||||
]
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.optimize.space</span><span class="w"> </span><span class="kn">import</span> <span class="n">Categorical</span><span class="p">,</span> <span class="n">Dimension</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">SKDecimal</span>
|
||||
|
||||
def generate_roi_table(params: Dict) -> dict[int, float]:
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyAwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">HyperOpt</span><span class="p">:</span>
|
||||
<span class="c1"># Define a custom stoploss space.</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">stoploss_space</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="n">SKDecimal</span><span class="p">(</span><span class="o">-</span><span class="mf">0.05</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.01</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'stoploss'</span><span class="p">)]</span>
|
||||
|
||||
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
|
||||
<span class="c1"># Define custom ROI space</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">roi_space</span><span class="p">()</span> <span class="o">-></span> <span class="n">List</span><span class="p">[</span><span class="n">Dimension</span><span class="p">]:</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="n">Integer</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">120</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_t1'</span><span class="p">),</span>
|
||||
<span class="n">Integer</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_t2'</span><span class="p">),</span>
|
||||
<span class="n">Integer</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_t3'</span><span class="p">),</span>
|
||||
<span class="n">SKDecimal</span><span class="p">(</span><span class="mf">0.01</span><span class="p">,</span> <span class="mf">0.04</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_p1'</span><span class="p">),</span>
|
||||
<span class="n">SKDecimal</span><span class="p">(</span><span class="mf">0.01</span><span class="p">,</span> <span class="mf">0.07</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_p2'</span><span class="p">),</span>
|
||||
<span class="n">SKDecimal</span><span class="p">(</span><span class="mf">0.01</span><span class="p">,</span> <span class="mf">0.20</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'roi_p3'</span><span class="p">),</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
return roi_table
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_roi_table</span><span class="p">(</span><span class="n">params</span><span class="p">:</span> <span class="n">Dict</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">]:</span>
|
||||
|
||||
def trailing_space() -> List[Dimension]:
|
||||
# All parameters here are mandatory, you can only modify their type or the range.
|
||||
return [
|
||||
# Fixed to true, if optimizing trailing_stop we assume to use trailing stop at all times.
|
||||
Categorical([True], name='trailing_stop'),
|
||||
<span class="n">roi_table</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="n">roi_table</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p1'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p2'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p3'</span><span class="p">]</span>
|
||||
<span class="n">roi_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">'roi_t3'</span><span class="p">]]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p1'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p2'</span><span class="p">]</span>
|
||||
<span class="n">roi_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">'roi_t3'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_t2'</span><span class="p">]]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_p1'</span><span class="p">]</span>
|
||||
<span class="n">roi_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">'roi_t3'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_t2'</span><span class="p">]</span> <span class="o">+</span> <span class="n">params</span><span class="p">[</span><span class="s1">'roi_t1'</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
|
||||
SKDecimal(0.01, 0.35, decimals=3, name='trailing_stop_positive'),
|
||||
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||
# so this intermediate parameter is used as the value of the difference between
|
||||
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||
# generate_trailing_params() method.
|
||||
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||
SKDecimal(0.001, 0.1, decimals=3, name='trailing_stop_positive_offset_p1'),
|
||||
<span class="k">return</span> <span class="n">roi_table</span>
|
||||
|
||||
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||
]
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">trailing_space</span><span class="p">()</span> <span class="o">-></span> <span class="n">List</span><span class="p">[</span><span class="n">Dimension</span><span class="p">]:</span>
|
||||
<span class="c1"># All parameters here are mandatory, you can only modify their type or the range.</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="c1"># Fixed to true, if optimizing trailing_stop we assume to use trailing stop at all times.</span>
|
||||
<span class="n">Categorical</span><span class="p">([</span><span class="kc">True</span><span class="p">],</span> <span class="n">name</span><span class="o">=</span><span class="s1">'trailing_stop'</span><span class="p">),</span>
|
||||
|
||||
# Define a custom max_open_trades space
|
||||
def max_open_trades_space() -> List[Dimension]:
|
||||
return [
|
||||
Integer(-1, 10, name='max_open_trades'),
|
||||
]
|
||||
<span class="n">SKDecimal</span><span class="p">(</span><span class="mf">0.01</span><span class="p">,</span> <span class="mf">0.35</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'trailing_stop_positive'</span><span class="p">),</span>
|
||||
<span class="c1"># 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',</span>
|
||||
<span class="c1"># so this intermediate parameter is used as the value of the difference between</span>
|
||||
<span class="c1"># them. The value of the 'trailing_stop_positive_offset' is constructed in the</span>
|
||||
<span class="c1"># generate_trailing_params() method.</span>
|
||||
<span class="c1"># This is similar to the hyperspace dimensions used for constructing the ROI tables.</span>
|
||||
<span class="n">SKDecimal</span><span class="p">(</span><span class="mf">0.001</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="n">decimals</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'trailing_stop_positive_offset_p1'</span><span class="p">),</span>
|
||||
|
||||
<span class="n">Categorical</span><span class="p">([</span><span class="kc">True</span><span class="p">,</span> <span class="kc">False</span><span class="p">],</span> <span class="n">name</span><span class="o">=</span><span class="s1">'trailing_only_offset_is_reached'</span><span class="p">),</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="c1"># Define a custom max_open_trades space</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">max_open_trades_space</span><span class="p">()</span> <span class="o">-></span> <span class="n">List</span><span class="p">[</span><span class="n">Dimension</span><span class="p">]:</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="n">Integer</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'max_open_trades'</span><span class="p">),</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>All overrides are optional and can be mixed/matched as necessary.</p>
|
||||
</div>
|
||||
<h2 id="dynamic-parameters">Dynamic parameters<a class="headerlink" href="#dynamic-parameters" title="Permanent link">¶</a></h2>
|
||||
<p>Parameters can also be defined dynamically, but must be available to the instance once the <a href="../strategy-callbacks/#bot-start"><code>bot_start()</code> callback</a> has been called.</p>
|
||||
<p>``` python</p>
|
||||
<p>class MyAwesomeStrategy(IStrategy):</p>
|
||||
<div class="codehilite"><pre><span></span><code>def bot_start(self, **kwargs) -> None:
|
||||
self.buy_adx = IntParameter(20, 30, default=30, optimize=True)
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">MyAwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
|
||||
# ...
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">bot_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">buy_adx</span> <span class="o">=</span> <span class="n">IntParameter</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">optimize</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Parameters created this way will not show up in the <code>list-strategies</code> parameter count.</p>
|
||||
</div>
|
||||
<h2 id="overriding-base-estimator">Overriding Base estimator<a class="headerlink" href="#overriding-base-estimator" title="Permanent link">¶</a></h2>
|
||||
<p>You can define your own optuna sampler for Hyperopt by implementing <code>generate_estimator()</code> in the Hyperopt subclass.</p>
|
||||
<p>```python
|
||||
class MyAwesomeStrategy(IStrategy):
|
||||
class HyperOpt:
|
||||
def generate_estimator(dimensions: List['Dimension'], **kwargs):
|
||||
return "NSGAIIISampler"</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">MyAwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">HyperOpt</span><span class="p">:</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_estimator</span><span class="p">(</span><span class="n">dimensions</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="s1">'Dimension'</span><span class="p">],</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="s2">"NSGAIIISampler"</span>
|
||||
</code></pre></div>
|
||||
<p>Possible values are either one of "NSGAIISampler", "TPESampler", "GPSampler", "CmaEsSampler", "NSGAIIISampler", "QMCSampler" (Details can be found in the <a href="https://optuna.readthedocs.io/en/stable/reference/samplers/index.html">optuna-samplers documentation</a>), or "an instance of a class that inherits from <code>optuna.samplers.BaseSampler</code>".</p>
|
||||
<p>Some research will be necessary to find additional Samplers (from optunahub) for example.</p>
|
||||
<div class="admonition note">
|
||||
@@ -2113,23 +2133,23 @@ If you're unsure about this, best use one of the Defaults (<code>"NSGAIIISampler
|
||||
<summary>Using <code>AutoSampler</code> from Optunahub</summary>
|
||||
<p><a href="https://hub.optuna.org/samplers/auto_sampler/">AutoSampler docs</a></p>
|
||||
<p>Install the necessary dependencies
|
||||
<code>bash
|
||||
pip install optunahub cmaes torch scipy</code>
|
||||
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>optunahub<span class="w"> </span>cmaes<span class="w"> </span>torch<span class="w"> </span>scipy
|
||||
</code></pre></div>
|
||||
Implement <code>generate_estimator()</code> in your strategy</p>
|
||||
<p>``` python</p>
|
||||
<h1 id="_1">...<a class="headerlink" href="#_1" title="Permanent link">¶</a></h1>
|
||||
<p>from freqtrade.strategy.interface import IStrategy
|
||||
from typing import List
|
||||
import optunahub</p>
|
||||
<h1 id="_2">...<a class="headerlink" href="#_2" title="Permanent link">¶</a></h1>
|
||||
<p>class my_strategy(IStrategy):
|
||||
class HyperOpt:
|
||||
def generate_estimator(dimensions: List["Dimension"], **kwargs):
|
||||
if "random_state" in kwargs.keys():
|
||||
return optunahub.load_module("samplers/auto_sampler").AutoSampler(seed=kwargs["random_state"])
|
||||
else:
|
||||
return optunahub.load_module("samplers/auto_sampler").AutoSampler()</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># ...</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.strategy.interface</span><span class="w"> </span><span class="kn">import</span> <span class="n">IStrategy</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">List</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">optunahub</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">my_strategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">HyperOpt</span><span class="p">:</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_estimator</span><span class="p">(</span><span class="n">dimensions</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="s2">"Dimension"</span><span class="p">],</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="s2">"random_state"</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">optunahub</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="s2">"samplers/auto_sampler"</span><span class="p">)</span><span class="o">.</span><span class="n">AutoSampler</span><span class="p">(</span><span class="n">seed</span><span class="o">=</span><span class="n">kwargs</span><span class="p">[</span><span class="s2">"random_state"</span><span class="p">])</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">optunahub</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="s2">"samplers/auto_sampler"</span><span class="p">)</span><span class="o">.</span><span class="n">AutoSampler</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<p>Obviously the same approach will work for all other Samplers optuna supports.</p>
|
||||
</details>
|
||||
<h2 id="space-options">Space options<a class="headerlink" href="#space-options" title="Permanent link">¶</a></h2>
|
||||
@@ -2141,8 +2161,8 @@ import optunahub</p>
|
||||
<li><code>Real</code> - Pick from a range of decimal numbers with full precision (e.g. <code>Real(0.1, 0.5, name='adx')</code></li>
|
||||
</ul>
|
||||
<p>You can import all of these from <code>freqtrade.optimize.space</code>, although <code>Categorical</code>, <code>Integer</code> and <code>Real</code> are only aliases for their corresponding scikit-optimize Spaces. <code>SKDecimal</code> is provided by freqtrade for faster optimizations.</p>
|
||||
<p><code>python
|
||||
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal, Real # noqa</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.optimize.space</span><span class="w"> </span><span class="kn">import</span> <span class="n">Categorical</span><span class="p">,</span> <span class="n">Dimension</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">SKDecimal</span><span class="p">,</span> <span class="n">Real</span> <span class="c1"># noqa</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition hint">
|
||||
<p class="admonition-title">SKDecimal vs. Real</p>
|
||||
<p>We recommend to use <code>SKDecimal</code> instead of the <code>Real</code> 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.</p>
|
||||
|
||||
@@ -2105,11 +2105,11 @@ It's also currently not been tested with freqAI - and combining these two featur
|
||||
<h2 id="getting-started">Getting Started<a class="headerlink" href="#getting-started" title="Permanent link">¶</a></h2>
|
||||
<h3 id="enable-public-trades">Enable Public Trades<a class="headerlink" href="#enable-public-trades" title="Permanent link">¶</a></h3>
|
||||
<p>In your <code>config.json</code> file, set the <code>use_public_trades</code> option to true under the <code>exchange</code> section.</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
...
|
||||
"use_public_trades": true,
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="err">...</span>
|
||||
<span class="w"> </span><span class="nt">"use_public_trades"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<h3 id="configure-orderflow-processing">Configure Orderflow Processing<a class="headerlink" href="#configure-orderflow-processing" title="Permanent link">¶</a></h3>
|
||||
<p>Define your desired settings for orderflow processing within the orderflow section of config.json. Here, you can adjust factors like:</p>
|
||||
<ul>
|
||||
@@ -2120,65 +2120,64 @@ It's also currently not been tested with freqAI - and combining these two featur
|
||||
<li><code>imbalance_volume</code>: Filters out imbalances with volume below this threshold.</li>
|
||||
<li><code>imbalance_ratio</code>: Filters out imbalances with a ratio (difference between ask and bid volume) lower than this value.</li>
|
||||
</ul>
|
||||
<p><code>json
|
||||
"orderflow": {
|
||||
"cache_size": 1000,
|
||||
"max_candles": 1500,
|
||||
"scale": 0.5,
|
||||
"stacked_imbalance_range": 3, // needs at least this amount of imbalance next to each other
|
||||
"imbalance_volume": 1, // filters out below
|
||||
"imbalance_ratio": 3 // filters out ratio lower than
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"orderflow"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"cache_size"</span><span class="p">:</span><span class="w"> </span><span class="mi">1000</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="nt">"max_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">1500</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="nt">"scale"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="nt">"stacked_imbalance_range"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="c1">// needs at least this amount of imbalance next to each other</span>
|
||||
<span class="w"> </span><span class="nt">"imbalance_volume"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="c1">// filters out below</span>
|
||||
<span class="w"> </span><span class="nt">"imbalance_ratio"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">// filters out ratio lower than</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<h2 id="downloading-trade-data-for-backtesting">Downloading Trade Data for Backtesting<a class="headerlink" href="#downloading-trade-data-for-backtesting" title="Permanent link">¶</a></h2>
|
||||
<p>To download historical trade data for backtesting, use the --dl-trades flag with the freqtrade download-data command.</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data -p BTC/USDT:USDT --timerange 20230101- --trading-mode futures --timeframes 5m --dl-trades</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>-p<span class="w"> </span>BTC/USDT:USDT<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20230101</span>-<span class="w"> </span>--trading-mode<span class="w"> </span>futures<span class="w"> </span>--timeframes<span class="w"> </span>5m<span class="w"> </span>--dl-trades
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Data availability</p>
|
||||
<p>Not all exchanges provide public trade data. For supported exchanges, freqtrade will warn you if public trade data is not available if you start downloading data with the <code>--dl-trades</code> flag.</p>
|
||||
</div>
|
||||
<h2 id="accessing-orderflow-data">Accessing Orderflow Data<a class="headerlink" href="#accessing-orderflow-data" title="Permanent link">¶</a></h2>
|
||||
<p>Once activated, several new columns become available in your dataframe:</p>
|
||||
<p>``` python</p>
|
||||
<p>dataframe["trades"] # Contains information about each individual trade.
|
||||
dataframe["orderflow"] # Represents a footprint chart dict (see below)
|
||||
dataframe["imbalances"] # Contains information about imbalances in the order flow.
|
||||
dataframe["bid"] # Total bid volume
|
||||
dataframe["ask"] # Total ask volume
|
||||
dataframe["delta"] # Difference between ask and bid volume.
|
||||
dataframe["min_delta"] # Minimum delta within the candle
|
||||
dataframe["max_delta"] # Maximum delta within the candle
|
||||
dataframe["total_trades"] # Total number of trades
|
||||
dataframe["stacked_imbalances_bid"] # List of price levels of stacked bid imbalance range beginnings
|
||||
dataframe["stacked_imbalances_ask"] # List of price levels of stacked ask imbalance range beginnings
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">dataframe</span><span class="p">[</span><span class="s2">"trades"</span><span class="p">]</span> <span class="c1"># Contains information about each individual trade.</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"orderflow"</span><span class="p">]</span> <span class="c1"># Represents a footprint chart dict (see below)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"imbalances"</span><span class="p">]</span> <span class="c1"># Contains information about imbalances in the order flow.</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"bid"</span><span class="p">]</span> <span class="c1"># Total bid volume </span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"ask"</span><span class="p">]</span> <span class="c1"># Total ask volume</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"delta"</span><span class="p">]</span> <span class="c1"># Difference between ask and bid volume.</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"min_delta"</span><span class="p">]</span> <span class="c1"># Minimum delta within the candle</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"max_delta"</span><span class="p">]</span> <span class="c1"># Maximum delta within the candle</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"total_trades"</span><span class="p">]</span> <span class="c1"># Total number of trades</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"stacked_imbalances_bid"</span><span class="p">]</span> <span class="c1"># List of price levels of stacked bid imbalance range beginnings</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"stacked_imbalances_ask"</span><span class="p">]</span> <span class="c1"># List of price levels of stacked ask imbalance range beginnings</span>
|
||||
</code></pre></div>
|
||||
<p>You can access these columns in your strategy code for further analysis. Here's an example:</p>
|
||||
<p>``` python
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# Calculating cumulative delta
|
||||
dataframe["cum_delta"] = cumulative_delta(dataframe["delta"])
|
||||
# Accessing total trades
|
||||
total_trades = dataframe["total_trades"]
|
||||
...</p>
|
||||
<p>def cumulative_delta(delta: Series):
|
||||
cumdelta = delta.cumsum()
|
||||
return cumdelta</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># Calculating cumulative delta</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"cum_delta"</span><span class="p">]</span> <span class="o">=</span> <span class="n">cumulative_delta</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"delta"</span><span class="p">])</span>
|
||||
<span class="c1"># Accessing total trades</span>
|
||||
<span class="n">total_trades</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"total_trades"</span><span class="p">]</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">cumulative_delta</span><span class="p">(</span><span class="n">delta</span><span class="p">:</span> <span class="n">Series</span><span class="p">):</span>
|
||||
<span class="n">cumdelta</span> <span class="o">=</span> <span class="n">delta</span><span class="o">.</span><span class="n">cumsum</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">cumdelta</span>
|
||||
</code></pre></div>
|
||||
<h3 id="footprint-chart-dataframeorderflow">Footprint chart (<code>dataframe["orderflow"]</code>)<a class="headerlink" href="#footprint-chart-dataframeorderflow" title="Permanent link">¶</a></h3>
|
||||
<p>This column provides a detailed breakdown of buy and sell orders at different price levels, offering valuable insights into order flow dynamics. The <code>scale</code> parameter in your configuration determines the price bin size for this representation</p>
|
||||
<p>The <code>orderflow</code> column contains a dict with the following structure:</p>
|
||||
<p><code>output
|
||||
{
|
||||
"price": {
|
||||
"bid_amount": 0.0,
|
||||
"ask_amount": 0.0,
|
||||
"bid": 0,
|
||||
"ask": 0,
|
||||
"delta": 0.0,
|
||||
"total_volume": 0.0,
|
||||
"total_trades": 0
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">{</span>
|
||||
<span class="go"> "price": {</span>
|
||||
<span class="go"> "bid_amount": 0.0,</span>
|
||||
<span class="go"> "ask_amount": 0.0,</span>
|
||||
<span class="go"> "bid": 0,</span>
|
||||
<span class="go"> "ask": 0,</span>
|
||||
<span class="go"> "delta": 0.0,</span>
|
||||
<span class="go"> "total_volume": 0.0,</span>
|
||||
<span class="go"> "total_trades": 0</span>
|
||||
<span class="go"> }</span>
|
||||
<span class="go">}</span>
|
||||
</code></pre></div>
|
||||
<h4 id="orderflow-column-explanation">Orderflow column explanation<a class="headerlink" href="#orderflow-column-explanation" title="Permanent link">¶</a></h4>
|
||||
<ul>
|
||||
<li>key: Price bin - binned at <code>scale</code> intervals</li>
|
||||
@@ -2206,13 +2205,13 @@ def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFr
|
||||
<h3 id="imbalances-dataframeimbalances">Imbalances (<code>dataframe["imbalances"]</code>)<a class="headerlink" href="#imbalances-dataframeimbalances" title="Permanent link">¶</a></h3>
|
||||
<p>This column provides a dict with information about imbalances in the order flow. An imbalance occurs when there is a significant difference between the ask and bid volume at a given price level.</p>
|
||||
<p>Each row looks as follows - with price as index, and the corresponding bid and ask imbalance values as columns</p>
|
||||
<p><code>output
|
||||
{
|
||||
"price": {
|
||||
"bid_imbalance": False,
|
||||
"ask_imbalance": False
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">{</span>
|
||||
<span class="go"> "price": {</span>
|
||||
<span class="go"> "bid_imbalance": False,</span>
|
||||
<span class="go"> "ask_imbalance": False</span>
|
||||
<span class="go"> }</span>
|
||||
<span class="go">}</span>
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1461,6 +1461,145 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#multiple-instances-using-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Multiple instances using docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#use-a-different-database-system" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Use a different database system
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Use a different database system">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#postgresql" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
PostgreSQL
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#mariadb-mysql" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
MariaDB / MySQL
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#configure-the-bot-running-as-a-systemd-service" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Configure the bot running as a systemd service
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-logging" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced Logging
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Advanced Logging">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#logging-to-syslog" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Logging to syslog
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Logging to syslog">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#syslog-usage" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Syslog usage
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#syslog-addressing" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Syslog addressing
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#logging-to-journald" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Logging to journald
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#log-format-as-json" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Log format as JSON
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1903,6 +2042,145 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#multiple-instances-using-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Multiple instances using docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#use-a-different-database-system" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Use a different database system
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Use a different database system">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#postgresql" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
PostgreSQL
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#mariadb-mysql" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
MariaDB / MySQL
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#configure-the-bot-running-as-a-systemd-service" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Configure the bot running as a systemd service
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-logging" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced Logging
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Advanced Logging">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#logging-to-syslog" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Logging to syslog
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Logging to syslog">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#syslog-usage" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Syslog usage
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#syslog-addressing" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Syslog addressing
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#logging-to-journald" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Logging to journald
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#log-format-as-json" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Log format as JSON
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1952,32 +2230,28 @@
|
||||
For live trading mode, the default database will be <code>tradesv3.sqlite</code> and for dry-run it will be <code>tradesv3.dryrun.sqlite</code>.</p>
|
||||
<p>The optional argument to the trade command used to specify the path of these files is <code>--db-url</code>, which requires a valid SQLAlchemy url.
|
||||
So when you are starting a bot with only the config and strategy arguments in dry-run mode, the following 2 commands would have the same outcome.</p>
|
||||
<p>``` bash
|
||||
freqtrade trade -c MyConfig.json -s MyStrategy</p>
|
||||
<h1 id="is-equivalent-to">is equivalent to<a class="headerlink" href="#is-equivalent-to" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trade -c MyConfig.json -s MyStrategy --db-url sqlite:///tradesv3.dryrun.sqlite
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfig.json<span class="w"> </span>-s<span class="w"> </span>MyStrategy
|
||||
<span class="c1"># is equivalent to</span>
|
||||
freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfig.json<span class="w"> </span>-s<span class="w"> </span>MyStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///tradesv3.dryrun.sqlite
|
||||
</code></pre></div>
|
||||
<p>It means that if you are running the trade command in two different terminals, for example to test your strategy both for trades in USDT and in another instance for trades in BTC, you will have to run them with different databases.</p>
|
||||
<p>If you specify the URL of a database which does not exist, freqtrade will create one with the name you specified. So to test your custom strategy with BTC and USDT stake currencies, you could use the following commands (in 2 separate terminals):</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="terminal-1">Terminal 1:<a class="headerlink" href="#terminal-1" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trade -c MyConfigBTC.json -s MyCustomStrategy --db-url sqlite:///user_data/tradesBTC.dryrun.sqlite</p>
|
||||
<h1 id="terminal-2">Terminal 2:<a class="headerlink" href="#terminal-2" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trade -c MyConfigUSDT.json -s MyCustomStrategy --db-url sqlite:///user_data/tradesUSDT.dryrun.sqlite
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Terminal 1:</span>
|
||||
freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfigBTC.json<span class="w"> </span>-s<span class="w"> </span>MyCustomStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///user_data/tradesBTC.dryrun.sqlite
|
||||
<span class="c1"># Terminal 2:</span>
|
||||
freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfigUSDT.json<span class="w"> </span>-s<span class="w"> </span>MyCustomStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///user_data/tradesUSDT.dryrun.sqlite
|
||||
</code></pre></div>
|
||||
<p>Conversely, if you wish to do the same thing in production mode, you will also have to create at least one new database (in addition to the default one) and specify the path to the "live" databases, for example:</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="terminal-1_1">Terminal 1:<a class="headerlink" href="#terminal-1_1" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trade -c MyConfigBTC.json -s MyCustomStrategy --db-url sqlite:///user_data/tradesBTC.live.sqlite</p>
|
||||
<h1 id="terminal-2_1">Terminal 2:<a class="headerlink" href="#terminal-2_1" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trade -c MyConfigUSDT.json -s MyCustomStrategy --db-url sqlite:///user_data/tradesUSDT.live.sqlite
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Terminal 1:</span>
|
||||
freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfigBTC.json<span class="w"> </span>-s<span class="w"> </span>MyCustomStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///user_data/tradesBTC.live.sqlite
|
||||
<span class="c1"># Terminal 2:</span>
|
||||
freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>MyConfigUSDT.json<span class="w"> </span>-s<span class="w"> </span>MyCustomStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///user_data/tradesUSDT.live.sqlite
|
||||
</code></pre></div>
|
||||
<p>For more information regarding usage of the sqlite databases, for example to manually enter or remove trades, please refer to the <a href="../sql_cheatsheet/">SQL Cheatsheet</a>.</p>
|
||||
<h3 id="multiple-instances-using-docker">Multiple instances using docker<a class="headerlink" href="#multiple-instances-using-docker" title="Permanent link">¶</a></h3>
|
||||
<p>To run multiple instances of freqtrade using docker you will need to edit the docker-compose.yml file and add all the instances you want as separate services. Remember, you can separate your configuration into multiple files, so it's a good idea to think about making them modular, then if you need to edit something common to all bots, you can do that in a single config file.
|
||||
``` yml</p>
|
||||
<hr />
|
||||
<p>version: '3'
|
||||
<div class="highlight"><pre><span></span><code>---
|
||||
version: '3'
|
||||
services:
|
||||
freqtrade1:
|
||||
image: freqtradeorg/freqtrade:stable
|
||||
@@ -1987,25 +2261,26 @@ services:
|
||||
# Build step - only needed when additional dependencies are needed
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: "./docker/Dockerfile.custom"
|
||||
# dockerfile: "./docker/Dockerfile.custom"
|
||||
restart: always
|
||||
container_name: freqtrade1
|
||||
volumes:
|
||||
- "./user_data:/freqtrade/user_data"
|
||||
- "./user_data:/freqtrade/user_data"
|
||||
# Expose api on port 8080 (localhost only)
|
||||
# Please read the <a href="https://www.freqtrade.io/en/stable/rest-api/">https://www.freqtrade.io/en/stable/rest-api/</a> documentation
|
||||
# Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
|
||||
# before enabling this.
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
# Default command used when running <code>docker compose up</code>
|
||||
- "127.0.0.1:8080:8080"
|
||||
# Default command used when running `docker compose up`
|
||||
command: >
|
||||
trade
|
||||
--logfile /freqtrade/user_data/logs/freqtrade1.log
|
||||
--db-url sqlite:////freqtrade/user_data/tradesv3_freqtrade1.sqlite
|
||||
--config /freqtrade/user_data/config.json
|
||||
--config /freqtrade/user_data/config.freqtrade1.json
|
||||
--strategy SampleStrategy</p>
|
||||
<p>freqtrade2:
|
||||
--strategy SampleStrategy
|
||||
|
||||
freqtrade2:
|
||||
image: freqtradeorg/freqtrade:stable
|
||||
# image: freqtradeorg/freqtrade:develop
|
||||
# Use plotting image
|
||||
@@ -2013,25 +2288,25 @@ services:
|
||||
# Build step - only needed when additional dependencies are needed
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: "./docker/Dockerfile.custom"
|
||||
# dockerfile: "./docker/Dockerfile.custom"
|
||||
restart: always
|
||||
container_name: freqtrade2
|
||||
volumes:
|
||||
- "./user_data:/freqtrade/user_data"
|
||||
- "./user_data:/freqtrade/user_data"
|
||||
# Expose api on port 8080 (localhost only)
|
||||
# Please read the <a href="https://www.freqtrade.io/en/stable/rest-api/">https://www.freqtrade.io/en/stable/rest-api/</a> documentation
|
||||
# Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
|
||||
# before enabling this.
|
||||
ports:
|
||||
- "127.0.0.1:8081:8080"
|
||||
# Default command used when running <code>docker compose up</code>
|
||||
- "127.0.0.1:8081:8080"
|
||||
# Default command used when running `docker compose up`
|
||||
command: >
|
||||
trade
|
||||
--logfile /freqtrade/user_data/logs/freqtrade2.log
|
||||
--db-url sqlite:////freqtrade/user_data/tradesv3_freqtrade2.sqlite
|
||||
--config /freqtrade/user_data/config.json
|
||||
--config /freqtrade/user_data/config.freqtrade2.json
|
||||
--strategy SampleStrategy</p>
|
||||
<p>```</p>
|
||||
--strategy SampleStrategy
|
||||
</code></pre></div></p>
|
||||
<p>You can use whatever naming convention you want, freqtrade1 and 2 are arbitrary. Note, that you will need to use different database files, port mappings and telegram configurations for each instance, as mentioned above. </p>
|
||||
<h2 id="use-a-different-database-system">Use a different database system<a class="headerlink" href="#use-a-different-database-system" title="Permanent link">¶</a></h2>
|
||||
<p>Freqtrade is using SQLAlchemy, which supports multiple different database systems. As such, a multitude of database systems should be supported.
|
||||
@@ -2066,11 +2341,11 @@ Freqtrade does not depend or install any additional database driver. Please refe
|
||||
<p>Certain systems (like Raspbian) don't load service unit files from the user directory. In this case, copy <code>freqtrade.service</code> into <code>/etc/systemd/user/</code> (requires superuser permissions).</p>
|
||||
</div>
|
||||
<p>After that you can start the daemon with:</p>
|
||||
<p><code>bash
|
||||
systemctl --user start freqtrade</code></p>
|
||||
<div class="highlight"><pre><span></span><code>systemctl<span class="w"> </span>--user<span class="w"> </span>start<span class="w"> </span>freqtrade
|
||||
</code></pre></div>
|
||||
<p>For this to be persistent (run when user is logged out) you'll need to enable <code>linger</code> for your freqtrade user.</p>
|
||||
<p><code>bash
|
||||
sudo loginctl enable-linger "$USER"</code></p>
|
||||
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>loginctl<span class="w"> </span>enable-linger<span class="w"> </span><span class="s2">"</span><span class="nv">$USER</span><span class="s2">"</span>
|
||||
</code></pre></div>
|
||||
<p>If you run the bot as a service, you can use systemd service manager as a software watchdog monitoring freqtrade bot
|
||||
state and restarting it in the case of failures. If the <code>internals.sd_notify</code> parameter is set to true in the
|
||||
configuration or the <code>--sd-notify</code> command line option is used, the bot will send keep-alive ping messages to systemd
|
||||
@@ -2090,40 +2365,40 @@ Using <code>--logfile logfile.log</code> will enable the RotatingFileHandler.</p
|
||||
<p>If you're not content with the log format, or with the default settings provided for the RotatingFileHandler, you can customize logging to your liking by adding the <code>log_config</code> configuration to your freqtrade configuration file(s).</p>
|
||||
<p>The default configuration looks roughly like the below, with the file handler being provided but not enabled as the <code>filename</code> is commented out.
|
||||
Uncomment this line and supply a valid path/filename to enable it.</p>
|
||||
<p><code>json hl_lines="5-7 13-16 27"
|
||||
{
|
||||
"log_config": {
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"basic": {
|
||||
"format": "%(message)s"
|
||||
},
|
||||
"standard": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "freqtrade.loggers.ft_rich_handler.FtRichHandler",
|
||||
"formatter": "basic"
|
||||
},
|
||||
"file": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"formatter": "standard",
|
||||
// "filename": "someRandomLogFile.log",
|
||||
"maxBytes": 10485760,
|
||||
"backupCount": 10
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"handlers": [
|
||||
"console",
|
||||
// "file"
|
||||
],
|
||||
"level": "INFO",
|
||||
}
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"log_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="hll"><span class="w"> </span><span class="nt">"basic"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span class="hll"><span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"%(message)s"</span>
|
||||
</span><span class="hll"><span class="w"> </span><span class="p">},</span>
|
||||
</span><span class="w"> </span><span class="nt">"standard"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"%(asctime)s - %(name)s - %(levelname)s - %(message)s"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="hll"><span class="w"> </span><span class="nt">"console"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span class="hll"><span class="w"> </span><span class="nt">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"freqtrade.loggers.ft_rich_handler.FtRichHandler"</span><span class="p">,</span>
|
||||
</span><span class="hll"><span class="w"> </span><span class="nt">"formatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"basic"</span>
|
||||
</span><span class="hll"><span class="w"> </span><span class="p">},</span>
|
||||
</span><span class="w"> </span><span class="nt">"file"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"logging.handlers.RotatingFileHandler"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"standard"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// "filename": "someRandomLogFile.log",</span>
|
||||
<span class="w"> </span><span class="nt">"maxBytes"</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"backupCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"root"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="hll"><span class="w"> </span><span class="s2">"console"</span><span class="p">,</span>
|
||||
</span><span class="w"> </span><span class="c1">// "file"</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"level"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INFO"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">highlighted lines</p>
|
||||
<p>Highlighted lines in the above code-block define the Rich handler and belong together.
|
||||
@@ -2140,36 +2415,35 @@ If this section is left out, freqtrade will provide no output (in the non-config
|
||||
<p>On many Linux systems the bot can be configured to send its log messages to <code>syslog</code> or <code>journald</code> system services. Logging to a remote <code>syslog</code> server is also available on Windows. The special values for the <code>--logfile</code> command line option can be used for this.</p>
|
||||
<h3 id="logging-to-syslog">Logging to syslog<a class="headerlink" href="#logging-to-syslog" title="Permanent link">¶</a></h3>
|
||||
<p>To send Freqtrade log messages to a local or remote <code>syslog</code> service use the <code>"log_config"</code> setup option to configure logging.</p>
|
||||
<p>``` json
|
||||
{
|
||||
// ...
|
||||
"log_config": {
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"syslog_fmt": {
|
||||
"format": "%(name)s - %(levelname)s - %(message)s"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
// Other handlers?
|
||||
"syslog": {
|
||||
"class": "logging.handlers.SysLogHandler",
|
||||
"formatter": "syslog_fmt",
|
||||
// Use one of the other options above as address instead?
|
||||
"address": "/dev/log"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"handlers": [
|
||||
// other handlers
|
||||
"syslog",</p>
|
||||
<div class="codehilite"><pre><span></span><code> ]
|
||||
}
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="nt">"log_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"syslog_fmt"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"%(name)s - %(levelname)s - %(message)s"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// Other handlers? </span>
|
||||
<span class="w"> </span><span class="nt">"syslog"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"logging.handlers.SysLogHandler"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"syslog_fmt"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// Use one of the other options above as address instead? </span>
|
||||
<span class="w"> </span><span class="nt">"address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/dev/log"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"root"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="c1">// other handlers</span>
|
||||
<span class="w"> </span><span class="s2">"syslog"</span><span class="p">,</span>
|
||||
|
||||
<p>}
|
||||
}
|
||||
```</p>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p><a href="#advanced-logging">Additional log-handlers</a> may need to be configured to for example also have log output in the console.</p>
|
||||
<h4 id="syslog-usage">Syslog usage<a class="headerlink" href="#syslog-usage" title="Permanent link">¶</a></h4>
|
||||
<p>Log messages are send to <code>syslog</code> with the <code>user</code> facility. So you can see them with the following commands:</p>
|
||||
@@ -2179,13 +2453,13 @@ If this section is left out, freqtrade will provide no output (in the non-config
|
||||
</ul>
|
||||
<p>On many systems <code>syslog</code> (<code>rsyslog</code>) fetches data from <code>journald</code> (and vice versa), so both syslog or journald can be used and the messages be viewed with both <code>journalctl</code> and a syslog viewer utility. You can combine this in any way which suites you better.</p>
|
||||
<p>For <code>rsyslog</code> the messages from the bot can be redirected into a separate dedicated log file. To achieve this, add</p>
|
||||
<p><code>if $programname startswith "freqtrade" then -/var/log/freqtrade.log</code></p>
|
||||
<div class="highlight"><pre><span></span><code>if $programname startswith "freqtrade" then -/var/log/freqtrade.log
|
||||
</code></pre></div>
|
||||
<p>to one of the rsyslog configuration files, for example at the end of the <code>/etc/rsyslog.d/50-default.conf</code>.</p>
|
||||
<p>For <code>syslog</code> (<code>rsyslog</code>), the reduction mode can be switched on. This will reduce the number of repeating messages. For instance, multiple bot Heartbeat messages will be reduced to a single message when nothing else happens with the bot. To achieve this, set in <code>/etc/rsyslog.conf</code>:</p>
|
||||
<p>```</p>
|
||||
<h1 id="filter-duplicated-messages">Filter duplicated messages<a class="headerlink" href="#filter-duplicated-messages" title="Permanent link">¶</a></h1>
|
||||
<p>$RepeatedMsgReduction on
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code># Filter duplicated messages
|
||||
$RepeatedMsgReduction on
|
||||
</code></pre></div>
|
||||
<h4 id="syslog-addressing">Syslog addressing<a class="headerlink" href="#syslog-addressing" title="Permanent link">¶</a></h4>
|
||||
<p>The syslog address can be either a Unix domain socket (socket filename) or a UDP socket specification, consisting of IP address and UDP port, separated by the <code>:</code> character.</p>
|
||||
<p>So, the following are the examples of possible addresses:</p>
|
||||
@@ -2211,34 +2485,33 @@ If this section is left out, freqtrade will provide no output (in the non-config
|
||||
<h3 id="logging-to-journald">Logging to journald<a class="headerlink" href="#logging-to-journald" title="Permanent link">¶</a></h3>
|
||||
<p>This needs the <code>cysystemd</code> python package installed as dependency (<code>pip install cysystemd</code>), which is not available on Windows. Hence, the whole journald logging functionality is not available for a bot running on Windows.</p>
|
||||
<p>To send Freqtrade log messages to <code>journald</code> system service, add the following configuration snippet to your configuration.</p>
|
||||
<p>``` json
|
||||
{
|
||||
// ...
|
||||
"log_config": {
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"journald_fmt": {
|
||||
"format": "%(name)s - %(levelname)s - %(message)s"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
// Other handlers?
|
||||
"journald": {
|
||||
"class": "cysystemd.journal.JournaldLogHandler",
|
||||
"formatter": "journald_fmt",
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"handlers": [
|
||||
// ..
|
||||
"journald",</p>
|
||||
<div class="codehilite"><pre><span></span><code> ]
|
||||
}
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="nt">"log_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"journald_fmt"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"%(name)s - %(levelname)s - %(message)s"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// Other handlers? </span>
|
||||
<span class="w"> </span><span class="nt">"journald"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cysystemd.journal.JournaldLogHandler"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"journald_fmt"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"root"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="c1">// .. </span>
|
||||
<span class="w"> </span><span class="s2">"journald"</span><span class="p">,</span>
|
||||
|
||||
<p>}
|
||||
}
|
||||
```</p>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p><a href="#advanced-logging">Additional log-handlers</a> may need to be configured to for example also have log output in the console.</p>
|
||||
<p>Log messages are send to <code>journald</code> with the <code>user</code> facility. So you can see them with the following commands:</p>
|
||||
<ul>
|
||||
@@ -2257,40 +2530,39 @@ If this section is left out, freqtrade will provide no output (in the non-config
|
||||
The "fmt_dict" attribute defines the keys for the json output - as well as the <a href="https://docs.python.org/3/library/logging.html#logrecord-attributes">python logging LogRecord attributes</a>.</p>
|
||||
<p>The below configuration will change the default output to JSON. The same formatter could however also be used in combination with the <code>RotatingFileHandler</code>.
|
||||
We recommend to keep one format in human readable form.</p>
|
||||
<p>``` json
|
||||
{
|
||||
// ...
|
||||
"log_config": {
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"json": {
|
||||
"()": "freqtrade.loggers.json_formatter.JsonFormatter",
|
||||
"fmt_dict": {
|
||||
"timestamp": "asctime",
|
||||
"level": "levelname",
|
||||
"logger": "name",
|
||||
"message": "message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
// Other handlers?
|
||||
"jsonStream": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "json"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"handlers": [
|
||||
// ..
|
||||
"jsonStream",</p>
|
||||
<div class="codehilite"><pre><span></span><code> ]
|
||||
}
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="nt">"log_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"json"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"()"</span><span class="p">:</span><span class="w"> </span><span class="s2">"freqtrade.loggers.json_formatter.JsonFormatter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"fmt_dict"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"asctime"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"level"</span><span class="p">:</span><span class="w"> </span><span class="s2">"levelname"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"logger"</span><span class="p">:</span><span class="w"> </span><span class="s2">"name"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"message"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// Other handlers? </span>
|
||||
<span class="w"> </span><span class="nt">"jsonStream"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"logging.StreamHandler"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"formatter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"json"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"root"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"handlers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="c1">// .. </span>
|
||||
<span class="w"> </span><span class="s2">"jsonStream"</span><span class="p">,</span>
|
||||
|
||||
<p>}
|
||||
}
|
||||
```</p>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
+192
-187
@@ -2393,122 +2393,124 @@
|
||||
To learn how to get data for the pairs and exchange you're interested in, head over to the <a href="../data-download/">Data Downloading</a> section of the documentation.</p>
|
||||
<p>Backtesting is also available in <a href="../freq-ui/#backtesting">webserver mode</a>, which allows you to run backtests via the web interface.</p>
|
||||
<h2 id="backtesting-command-reference">Backtesting command reference<a class="headerlink" href="#backtesting-command-reference" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade backtesting [-h] [-v] [--no-color] [--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,feather,parquet}]
|
||||
[--max-open-trades INT]
|
||||
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
|
||||
[-p PAIRS [PAIRS ...]] [--eps]
|
||||
[--enable-protections]
|
||||
[--enable-dynamic-pairlist]
|
||||
[--dry-run-wallet DRY_RUN_WALLET]
|
||||
[--timeframe-detail TIMEFRAME_DETAIL]
|
||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||
[--export {none,trades,signals}]
|
||||
[--backtest-filename PATH]
|
||||
[--backtest-directory PATH]
|
||||
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
|
||||
[--cache {none,day,week,month}]
|
||||
[--freqai-backtest-live-models] [--notes TEXT]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-i, --timeframe TIMEFRAME
|
||||
Specify timeframe (<code>1m</code>, <code>5m</code>, <code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
--data-format-ohlcv {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
--max-open-trades INT
|
||||
Override the value of the <code>max_open_trades</code>
|
||||
configuration setting.
|
||||
--stake-amount STAKE_AMOUNT
|
||||
Override the value of the <code>stake_amount</code> configuration
|
||||
setting.
|
||||
--fee FLOAT Specify fee ratio. Will be applied twice (on trade
|
||||
entry and exit).
|
||||
-p, --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). Only applicable to backtesting and
|
||||
hyperopt. Results archived by this cannot be
|
||||
reproduced in dry/live trading.
|
||||
--enable-protections, --enableprotections
|
||||
Enable protections for backtesting. Will slow
|
||||
backtesting down by a considerable amount, but will
|
||||
include configured protections
|
||||
--enable-dynamic-pairlist
|
||||
Enables dynamic pairlist refreshes in backtesting. The
|
||||
pairlist will be generated for each new candle if
|
||||
you're using a pairlist handler that supports this
|
||||
feature, for example, ShuffleFilter.
|
||||
--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 (<code>1m</code>, <code>5m</code>,
|
||||
<code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--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.
|
||||
--export {none,trades,signals}
|
||||
Export backtest results (default: trades).
|
||||
--backtest-filename, --export-filename PATH
|
||||
DEPRECATED: This option is deprecated for backtesting
|
||||
and will be removed in a future release. Using a
|
||||
custom filename for backtest results is no longer
|
||||
supported. Use <code>--backtest-directory</code> to specify the
|
||||
directory.
|
||||
--backtest-directory, --export-directory PATH
|
||||
Directory to use for backtest results. Example:
|
||||
<code>--export-directory=user_data/backtest_results/</code>.
|
||||
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
|
||||
Show backtesting breakdown per [day, week, month,
|
||||
year, weekday].
|
||||
--cache {none,day,week,month}
|
||||
Load a cached backtest result no older than specified
|
||||
age (default: day).
|
||||
--freqai-backtest-live-models
|
||||
Run backtest with ready models.
|
||||
--notes TEXT Add notes to the backtest results.</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH] [-s NAME]</span>
|
||||
<span class="go"> [--strategy-path PATH]</span>
|
||||
<span class="go"> [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME] [--freqaimodel-path PATH]</span>
|
||||
<span class="go"> [-i TIMEFRAME] [--timerange TIMERANGE]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--max-open-trades INT]</span>
|
||||
<span class="go"> [--stake-amount STAKE_AMOUNT] [--fee FLOAT]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]] [--eps]</span>
|
||||
<span class="go"> [--enable-protections]</span>
|
||||
<span class="go"> [--enable-dynamic-pairlist]</span>
|
||||
<span class="go"> [--dry-run-wallet DRY_RUN_WALLET]</span>
|
||||
<span class="go"> [--timeframe-detail TIMEFRAME_DETAIL]</span>
|
||||
<span class="go"> [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]</span>
|
||||
<span class="go"> [--export {none,trades,signals}]</span>
|
||||
<span class="go"> [--backtest-filename PATH]</span>
|
||||
<span class="go"> [--backtest-directory PATH]</span>
|
||||
<span class="go"> [--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]</span>
|
||||
<span class="go"> [--cache {none,day,week,month}]</span>
|
||||
<span class="go"> [--freqai-backtest-live-models] [--notes TEXT]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -i, --timeframe TIMEFRAME</span>
|
||||
<span class="go"> Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> --max-open-trades INT</span>
|
||||
<span class="go"> Override the value of the `max_open_trades`</span>
|
||||
<span class="go"> configuration setting.</span>
|
||||
<span class="go"> --stake-amount STAKE_AMOUNT</span>
|
||||
<span class="go"> Override the value of the `stake_amount` configuration</span>
|
||||
<span class="go"> setting.</span>
|
||||
<span class="go"> --fee FLOAT Specify fee ratio. Will be applied twice (on trade</span>
|
||||
<span class="go"> entry and exit).</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --eps, --enable-position-stacking</span>
|
||||
<span class="go"> Allow buying the same pair multiple times (position</span>
|
||||
<span class="go"> stacking). Only applicable to backtesting and</span>
|
||||
<span class="go"> hyperopt. Results archived by this cannot be</span>
|
||||
<span class="go"> reproduced in dry/live trading.</span>
|
||||
<span class="go"> --enable-protections, --enableprotections</span>
|
||||
<span class="go"> Enable protections for backtesting. Will slow</span>
|
||||
<span class="go"> backtesting down by a considerable amount, but will</span>
|
||||
<span class="go"> include configured protections</span>
|
||||
<span class="go"> --enable-dynamic-pairlist</span>
|
||||
<span class="go"> Enables dynamic pairlist refreshes in backtesting. The</span>
|
||||
<span class="go"> pairlist will be generated for each new candle if</span>
|
||||
<span class="go"> you're using a pairlist handler that supports this</span>
|
||||
<span class="go"> feature, for example, ShuffleFilter.</span>
|
||||
<span class="go"> --dry-run-wallet, --starting-balance DRY_RUN_WALLET</span>
|
||||
<span class="go"> Starting balance, used for backtesting / hyperopt and</span>
|
||||
<span class="go"> dry-runs.</span>
|
||||
<span class="go"> --timeframe-detail TIMEFRAME_DETAIL</span>
|
||||
<span class="go"> Specify detail timeframe for backtesting (`1m`, `5m`,</span>
|
||||
<span class="go"> `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --strategy-list STRATEGY_LIST [STRATEGY_LIST ...]</span>
|
||||
<span class="go"> Provide a space-separated list of strategies to</span>
|
||||
<span class="go"> backtest. Please note that timeframe needs to be set</span>
|
||||
<span class="go"> either in config or via command line.</span>
|
||||
<span class="go"> --export {none,trades,signals}</span>
|
||||
<span class="go"> Export backtest results (default: trades).</span>
|
||||
<span class="go"> --backtest-filename, --export-filename PATH</span>
|
||||
<span class="go"> DEPRECATED: This option is deprecated for backtesting</span>
|
||||
<span class="go"> and will be removed in a future release. Using a</span>
|
||||
<span class="go"> custom filename for backtest results is no longer</span>
|
||||
<span class="go"> supported. Use `--backtest-directory` to specify the</span>
|
||||
<span class="go"> directory.</span>
|
||||
<span class="go"> --backtest-directory, --export-directory PATH</span>
|
||||
<span class="go"> Directory to use for backtest results. Example:</span>
|
||||
<span class="go"> `--export-directory=user_data/backtest_results/`.</span>
|
||||
<span class="go"> --breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]</span>
|
||||
<span class="go"> Show backtesting breakdown per [day, week, month,</span>
|
||||
<span class="go"> year, weekday].</span>
|
||||
<span class="go"> --cache {none,day,week,month}</span>
|
||||
<span class="go"> Load a cached backtest result no older than specified</span>
|
||||
<span class="go"> age (default: day).</span>
|
||||
<span class="go"> --freqai-backtest-live-models</span>
|
||||
<span class="go"> Run backtest with ready models.</span>
|
||||
<span class="go"> --notes TEXT Add notes to the backtest results.</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<h2 id="test-your-strategy-with-backtesting">Test your strategy with Backtesting<a class="headerlink" href="#test-your-strategy-with-backtesting" title="Permanent link">¶</a></h2>
|
||||
<p>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 <a href="https://en.wikipedia.org/wiki/Backtesting">backtesting</a>.</p>
|
||||
@@ -2537,37 +2539,37 @@ This amount must be higher than <code>stake_amount</code>, otherwise the bot wil
|
||||
Profits from early trades will result in subsequent higher stake amounts, resulting in compounding of profits over the backtesting period.</p>
|
||||
<h3 id="example-backtesting-commands">Example backtesting commands<a class="headerlink" href="#example-backtesting-commands" title="Permanent link">¶</a></h3>
|
||||
<p>With 5 min candle (OHLCV) data (per default)</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy AwesomeStrategy</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy
|
||||
</code></pre></div>
|
||||
<p>Where <code>--strategy AwesomeStrategy</code> / <code>-s AwesomeStrategy</code> refers to the class name of the strategy, which is within a python file in the <code>user_data/strategies</code> directory.</p>
|
||||
<hr />
|
||||
<p>With 1 min candle (OHLCV) data</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy AwesomeStrategy --timeframe 1m</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--timeframe<span class="w"> </span>1m
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<p>Providing a custom starting balance of 1000 (in stake currency)</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy AwesomeStrategy --dry-run-wallet 1000</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--dry-run-wallet<span class="w"> </span><span class="m">1000</span>
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<p>Using a different on-disk historical candle (OHLCV) data source</p>
|
||||
<p>Assume you downloaded the history data from the Binance exchange and kept it in the <code>user_data/data/binance-20180101</code> directory.
|
||||
You can then use this data for backtesting as follows:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/binance-20180101</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--datadir<span class="w"> </span>user_data/data/binance-20180101<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<p>Comparing multiple Strategies</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy-list SampleStrategy1 AwesomeStrategy --timeframe 5m</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy-list<span class="w"> </span>SampleStrategy1<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--timeframe<span class="w"> </span>5m
|
||||
</code></pre></div>
|
||||
<p>Where <code>SampleStrategy1</code> and <code>AwesomeStrategy</code> refer to class names of strategies.</p>
|
||||
<hr />
|
||||
<p>Prevent exporting trades to file</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy backtesting --export none --config config.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>backtesting<span class="w"> </span>--export<span class="w"> </span>none<span class="w"> </span>--config<span class="w"> </span>config.json<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<p>Only use this if you're sure you'll not want to plot or analyze your results further.</p>
|
||||
<hr />
|
||||
<p>Exporting trades to file specifying a custom directory</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy backtesting --export trades --backtest-directory=user_data/custom-backtest-results</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>backtesting<span class="w"> </span>--export<span class="w"> </span>trades<span class="w"> </span>--backtest-directory<span class="o">=</span>user_data/custom-backtest-results
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<p>Please also read about the <a href="../strategy-customization/#strategy-startup-period">strategy startup period</a>.</p>
|
||||
<hr />
|
||||
@@ -2576,8 +2578,8 @@ freqtrade backtesting --strategy backtesting --export trades --backtest-director
|
||||
To account for this in backtesting, you can use the <code>--fee</code> 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).</p>
|
||||
<p>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:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --fee 0.001</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--fee<span class="w"> </span><span class="m">0</span>.001
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>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.</p>
|
||||
@@ -2586,8 +2588,8 @@ freqtrade backtesting --fee 0.001</code></p>
|
||||
<p>Running backtest with smaller test-set by using timerange</p>
|
||||
<p>Use the <code>--timerange</code> argument to change how much of the test-set you want to use.</p>
|
||||
<p>For example, running backtesting with the <code>--timerange=20190501-</code> option will use all available data starting with May 1<sup>st</sup>, 2019 from your input data.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --timerange=20190501-</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--timerange<span class="o">=</span><span class="m">20190501</span>-
|
||||
</code></pre></div>
|
||||
<p>You can also specify particular date ranges.</p>
|
||||
<p>The full timerange specification:</p>
|
||||
<ul>
|
||||
@@ -2599,8 +2601,7 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
<h2 id="understand-the-backtesting-result">Understand the backtesting result<a class="headerlink" href="#understand-the-backtesting-result" title="Permanent link">¶</a></h2>
|
||||
<p>The most important in the backtesting is to understand the result.</p>
|
||||
<p>A backtesting result will look like that:</p>
|
||||
<p>```
|
||||
BACKTESTING REPORT <br />
|
||||
<div class="highlight"><pre><span></span><code> BACKTESTING REPORT
|
||||
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
@@ -2614,7 +2615,7 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
│ ADA/USDT:USDT │ 8 │ -1.76 │ -52.098 │ -5.21 │ 11:38:00 │ 6 0 2 75.0 │
|
||||
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||
LEFT OPEN TRADES REPORT <br />
|
||||
LEFT OPEN TRADES REPORT
|
||||
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
@@ -2623,14 +2624,14 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
│ DOT/USDT:USDT │ 1 │ -5.29 │ -19.125 │ -1.91 │ 11:30:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
|
||||
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┘
|
||||
ENTER TAG STATS <br />
|
||||
ENTER TAG STATS
|
||||
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Enter Tag ┃ Entries ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ OTHER │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
|
||||
EXIT REASON STATS <br />
|
||||
EXIT REASON STATS
|
||||
┏━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
@@ -2640,7 +2641,7 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
│ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
|
||||
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
└─────────────┴───────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||
MIXED TAG STATS <br />
|
||||
MIXED TAG STATS
|
||||
┏━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Enter Tag ┃ Exit Reason ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
@@ -2650,7 +2651,7 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
│ │ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
|
||||
│ TOTAL │ │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
└───────────┴─────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||
SUMMARY METRICS <br />
|
||||
SUMMARY METRICS
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Metric ┃ Value ┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
@@ -2702,30 +2703,32 @@ freqtrade backtesting --timerange=20190501-</code></p>
|
||||
│ Drawdown start │ 2025-07-22 15:10:00 │
|
||||
│ Drawdown end │ 2025-08-01 00:00:00 │
|
||||
│ Market change │ 30.51% │
|
||||
└───────────────────────────────┴─────────────────────────────────┘</p>
|
||||
<p>Backtested 2025-07-01 00:00:00 -> 2025-08-01 00:00:00 | Max open trades : 3
|
||||
STRATEGY SUMMARY <br />
|
||||
└───────────────────────────────┴─────────────────────────────────┘
|
||||
|
||||
Backtested 2025-07-01 00:00:00 -> 2025-08-01 00:00:00 | Max open trades : 3
|
||||
STRATEGY SUMMARY
|
||||
┏━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃
|
||||
┡━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ SampleStrategy │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │ 94.647 USDT 8.23% │
|
||||
└────────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┴────────────────────┘
|
||||
```</p>
|
||||
</code></pre></div>
|
||||
<h3 id="backtesting-report-table">Backtesting report table<a class="headerlink" href="#backtesting-report-table" title="Permanent link">¶</a></h3>
|
||||
<p>The first table contains all trades the bot made, including "left open trades".</p>
|
||||
<p>The last line will give you the overall performance of your strategy,
|
||||
here:</p>
|
||||
<p><code>│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │</code></p>
|
||||
<div class="highlight"><pre><span></span><code>│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||
</code></pre></div>
|
||||
<p>The bot has made <code>77</code> trades for an average duration of <code>22:12:00</code>, with a performance of <code>5.48%</code> (profit), that means it has earned a total of <code>54.774 USDT</code> starting with a capital of 1000 USDT.</p>
|
||||
<p>The column <code>Avg Profit %</code> shows the average profit for all trades made.
|
||||
The column <code>Tot Profit %</code> shows instead the total profit % in relation to the starting balance.</p>
|
||||
<p>In the above results, we have a starting balance of 1000 USDT and an absolute profit of 54.774 USDT - so the <code>Tot Profit %</code> will be <code>(54.774 / 1000) * 100 ~= 5.48%</code>.</p>
|
||||
<p>Your strategy performance is influenced by your entry strategy, your exit strategy, and also by the <code>minimal_roi</code> and <code>stop_loss</code> you have set.</p>
|
||||
<p>For example, if your <code>minimal_roi</code> is only <code>"0": 0.01</code> you cannot expect the bot to make more profit than 1% (because it will exit every time a trade reaches 1%).</p>
|
||||
<p><code>json
|
||||
"minimal_roi": {
|
||||
"0": 0.01
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"minimal_roi"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"0"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>On the other hand, if you set a too high <code>minimal_roi</code> like <code>"0": 0.55</code>
|
||||
(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.</p>
|
||||
@@ -2742,7 +2745,7 @@ These trades are also included in the first table, but are also shown separately
|
||||
<h3 id="summary-metrics">Summary metrics<a class="headerlink" href="#summary-metrics" title="Permanent link">¶</a></h3>
|
||||
<p>The last element of the backtest report is the summary metrics table.
|
||||
It contains key metrics about the performance of your strategy on backtesting data.</p>
|
||||
<p><code>┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
<div class="highlight"><pre><span></span><code>┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Metric ┃ Value ┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ Backtesting from │ 2025-07-01 00:00:00 │
|
||||
@@ -2789,7 +2792,8 @@ It contains key metrics about the performance of your strategy on backtesting da
|
||||
│ Drawdown start │ 2025-07-22 15:10:00 │
|
||||
│ Drawdown end │ 2025-08-01 00:00:00 │
|
||||
│ Market change │ 30.51% │
|
||||
└───────────────────────────────┴─────────────────────────────────┘</code></p>
|
||||
└───────────────────────────────┴─────────────────────────────────┘
|
||||
</code></pre></div>
|
||||
<ul>
|
||||
<li><code>Backtesting from</code> / <code>Backtesting to</code>: Backtesting range (usually defined with the <code>--timerange</code> option).</li>
|
||||
<li><code>Trading Mode</code>: Spot or Futures trading.</li>
|
||||
@@ -2832,35 +2836,35 @@ It contains key metrics about the performance of your strategy on backtesting da
|
||||
<h3 id="daily-weekly-monthly-yearly-breakdown">Daily / Weekly / Monthly / Yearly breakdown<a class="headerlink" href="#daily-weekly-monthly-yearly-breakdown" title="Permanent link">¶</a></h3>
|
||||
<p>You can get an overview over daily, weekly, monthly, or yearly results by using the <code>--breakdown <></code> switch.</p>
|
||||
<p>To visualize monthly and yearly breakdowns, you can use the following:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown month year</code></p>
|
||||
<p><code>output
|
||||
MONTH BREAKDOWN
|
||||
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Month ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ 31/01/2020 │ 12 │ 44.451 │ 7.28 │ 10 0 2 83.3 │
|
||||
│ 29/02/2020 │ 30 │ 45.41 │ 2.36 │ 17 0 13 56.7 │
|
||||
│ 31/03/2020 │ 35 │ 142.024 │ 2.42 │ 14 0 21 40.0 │
|
||||
│ 30/04/2020 │ 67 │ -23.692 │ 0.81 │ 24 0 43 35.8 │
|
||||
...
|
||||
...
|
||||
│ 30/04/2025 │ 203 │ -63.43 │ 0.81 │ 73 0 130 36.0 │
|
||||
│ 31/05/2025 │ 142 │ 104.675 │ 1.28 │ 59 0 83 41.5 │
|
||||
│ 30/06/2025 │ 177 │ -1.014 │ 1.0 │ 85 0 92 48.0 │
|
||||
│ 31/07/2025 │ 155 │ 232.762 │ 1.6 │ 63 0 92 40.6 │
|
||||
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
|
||||
YEAR BREAKDOWN
|
||||
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Year ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ 31/12/2020 │ 896 │ 868.889 │ 1.46 │ 351 0 545 39.2 │
|
||||
│ 31/12/2021 │ 1778 │ 4487.163 │ 1.93 │ 745 0 1033 41.9 │
|
||||
│ 31/12/2022 │ 1736 │ 938.27 │ 1.27 │ 698 0 1038 40.2 │
|
||||
│ 31/12/2023 │ 1712 │ 1677.126 │ 1.68 │ 670 0 1042 39.1 │
|
||||
│ 31/12/2024 │ 1609 │ 3198.424 │ 2.22 │ 773 0 836 48.0 │
|
||||
│ 31/12/2025 │ 1042 │ 716.174 │ 1.33 │ 420 0 622 40.3 │
|
||||
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>MyAwesomeStrategy<span class="w"> </span>--breakdown<span class="w"> </span>month<span class="w"> </span>year
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="go"> MONTH BREAKDOWN</span>
|
||||
<span class="go">┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓</span>
|
||||
<span class="go">┃ Month ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃</span>
|
||||
<span class="go">┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩</span>
|
||||
<span class="go">│ 31/01/2020 │ 12 │ 44.451 │ 7.28 │ 10 0 2 83.3 │</span>
|
||||
<span class="go">│ 29/02/2020 │ 30 │ 45.41 │ 2.36 │ 17 0 13 56.7 │</span>
|
||||
<span class="go">│ 31/03/2020 │ 35 │ 142.024 │ 2.42 │ 14 0 21 40.0 │</span>
|
||||
<span class="go">│ 30/04/2020 │ 67 │ -23.692 │ 0.81 │ 24 0 43 35.8 │</span>
|
||||
<span class="go">...</span>
|
||||
<span class="go">...</span>
|
||||
<span class="go">│ 30/04/2025 │ 203 │ -63.43 │ 0.81 │ 73 0 130 36.0 │</span>
|
||||
<span class="go">│ 31/05/2025 │ 142 │ 104.675 │ 1.28 │ 59 0 83 41.5 │</span>
|
||||
<span class="go">│ 30/06/2025 │ 177 │ -1.014 │ 1.0 │ 85 0 92 48.0 │</span>
|
||||
<span class="go">│ 31/07/2025 │ 155 │ 232.762 │ 1.6 │ 63 0 92 40.6 │</span>
|
||||
<span class="go">└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘</span>
|
||||
<span class="go"> YEAR BREAKDOWN</span>
|
||||
<span class="go">┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓</span>
|
||||
<span class="go">┃ Year ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃</span>
|
||||
<span class="go">┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩</span>
|
||||
<span class="go">│ 31/12/2020 │ 896 │ 868.889 │ 1.46 │ 351 0 545 39.2 │</span>
|
||||
<span class="go">│ 31/12/2021 │ 1778 │ 4487.163 │ 1.93 │ 745 0 1033 41.9 │</span>
|
||||
<span class="go">│ 31/12/2022 │ 1736 │ 938.27 │ 1.27 │ 698 0 1038 40.2 │</span>
|
||||
<span class="go">│ 31/12/2023 │ 1712 │ 1677.126 │ 1.68 │ 670 0 1042 39.1 │</span>
|
||||
<span class="go">│ 31/12/2024 │ 1609 │ 3198.424 │ 2.22 │ 773 0 836 48.0 │</span>
|
||||
<span class="go">│ 31/12/2025 │ 1042 │ 716.174 │ 1.33 │ 420 0 622 40.3 │</span>
|
||||
<span class="go">└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘</span>
|
||||
</code></pre></div>
|
||||
<p>The output will display tables containing the realized absolute profit (in stake currency) for the selected period, along with additional statistics such as number of trades, profit factor, and distribution of wins, draws, and losses that materialized (closed) on this period.</p>
|
||||
<h3 id="backtest-result-caching">Backtest result caching<a class="headerlink" href="#backtest-result-caching" title="Permanent link">¶</a></h3>
|
||||
<p>To save time, by default backtest will reuse a cached result from within the last day when the backtested strategy and config match that of a previous backtest. To force a new backtest despite existing result for an identical run specify <code>--cache none</code> parameter.</p>
|
||||
@@ -2948,8 +2952,8 @@ So assuming you run backtesting with a 1h timeframe, there will be 4 prices for
|
||||
<p>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.</p>
|
||||
<p>To utilize this, you can append <code>--timeframe-detail 5m</code> to your regular backtesting command.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-detail 5m</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--timeframe<span class="w"> </span>1h<span class="w"> </span>--timeframe-detail<span class="w"> </span>5m
|
||||
</code></pre></div>
|
||||
<p>This will load 1h data (the main timeframe) as well as 5m data (detail timeframe) for the selected timerange.
|
||||
The strategy will be analyzed with the 1h timeframe.
|
||||
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
|
||||
@@ -3040,16 +3044,17 @@ Also, data must be available / downloaded already.</p>
|
||||
<p>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.</p>
|
||||
<p>All listed Strategies need to be in the same directory, unless also <code>--recursive-strategy-search</code> is specified, where sub-directories within the strategy directory are also considered.</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --timerange 20180401-20180410 --timeframe 5m --strategy-list Strategy001 Strategy002 --export trades</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20180401</span>-20180410<span class="w"> </span>--timeframe<span class="w"> </span>5m<span class="w"> </span>--strategy-list<span class="w"> </span>Strategy001<span class="w"> </span>Strategy002<span class="w"> </span>--export<span class="w"> </span>trades
|
||||
</code></pre></div>
|
||||
<p>This will save the results to <code>user_data/backtest_results/backtest-result-<datetime>.json</code>, including results for both <code>Strategy001</code> and <code>Strategy002</code>.
|
||||
There will be an additional table comparing win/losses of the different strategies (identical to the "Total" row in the first table).
|
||||
Detailed output for all strategies one after the other will be available, so make sure to scroll up to see the details per strategy.</p>
|
||||
<p><code>================================================== STRATEGY SUMMARY ===================================================================
|
||||
<div class="highlight"><pre><span></span><code>================================================== STRATEGY SUMMARY ===================================================================
|
||||
| Strategy | Trades | Avg Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | Drawdown % |
|
||||
|-------------+---------+----------------+------------------+----------------+----------------+-------+--------+--------+------------|
|
||||
| Strategy1 | 429 | 0.36 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | 45.2 |
|
||||
| Strategy2 | 1487 | -0.13 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | 241.68 |</code></p>
|
||||
| Strategy2 | 1487 | -0.13 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | 241.68 |
|
||||
</code></pre></div>
|
||||
<h2 id="next-step">Next step<a class="headerlink" href="#next-step" title="Permanent link">¶</a></h2>
|
||||
<p>Great, your strategy is profitable. What if the bot can give you the optimal parameters to use for your strategy?
|
||||
Your next step is to learn <a href="../hyperopt/">how to find optimal parameters with Hyperopt</a></p>
|
||||
|
||||
+116
-111
@@ -2110,109 +2110,113 @@
|
||||
<p>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.</p>
|
||||
</div>
|
||||
<h2 id="bot-commands">Bot commands<a class="headerlink" href="#bot-commands" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade [-h] [-V]
|
||||
{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-hyperoptloss,list-freqaimodels,list-timeframes,show-trades,test-pairlist,convert-db,install-ui,plot-dataframe,plot-profit,webserver,strategy-updater,lookahead-analysis,recursive-analysis} ...</p>
|
||||
<p>Free, open source crypto trading bot</p>
|
||||
<p>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-hyperoptloss,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. No longer part of Freqtrade
|
||||
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-hyperoptloss Print available hyperopt loss functions.
|
||||
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.</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade [-h] [-V]</span>
|
||||
<span class="go"> {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-hyperoptloss,list-freqaimodels,list-timeframes,show-trades,test-pairlist,convert-db,install-ui,plot-dataframe,plot-profit,webserver,strategy-updater,lookahead-analysis,recursive-analysis} ...</span>
|
||||
|
||||
<span class="go">Free, open source crypto trading bot</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> {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-hyperoptloss,list-freqaimodels,list-timeframes,show-trades,test-pairlist,convert-db,install-ui,plot-dataframe,plot-profit,webserver,strategy-updater,lookahead-analysis,recursive-analysis}</span>
|
||||
<span class="go"> trade Trade module.</span>
|
||||
<span class="go"> create-userdir Create user-data directory.</span>
|
||||
<span class="go"> new-config Create new config</span>
|
||||
<span class="go"> show-config Show resolved config</span>
|
||||
<span class="go"> new-strategy Create new strategy</span>
|
||||
<span class="go"> download-data Download backtesting data.</span>
|
||||
<span class="go"> convert-data Convert candle (OHLCV) data from one format to</span>
|
||||
<span class="go"> another.</span>
|
||||
<span class="go"> convert-trade-data Convert trade data from one format to another.</span>
|
||||
<span class="go"> trades-to-ohlcv Convert trade data to OHLCV data.</span>
|
||||
<span class="go"> list-data List downloaded data.</span>
|
||||
<span class="go"> backtesting Backtesting module.</span>
|
||||
<span class="go"> backtesting-show Show past Backtest results</span>
|
||||
<span class="go"> backtesting-analysis</span>
|
||||
<span class="go"> Backtest Analysis module.</span>
|
||||
<span class="go"> edge Edge module. No longer part of Freqtrade</span>
|
||||
<span class="go"> hyperopt Hyperopt module.</span>
|
||||
<span class="go"> hyperopt-list List Hyperopt results</span>
|
||||
<span class="go"> hyperopt-show Show details of Hyperopt results</span>
|
||||
<span class="go"> list-exchanges Print available exchanges.</span>
|
||||
<span class="go"> list-markets Print markets on exchange.</span>
|
||||
<span class="go"> list-pairs Print pairs on exchange.</span>
|
||||
<span class="go"> list-strategies Print available strategies.</span>
|
||||
<span class="go"> list-hyperoptloss Print available hyperopt loss functions.</span>
|
||||
<span class="go"> list-freqaimodels Print available freqAI models.</span>
|
||||
<span class="go"> list-timeframes Print available timeframes for the exchange.</span>
|
||||
<span class="go"> show-trades Show trades.</span>
|
||||
<span class="go"> test-pairlist Test your pairlist configuration.</span>
|
||||
<span class="go"> convert-db Migrate database to different system</span>
|
||||
<span class="go"> install-ui Install FreqUI</span>
|
||||
<span class="go"> plot-dataframe Plot candles with indicators.</span>
|
||||
<span class="go"> plot-profit Generate plot showing profits.</span>
|
||||
<span class="go"> webserver Webserver module.</span>
|
||||
<span class="go"> strategy-updater updates outdated strategy files to the current version</span>
|
||||
<span class="go"> lookahead-analysis Check for potential look ahead bias.</span>
|
||||
<span class="go"> recursive-analysis Check for potential recursive formula issue.</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
</code></pre></div>
|
||||
<h3 id="bot-trading-commands">Bot trading commands<a class="headerlink" href="#bot-trading-commands" title="Permanent link">¶</a></h3>
|
||||
<p>``` output
|
||||
usage: freqtrade trade [-h] [-v] [--no-color] [--logfile FILE] [-V] [-c PATH]
|
||||
[-d PATH] [--userdir PATH] [-s NAME]
|
||||
[--strategy-path PATH] [--recursive-strategy-search]
|
||||
[--freqaimodel NAME] [--freqaimodel-path PATH]
|
||||
[--db-url PATH] [--sd-notify] [--dry-run]
|
||||
[--dry-run-wallet DRY_RUN_WALLET] [--fee FLOAT]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
--db-url PATH Override trades database URL, this is useful in custom
|
||||
deployments (default: <code>sqlite:///tradesv3.sqlite</code> for
|
||||
Live Run mode, <code>sqlite:///tradesv3.dryrun.sqlite</code> 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, --starting-balance DRY_RUN_WALLET
|
||||
Starting balance, used for backtesting / hyperopt and
|
||||
dry-runs.
|
||||
--fee FLOAT Specify fee ratio. Will be applied twice (on trade
|
||||
entry and exit).</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade trade [-h] [-v] [--no-color] [--logfile FILE] [-V] [-c PATH]</span>
|
||||
<span class="go"> [-d PATH] [--userdir PATH] [-s NAME]</span>
|
||||
<span class="go"> [--strategy-path PATH] [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME] [--freqaimodel-path PATH]</span>
|
||||
<span class="go"> [--db-url PATH] [--sd-notify] [--dry-run]</span>
|
||||
<span class="go"> [--dry-run-wallet DRY_RUN_WALLET] [--fee FLOAT]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> --db-url PATH Override trades database URL, this is useful in custom</span>
|
||||
<span class="go"> deployments (default: `sqlite:///tradesv3.sqlite` for</span>
|
||||
<span class="go"> Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for</span>
|
||||
<span class="go"> Dry Run).</span>
|
||||
<span class="go"> --sd-notify Notify systemd service manager.</span>
|
||||
<span class="go"> --dry-run Enforce dry-run for trading (removes Exchange secrets</span>
|
||||
<span class="go"> and simulates trades).</span>
|
||||
<span class="go"> --dry-run-wallet, --starting-balance DRY_RUN_WALLET</span>
|
||||
<span class="go"> Starting balance, used for backtesting / hyperopt and</span>
|
||||
<span class="go"> dry-runs.</span>
|
||||
<span class="go"> --fee FLOAT Specify fee ratio. Will be applied twice (on trade</span>
|
||||
<span class="go"> entry and exit).</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="how-to-specify-which-configuration-file-be-used">How to specify which configuration file be used?<a class="headerlink" href="#how-to-specify-which-configuration-file-be-used" title="Permanent link">¶</a></h3>
|
||||
<p>The bot allows you to select which configuration file you want to use by means of
|
||||
the <code>-c/--config</code> command line option:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade -c path/far/far/away/config.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>path/far/far/away/config.json
|
||||
</code></pre></div>
|
||||
<p>Per default, the bot loads the <code>config.json</code> configuration file from the current
|
||||
working directory.</p>
|
||||
<h3 id="how-to-use-multiple-configuration-files">How to use multiple configuration files?<a class="headerlink" href="#how-to-use-multiple-configuration-files" title="Permanent link">¶</a></h3>
|
||||
@@ -2224,11 +2228,11 @@ defined in the previous configuration files specified in the command line earlie
|
||||
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):</p>
|
||||
<p><code>bash
|
||||
freqtrade trade -c ./config.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>./config.json
|
||||
</code></pre></div>
|
||||
<p>and specify both configuration files when running in the normal Live Trade Mode:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade -c ./config.json -c path/to/secrets/keys.config.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>./config.json<span class="w"> </span>-c<span class="w"> </span>path/to/secrets/keys.config.json
|
||||
</code></pre></div>
|
||||
<p>This could help you hide your private Exchange key and Exchange secret on you local machine
|
||||
by setting appropriate file permissions for the file which contains actual secrets and, additionally,
|
||||
prevent unintended disclosure of sensitive private data when you publish examples
|
||||
@@ -2238,13 +2242,14 @@ of your configuration in the project issues or in the Internet.</p>
|
||||
<h3 id="where-to-store-custom-data">Where to store custom data<a class="headerlink" href="#where-to-store-custom-data" title="Permanent link">¶</a></h3>
|
||||
<p>Freqtrade allows the creation of a user-data directory using <code>freqtrade create-userdir --userdir someDirectory</code>.
|
||||
This directory will look as follows:</p>
|
||||
<p><code>user_data/
|
||||
<div class="highlight"><pre><span></span><code>user_data/
|
||||
├── backtest_results
|
||||
├── data
|
||||
├── hyperopts
|
||||
├── hyperopt_results
|
||||
├── plot
|
||||
└── strategies</code></p>
|
||||
└── strategies
|
||||
</code></pre></div>
|
||||
<p>You can add the entry "user_data_dir" setting to your configuration, to always point your bot to this directory.
|
||||
Alternatively, pass in <code>--userdir</code> to every command.
|
||||
The bot will fail to start if the directory does not exist, but will create necessary subdirectories.</p>
|
||||
@@ -2259,8 +2264,8 @@ To use other directories, please read the next section about <code>--strategy-pa
|
||||
<p><strong>Example:</strong>
|
||||
In <code>user_data/strategies</code> you have a file <code>my_awesome_strategy.py</code> which has
|
||||
a strategy class called <code>AwesomeStrategy</code> to load it:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --strategy AwesomeStrategy</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy
|
||||
</code></pre></div>
|
||||
<p>If the bot does not find your strategy file, it will display in an error
|
||||
message the reason (File not found, or errors in your code).</p>
|
||||
<p>Learn more about strategy file in
|
||||
@@ -2268,8 +2273,8 @@ message the reason (File not found, or errors in your code).</p>
|
||||
<h3 id="how-to-use-strategy-path">How to use <strong>--strategy-path</strong>?<a class="headerlink" href="#how-to-use-strategy-path" title="Permanent link">¶</a></h3>
|
||||
<p>This parameter allows you to add an additional strategy lookup path, which gets
|
||||
checked before the default locations (The passed path must be a directory!):</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--strategy-path<span class="w"> </span>/some/directory
|
||||
</code></pre></div>
|
||||
<h4 id="how-to-install-a-strategy">How to install a strategy?<a class="headerlink" href="#how-to-install-a-strategy" title="Permanent link">¶</a></h4>
|
||||
<p>This is very simple. Copy paste your strategy file into the directory
|
||||
<code>user_data/strategies</code> or use <code>--strategy-path</code>. And voila, the bot is ready to use it.</p>
|
||||
@@ -2278,8 +2283,8 @@ freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory</code
|
||||
stored in a database. If you want to store your bot actions in a DB
|
||||
using <code>--db-url</code>. This can also be used to specify a custom database
|
||||
in production mode. Example command:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>-c<span class="w"> </span>config.json<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///tradesv3.dry_run.sqlite
|
||||
</code></pre></div>
|
||||
<h2 id="next-step">Next step<a class="headerlink" href="#next-step" title="Permanent link">¶</a></h2>
|
||||
<p>The optimal strategy of the bot will change with time depending of the market trends. The next step is to
|
||||
<a href="../strategy-customization/">Strategy Customization</a>.</p>
|
||||
|
||||
+134
-134
@@ -3056,14 +3056,14 @@ As such - an environment variable defined as <code>export FREQTRADE__STAKE_AMOU
|
||||
Using this scheme, all configuration settings will also be available as environment variables.</p>
|
||||
<p>Please note that Environment variables will overwrite corresponding settings in your configuration, but command line Arguments will always win.</p>
|
||||
<p>Common example:</p>
|
||||
<p><code>bash
|
||||
FREQTRADE__TELEGRAM__CHAT_ID=<telegramchatid>
|
||||
FREQTRADE__TELEGRAM__TOKEN=<telegramToken>
|
||||
FREQTRADE__EXCHANGE__KEY=<yourExchangeKey>
|
||||
FREQTRADE__EXCHANGE__SECRET=<yourExchangeSecret></code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nv">FREQTRADE__TELEGRAM__CHAT_ID</span><span class="o">=</span><telegramchatid>
|
||||
<span class="nv">FREQTRADE__TELEGRAM__TOKEN</span><span class="o">=</span><telegramToken>
|
||||
<span class="nv">FREQTRADE__EXCHANGE__KEY</span><span class="o">=</span><yourExchangeKey>
|
||||
<span class="nv">FREQTRADE__EXCHANGE__SECRET</span><span class="o">=</span><yourExchangeSecret>
|
||||
</code></pre></div>
|
||||
<p>Json lists are parsed as json - so you can use the following to set a list of pairs:</p>
|
||||
<p><code>bash
|
||||
export FREQTRADE__EXCHANGE__PAIR_WHITELIST='["BTC/USDT", "ETH/USDT"]'</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nb">export</span><span class="w"> </span><span class="nv">FREQTRADE__EXCHANGE__PAIR_WHITELIST</span><span class="o">=</span><span class="s1">'["BTC/USDT", "ETH/USDT"]'</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>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.</p>
|
||||
@@ -3091,16 +3091,16 @@ This is similar to using multiple <code>--config</code> parameters, but simpler
|
||||
The 2<sup>nd</sup> 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, <code>config-private.json</code>).</p>
|
||||
<p>For one-off commands, you can also use the below syntax by specifying multiple "--config" parameters.</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --config user_data/config1.json --config user_data/config-private.json <...></code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--config<span class="w"> </span>user_data/config1.json<span class="w"> </span>--config<span class="w"> </span>user_data/config-private.json<span class="w"> </span><...>
|
||||
</code></pre></div>
|
||||
<p>The below is equivalent to the example above - but having 2 configuration files in the configuration, for easier reuse.</p>
|
||||
<div class="highlight"><span class="filename">user_data/config.json</span><pre><span></span><code><span class="nt">"add_config_files"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"config1.json"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"config-private.json"</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p><code>bash
|
||||
freqtrade trade --config user_data/config.json <...></code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--config<span class="w"> </span>user_data/config.json<span class="w"> </span><...>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<details class="note">
|
||||
<summary>config collision handling</summary>
|
||||
@@ -3130,10 +3130,10 @@ In the below case, <code>max_open_trades</code> would be 3 after the merging - a
|
||||
</details>
|
||||
<h2 id="editor-autocomplete-and-validation">Editor autocomplete and validation<a class="headerlink" href="#editor-autocomplete-and-validation" title="Permanent link">¶</a></h2>
|
||||
<p>If you are using an editor that supports JSON schema, you can use the schema provided by Freqtrade to get autocompletion and validation of your configuration file by adding the following line to the top of your configuration file:</p>
|
||||
<p><code>json
|
||||
{
|
||||
"$schema": "https://schema.freqtrade.io/schema.json",
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"$schema"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://schema.freqtrade.io/schema.json"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<details class="note">
|
||||
<summary>Develop version</summary>
|
||||
<p>The develop schema is available as <code>https://schema.freqtrade.io/schema_dev.json</code> - though we recommend to stick to the stable version for the best experience.</p>
|
||||
@@ -3679,12 +3679,12 @@ This exchange has also a limit on USD - where all orders must be > 10$ - whic
|
||||
<h4 id="dry-run-wallet">Dry-run wallet<a class="headerlink" href="#dry-run-wallet" title="Permanent link">¶</a></h4>
|
||||
<p>When running in dry-run mode, the bot will use a simulated wallet to execute trades. The starting balance of this wallet is defined by <code>dry_run_wallet</code> (defaults to 1000).
|
||||
For more complex scenarios, you can also assign a dictionary to <code>dry_run_wallet</code> to define the starting balance for each currency.</p>
|
||||
<p><code>json
|
||||
"dry_run_wallet": {
|
||||
"BTC": 0.01,
|
||||
"ETH": 2,
|
||||
"USDT": 1000
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"dry_run_wallet"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"BTC"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ETH"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"USDT"</span><span class="p">:</span><span class="w"> </span><span class="mi">1000</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Command line options (<code>--dry-run-wallet</code>) can be used to override the configuration value, but only for the float value, not for the dictionary. If you'd like to use the dictionary, please adjust the configuration file.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -3747,12 +3747,12 @@ For example, the bot will at most use (0.05 BTC x 3) = 0.15 BTC, assuming a conf
|
||||
<p>Alternatively, you can use a dynamic stake amount, which will use the available balance on the exchange, and divide that equally by the number of allowed trades (<code>max_open_trades</code>).</p>
|
||||
<p>To configure this, set <code>stake_amount="unlimited"</code>. We also recommend to set <code>tradable_balance_ratio=0.99</code> (99%) - to keep a minimum balance for eventual fees.</p>
|
||||
<p>In this case a trade amount is calculated as:</p>
|
||||
<p><code>python
|
||||
currency_balance / (max_open_trades - current_open_trades)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">currency_balance</span> <span class="o">/</span> <span class="p">(</span><span class="n">max_open_trades</span> <span class="o">-</span> <span class="n">current_open_trades</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>To allow the bot to trade all the available <code>stake_currency</code> in your account (minus <code>tradable_balance_ratio</code>) set</p>
|
||||
<p><code>json
|
||||
"stake_amount" : "unlimited",
|
||||
"tradable_balance_ratio": 0.99,</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"stake_amount"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"unlimited"</span><span class="p">,</span>
|
||||
<span class="nt">"tradable_balance_ratio"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.99</span><span class="p">,</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Compounding profits</p>
|
||||
<p>This configuration will allow increasing/decreasing stakes depending on the performance of the bot (lower stake if the bot is losing, higher stakes if the bot has a winning record since higher balances are available), and will result in profit compounding.</p>
|
||||
@@ -3782,8 +3782,7 @@ Prices are always retrieved right before an order is placed, either by querying
|
||||
<h4 id="enter-price-side">Enter price side<a class="headerlink" href="#enter-price-side" title="Permanent link">¶</a></h4>
|
||||
<p>The configuration setting <code>entry_pricing.price_side</code> defines the side of the orderbook the bot looks for when buying.</p>
|
||||
<p>The following displays an orderbook.</p>
|
||||
<p><code>explanation
|
||||
...
|
||||
<div class="highlight"><pre><span></span><code>...
|
||||
103
|
||||
102
|
||||
101 # ask
|
||||
@@ -3791,7 +3790,8 @@ Prices are always retrieved right before an order is placed, either by querying
|
||||
99 # bid
|
||||
98
|
||||
97
|
||||
...</code></p>
|
||||
...
|
||||
</code></pre></div>
|
||||
<p>If <code>entry_pricing.price_side</code> is set to <code>"bid"</code>, then the bot will use 99 as entry price.<br />
|
||||
In line with that, if <code>entry_pricing.price_side</code> is set to <code>"ask"</code>, then the bot will use 101 as entry price.</p>
|
||||
<p>Depending on the order direction (<em>long</em>/<em>short</em>), this will lead to different results. Therefore we recommend to use <code>"same"</code> or <code>"other"</code> for this configuration instead.
|
||||
@@ -3885,8 +3885,7 @@ Also, prices at the "other" side of the spread are higher than prices at the "bi
|
||||
<h4 id="exit-price-side">Exit price side<a class="headerlink" href="#exit-price-side" title="Permanent link">¶</a></h4>
|
||||
<p>The configuration setting <code>exit_pricing.price_side</code> defines the side of the spread the bot looks for when exiting a trade.</p>
|
||||
<p>The following displays an orderbook:</p>
|
||||
<p><code>explanation
|
||||
...
|
||||
<div class="highlight"><pre><span></span><code>...
|
||||
103
|
||||
102
|
||||
101 # ask
|
||||
@@ -3894,7 +3893,8 @@ Also, prices at the "other" side of the spread are higher than prices at the "bi
|
||||
99 # bid
|
||||
98
|
||||
97
|
||||
...</code></p>
|
||||
...
|
||||
</code></pre></div>
|
||||
<p>If <code>exit_pricing.price_side</code> is set to <code>"ask"</code>, then the bot will use 101 as exiting price.<br />
|
||||
In line with that, if <code>exit_pricing.price_side</code> is set to <code>"bid"</code>, then the bot will use 99 as exiting price.</p>
|
||||
<p>Depending on the order direction (<em>long</em>/<em>short</em>), this will lead to different results. Therefore we recommend to use <code>"same"</code> or <code>"other"</code> for this configuration instead.
|
||||
@@ -3978,33 +3978,33 @@ This would result in the following pricing matrix:</p>
|
||||
<h3 id="market-order-pricing">Market order pricing<a class="headerlink" href="#market-order-pricing" title="Permanent link">¶</a></h3>
|
||||
<p>When using market orders, prices should be configured to use the "correct" side of the orderbook to allow realistic pricing detection.
|
||||
Assuming both entry and exits are using market orders, a configuration similar to the following must be used</p>
|
||||
<p><code>jsonc
|
||||
"order_types": {
|
||||
"entry": "market",
|
||||
"exit": "market"
|
||||
<div class="highlight"><pre><span></span><code> "order_types": {
|
||||
"entry": "market",
|
||||
"exit": "market"
|
||||
// ...
|
||||
},
|
||||
"entry_pricing": {
|
||||
"price_side": "other",
|
||||
"entry_pricing": {
|
||||
"price_side": "other",
|
||||
// ...
|
||||
},
|
||||
"exit_pricing":{
|
||||
"price_side": "other",
|
||||
"exit_pricing":{
|
||||
"price_side": "other",
|
||||
// ...
|
||||
},</code></p>
|
||||
},
|
||||
</code></pre></div>
|
||||
<p>Obviously, if only one side is using limit orders, different pricing combinations can be used.</p>
|
||||
<h2 id="further-configuration-details">Further Configuration details<a class="headerlink" href="#further-configuration-details" title="Permanent link">¶</a></h2>
|
||||
<h3 id="understand-minimal_roi">Understand minimal_roi<a class="headerlink" href="#understand-minimal_roi" title="Permanent link">¶</a></h3>
|
||||
<p>The <code>minimal_roi</code> configuration parameter is a JSON object where the key is a duration
|
||||
in minutes and the value is the minimum ROI as a ratio.
|
||||
See the example below:</p>
|
||||
<p><code>json
|
||||
"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
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"minimal_roi"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"40"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="p">,</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="err">Exi</span><span class="kc">t</span><span class="w"> </span><span class="err">a</span><span class="kc">fter</span><span class="w"> </span><span class="mi">40</span><span class="w"> </span><span class="err">mi</span><span class="kc">nutes</span><span class="w"> </span><span class="err">i</span><span class="kc">f</span><span class="w"> </span><span class="kc">t</span><span class="err">he</span><span class="w"> </span><span class="err">pro</span><span class="kc">f</span><span class="err">i</span><span class="kc">t</span><span class="w"> </span><span class="err">is</span><span class="w"> </span><span class="kc">n</span><span class="err">o</span><span class="kc">t</span><span class="w"> </span><span class="kc">ne</span><span class="err">ga</span><span class="kc">t</span><span class="err">ive</span>
|
||||
<span class="w"> </span><span class="nt">"30"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="p">,</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="err">Exi</span><span class="kc">t</span><span class="w"> </span><span class="err">a</span><span class="kc">fter</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="err">mi</span><span class="kc">nutes</span><span class="w"> </span><span class="err">i</span><span class="kc">f</span><span class="w"> </span><span class="kc">t</span><span class="err">here</span><span class="w"> </span><span class="err">is</span><span class="w"> </span><span class="err">a</span><span class="kc">t</span><span class="w"> </span><span class="err">leas</span><span class="kc">t</span><span class="w"> </span><span class="mi">1</span><span class="err">%</span><span class="w"> </span><span class="err">pro</span><span class="kc">f</span><span class="err">i</span><span class="kc">t</span>
|
||||
<span class="w"> </span><span class="nt">"20"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.02</span><span class="p">,</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="err">Exi</span><span class="kc">t</span><span class="w"> </span><span class="err">a</span><span class="kc">fter</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="err">mi</span><span class="kc">nutes</span><span class="w"> </span><span class="err">i</span><span class="kc">f</span><span class="w"> </span><span class="kc">t</span><span class="err">here</span><span class="w"> </span><span class="err">is</span><span class="w"> </span><span class="err">a</span><span class="kc">t</span><span class="w"> </span><span class="err">leas</span><span class="kc">t</span><span class="w"> </span><span class="mi">2</span><span class="err">%</span><span class="w"> </span><span class="err">pro</span><span class="kc">f</span><span class="err">i</span><span class="kc">t</span>
|
||||
<span class="w"> </span><span class="nt">"0"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.04</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="err">Exi</span><span class="kc">t</span><span class="w"> </span><span class="err">immedia</span><span class="kc">tel</span><span class="err">y</span><span class="w"> </span><span class="err">i</span><span class="kc">f</span><span class="w"> </span><span class="kc">t</span><span class="err">here</span><span class="w"> </span><span class="err">is</span><span class="w"> </span><span class="err">a</span><span class="kc">t</span><span class="w"> </span><span class="err">leas</span><span class="kc">t</span><span class="w"> </span><span class="mi">4</span><span class="err">%</span><span class="w"> </span><span class="err">pro</span><span class="kc">f</span><span class="err">i</span><span class="kc">t</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>Most of the strategy files already include the optimal <code>minimal_roi</code> value.
|
||||
This parameter can be set in either Strategy or Configuration file. If you use it in the configuration file, it will override the
|
||||
<code>minimal_roi</code> value from the strategy file.
|
||||
@@ -4023,12 +4023,12 @@ For example, you can send <code>/forceenter ETH/BTC</code> to the bot, which wil
|
||||
<p>When working with larger timeframes (for example 1h or more) and using a low <code>max_open_trades</code> value, the last candle can be processed as soon as a trade slot becomes available. When processing the last candle, this can lead to a situation where it may not be desirable to use the buy signal on that candle. For example, when using a condition in your strategy where you use a cross-over, that point may have passed too long ago for you to start a trade on it.</p>
|
||||
<p>In these situations, you can enable the functionality to ignore candles that are beyond a specified period by setting <code>ignore_buying_expired_candle_after</code> to a positive number, indicating the number of seconds after which the buy signal becomes expired.</p>
|
||||
<p>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:</p>
|
||||
<p><code>json
|
||||
{
|
||||
//...
|
||||
"ignore_buying_expired_candle_after": 300,
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="nt">"ignore_buying_expired_candle_after"</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>This setting resets with each new candle, so it will not prevent sticking-signals from executing on the 2<sup>nd</sup> or 3<sup>rd</sup> candle they're active. Best use a "trigger" selector for buy signals, which are only active for one candle.</p>
|
||||
@@ -4042,30 +4042,30 @@ stoploss "on exchange" which means stoploss order would be placed immediately on
|
||||
<p>If this is configured, the following 4 values (<code>entry</code>, <code>exit</code>, <code>stoploss</code> and <code>stoploss_on_exchange</code>) need to be present, otherwise, the bot will fail to start.</p>
|
||||
<p>For information on (<code>emergency_exit</code>,<code>force_exit</code>, <code>force_entry</code>, <code>stoploss_on_exchange</code>,<code>stoploss_on_exchange_interval</code>,<code>stoploss_on_exchange_limit_ratio</code>) please see stop loss documentation <a href="../stoploss/">stop loss on exchange</a></p>
|
||||
<p>Syntax for Strategy:</p>
|
||||
<p><code>python
|
||||
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,
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">order_types</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"entry"</span><span class="p">:</span> <span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="s2">"exit"</span><span class="p">:</span> <span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="s2">"emergency_exit"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"force_entry"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"force_exit"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange_interval"</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange_limit_ratio"</span><span class="p">:</span> <span class="mf">0.99</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Configuration:</p>
|
||||
<p><code>json
|
||||
"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
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"order_types"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"entry"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"emergency_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"force_entry"</span><span class="p">:</span><span class="w"> </span><span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"force_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"stoploss"</span><span class="p">:</span><span class="w"> </span><span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"stoploss_on_exchange"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"stoploss_on_exchange_interval"</span><span class="p">:</span><span class="w"> </span><span class="mi">60</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Market order support</p>
|
||||
<p>Not all exchanges support "market" orders.
|
||||
@@ -4106,11 +4106,11 @@ This means the order must be placed on orderbook for at least time in an unfille
|
||||
This can be set in the configuration file or in the strategy.
|
||||
Values set in the configuration file overwrite values from in the strategy, following the regular <a href="#configuration-option-prevalence">precedence rules</a>.</p>
|
||||
<p>The possible values are: <code>GTC</code> (default), <code>FOK</code> or <code>IOC</code>.</p>
|
||||
<p><code>python
|
||||
"order_time_in_force": {
|
||||
"entry": "GTC",
|
||||
"exit": "GTC"
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="s2">"order_time_in_force"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s2">"entry"</span><span class="p">:</span> <span class="s2">"GTC"</span><span class="p">,</span>
|
||||
<span class="s2">"exit"</span><span class="p">:</span> <span class="s2">"GTC"</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>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.</p>
|
||||
@@ -4123,23 +4123,23 @@ The FIAT currency can be set in the configuration file as <code>fiat_display_cur
|
||||
<p>The <code>fiat_display_currency</code> configuration parameter sets the base currency to use for the
|
||||
conversion from coin to fiat in the bot Telegram reports.</p>
|
||||
<p>The valid values are:</p>
|
||||
<p><code>json
|
||||
"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"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="s2">"AUD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"BRL"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CAD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CHF"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CLP"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CNY"</span><span class="p">,</span><span class="w"> </span><span class="s2">"CZK"</span><span class="p">,</span><span class="w"> </span><span class="s2">"DKK"</span><span class="p">,</span><span class="w"> </span><span class="s2">"EUR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"GBP"</span><span class="p">,</span><span class="w"> </span><span class="s2">"HKD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"HUF"</span><span class="p">,</span><span class="w"> </span><span class="s2">"IDR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"ILS"</span><span class="p">,</span><span class="w"> </span><span class="s2">"INR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"JPY"</span><span class="p">,</span><span class="w"> </span><span class="s2">"KRW"</span><span class="p">,</span><span class="w"> </span><span class="s2">"MXN"</span><span class="p">,</span><span class="w"> </span><span class="s2">"MYR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"NOK"</span><span class="p">,</span><span class="w"> </span><span class="s2">"NZD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"PHP"</span><span class="p">,</span><span class="w"> </span><span class="s2">"PKR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"PLN"</span><span class="p">,</span><span class="w"> </span><span class="s2">"RUB"</span><span class="p">,</span><span class="w"> </span><span class="s2">"SEK"</span><span class="p">,</span><span class="w"> </span><span class="s2">"SGD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"THB"</span><span class="p">,</span><span class="w"> </span><span class="s2">"TRY"</span><span class="p">,</span><span class="w"> </span><span class="s2">"TWD"</span><span class="p">,</span><span class="w"> </span><span class="s2">"ZAR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"USD"</span>
|
||||
</code></pre></div>
|
||||
<p>In addition to fiat currencies, a range of crypto currencies is supported.</p>
|
||||
<p>The valid values are:</p>
|
||||
<p><code>json
|
||||
"BTC", "ETH", "XRP", "LTC", "BCH", "BNB"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="s2">"BTC"</span><span class="p">,</span><span class="w"> </span><span class="s2">"ETH"</span><span class="p">,</span><span class="w"> </span><span class="s2">"XRP"</span><span class="p">,</span><span class="w"> </span><span class="s2">"LTC"</span><span class="p">,</span><span class="w"> </span><span class="s2">"BCH"</span><span class="p">,</span><span class="w"> </span><span class="s2">"BNB"</span>
|
||||
</code></pre></div>
|
||||
<h4 id="coingecko-rate-limit-problems">Coingecko Rate limit problems<a class="headerlink" href="#coingecko-rate-limit-problems" title="Permanent link">¶</a></h4>
|
||||
<p>On some IP ranges, coingecko is heavily rate-limiting.
|
||||
In such cases, you may want to add your coingecko API key to the configuration.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"fiat_display_currency": "USD",
|
||||
"coingecko": {
|
||||
"api_key": "your-api",
|
||||
"is_demo": true
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"fiat_display_currency"</span><span class="p">:</span><span class="w"> </span><span class="s2">"USD"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"coingecko"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"api_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your-api"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"is_demo"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Freqtrade supports both Demo and Pro coingecko API keys.</p>
|
||||
<p>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.</p>
|
||||
@@ -4148,12 +4148,12 @@ It is only used for the conversion of coin to fiat in the Telegram reports, whic
|
||||
<p>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.</p>
|
||||
<p>Should you experience problems you suspect are caused by websockets, you can disable these via the setting <code>exchange.enable_ws</code>, which defaults to true.</p>
|
||||
<p><code>jsonc
|
||||
"exchange": {
|
||||
<div class="highlight"><pre><span></span><code>"exchange": {
|
||||
// ...
|
||||
"enable_ws": false,
|
||||
"enable_ws": false,
|
||||
// ...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<p>Should you be required to use a proxy, please refer to the <a href="#using-a-proxy-with-freqtrade">proxy section</a> for more information.</p>
|
||||
<div class="admonition info">
|
||||
<p class="admonition-title">Rollout</p>
|
||||
@@ -4170,19 +4170,19 @@ creating trades on the exchange.</p>
|
||||
<li>Edit your <code>config.json</code> configuration file.</li>
|
||||
<li>Switch <code>dry-run</code> to <code>true</code> and specify <code>db_url</code> for a persistence database.</li>
|
||||
</ol>
|
||||
<p><code>json
|
||||
"dry_run": true,
|
||||
"db_url": "sqlite:///tradesv3.dryrun.sqlite",</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"dry_run"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"db_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sqlite:///tradesv3.dryrun.sqlite"</span><span class="p">,</span>
|
||||
</code></pre></div>
|
||||
<ol>
|
||||
<li>Remove your Exchange API key and secret (change them by empty values or fake credentials):</li>
|
||||
</ol>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "binance",
|
||||
"key": "key",
|
||||
"secret": "secret",
|
||||
...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"binance"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="err">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Once you will be happy with your bot performance running in the Dry-run mode, you can switch it to production mode.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -4209,20 +4209,20 @@ API Keys are usually only required for live trading (trading for real money, bot
|
||||
<h3 id="to-switch-your-bot-in-production-mode">To switch your bot in production mode<a class="headerlink" href="#to-switch-your-bot-in-production-mode" title="Permanent link">¶</a></h3>
|
||||
<p><strong>Edit your <code>config.json</code> file.</strong></p>
|
||||
<p><strong>Switch dry-run to false and don't forget to adapt your database URL if set:</strong></p>
|
||||
<p><code>json
|
||||
"dry_run": false,</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"dry_run"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
|
||||
</code></pre></div>
|
||||
<p><strong>Insert your Exchange API key (change them by fake API keys):</strong></p>
|
||||
<p><code>json
|
||||
{
|
||||
"exchange": {
|
||||
"name": "binance",
|
||||
"key": "af8ddd35195e9dc500b9a6f799f6f5c93d89193b",
|
||||
"secret": "08a9dc6db3d7b53e1acebd9275677f4b0a04f1a5",
|
||||
//"password": "", // Optional, not needed by all exchanges)
|
||||
// ...
|
||||
}
|
||||
//...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"binance"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"af8ddd35195e9dc500b9a6f799f6f5c93d89193b"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"08a9dc6db3d7b53e1acebd9275677f4b0a04f1a5"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">//"password": "", // Optional, not needed by all exchanges)</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>You should also make sure to read the <a href="../exchanges/">Exchanges</a> section of the documentation to be aware of potential configuration details specific to your exchange.</p>
|
||||
<div class="admonition hint">
|
||||
<p class="admonition-title">Keep your secrets secret</p>
|
||||
@@ -4234,21 +4234,21 @@ You can then start the bot with <code>freqtrade trade --config user_data/config.
|
||||
<h2 id="using-a-proxy-with-freqtrade">Using a proxy with Freqtrade<a class="headerlink" href="#using-a-proxy-with-freqtrade" title="Permanent link">¶</a></h2>
|
||||
<p>To use a proxy with freqtrade, export your proxy settings using the variables <code>"HTTP_PROXY"</code> and <code>"HTTPS_PROXY"</code> set to the appropriate values.
|
||||
This will have the proxy settings applied to everything (telegram, coingecko, ...) <strong>except</strong> for exchange requests.</p>
|
||||
<p><code>bash
|
||||
export HTTP_PROXY="http://addr:port"
|
||||
export HTTPS_PROXY="http://addr:port"
|
||||
freqtrade</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nb">export</span><span class="w"> </span><span class="nv">HTTP_PROXY</span><span class="o">=</span><span class="s2">"http://addr:port"</span>
|
||||
<span class="nb">export</span><span class="w"> </span><span class="nv">HTTPS_PROXY</span><span class="o">=</span><span class="s2">"http://addr:port"</span>
|
||||
freqtrade
|
||||
</code></pre></div>
|
||||
<h3 id="proxy-exchange-requests">Proxy exchange requests<a class="headerlink" href="#proxy-exchange-requests" title="Permanent link">¶</a></h3>
|
||||
<p>To use a proxy for exchange connections - you will have to define the proxies as part of the ccxt configuration.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"exchange": {
|
||||
"ccxt_config": {
|
||||
"httpsProxy": "http://addr:port",
|
||||
"wsProxy": "http://addr:port",
|
||||
}
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"httpsProxy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://addr:port"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"wsProxy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://addr:port"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>For more information on available proxy types, please consult the <a href="https://docs.ccxt.com/#/README?id=proxy">ccxt proxy documentation</a>.</p>
|
||||
<h2 id="next-step">Next step<a class="headerlink" href="#next-step" title="Permanent link">¶</a></h2>
|
||||
<p>Now you have configured your config.json, the next step is to <a href="../bot-usage/">start your bot</a>.</p>
|
||||
|
||||
@@ -1328,6 +1328,67 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#recommended-workflow" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Recommended workflow
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-utility-snippets" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example utility snippets
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Example utility snippets">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#change-directory-to-root" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Change directory to root
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-multiple-configuration-files" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load multiple configuration files
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#further-data-analysis-documentation" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Further Data analysis documentation
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1908,6 +1969,67 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#recommended-workflow" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Recommended workflow
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-utility-snippets" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example utility snippets
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Example utility snippets">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#change-directory-to-root" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Change directory to root
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-multiple-configuration-files" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load multiple configuration files
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#further-data-analysis-documentation" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Further Data analysis documentation
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1953,14 +2075,14 @@ Please use the link that's printed in the console after startup for simplified l
|
||||
<p>Sometimes it can be desired to use a system-wide installation of Jupyter notebook, and use a jupyter kernel from the virtual environment.
|
||||
This prevents you from installing the full jupyter suite multiple times per system, and provides an easy way to switch between tasks (freqtrade / other analytics tasks).</p>
|
||||
<p>For this to work, first activate your virtual environment and run the following commands:</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="activate-virtual-environment">Activate virtual environment<a class="headerlink" href="#activate-virtual-environment" title="Permanent link">¶</a></h1>
|
||||
<p>source .venv/bin/activate</p>
|
||||
<p>pip install ipykernel
|
||||
ipython kernel install --user --name=freqtrade</p>
|
||||
<h1 id="restart-jupyter-lab-notebook">Restart jupyter (lab / notebook)<a class="headerlink" href="#restart-jupyter-lab-notebook" title="Permanent link">¶</a></h1>
|
||||
<h1 id="select-kernel-freqtrade-in-the-notebook">select kernel "freqtrade" in the notebook<a class="headerlink" href="#select-kernel-freqtrade-in-the-notebook" title="Permanent link">¶</a></h1>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Activate virtual environment</span>
|
||||
<span class="nb">source</span><span class="w"> </span>.venv/bin/activate
|
||||
|
||||
pip<span class="w"> </span>install<span class="w"> </span>ipykernel
|
||||
ipython<span class="w"> </span>kernel<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>--name<span class="o">=</span>freqtrade
|
||||
<span class="c1"># Restart jupyter (lab / notebook)</span>
|
||||
<span class="c1"># select kernel "freqtrade" in the notebook</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>This section is provided for completeness, the Freqtrade Team won't provide full support for problems with this setup and will recommend to install Jupyter in the virtual environment directly, as that is the easiest way to get jupyter notebooks up and running. For help with this setup please refer to the <a href="https://jupyter.org/">Project Jupyter</a> <a href="https://jupyter.org/documentation">documentation</a> or <a href="https://jupyter.org/community">help channels</a>.</p>
|
||||
@@ -2015,41 +2137,42 @@ ipython kernel install --user --name=freqtrade</p>
|
||||
<h2 id="example-utility-snippets">Example utility snippets<a class="headerlink" href="#example-utility-snippets" title="Permanent link">¶</a></h2>
|
||||
<h3 id="change-directory-to-root">Change directory to root<a class="headerlink" href="#change-directory-to-root" title="Permanent link">¶</a></h3>
|
||||
<p>Jupyter notebooks execute from the notebook directory. The following snippet searches for the project root, so relative paths remain consistent.</p>
|
||||
<p>```python
|
||||
import os
|
||||
from pathlib import Path</p>
|
||||
<h1 id="change-directory">Change directory<a class="headerlink" href="#change-directory" title="Permanent link">¶</a></h1>
|
||||
<h1 id="modify-this-cell-to-insure-that-the-output-shows-the-correct-path">Modify this cell to insure that the output shows the correct path.<a class="headerlink" href="#modify-this-cell-to-insure-that-the-output-shows-the-correct-path" title="Permanent link">¶</a></h1>
|
||||
<h1 id="define-all-paths-relative-to-the-project-root-shown-in-the-cell-output">Define all paths relative to the project root shown in the cell output<a class="headerlink" href="#define-all-paths-relative-to-the-project-root-shown-in-the-cell-output" title="Permanent link">¶</a></h1>
|
||||
<p>project_root = "somedir/freqtrade"
|
||||
i=0
|
||||
try:
|
||||
os.chdir(project_root)
|
||||
assert Path('LICENSE').is_file()
|
||||
except:
|
||||
while i<4 and (not Path('LICENSE').is_file()):
|
||||
os.chdir(Path(Path.cwd(), '../'))
|
||||
i+=1
|
||||
project_root = Path.cwd()
|
||||
print(Path.cwd())
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>
|
||||
|
||||
<span class="c1"># Change directory</span>
|
||||
<span class="c1"># Modify this cell to insure that the output shows the correct path.</span>
|
||||
<span class="c1"># Define all paths relative to the project root shown in the cell output</span>
|
||||
<span class="n">project_root</span> <span class="o">=</span> <span class="s2">"somedir/freqtrade"</span>
|
||||
<span class="n">i</span><span class="o">=</span><span class="mi">0</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">project_root</span><span class="p">)</span>
|
||||
<span class="k">assert</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'LICENSE'</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">()</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="k">while</span> <span class="n">i</span><span class="o"><</span><span class="mi">4</span> <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'LICENSE'</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">()):</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">Path</span><span class="p">(</span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">(),</span> <span class="s1">'../'</span><span class="p">))</span>
|
||||
<span class="n">i</span><span class="o">+=</span><span class="mi">1</span>
|
||||
<span class="n">project_root</span> <span class="o">=</span> <span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">())</span>
|
||||
</code></pre></div>
|
||||
<h3 id="load-multiple-configuration-files">Load multiple configuration files<a class="headerlink" href="#load-multiple-configuration-files" title="Permanent link">¶</a></h3>
|
||||
<p>This option can be useful to inspect the results of passing in multiple configs.
|
||||
This will also run through the whole Configuration initialization, so the configuration is completely initialized to be passed to other methods.</p>
|
||||
<p>``` python
|
||||
import json
|
||||
from freqtrade.configuration import Configuration</p>
|
||||
<h1 id="load-config-from-multiple-files">Load config from multiple files<a class="headerlink" href="#load-config-from-multiple-files" title="Permanent link">¶</a></h1>
|
||||
<p>config = Configuration.from_files(["config1.json", "config2.json"])</p>
|
||||
<h1 id="show-the-config-in-memory">Show the config in memory<a class="headerlink" href="#show-the-config-in-memory" title="Permanent link">¶</a></h1>
|
||||
<p>print(json.dumps(config['original_config'], indent=2))
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">Configuration</span>
|
||||
|
||||
<span class="c1"># Load config from multiple files</span>
|
||||
<span class="n">config</span> <span class="o">=</span> <span class="n">Configuration</span><span class="o">.</span><span class="n">from_files</span><span class="p">([</span><span class="s2">"config1.json"</span><span class="p">,</span> <span class="s2">"config2.json"</span><span class="p">])</span>
|
||||
|
||||
<span class="c1"># Show the config in memory</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s1">'original_config'</span><span class="p">],</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
|
||||
</code></pre></div>
|
||||
<p>For Interactive environments, have an additional configuration specifying <code>user_data_dir</code> and pass this in last, so you don't have to change directories while running the bot.
|
||||
Best avoid relative paths, since this starts at the storage location of the jupyter notebook, unless the directory is changed.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"user_data_dir": "~/.freqtrade/"
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"user_data_dir"</span><span class="p">:</span><span class="w"> </span><span class="s2">"~/.freqtrade/"</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<h3 id="further-data-analysis-documentation">Further Data analysis documentation<a class="headerlink" href="#further-data-analysis-documentation" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
<li><a href="../strategy_analysis_example/">Strategy debugging</a> - also available as Jupyter notebook (<code>user_data/notebooks/strategy_analysis_example.ipynb</code>)</li>
|
||||
|
||||
+320
-319
@@ -2336,84 +2336,85 @@ Without provided configuration, <code>--exchange</code> becomes mandatory.</p>
|
||||
If you are updating existing data after inserting new pairs that you have no data for, use the <code>--new-pairs-days xx</code> parameter. Specified number of days will be downloaded for new pairs while old pairs will be updated with missing data only. </p>
|
||||
</div>
|
||||
<h3 id="usage">Usage<a class="headerlink" href="#usage" title="Permanent link">¶</a></h3>
|
||||
<p>``` output
|
||||
usage: freqtrade download-data [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH]
|
||||
[-p PAIRS [PAIRS ...]] [--pairs-file FILE]
|
||||
[--days INT] [--new-pairs-days INT]
|
||||
[--include-inactive-pairs]
|
||||
[--no-parallel-download]
|
||||
[--timerange TIMERANGE] [--dl-trades]
|
||||
[--convert] [--exchange EXCHANGE]
|
||||
[-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]
|
||||
[--data-format-ohlcv {json,jsongz,feather,parquet}]
|
||||
[--data-format-trades {json,jsongz,feather,parquet}]
|
||||
[--trading-mode {spot,margin,futures}]
|
||||
[--candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]]
|
||||
[--prepend]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --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: <code>None</code>.
|
||||
--include-inactive-pairs
|
||||
Also download data from inactive pairs.
|
||||
--no-parallel-download
|
||||
Disable parallel startup download. Only use this if
|
||||
you experience issues.
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
--dl-trades Download trades instead of OHLCV data.
|
||||
--convert Convert downloaded trades to OHLCV data. Only
|
||||
applicable in combination with <code>--dl-trades</code>. Will be
|
||||
automatic for exchanges which don't have historic
|
||||
OHLCV (e.g. Kraken). If not provided, use <code>trades-to-
|
||||
ohlcv</code> to convert trades data to OHLCV data.
|
||||
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
|
||||
-t, --timeframes TIMEFRAMES [TIMEFRAMES ...]
|
||||
Specify which tickers to download. Space-separated
|
||||
list. Default: <code>1m 5m</code>.
|
||||
--erase Clean all existing data for the selected
|
||||
exchange/pairs/timeframes.
|
||||
--data-format-ohlcv {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
--data-format-trades {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded trades data. (default:
|
||||
<code>feather</code>).
|
||||
--trading-mode, --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 download. Defaults to the
|
||||
necessary candles for the selected trading mode (e.g.
|
||||
'spot' or ('futures', 'funding_rate' and 'mark') for
|
||||
futures).
|
||||
--prepend Allow data prepending. (Data-appending is disabled)</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade download-data [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]] [--pairs-file FILE]</span>
|
||||
<span class="go"> [--days INT] [--new-pairs-days INT]</span>
|
||||
<span class="go"> [--include-inactive-pairs]</span>
|
||||
<span class="go"> [--no-parallel-download]</span>
|
||||
<span class="go"> [--timerange TIMERANGE] [--dl-trades]</span>
|
||||
<span class="go"> [--convert] [--exchange EXCHANGE]</span>
|
||||
<span class="go"> [-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--data-format-trades {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--trading-mode {spot,margin,futures}]</span>
|
||||
<span class="go"> [--candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]]</span>
|
||||
<span class="go"> [--prepend]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --pairs-file FILE File containing a list of pairs. Takes precedence over</span>
|
||||
<span class="go"> --pairs or pairs configured in the configuration.</span>
|
||||
<span class="go"> --days INT Download data for given number of days.</span>
|
||||
<span class="go"> --new-pairs-days INT Download data of new pairs for given number of days.</span>
|
||||
<span class="go"> Default: `None`.</span>
|
||||
<span class="go"> --include-inactive-pairs</span>
|
||||
<span class="go"> Also download data from inactive pairs.</span>
|
||||
<span class="go"> --no-parallel-download</span>
|
||||
<span class="go"> Disable parallel startup download. Only use this if</span>
|
||||
<span class="go"> you experience issues.</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> --dl-trades Download trades instead of OHLCV data.</span>
|
||||
<span class="go"> --convert Convert downloaded trades to OHLCV data. Only</span>
|
||||
<span class="go"> applicable in combination with `--dl-trades`. Will be</span>
|
||||
<span class="go"> automatic for exchanges which don't have historic</span>
|
||||
<span class="go"> OHLCV (e.g. Kraken). If not provided, use `trades-to-</span>
|
||||
<span class="go"> ohlcv` to convert trades data to OHLCV data.</span>
|
||||
<span class="go"> --exchange EXCHANGE Exchange name. Only valid if no config is provided.</span>
|
||||
<span class="go"> -t, --timeframes TIMEFRAMES [TIMEFRAMES ...]</span>
|
||||
<span class="go"> Specify which tickers to download. Space-separated</span>
|
||||
<span class="go"> list. Default: `1m 5m`.</span>
|
||||
<span class="go"> --erase Clean all existing data for the selected</span>
|
||||
<span class="go"> exchange/pairs/timeframes.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> --data-format-trades {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded trades data. (default:</span>
|
||||
<span class="go"> `feather`).</span>
|
||||
<span class="go"> --trading-mode, --tradingmode {spot,margin,futures}</span>
|
||||
<span class="go"> Select Trading mode</span>
|
||||
<span class="go"> --candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]</span>
|
||||
<span class="go"> Select candle type to download. Defaults to the</span>
|
||||
<span class="go"> necessary candles for the selected trading mode (e.g.</span>
|
||||
<span class="go"> 'spot' or ('futures', 'funding_rate' and 'mark') for</span>
|
||||
<span class="go"> futures).</span>
|
||||
<span class="go"> --prepend Allow data prepending. (Data-appending is disabled)</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Downloading all data for one quote currency</p>
|
||||
<p>Often, you'll want to download data for all pairs of a specific quote-currency. In such cases, you can use the following shorthand:
|
||||
@@ -2427,15 +2428,15 @@ To also download data for inactive (delisted) pairs, add <code>--include-inactiv
|
||||
</div>
|
||||
<h3 id="start-download">Start download<a class="headerlink" href="#start-download" title="Permanent link">¶</a></h3>
|
||||
<p>A very simple command (assuming an available <code>config.json</code> file) can look as follows.</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange binance</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>binance
|
||||
</code></pre></div>
|
||||
<p>This will download historical candle (OHLCV) data for all the currency pairs defined in the configuration.</p>
|
||||
<p>Alternatively, specify the pairs directly</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>binance<span class="w"> </span>--pairs<span class="w"> </span>ETH/USDT<span class="w"> </span>XRP/USDT<span class="w"> </span>BTC/USDT
|
||||
</code></pre></div>
|
||||
<p>or as regex (in this case, to download all active USDT pairs)</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange binance --pairs ".*/USDT"</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>binance<span class="w"> </span>--pairs<span class="w"> </span><span class="s2">".*/USDT"</span>
|
||||
</code></pre></div>
|
||||
<h3 id="other-notes">Other Notes<a class="headerlink" href="#other-notes" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
<li>To use a different directory than the exchange specific default, use <code>--datadir user_data/data/some_directory</code>.</li>
|
||||
@@ -2451,15 +2452,17 @@ freqtrade download-data --exchange binance --pairs ".*/USDT"</code></p>
|
||||
<details class="note">
|
||||
<summary>Permission denied errors</summary>
|
||||
<p>If your configuration directory <code>user_data</code> was made by docker, you may get the following error:</p>
|
||||
<p><code>cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied</code></p>
|
||||
<div class="highlight"><pre><span></span><code>cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied
|
||||
</code></pre></div>
|
||||
<p>You can fix the permissions of your user-data directory as follows:</p>
|
||||
<p><code>sudo chown -R $UID:$GID user_data</code></p>
|
||||
<div class="highlight"><pre><span></span><code>sudo chown -R $UID:$GID user_data
|
||||
</code></pre></div>
|
||||
</details>
|
||||
<h3 id="download-additional-data-before-the-current-timerange">Download additional data before the current timerange<a class="headerlink" href="#download-additional-data-before-the-current-timerange" title="Permanent link">¶</a></h3>
|
||||
<p>Assuming you downloaded all data from 2022 (<code>--timerange 20220101-</code>) - but you'd now like to also backtest with earlier data.
|
||||
You can do so by using the <code>--prepend</code> flag, combined with <code>--timerange</code> - specifying an end-date.</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT --prepend --timerange 20210101-20220101</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>binance<span class="w"> </span>--pairs<span class="w"> </span>ETH/USDT<span class="w"> </span>XRP/USDT<span class="w"> </span>BTC/USDT<span class="w"> </span>--prepend<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20210101</span>-20220101
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Freqtrade will ignore the end-date in this mode if data is available, updating the end-date to the existing data start point.</p>
|
||||
@@ -2475,11 +2478,11 @@ freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT --
|
||||
<p>By default, both OHLCV data and trades data are stored in the <code>feather</code> format.</p>
|
||||
<p>This can be changed via the <code>--data-format-ohlcv</code> and <code>--data-format-trades</code> command line arguments respectively.
|
||||
To persist this change, you should also add the following snippet to your configuration, so you don't have to insert the above arguments each time:</p>
|
||||
<p><code>jsonc
|
||||
<div class="highlight"><pre><span></span><code> // ...
|
||||
"dataformat_ohlcv": "feather",
|
||||
"dataformat_trades": "feather",
|
||||
// ...
|
||||
"dataformat_ohlcv": "feather",
|
||||
"dataformat_trades": "feather",
|
||||
// ...</code></p>
|
||||
</code></pre></div>
|
||||
<p>If the default data-format has been changed during download, then the keys <code>dataformat_ohlcv</code> and <code>dataformat_trades</code> in the configuration file need to be adjusted to the selected dataformat as well.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2487,7 +2490,7 @@ To persist this change, you should also add the following snippet to your config
|
||||
</div>
|
||||
<h4 id="dataformat-comparison">Dataformat comparison<a class="headerlink" href="#dataformat-comparison" title="Permanent link">¶</a></h4>
|
||||
<p>The following comparisons have been made with the following data, and by using the linux <code>time</code> command.</p>
|
||||
<p><code>Found 6 pair / timeframe combinations.
|
||||
<div class="highlight"><pre><span></span><code>Found 6 pair / timeframe combinations.
|
||||
+----------+-------------+--------+---------------------+---------------------+
|
||||
| Pair | Timeframe | Type | From | To |
|
||||
|----------+-------------+--------+---------------------+---------------------|
|
||||
@@ -2497,10 +2500,11 @@ To persist this change, you should also add the following snippet to your config
|
||||
| XRP/USDT | 5m | spot | 2018-05-04 08:10:00 | 2022-09-13 19:15:00 |
|
||||
| XRP/USDT | 1m | spot | 2018-05-04 08:11:00 | 2022-09-13 19:22:00 |
|
||||
| ETH/USDT | 5m | spot | 2017-08-17 04:00:00 | 2022-09-13 19:20:00 |
|
||||
+----------+-------------+--------+---------------------+---------------------+</code></p>
|
||||
+----------+-------------+--------+---------------------+---------------------+
|
||||
</code></pre></div>
|
||||
<p>Timings have been taken in a not very scientific way with the following command, which forces reading the data into memory.</p>
|
||||
<p><code>bash
|
||||
time freqtrade list-data --show-timerange --data-format-ohlcv <dataformat></code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nb">time</span><span class="w"> </span>freqtrade<span class="w"> </span>list-data<span class="w"> </span>--show-timerange<span class="w"> </span>--data-format-ohlcv<span class="w"> </span><dataformat>
|
||||
</code></pre></div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2541,253 +2545,250 @@ If you are using Binance for example:</p>
|
||||
<li>create a directory <code>user_data/data/binance</code> and copy or create the <code>pairs.json</code> file in that directory.</li>
|
||||
<li>update the <code>pairs.json</code> file to contain the currency pairs you are interested in.</li>
|
||||
</ul>
|
||||
<p><code>bash
|
||||
mkdir -p user_data/data/binance
|
||||
touch user_data/data/binance/pairs.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>-p<span class="w"> </span>user_data/data/binance
|
||||
touch<span class="w"> </span>user_data/data/binance/pairs.json
|
||||
</code></pre></div>
|
||||
<p>The format of the <code>pairs.json</code> file is a simple json list.
|
||||
Mixing different stake-currencies is allowed for this file, since it's only used for downloading.</p>
|
||||
<p><code>json
|
||||
[
|
||||
"ETH/BTC",
|
||||
"ETH/USDT",
|
||||
"BTC/USDT",
|
||||
"XRP/ETH"
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"ETH/BTC"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"ETH/USDT"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"BTC/USDT"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"XRP/ETH"</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code>pairs.json</code> file is only used when no configuration is loaded (implicitly by naming, or via <code>--config</code> flag).
|
||||
You can force the usage of this file via <code>--pairs-file pairs.json</code> - however we recommend to use the pairlist from within the configuration, either via <code>exchange.pair_whitelist</code> or <code>pairs</code> setting in the configuration.</p>
|
||||
</div>
|
||||
<h2 id="sub-command-convert-data">Sub-command convert data<a class="headerlink" href="#sub-command-convert-data" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade convert-data [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH]
|
||||
[-p PAIRS [PAIRS ...]]
|
||||
--format-from {json,jsongz,feather,parquet}
|
||||
--format-to {json,jsongz,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} ...]]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--format-from {json,jsongz,feather,parquet}
|
||||
Source format for data conversion.
|
||||
--format-to {json,jsongz,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 ...]
|
||||
Specify which tickers to download. Space-separated
|
||||
list. Default: <code>1m 5m</code>.
|
||||
--trading-mode, --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.</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade convert-data [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> --format-from {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> --format-to {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> [--erase] [--exchange EXCHANGE]</span>
|
||||
<span class="go"> [-t TIMEFRAMES [TIMEFRAMES ...]]</span>
|
||||
<span class="go"> [--trading-mode {spot,margin,futures}]</span>
|
||||
<span class="go"> [--candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --format-from {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Source format for data conversion.</span>
|
||||
<span class="go"> --format-to {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Destination format for data conversion.</span>
|
||||
<span class="go"> --erase Clean all existing data for the selected</span>
|
||||
<span class="go"> exchange/pairs/timeframes.</span>
|
||||
<span class="go"> --exchange EXCHANGE Exchange name. Only valid if no config is provided.</span>
|
||||
<span class="go"> -t, --timeframes TIMEFRAMES [TIMEFRAMES ...]</span>
|
||||
<span class="go"> Specify which tickers to download. Space-separated</span>
|
||||
<span class="go"> list. Default: `1m 5m`.</span>
|
||||
<span class="go"> --trading-mode, --tradingmode {spot,margin,futures}</span>
|
||||
<span class="go"> Select Trading mode</span>
|
||||
<span class="go"> --candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]</span>
|
||||
<span class="go"> Select candle type to convert. Defaults to all</span>
|
||||
<span class="go"> available types.</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="example-converting-data">Example converting data<a class="headerlink" href="#example-converting-data" title="Permanent link">¶</a></h3>
|
||||
<p>The following command will convert all candle (OHLCV) data available in <code>~/.freqtrade/data/binance</code> from json to jsongz, saving diskspace in the process.
|
||||
It'll also remove original json data files (<code>--erase</code> parameter).</p>
|
||||
<p><code>bash
|
||||
freqtrade convert-data --format-from json --format-to jsongz --datadir ~/.freqtrade/data/binance -t 5m 15m --erase</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>convert-data<span class="w"> </span>--format-from<span class="w"> </span>json<span class="w"> </span>--format-to<span class="w"> </span>jsongz<span class="w"> </span>--datadir<span class="w"> </span>~/.freqtrade/data/binance<span class="w"> </span>-t<span class="w"> </span>5m<span class="w"> </span>15m<span class="w"> </span>--erase
|
||||
</code></pre></div>
|
||||
<h2 id="sub-command-convert-trade-data">Sub-command convert trade data<a class="headerlink" href="#sub-command-convert-trade-data" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade convert-trade-data [-h] [-v] [--no-color] [--logfile FILE]
|
||||
[-V] [-c PATH] [-d PATH] [--userdir PATH]
|
||||
[-p PAIRS [PAIRS ...]]
|
||||
--format-from {json,jsongz,feather,parquet,kraken_csv}
|
||||
--format-to {json,jsongz,feather,parquet}
|
||||
[--erase] [--exchange EXCHANGE]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--format-from {json,jsongz,feather,parquet,kraken_csv}
|
||||
Source format for data conversion.
|
||||
--format-to {json,jsongz,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.</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade convert-trade-data [-h] [-v] [--no-color] [--logfile FILE]</span>
|
||||
<span class="go"> [-V] [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> --format-from {json,jsongz,feather,parquet,kraken_csv}</span>
|
||||
<span class="go"> --format-to {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> [--erase] [--exchange EXCHANGE]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --format-from {json,jsongz,feather,parquet,kraken_csv}</span>
|
||||
<span class="go"> Source format for data conversion.</span>
|
||||
<span class="go"> --format-to {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Destination format for data conversion.</span>
|
||||
<span class="go"> --erase Clean all existing data for the selected</span>
|
||||
<span class="go"> exchange/pairs/timeframes.</span>
|
||||
<span class="go"> --exchange EXCHANGE Exchange name. Only valid if no config is provided.</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="example-converting-trades">Example converting trades<a class="headerlink" href="#example-converting-trades" title="Permanent link">¶</a></h3>
|
||||
<p>The following command will convert all available trade-data in <code>~/.freqtrade/data/kraken</code> from jsongz to json.
|
||||
It'll also remove original jsongz data files (<code>--erase</code> parameter).</p>
|
||||
<p><code>bash
|
||||
freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>convert-trade-data<span class="w"> </span>--format-from<span class="w"> </span>jsongz<span class="w"> </span>--format-to<span class="w"> </span>json<span class="w"> </span>--datadir<span class="w"> </span>~/.freqtrade/data/kraken<span class="w"> </span>--erase
|
||||
</code></pre></div>
|
||||
<h2 id="sub-command-trades-to-ohlcv">Sub-command trades to ohlcv<a class="headerlink" href="#sub-command-trades-to-ohlcv" title="Permanent link">¶</a></h2>
|
||||
<p>When you need to use <code>--dl-trades</code> (kraken only) to download data, conversion of trades data to ohlcv data is the last step.
|
||||
This command will allow you to repeat this last step for additional timeframes without re-downloading the data.</p>
|
||||
<p>``` output
|
||||
usage: freqtrade trades-to-ohlcv [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH]
|
||||
[-p PAIRS [PAIRS ...]]
|
||||
[-t TIMEFRAMES [TIMEFRAMES ...]]
|
||||
[--exchange EXCHANGE]
|
||||
[--data-format-ohlcv {json,jsongz,feather,parquet}]
|
||||
[--data-format-trades {json,jsongz,feather,parquet}]
|
||||
[--trading-mode {spot,margin,futures}]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
-t, --timeframes TIMEFRAMES [TIMEFRAMES ...]
|
||||
Specify which tickers to download. Space-separated
|
||||
list. Default: <code>1m 5m</code>.
|
||||
--exchange EXCHANGE Exchange name. Only valid if no config is provided.
|
||||
--data-format-ohlcv {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
--data-format-trades {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded trades data. (default:
|
||||
<code>feather</code>).
|
||||
--trading-mode, --tradingmode {spot,margin,futures}
|
||||
Select Trading mode</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade trades-to-ohlcv [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> [-t TIMEFRAMES [TIMEFRAMES ...]]</span>
|
||||
<span class="go"> [--exchange EXCHANGE]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--data-format-trades {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--trading-mode {spot,margin,futures}]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> -t, --timeframes TIMEFRAMES [TIMEFRAMES ...]</span>
|
||||
<span class="go"> Specify which tickers to download. Space-separated</span>
|
||||
<span class="go"> list. Default: `1m 5m`.</span>
|
||||
<span class="go"> --exchange EXCHANGE Exchange name. Only valid if no config is provided.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> --data-format-trades {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded trades data. (default:</span>
|
||||
<span class="go"> `feather`).</span>
|
||||
<span class="go"> --trading-mode, --tradingmode {spot,margin,futures}</span>
|
||||
<span class="go"> Select Trading mode</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="example-trade-to-ohlcv-conversion">Example trade-to-ohlcv conversion<a class="headerlink" href="#example-trade-to-ohlcv-conversion" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
freqtrade trades-to-ohlcv --exchange kraken -t 5m 1h 1d --pairs BTC/EUR ETH/EUR</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trades-to-ohlcv<span class="w"> </span>--exchange<span class="w"> </span>kraken<span class="w"> </span>-t<span class="w"> </span>5m<span class="w"> </span>1h<span class="w"> </span>1d<span class="w"> </span>--pairs<span class="w"> </span>BTC/EUR<span class="w"> </span>ETH/EUR
|
||||
</code></pre></div>
|
||||
<h2 id="sub-command-list-data">Sub-command list-data<a class="headerlink" href="#sub-command-list-data" title="Permanent link">¶</a></h2>
|
||||
<p>You can get a list of downloaded data using the <code>list-data</code> sub-command.</p>
|
||||
<p>``` output
|
||||
usage: freqtrade list-data [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH]
|
||||
[--exchange EXCHANGE]
|
||||
[--data-format-ohlcv {json,jsongz,feather,parquet}]
|
||||
[--data-format-trades {json,jsongz,feather,parquet}]
|
||||
[--trades] [-p PAIRS [PAIRS ...]]
|
||||
[--trading-mode {spot,margin,futures}]
|
||||
[--show-timerange]</p>
|
||||
<p>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,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
--data-format-trades {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded trades data. (default:
|
||||
<code>feather</code>).
|
||||
--trades Work on trades data instead of OHLCV data.
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--trading-mode, --tradingmode {spot,margin,futures}
|
||||
Select Trading mode
|
||||
--show-timerange Show timerange available for available data. (May take
|
||||
a while to calculate).</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>```</p>
|
||||
<h3 id="example-list-data">Example list-data<a class="headerlink" href="#example-list-data" title="Permanent link">¶</a></h3>
|
||||
<p>```bash</p>
|
||||
<blockquote>
|
||||
<p>freqtrade list-data --userdir ~/.freqtrade/user_data/</p>
|
||||
</blockquote>
|
||||
<div class="codehilite"><pre><span></span><code> Found 33 pair / timeframe combinations.
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade list-data [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [--exchange EXCHANGE]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--data-format-trades {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--trades] [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> [--trading-mode {spot,margin,futures}]</span>
|
||||
<span class="go"> [--show-timerange]</span>
|
||||
|
||||
<p>┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━┓
|
||||
┃ Pair ┃ Timeframe ┃ Type ┃
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> --exchange EXCHANGE Exchange name. Only valid if no config is provided.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> --data-format-trades {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded trades data. (default:</span>
|
||||
<span class="go"> `feather`).</span>
|
||||
<span class="go"> --trades Work on trades data instead of OHLCV data.</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --trading-mode, --tradingmode {spot,margin,futures}</span>
|
||||
<span class="go"> Select Trading mode</span>
|
||||
<span class="go"> --show-timerange Show timerange available for available data. (May take</span>
|
||||
<span class="go"> a while to calculate).</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="example-list-data">Example list-data<a class="headerlink" href="#example-list-data" title="Permanent link">¶</a></h3>
|
||||
<div class="highlight"><pre><span></span><code>><span class="w"> </span>freqtrade<span class="w"> </span>list-data<span class="w"> </span>--userdir<span class="w"> </span>~/.freqtrade/user_data/
|
||||
|
||||
<span class="w"> </span>Found<span class="w"> </span><span class="m">33</span><span class="w"> </span>pair<span class="w"> </span>/<span class="w"> </span>timeframe<span class="w"> </span>combinations.
|
||||
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━┓
|
||||
┃<span class="w"> </span>Pair<span class="w"> </span>┃<span class="w"> </span>Timeframe<span class="w"> </span>┃<span class="w"> </span>Type<span class="w"> </span>┃
|
||||
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━┩
|
||||
│ ADA/BTC │ 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d │ spot │
|
||||
│ ADA/ETH │ 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d │ spot │
|
||||
│ ETH/BTC │ 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d │ spot │
|
||||
│ ETH/USDT │ 5m, 15m, 30m, 1h, 2h, 4h │ spot │
|
||||
└───────────────┴───────────────────────────────────────────┴──────┘</p>
|
||||
<p>```</p>
|
||||
│<span class="w"> </span>ADA/BTC<span class="w"> </span>│<span class="w"> </span>5m,<span class="w"> </span>15m,<span class="w"> </span>30m,<span class="w"> </span>1h,<span class="w"> </span>2h,<span class="w"> </span>4h,<span class="w"> </span>6h,<span class="w"> </span>12h,<span class="w"> </span>1d<span class="w"> </span>│<span class="w"> </span>spot<span class="w"> </span>│
|
||||
│<span class="w"> </span>ADA/ETH<span class="w"> </span>│<span class="w"> </span>5m,<span class="w"> </span>15m,<span class="w"> </span>30m,<span class="w"> </span>1h,<span class="w"> </span>2h,<span class="w"> </span>4h,<span class="w"> </span>6h,<span class="w"> </span>12h,<span class="w"> </span>1d<span class="w"> </span>│<span class="w"> </span>spot<span class="w"> </span>│
|
||||
│<span class="w"> </span>ETH/BTC<span class="w"> </span>│<span class="w"> </span>5m,<span class="w"> </span>15m,<span class="w"> </span>30m,<span class="w"> </span>1h,<span class="w"> </span>2h,<span class="w"> </span>4h,<span class="w"> </span>6h,<span class="w"> </span>12h,<span class="w"> </span>1d<span class="w"> </span>│<span class="w"> </span>spot<span class="w"> </span>│
|
||||
│<span class="w"> </span>ETH/USDT<span class="w"> </span>│<span class="w"> </span>5m,<span class="w"> </span>15m,<span class="w"> </span>30m,<span class="w"> </span>1h,<span class="w"> </span>2h,<span class="w"> </span>4h<span class="w"> </span>│<span class="w"> </span>spot<span class="w"> </span>│
|
||||
└───────────────┴───────────────────────────────────────────┴──────┘
|
||||
</code></pre></div>
|
||||
<p>Show all trades data including from/to timerange</p>
|
||||
<p>``` bash</p>
|
||||
<blockquote>
|
||||
<p>freqtrade list-data --show --trades
|
||||
Found trades data for 1 pair. <br />
|
||||
<div class="highlight"><pre><span></span><code>><span class="w"> </span>freqtrade<span class="w"> </span>list-data<span class="w"> </span>--show<span class="w"> </span>--trades
|
||||
<span class="w"> </span>Found<span class="w"> </span>trades<span class="w"> </span>data<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="m">1</span><span class="w"> </span>pair.<span class="w"> </span>
|
||||
┏━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
|
||||
┃ Pair ┃ Type ┃ From ┃ To ┃ Trades ┃
|
||||
┃<span class="w"> </span>Pair<span class="w"> </span>┃<span class="w"> </span>Type<span class="w"> </span>┃<span class="w"> </span>From<span class="w"> </span>┃<span class="w"> </span>To<span class="w"> </span>┃<span class="w"> </span>Trades<span class="w"> </span>┃
|
||||
┡━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩
|
||||
│ XRP/ETH │ spot │ 2019-10-11 00:00:11 │ 2019-10-13 11:19:28 │ 12477 │
|
||||
└─────────┴──────┴─────────────────────┴─────────────────────┴────────┘</p>
|
||||
</blockquote>
|
||||
<p>```</p>
|
||||
│<span class="w"> </span>XRP/ETH<span class="w"> </span>│<span class="w"> </span>spot<span class="w"> </span>│<span class="w"> </span><span class="m">2019</span>-10-11<span class="w"> </span><span class="m">00</span>:00:11<span class="w"> </span>│<span class="w"> </span><span class="m">2019</span>-10-13<span class="w"> </span><span class="m">11</span>:19:28<span class="w"> </span>│<span class="w"> </span><span class="m">12477</span><span class="w"> </span>│
|
||||
└─────────┴──────┴─────────────────────┴─────────────────────┴────────┘
|
||||
</code></pre></div>
|
||||
<h2 id="trades-tick-data">Trades (tick) data<a class="headerlink" href="#trades-tick-data" title="Permanent link">¶</a></h2>
|
||||
<p>By default, <code>download-data</code> sub-command downloads Candles (OHLCV) data. Most exchanges also provide historic trade-data via their API.
|
||||
This data can be useful if you need many different timeframes, since it is only downloaded once, and then resampled locally to the desired timeframes.</p>
|
||||
@@ -2805,8 +2806,8 @@ Most other exchanges provide OHLCV data with sufficient history, so downloading
|
||||
<p>Kraken Futures uses standard OHLCV downloads and does not require <code>--dl-trades</code>.</p>
|
||||
</div>
|
||||
<p>Example call:</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange kraken --pairs XRP/EUR ETH/EUR --days 20 --dl-trades</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>kraken<span class="w"> </span>--pairs<span class="w"> </span>XRP/EUR<span class="w"> </span>ETH/EUR<span class="w"> </span>--days<span class="w"> </span><span class="m">20</span><span class="w"> </span>--dl-trades
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>While this method uses async calls, it will be slow, since it requires the result of the previous call to generate the next request to the exchange.</p>
|
||||
|
||||
@@ -2020,6 +2020,17 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#catboost-models-in-freqai" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Catboost models in freqAI
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2338,6 +2349,17 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#catboost-models-in-freqai" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Catboost models in freqAI
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2437,13 +2459,13 @@ The same is true for <code>dp.get_pair_dataframe(metadata["pair"], "8h", candle_
|
||||
<p>freqtrade will auto-adjust the timeframe and return <code>funding_rates</code> despite the wrongly given timeframe. It'll issue a warning - and may still break your strategy.</p>
|
||||
<h3 id="selective-data-re-download">Selective data re-download<a class="headerlink" href="#selective-data-re-download" title="Permanent link">¶</a></h3>
|
||||
<p>The script below should serve as an example - you may need to adjust the timeframe and exchange to your needs!</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="cleanup-no-longer-needed-data">Cleanup no longer needed data<a class="headerlink" href="#cleanup-no-longer-needed-data" title="Permanent link">¶</a></h1>
|
||||
<p>rm user_data/data/<exchange>/futures/<em>-mark</em>
|
||||
rm user_data/data/<exchange>/futures/<em>-funding_rate</em></p>
|
||||
<h1 id="download-new-data-only-required-once-to-fix-the-mark-and-funding-fee-data">download new data (only required once to fix the mark and funding fee data)<a class="headerlink" href="#download-new-data-only-required-once-to-fix-the-mark-and-funding-fee-data" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade download-data -t 1h --trading-mode futures --candle-types funding_rate mark [...] --timerange <full timerange you've got other data for></p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Cleanup no longer needed data</span>
|
||||
rm<span class="w"> </span>user_data/data/<exchange>/futures/*-mark*
|
||||
rm<span class="w"> </span>user_data/data/<exchange>/futures/*-funding_rate*
|
||||
|
||||
<span class="c1"># download new data (only required once to fix the mark and funding fee data)</span>
|
||||
freqtrade<span class="w"> </span>download-data<span class="w"> </span>-t<span class="w"> </span>1h<span class="w"> </span>--trading-mode<span class="w"> </span>futures<span class="w"> </span>--candle-types<span class="w"> </span>funding_rate<span class="w"> </span>mark<span class="w"> </span><span class="o">[</span>...<span class="o">]</span><span class="w"> </span>--timerange<span class="w"> </span><full<span class="w"> </span>timerange<span class="w"> </span>you<span class="err">'</span>ve<span class="w"> </span>got<span class="w"> </span>other<span class="w"> </span>data<span class="w"> </span><span class="k">for</span>>
|
||||
</code></pre></div>
|
||||
<p>The result of the above will be that your funding_rates and mark data will have the 1h timeframe.
|
||||
you can verify this with <code>freqtrade list-data --exchange <yourexchange> --show</code>.</p>
|
||||
<div class="admonition note">
|
||||
|
||||
+410
-129
@@ -2142,6 +2142,139 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#update-binance-cached-leverage-tiers" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Update binance cached leverage tiers
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#updating-example-notebooks" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Updating example notebooks
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#backtest-documentation-results" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Backtest documentation results
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#continuous-integration" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Continuous integration
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#creating-a-release" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Creating a release
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Creating a release">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-release-branch" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create release branch
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-changelog-from-git-commits" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create changelog from git commits
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#frequi-release" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
FreqUI release
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-github-release-tag" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create github release / tag
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#releases" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Releases
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Releases">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#pypi" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
pypi
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2535,6 +2668,139 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#update-binance-cached-leverage-tiers" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Update binance cached leverage tiers
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#updating-example-notebooks" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Updating example notebooks
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#backtest-documentation-results" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Backtest documentation results
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#continuous-integration" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Continuous integration
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#creating-a-release" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Creating a release
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Creating a release">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-release-branch" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create release branch
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-changelog-from-git-commits" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create changelog from git commits
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#frequi-release" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
FreqUI release
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#create-github-release-tag" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Create github release / tag
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#releases" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Releases
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Releases">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#pypi" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
pypi
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2574,17 +2840,17 @@
|
||||
<p>Documentation is available at <a href="https://www.freqtrade.io/">https://freqtrade.io</a> and needs to be provided with every new feature PR.</p>
|
||||
<p>Special fields for the documentation (like Note boxes, ...) can be found <a href="https://squidfunk.github.io/mkdocs-material/reference/admonitions/">here</a>.</p>
|
||||
<p>To test the documentation locally use the following commands.</p>
|
||||
<p><code>bash
|
||||
pip install -r docs/requirements-docs.txt
|
||||
mkdocs serve</code></p>
|
||||
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>docs/requirements-docs.txt
|
||||
mkdocs<span class="w"> </span>serve
|
||||
</code></pre></div>
|
||||
<p>This will spin up a local server (usually on port 8000) so you can see if everything looks as you'd like it to.</p>
|
||||
<h2 id="developer-setup">Developer setup<a class="headerlink" href="#developer-setup" title="Permanent link">¶</a></h2>
|
||||
<p>To configure a development environment, you can either use the provided <a href="#devcontainer-setup">DevContainer</a>, or use the <code>setup.sh</code> script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ".
|
||||
Alternatively (e.g. if your system is not supported by the setup.sh script), follow the manual installation process and run <code>pip3 install -r requirements-dev.txt</code> - followed by <code>pip3 install -e .[all]</code>.</p>
|
||||
<p>This will install all required tools for development, including <code>pytest</code>, <code>ruff</code>, <code>mypy</code>, and <code>coveralls</code>.</p>
|
||||
<p>Run the following command to install the git hook scripts:</p>
|
||||
<p><code>bash
|
||||
pre-commit install</code></p>
|
||||
<div class="highlight"><pre><span></span><code>pre-commit<span class="w"> </span>install
|
||||
</code></pre></div>
|
||||
<p>These pre-commit scripts check your changes automatically before each commit.<br />
|
||||
If any formatting issues are found, the commit will fail and will prompt for fixes.
|
||||
This reduces unnecessary CI failures, reduces maintenance burden, and improves code quality.</p>
|
||||
@@ -2613,34 +2879,33 @@ If necessary, the Freqtrade team can assist and give guidance with writing good
|
||||
<p>Freqtrade uses 2 main methods to check log content in tests, <code>log_has()</code> and <code>log_has_re()</code> (to check using regex, in case of dynamic log-messages).
|
||||
These are available from <code>conftest.py</code> and can be imported in any test module.</p>
|
||||
<p>A sample check looks as follows:</p>
|
||||
<p>``` python
|
||||
from tests.conftest import log_has, log_has_re</p>
|
||||
<p>def test_method_to_test(caplog):
|
||||
method_to_test()</p>
|
||||
<div class="codehilite"><pre><span></span><code>assert log_has("This event happened", caplog)
|
||||
# Check regex with trailing number ...
|
||||
assert log_has_re(r"This dynamic event happened and produced \d+", caplog)
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">tests.conftest</span><span class="w"> </span><span class="kn">import</span> <span class="n">log_has</span><span class="p">,</span> <span class="n">log_has_re</span>
|
||||
|
||||
<p>```</p>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">test_method_to_test</span><span class="p">(</span><span class="n">caplog</span><span class="p">):</span>
|
||||
<span class="n">method_to_test</span><span class="p">()</span>
|
||||
|
||||
<span class="k">assert</span> <span class="n">log_has</span><span class="p">(</span><span class="s2">"This event happened"</span><span class="p">,</span> <span class="n">caplog</span><span class="p">)</span>
|
||||
<span class="c1"># Check regex with trailing number ...</span>
|
||||
<span class="k">assert</span> <span class="n">log_has_re</span><span class="p">(</span><span class="sa">r</span><span class="s2">"This dynamic event happened and produced \d+"</span><span class="p">,</span> <span class="n">caplog</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<h3 id="debug-configuration">Debug configuration<a class="headerlink" href="#debug-configuration" title="Permanent link">¶</a></h3>
|
||||
<p>To debug freqtrade, we recommend VSCode (with the Python extension) with the following launch configuration (located in <code>.vscode/launch.json</code>).
|
||||
Details will obviously vary between setups - but this should work to get you started.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"name": "freqtrade trade",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "freqtrade",
|
||||
"console": "integratedTerminal",
|
||||
"args": [
|
||||
"trade",
|
||||
// Optional:
|
||||
// "--userdir", "user_data",
|
||||
"--strategy",
|
||||
"MyAwesomeStrategy",
|
||||
]
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"freqtrade trade"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"debugpy"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"request"</span><span class="p">:</span><span class="w"> </span><span class="s2">"launch"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"module"</span><span class="p">:</span><span class="w"> </span><span class="s2">"freqtrade"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"console"</span><span class="p">:</span><span class="w"> </span><span class="s2">"integratedTerminal"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"trade"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// Optional:</span>
|
||||
<span class="w"> </span><span class="c1">// "--userdir", "user_data",</span>
|
||||
<span class="w"> </span><span class="s2">"--strategy"</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="s2">"MyAwesomeStrategy"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>Command line arguments can be added in the <code>"args"</code> array.
|
||||
This method can also be used to debug a strategy, by setting the breakpoints within the strategy.</p>
|
||||
<p>A similar setup can also be taken for Pycharm - using <code>freqtrade</code> as module name, and setting the command line arguments as "parameters".</p>
|
||||
@@ -2662,7 +2927,7 @@ If your environment has not been detected, you can also pick a path manually.</p
|
||||
<p>Freqtrade Exceptions all inherit from <code>FreqtradeException</code>.
|
||||
This general class of error should however not be used directly. Instead, multiple specialized sub-Exceptions exist.</p>
|
||||
<p>Below is an outline of exception inheritance hierarchy:</p>
|
||||
<p><code>+ FreqtradeException
|
||||
<div class="highlight"><pre><span></span><code>+ FreqtradeException
|
||||
|
|
||||
+---+ OperationalException
|
||||
| |
|
||||
@@ -2684,7 +2949,8 @@ This general class of error should however not be used directly. Instead, multip
|
||||
| |
|
||||
| +---+ InsufficientFundsError
|
||||
|
|
||||
+---+ StrategyError</code></p>
|
||||
+---+ StrategyError
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<h2 id="plugins">Plugins<a class="headerlink" href="#plugins" title="Permanent link">¶</a></h2>
|
||||
<h3 id="pairlists">Pairlists<a class="headerlink" href="#pairlists" title="Permanent link">¶</a></h3>
|
||||
@@ -2695,12 +2961,12 @@ Hopefully you also want to contribute this back upstream.</p>
|
||||
<p>This is a simple Handler, which however serves as a good example on how to start developing.</p>
|
||||
<p>Next, modify the class-name of the Handler (ideally align this with the module filename).</p>
|
||||
<p>The base-class provides an instance of the exchange (<code>self._exchange</code>) the pairlist manager (<code>self._pairlistmanager</code>), as well as the main configuration (<code>self._config</code>), the pairlist dedicated configuration (<code>self._pairlistconfig</code>) and the absolute position within the list of pairlists.</p>
|
||||
<p><code>python
|
||||
self._exchange = exchange
|
||||
self._pairlistmanager = pairlistmanager
|
||||
self._config = config
|
||||
self._pairlistconfig = pairlistconfig
|
||||
self._pairlist_pos = pairlist_pos</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="bp">self</span><span class="o">.</span><span class="n">_exchange</span> <span class="o">=</span> <span class="n">exchange</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_pairlistmanager</span> <span class="o">=</span> <span class="n">pairlistmanager</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_config</span> <span class="o">=</span> <span class="n">config</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_pairlistconfig</span> <span class="o">=</span> <span class="n">pairlistconfig</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_pairlist_pos</span> <span class="o">=</span> <span class="n">pairlist_pos</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>Don't forget to register your pairlist in <code>constants.py</code> under the variable <code>AVAILABLE_PAIRLISTS</code> - otherwise it will not be selectable.</p>
|
||||
@@ -2727,11 +2993,11 @@ Hopefully you also want to contribute this back upstream.</p>
|
||||
<p>Validations are optional, the parent class exposes a <code>verify_blacklist(pairlist)</code> and <code>_whitelist_for_active_markets(pairlist)</code> to do default filters. Use this if you limit your result to a certain number of pairs - so the end result is not shorter than expected.</p>
|
||||
<p>In <code>VolumePairList</code>, this implements different methods of sorting, does early validation so only the expected number of pairs is returned.</p>
|
||||
<h5 id="sample">sample<a class="headerlink" href="#sample" title="Permanent link">¶</a></h5>
|
||||
<p><code>python
|
||||
def filter_pairlist(self, pairlist: list[str], tickers: dict) -> List[str]:
|
||||
# Generate dynamic whitelist
|
||||
pairs = self._calculate_pairlist(pairlist, tickers)
|
||||
return pairs</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">def</span><span class="w"> </span><span class="nf">filter_pairlist</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pairlist</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">tickers</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
||||
<span class="c1"># Generate dynamic whitelist</span>
|
||||
<span class="n">pairs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calculate_pairlist</span><span class="p">(</span><span class="n">pairlist</span><span class="p">,</span> <span class="n">tickers</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">pairs</span>
|
||||
</code></pre></div>
|
||||
<h3 id="protections">Protections<a class="headerlink" href="#protections" title="Permanent link">¶</a></h3>
|
||||
<p>Best read the <a href="../plugins/#protections">Protection documentation</a> to understand protections.
|
||||
This Guide is directed towards Developers who want to develop a new protection.</p>
|
||||
@@ -2824,59 +3090,63 @@ The below are "extras", which will make an exchange better (feature-complete) -
|
||||
To demonstrate this, we'll use daily candles (<code>"1d"</code>) to keep things simple.
|
||||
We query the api (<code>ct.fetch_ohlcv()</code>) for the timeframe and look at the date of the last entry. If this entry changes or shows the date of a "incomplete" candle, then we should drop this since having incomplete candles is problematic because indicators assume that only complete candles are passed to them, and will generate a lot of false buy signals. By default, we're therefore removing the last candle assuming it's incomplete.</p>
|
||||
<p>To check how the new exchange behaves, you can use the following snippet:</p>
|
||||
<p>``` python
|
||||
import ccxt
|
||||
from datetime import datetime, timezone
|
||||
from freqtrade.data.converter import ohlcv_to_dataframe
|
||||
ct = ccxt.binance() # Use the exchange you're testing
|
||||
timeframe = "1d"
|
||||
pair = "BTC/USDT" # Make sure to use a pair that exists on that exchange!
|
||||
raw = ct.fetch_ohlcv(pair, timeframe=timeframe)</p>
|
||||
<h1 id="convert-to-dataframe">convert to dataframe<a class="headerlink" href="#convert-to-dataframe" title="Permanent link">¶</a></h1>
|
||||
<p>df1 = ohlcv_to_dataframe(raw, timeframe, pair=pair, drop_incomplete=False)</p>
|
||||
<p>print(df1.tail(1))
|
||||
print(datetime.now(timezone.utc))
|
||||
```</p>
|
||||
<p><code>output
|
||||
date open high low close volume
|
||||
499 2019-06-08 00:00:00+00:00 0.000007 0.000007 0.000007 0.000007 26264344.0
|
||||
2019-06-09 12:30:27.873327</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">ccxt</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.converter</span><span class="w"> </span><span class="kn">import</span> <span class="n">ohlcv_to_dataframe</span>
|
||||
<span class="n">ct</span> <span class="o">=</span> <span class="n">ccxt</span><span class="o">.</span><span class="n">binance</span><span class="p">()</span> <span class="c1"># Use the exchange you're testing</span>
|
||||
<span class="n">timeframe</span> <span class="o">=</span> <span class="s2">"1d"</span>
|
||||
<span class="n">pair</span> <span class="o">=</span> <span class="s2">"BTC/USDT"</span> <span class="c1"># Make sure to use a pair that exists on that exchange!</span>
|
||||
<span class="n">raw</span> <span class="o">=</span> <span class="n">ct</span><span class="o">.</span><span class="n">fetch_ohlcv</span><span class="p">(</span><span class="n">pair</span><span class="p">,</span> <span class="n">timeframe</span><span class="o">=</span><span class="n">timeframe</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># convert to dataframe</span>
|
||||
<span class="n">df1</span> <span class="o">=</span> <span class="n">ohlcv_to_dataframe</span><span class="p">(</span><span class="n">raw</span><span class="p">,</span> <span class="n">timeframe</span><span class="p">,</span> <span class="n">pair</span><span class="o">=</span><span class="n">pair</span><span class="p">,</span> <span class="n">drop_incomplete</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">df1</span><span class="o">.</span><span class="n">tail</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">))</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="go"> date open high low close volume </span>
|
||||
<span class="go">499 2019-06-08 00:00:00+00:00 0.000007 0.000007 0.000007 0.000007 26264344.0 </span>
|
||||
<span class="go">2019-06-09 12:30:27.873327</span>
|
||||
</code></pre></div>
|
||||
<p>The output will show the last entry from the Exchange as well as the current UTC date.
|
||||
If the day shows the same day, then the last candle can be assumed as incomplete and should be dropped (leave the setting <code>"ohlcv_partial_candle"</code> from the exchange-class untouched / True). Otherwise, set <code>"ohlcv_partial_candle"</code> to <code>False</code> to not drop Candles (shown in the example above).
|
||||
Another way is to run this command multiple times in a row and observe if the volume is changing (while the date remains the same).</p>
|
||||
<h3 id="update-binance-cached-leverage-tiers">Update binance cached leverage tiers<a class="headerlink" href="#update-binance-cached-leverage-tiers" title="Permanent link">¶</a></h3>
|
||||
<p>Updating leveraged tiers should be done regularly - and requires an authenticated account with futures enabled.</p>
|
||||
<p>``` python
|
||||
import ccxt
|
||||
import json
|
||||
from pathlib import Path</p>
|
||||
<p>exchange = ccxt.binance({
|
||||
'apiKey': '<apikey>',
|
||||
'secret': '<secret>',
|
||||
'options': {'defaultType': 'swap'}
|
||||
})
|
||||
_ = exchange.load_markets()</p>
|
||||
<p>lev_tiers = exchange.fetch_leverage_tiers()</p>
|
||||
<h1 id="assumes-this-is-running-in-the-root-of-the-repository">Assumes this is running in the root of the repository.<a class="headerlink" href="#assumes-this-is-running-in-the-root-of-the-repository" title="Permanent link">¶</a></h1>
|
||||
<p>file = Path('freqtrade/exchange/binance_leverage_tiers.json')
|
||||
json.dump(dict(sorted(lev_tiers.items())), file.open('w'), indent=2)</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">ccxt</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>
|
||||
|
||||
<span class="n">exchange</span> <span class="o">=</span> <span class="n">ccxt</span><span class="o">.</span><span class="n">binance</span><span class="p">({</span>
|
||||
<span class="s1">'apiKey'</span><span class="p">:</span> <span class="s1">'<apikey>'</span><span class="p">,</span>
|
||||
<span class="s1">'secret'</span><span class="p">:</span> <span class="s1">'<secret>'</span><span class="p">,</span>
|
||||
<span class="s1">'options'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'defaultType'</span><span class="p">:</span> <span class="s1">'swap'</span><span class="p">}</span>
|
||||
<span class="p">})</span>
|
||||
<span class="n">_</span> <span class="o">=</span> <span class="n">exchange</span><span class="o">.</span><span class="n">load_markets</span><span class="p">()</span>
|
||||
|
||||
<span class="n">lev_tiers</span> <span class="o">=</span> <span class="n">exchange</span><span class="o">.</span><span class="n">fetch_leverage_tiers</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Assumes this is running in the root of the repository.</span>
|
||||
<span class="n">file</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'freqtrade/exchange/binance_leverage_tiers.json'</span><span class="p">)</span>
|
||||
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">lev_tiers</span><span class="o">.</span><span class="n">items</span><span class="p">())),</span> <span class="n">file</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">'w'</span><span class="p">),</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>This file should then be contributed upstream, so others can benefit from this, too.</p>
|
||||
<h2 id="updating-example-notebooks">Updating example notebooks<a class="headerlink" href="#updating-example-notebooks" title="Permanent link">¶</a></h2>
|
||||
<p>To keep the jupyter notebooks aligned with the documentation, the following should be ran after updating a example notebook.</p>
|
||||
<p><code>bash
|
||||
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace freqtrade/templates/strategy_analysis_example.ipynb
|
||||
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade/templates/strategy_analysis_example.ipynb --stdout > docs/strategy_analysis_example.md</code></p>
|
||||
<div class="highlight"><pre><span></span><code>jupyter<span class="w"> </span>nbconvert<span class="w"> </span>--ClearOutputPreprocessor.enabled<span class="o">=</span>True<span class="w"> </span>--inplace<span class="w"> </span>freqtrade/templates/strategy_analysis_example.ipynb
|
||||
jupyter<span class="w"> </span>nbconvert<span class="w"> </span>--ClearOutputPreprocessor.enabled<span class="o">=</span>True<span class="w"> </span>--to<span class="w"> </span>markdown<span class="w"> </span>freqtrade/templates/strategy_analysis_example.ipynb<span class="w"> </span>--stdout<span class="w"> </span>><span class="w"> </span>docs/strategy_analysis_example.md
|
||||
</code></pre></div>
|
||||
<h2 id="backtest-documentation-results">Backtest documentation results<a class="headerlink" href="#backtest-documentation-results" title="Permanent link">¶</a></h2>
|
||||
<p>To generate backtest outputs, please use the following commands:</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="assume-a-dedicated-user-directory-for-this-output">Assume a dedicated user directory for this output<a class="headerlink" href="#assume-a-dedicated-user-directory-for-this-output" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade create-userdir --userdir user_data_bttest/</p>
|
||||
<h1 id="set-can_short-true">set can_short = True<a class="headerlink" href="#set-can_short-true" title="Permanent link">¶</a></h1>
|
||||
<p>sed -i "s/can_short: bool = False/can_short: bool = True/" user_data_bttest/strategies/sample_strategy.py</p>
|
||||
<p>freqtrade download-data --timerange 20250625-20250801 --config tests/testdata/config.tests.usdt.json --userdir user_data_bttest/ -t 5m</p>
|
||||
<p>freqtrade backtesting --config tests/testdata/config.tests.usdt.json -s SampleStrategy --userdir user_data_bttest/ --cache none --timerange 20250701-20250801
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Assume a dedicated user directory for this output</span>
|
||||
freqtrade<span class="w"> </span>create-userdir<span class="w"> </span>--userdir<span class="w"> </span>user_data_bttest/
|
||||
<span class="c1"># set can_short = True</span>
|
||||
sed<span class="w"> </span>-i<span class="w"> </span><span class="s2">"s/can_short: bool = False/can_short: bool = True/"</span><span class="w"> </span>user_data_bttest/strategies/sample_strategy.py
|
||||
|
||||
freqtrade<span class="w"> </span>download-data<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20250625</span>-20250801<span class="w"> </span>--config<span class="w"> </span>tests/testdata/config.tests.usdt.json<span class="w"> </span>--userdir<span class="w"> </span>user_data_bttest/<span class="w"> </span>-t<span class="w"> </span>5m
|
||||
|
||||
freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--config<span class="w"> </span>tests/testdata/config.tests.usdt.json<span class="w"> </span>-s<span class="w"> </span>SampleStrategy<span class="w"> </span>--userdir<span class="w"> </span>user_data_bttest/<span class="w"> </span>--cache<span class="w"> </span>none<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20250701</span>-20250801
|
||||
</code></pre></div>
|
||||
<h2 id="continuous-integration">Continuous integration<a class="headerlink" href="#continuous-integration" title="Permanent link">¶</a></h2>
|
||||
<p>This documents some decisions taken for the CI Pipeline.</p>
|
||||
<ul>
|
||||
@@ -2896,10 +3166,9 @@ jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade
|
||||
<p>Make sure that the <code>stable</code> branch is up-to-date!</p>
|
||||
</div>
|
||||
<p>First, pick a commit that's about one week old (to not include latest additions to releases).</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="create-new-branch">create new branch<a class="headerlink" href="#create-new-branch" title="Permanent link">¶</a></h1>
|
||||
<p>git checkout -b new_release <commitid>
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># create new branch</span>
|
||||
git<span class="w"> </span>checkout<span class="w"> </span>-b<span class="w"> </span>new_release<span class="w"> </span><commitid>
|
||||
</code></pre></div>
|
||||
<p>Determine if crucial bugfixes have been made between this commit and the current state, and eventually cherry-pick these.</p>
|
||||
<ul>
|
||||
<li>Merge the release branch (stable) into this branch.</li>
|
||||
@@ -2909,19 +3178,17 @@ jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade
|
||||
<li>Update develop version to next version following the pattern <code>2025.8-dev</code>.</li>
|
||||
</ul>
|
||||
<h3 id="create-changelog-from-git-commits">Create changelog from git commits<a class="headerlink" href="#create-changelog-from-git-commits" title="Permanent link">¶</a></h3>
|
||||
<p>``` bash</p>
|
||||
<h1 id="needs-to-be-done-before-merging-pulling-that-branch">Needs to be done before merging / pulling that branch.<a class="headerlink" href="#needs-to-be-done-before-merging-pulling-that-branch" title="Permanent link">¶</a></h1>
|
||||
<p>git log --oneline --no-decorate --no-merges stable..new_release
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Needs to be done before merging / pulling that branch.</span>
|
||||
git<span class="w"> </span>log<span class="w"> </span>--oneline<span class="w"> </span>--no-decorate<span class="w"> </span>--no-merges<span class="w"> </span>stable..new_release
|
||||
</code></pre></div>
|
||||
<p>To keep the release-log short, best wrap the full git changelog into a collapsible details section.</p>
|
||||
<p>```markdown</p>
|
||||
<details>
|
||||
<summary>Expand full changelog</summary>
|
||||
<div class="highlight"><pre><span></span><code><details>
|
||||
<summary>Expand full changelog</summary>
|
||||
|
||||
... Full git changelog
|
||||
|
||||
</details>
|
||||
<p>```</p>
|
||||
</details>
|
||||
</code></pre></div>
|
||||
<h3 id="frequi-release">FreqUI release<a class="headerlink" href="#frequi-release" title="Permanent link">¶</a></h3>
|
||||
<p>If FreqUI has been updated substantially, make sure to create a release before merging the release branch.
|
||||
Make sure that freqUI CI on the release is finished and passed before merging the release.</p>
|
||||
@@ -2936,31 +3203,44 @@ Make sure that freqUI CI on the release is finished and passed before merging th
|
||||
</ul>
|
||||
<details class="tip">
|
||||
<summary>Release template</summary>
|
||||
<p>````</p>
|
||||
<h1 id="highlighted-changes">Highlighted changes<a class="headerlink" href="#highlighted-changes" title="Permanent link">¶</a></h1>
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<h2 id="how-to-update">How to update<a class="headerlink" href="#how-to-update" title="Permanent link">¶</a></h2>
|
||||
<p>As always, you can update your bot using one of the following commands:</p>
|
||||
<h3 id="docker-compose">docker-compose<a class="headerlink" href="#docker-compose" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
<div class="highlight"><pre><span></span><code># Highlighted changes
|
||||
|
||||
- ...
|
||||
|
||||
## How to update
|
||||
|
||||
As always, you can update your bot using one of the following commands:
|
||||
|
||||
### docker-compose
|
||||
|
||||
```bash
|
||||
docker-compose pull
|
||||
docker-compose up -d</code></p>
|
||||
<h3 id="installation-via-setup-script">Installation via setup script<a class="headerlink" href="#installation-via-setup-script" title="Permanent link">¶</a></h3>
|
||||
<p>``` bash</p>
|
||||
<h1 id="deactivate-venv-and-run">Deactivate venv and run<a class="headerlink" href="#deactivate-venv-and-run" title="Permanent link">¶</a></h1>
|
||||
<p>./setup.sh --update
|
||||
```</p>
|
||||
<h3 id="plain-native-installation">Plain native installation<a class="headerlink" href="#plain-native-installation" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Installation via setup script
|
||||
|
||||
``` bash
|
||||
# Deactivate venv and run
|
||||
./setup.sh --update
|
||||
```
|
||||
|
||||
### Plain native installation
|
||||
|
||||
``` bash
|
||||
git pull
|
||||
pip install -U -r requirements.txt</code></p>
|
||||
<p><details>
|
||||
<summary>Expand full changelog</summary></p>
|
||||
<p><code><Paste your changelog here></code></p>
|
||||
</details>
|
||||
<p>````</p>
|
||||
pip install -U -r requirements.txt
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Expand full changelog</summary>
|
||||
|
||||
```
|
||||
<Paste your changelog here>
|
||||
```
|
||||
|
||||
</details>
|
||||
</code></pre></div>
|
||||
</details>
|
||||
<h2 id="releases">Releases<a class="headerlink" href="#releases" title="Permanent link">¶</a></h2>
|
||||
<h3 id="pypi">pypi<a class="headerlink" href="#pypi" title="Permanent link">¶</a></h3>
|
||||
@@ -2973,14 +3253,15 @@ Manual pypi pushes should not be necessary.</p>
|
||||
<summary>Manual release</summary>
|
||||
<p>To manually create a pypi release, please run the following commands:</p>
|
||||
<p>Additional requirement: <code>wheel</code>, <code>twine</code> (for uploading), account on pypi with proper permissions.</p>
|
||||
<p>``` bash
|
||||
pip install -U build
|
||||
python -m build --sdist --wheel</p>
|
||||
<h1 id="for-pypi-test-to-check-if-some-change-to-the-installation-did-work">For pypi test (to check if some change to the installation did work)<a class="headerlink" href="#for-pypi-test-to-check-if-some-change-to-the-installation-did-work" title="Permanent link">¶</a></h1>
|
||||
<p>twine upload --repository-url <a href="https://test.pypi.org/legacy/">https://test.pypi.org/legacy/</a> dist/*</p>
|
||||
<h1 id="for-production">For production:<a class="headerlink" href="#for-production" title="Permanent link">¶</a></h1>
|
||||
<p>twine upload dist/*
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span>build
|
||||
python<span class="w"> </span>-m<span class="w"> </span>build<span class="w"> </span>--sdist<span class="w"> </span>--wheel
|
||||
|
||||
<span class="c1"># For pypi test (to check if some change to the installation did work)</span>
|
||||
twine<span class="w"> </span>upload<span class="w"> </span>--repository-url<span class="w"> </span>https://test.pypi.org/legacy/<span class="w"> </span>dist/*
|
||||
|
||||
<span class="c1"># For production:</span>
|
||||
twine<span class="w"> </span>upload<span class="w"> </span>dist/*
|
||||
</code></pre></div>
|
||||
<p>Please don't push non-releases to the productive / real pypi instance.</p>
|
||||
</details>
|
||||
|
||||
|
||||
@@ -399,6 +399,178 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Docker quick start">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#adding-a-custom-strategy" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Adding a custom strategy
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#accessing-the-ui" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Accessing the UI
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#monitoring-the-bot" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Monitoring the bot
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#docker-compose-logs" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Docker compose logs
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#database" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Database
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#updating-freqtrade-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Updating freqtrade with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#editing-the-docker-compose-file" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Editing the docker-compose file
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Editing the docker-compose file">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-download-data-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example: Download data with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-backtest-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example: Backtest with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#additional-dependencies-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Additional dependencies with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plotting-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plotting with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#data-analysis-using-docker-compose" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Data analysis using docker compose
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#troubleshooting" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Troubleshooting
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Troubleshooting">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#docker-on-windows" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Docker on Windows
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1901,6 +2073,178 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Docker quick start">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#adding-a-custom-strategy" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Adding a custom strategy
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#accessing-the-ui" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Accessing the UI
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#monitoring-the-bot" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Monitoring the bot
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#docker-compose-logs" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Docker compose logs
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#database" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Database
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#updating-freqtrade-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Updating freqtrade with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#editing-the-docker-compose-file" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Editing the docker-compose file
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Editing the docker-compose file">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-download-data-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example: Download data with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#example-backtest-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Example: Backtest with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#additional-dependencies-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Additional dependencies with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plotting-with-docker" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plotting with docker
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#data-analysis-using-docker-compose" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Data analysis using docker compose
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#troubleshooting" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Troubleshooting
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Troubleshooting">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#docker-on-windows" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Docker on Windows
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1962,18 +2306,20 @@ While the docker-compose standalone installation still works, it will require ch
|
||||
</div>
|
||||
<h3 id="docker-quick-start">Docker quick start<a class="headerlink" href="#docker-quick-start" title="Permanent link">¶</a></h3>
|
||||
<p>Create a new directory and place the <a href="https://raw.githubusercontent.com/freqtrade/freqtrade/stable/docker-compose.yml">docker-compose file</a> in this directory.</p>
|
||||
<p>``` bash
|
||||
mkdir ft_userdata
|
||||
cd ft_userdata/</p>
|
||||
<h1 id="download-the-docker-compose-file-from-the-repository">Download the docker-compose file from the repository<a class="headerlink" href="#download-the-docker-compose-file-from-the-repository" title="Permanent link">¶</a></h1>
|
||||
<p>curl <a href="https://raw.githubusercontent.com/freqtrade/freqtrade/stable/docker-compose.yml">https://raw.githubusercontent.com/freqtrade/freqtrade/stable/docker-compose.yml</a> -o docker-compose.yml</p>
|
||||
<h1 id="pull-the-freqtrade-image">Pull the freqtrade image<a class="headerlink" href="#pull-the-freqtrade-image" title="Permanent link">¶</a></h1>
|
||||
<p>docker compose pull</p>
|
||||
<h1 id="create-user-directory-structure">Create user directory structure<a class="headerlink" href="#create-user-directory-structure" title="Permanent link">¶</a></h1>
|
||||
<p>docker compose run --rm freqtrade create-userdir --userdir user_data</p>
|
||||
<h1 id="create-configuration-requires-answering-interactive-questions">Create configuration - Requires answering interactive questions<a class="headerlink" href="#create-configuration-requires-answering-interactive-questions" title="Permanent link">¶</a></h1>
|
||||
<p>docker compose run --rm freqtrade new-config --config user_data/config.json
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>ft_userdata
|
||||
<span class="nb">cd</span><span class="w"> </span>ft_userdata/
|
||||
<span class="c1"># Download the docker-compose file from the repository</span>
|
||||
curl<span class="w"> </span>https://raw.githubusercontent.com/freqtrade/freqtrade/stable/docker-compose.yml<span class="w"> </span>-o<span class="w"> </span>docker-compose.yml
|
||||
|
||||
<span class="c1"># Pull the freqtrade image</span>
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>pull
|
||||
|
||||
<span class="c1"># Create user directory structure</span>
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>freqtrade<span class="w"> </span>create-userdir<span class="w"> </span>--userdir<span class="w"> </span>user_data
|
||||
|
||||
<span class="c1"># Create configuration - Requires answering interactive questions</span>
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>freqtrade<span class="w"> </span>new-config<span class="w"> </span>--config<span class="w"> </span>user_data/config.json
|
||||
</code></pre></div>
|
||||
<p>The above snippet creates a new directory called <code>ft_userdata</code>, downloads the latest compose file and pulls the freqtrade image.
|
||||
The last 2 steps in the snippet create the directory with <code>user_data</code>, as well as (interactively) the default configuration based on your selections.</p>
|
||||
<div class="admonition question">
|
||||
@@ -1995,8 +2341,8 @@ Please always backtest your strategy and use dry-run for some time before riskin
|
||||
You will find more information about Strategy development in the <a href="../strategy-customization/">Strategy documentation</a>.</p>
|
||||
</div>
|
||||
<p>Once this is done, you're ready to launch the bot in trading mode (Dry-run or Live-trading, depending on your answer to the corresponding question you made above).</p>
|
||||
<p><code>bash
|
||||
docker compose up -d</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Default configuration</p>
|
||||
<p>While the configuration generated will be mostly functional, you will still need to verify that all options correspond to what you want (like Pricing, pairlist, ...) before starting the bot.</p>
|
||||
@@ -2021,12 +2367,11 @@ You can also check the latest log with the command <code>docker compose logs -f<
|
||||
<p>The database will be located at: <code>user_data/tradesv3.sqlite</code></p>
|
||||
<h4 id="updating-freqtrade-with-docker">Updating freqtrade with docker<a class="headerlink" href="#updating-freqtrade-with-docker" title="Permanent link">¶</a></h4>
|
||||
<p>Updating freqtrade when using <code>docker</code> is as simple as running the following 2 commands:</p>
|
||||
<p>``` bash</p>
|
||||
<h1 id="download-the-latest-image">Download the latest image<a class="headerlink" href="#download-the-latest-image" title="Permanent link">¶</a></h1>
|
||||
<p>docker compose pull</p>
|
||||
<h1 id="restart-the-image">Restart the image<a class="headerlink" href="#restart-the-image" title="Permanent link">¶</a></h1>
|
||||
<p>docker compose up -d
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Download the latest image</span>
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>pull
|
||||
<span class="c1"># Restart the image</span>
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d
|
||||
</code></pre></div>
|
||||
<p>This will first pull the latest image, and will then restart the container with the just pulled version.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Check the Changelog</p>
|
||||
@@ -2054,40 +2399,40 @@ This can be useful for fetching exchange information to add to your <code>config
|
||||
</details>
|
||||
<h4 id="example-download-data-with-docker">Example: Download data with docker<a class="headerlink" href="#example-download-data-with-docker" title="Permanent link">¶</a></h4>
|
||||
<p>Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory <code>user_data/data/</code> on the host.</p>
|
||||
<p><code>bash
|
||||
docker compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--pairs<span class="w"> </span>ETH/BTC<span class="w"> </span>--exchange<span class="w"> </span>binance<span class="w"> </span>--days<span class="w"> </span><span class="m">5</span><span class="w"> </span>-t<span class="w"> </span>1h
|
||||
</code></pre></div>
|
||||
<p>Head over to the <a href="../data-download/">Data Downloading Documentation</a> for more details on downloading data.</p>
|
||||
<h4 id="example-backtest-with-docker">Example: Backtest with docker<a class="headerlink" href="#example-backtest-with-docker" title="Permanent link">¶</a></h4>
|
||||
<p>Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe:</p>
|
||||
<p><code>bash
|
||||
docker compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--config<span class="w"> </span>user_data/config.json<span class="w"> </span>--strategy<span class="w"> </span>SampleStrategy<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20190801</span>-20191001<span class="w"> </span>-i<span class="w"> </span>5m
|
||||
</code></pre></div>
|
||||
<p>Head over to the <a href="../backtesting/">Backtesting Documentation</a> to learn more.</p>
|
||||
<h3 id="additional-dependencies-with-docker">Additional dependencies with docker<a class="headerlink" href="#additional-dependencies-with-docker" title="Permanent link">¶</a></h3>
|
||||
<p>If your strategy requires dependencies not included in the default image - it will be necessary to build the image on your host.
|
||||
For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at <a href="https://github.com/freqtrade/freqtrade/blob/develop/docker/Dockerfile.custom">docker/Dockerfile.custom</a> for an example).</p>
|
||||
<p>You'll then also need to modify the <code>docker-compose.yml</code> file and uncomment the build step, as well as rename the image to avoid naming collisions.</p>
|
||||
<p><code>yaml
|
||||
image: freqtrade_custom
|
||||
build:
|
||||
context: .
|
||||
dockerfile: "./Dockerfile.<yourextension>"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">freqtrade_custom</span>
|
||||
<span class="w"> </span><span class="nt">build</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">context</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">.</span>
|
||||
<span class="w"> </span><span class="nt">dockerfile</span><span class="p">:</span><span class="w"> </span><span class="s">"./Dockerfile.<yourextension>"</span>
|
||||
</code></pre></div>
|
||||
<p>You can then run <code>docker compose build --pull</code> to build the docker image, and run it using the commands described above.</p>
|
||||
<h3 id="plotting-with-docker">Plotting with docker<a class="headerlink" href="#plotting-with-docker" title="Permanent link">¶</a></h3>
|
||||
<p>Commands <code>freqtrade plot-profit</code> and <code>freqtrade plot-dataframe</code> (<a href="../plotting/">Documentation</a>) are available by changing the image to <code>*_plot</code> in your <code>docker-compose.yml</code> file.
|
||||
You can then use these commands as follows:</p>
|
||||
<p><code>bash
|
||||
docker compose run --rm freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --timerange=20180801-20180805</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>--timerange<span class="o">=</span><span class="m">20180801</span>-20180805
|
||||
</code></pre></div>
|
||||
<p>The output will be stored in the <code>user_data/plot</code> directory, and can be opened with any modern browser.</p>
|
||||
<h3 id="data-analysis-using-docker-compose">Data analysis using docker compose<a class="headerlink" href="#data-analysis-using-docker-compose" title="Permanent link">¶</a></h3>
|
||||
<p>Freqtrade provides a docker-compose file which starts up a jupyter lab server.
|
||||
You can run this server using the following command:</p>
|
||||
<p><code>bash
|
||||
docker compose -f docker/docker-compose-jupyter.yml up</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>-f<span class="w"> </span>docker/docker-compose-jupyter.yml<span class="w"> </span>up
|
||||
</code></pre></div>
|
||||
<p>This will create a docker-container running jupyter lab, which will be accessible using <code>https://127.0.0.1:8888/lab</code>.
|
||||
Please use the link that's printed in the console after startup for simplified login.</p>
|
||||
<p>Since part of this image is built on your machine, it is recommended to rebuild the image from time to time to keep freqtrade (and dependencies) up-to-date.</p>
|
||||
<p><code>bash
|
||||
docker compose -f docker/docker-compose-jupyter.yml build --no-cache</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>-f<span class="w"> </span>docker/docker-compose-jupyter.yml<span class="w"> </span>build<span class="w"> </span>--no-cache
|
||||
</code></pre></div>
|
||||
<h2 id="troubleshooting">Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permanent link">¶</a></h2>
|
||||
<h3 id="docker-on-windows">Docker on Windows<a class="headerlink" href="#docker-on-windows" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
@@ -2096,10 +2441,10 @@ docker compose -f docker/docker-compose-jupyter.yml build --no-cache</code></p>
|
||||
The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past.
|
||||
To fix this issue temporarily you need to run <code>wsl --shutdown</code> and restart docker again (a popup on windows 10 will ask you to do so).
|
||||
A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler.</p>
|
||||
<p><code>bash
|
||||
taskkill /IM "Docker Desktop.exe" /F
|
||||
wsl --shutdown
|
||||
start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe"</code></p>
|
||||
<div class="highlight"><pre><span></span><code>taskkill<span class="w"> </span>/IM<span class="w"> </span><span class="s2">"Docker Desktop.exe"</span><span class="w"> </span>/F
|
||||
wsl<span class="w"> </span>--shutdown
|
||||
start<span class="w"> </span><span class="s2">""</span><span class="w"> </span><span class="s2">"C:\Program Files\Docker\Docker\Docker Desktop.exe"</span>
|
||||
</code></pre></div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
|
||||
+641
-141
@@ -1391,6 +1391,256 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kraken-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kraken Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kucoin" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kucoin
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Kucoin">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kucoin-blacklists" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kucoin Blacklists
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#htx" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
HTX
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#okx" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
OKX
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#gateio" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Gate.io
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bybit" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bybit
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Bybit">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bybit-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bybit Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitmart" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitmart
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitget" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitget
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Bitget">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitget-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitget Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hyperliquid" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Hyperliquid
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Hyperliquid">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hyperliquid-vault-subaccount" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Hyperliquid Vault / Subaccount
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#historic-hyperliquid-data" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Historic Hyperliquid data
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hip-3-dexes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
HIP-3 DEXes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitvavo" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitvavo
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#all-exchanges" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
All exchanges
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#random-notes-for-other-exchanges" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Random notes for other exchanges
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Random notes for other exchanges">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#getting-latest-price-incomplete-candles" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Getting latest price / Incomplete candles
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-freqtrade-exchange-configuration" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced Freqtrade Exchange configuration
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2184,6 +2434,256 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kraken-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kraken Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kucoin" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kucoin
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Kucoin">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#kucoin-blacklists" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Kucoin Blacklists
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#htx" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
HTX
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#okx" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
OKX
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#gateio" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Gate.io
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bybit" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bybit
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Bybit">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bybit-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bybit Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitmart" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitmart
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitget" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitget
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Bitget">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitget-futures" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitget Futures
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hyperliquid" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Hyperliquid
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Hyperliquid">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hyperliquid-vault-subaccount" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Hyperliquid Vault / Subaccount
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#historic-hyperliquid-data" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Historic Hyperliquid data
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#hip-3-dexes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
HIP-3 DEXes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#bitvavo" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Bitvavo
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#all-exchanges" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
All exchanges
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#random-notes-for-other-exchanges" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Random notes for other exchanges
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Random notes for other exchanges">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#getting-latest-price-incomplete-candles" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Getting latest price / Incomplete candles
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-freqtrade-exchange-configuration" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced Freqtrade Exchange configuration
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2350,27 +2850,27 @@ A current list of these can be found in the "Home" section of this documentation
|
||||
<p>Some exchanges require special configuration, which can be found below.</p>
|
||||
<h3 id="sample-exchange-configuration">Sample exchange configuration<a class="headerlink" href="#sample-exchange-configuration" title="Permanent link">¶</a></h3>
|
||||
<p>A exchange configuration for "binance" would look as follows:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "binance",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"ccxt_config": {},
|
||||
"ccxt_async_config": {},
|
||||
// ...</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"binance"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_async_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span>
|
||||
<span class="w"> </span><span class="c1">// ... </span>
|
||||
</code></pre></div>
|
||||
<h3 id="setting-rate-limits">Setting rate limits<a class="headerlink" href="#setting-rate-limits" title="Permanent link">¶</a></h3>
|
||||
<p>Usually, rate limits set by CCXT are reliable and work well.
|
||||
In case of problems related to rate-limits (usually DDOS Exceptions in your logs), it's easy to change rateLimit settings to other values.</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "kraken",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"ccxt_config": {"enableRateLimit": true},
|
||||
"ccxt_async_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 3100
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"kraken"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nt">"enableRateLimit"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_async_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enableRateLimit"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"rateLimit"</span><span class="p">:</span><span class="w"> </span><span class="mi">3100</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>This configuration enables kraken, as well as rate-limiting to avoid bans from the exchange.
|
||||
<code>"rateLimit": 3100</code> defines a wait-event of 3.1s between each call. This can also be completely disabled by setting <code>"enableRateLimit"</code> to false.</p>
|
||||
<div class="admonition note">
|
||||
@@ -2402,31 +2902,31 @@ Binance accounts may use <code>BNB</code> for fees, and if a trade happens to be
|
||||
<h3 id="binance-rsa-keys">Binance RSA keys<a class="headerlink" href="#binance-rsa-keys" title="Permanent link">¶</a></h3>
|
||||
<p>Freqtrade supports binance RSA API keys.</p>
|
||||
<p>We recommend to use them as environment variable.</p>
|
||||
<p><code>bash
|
||||
export FREQTRADE__EXCHANGE__SECRET="$(cat ./rsa_binance.private)"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nb">export</span><span class="w"> </span><span class="nv">FREQTRADE__EXCHANGE__SECRET</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>cat<span class="w"> </span>./rsa_binance.private<span class="k">)</span><span class="s2">"</span>
|
||||
</code></pre></div>
|
||||
<p>They can however also be configured via configuration file. Since json doesn't support multi-line strings, you'll have to replace all newlines with <code>\n</code> to have a valid json file.</p>
|
||||
<p><code>json
|
||||
// ...
|
||||
"key": "<someapikey>",
|
||||
"secret": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBABACAFQA<...>s8KX8=\n-----END PRIVATE KEY-----"
|
||||
// ...</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"<someapikey>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-----BEGIN PRIVATE KEY-----\nMIIEvQIBABACAFQA<...>s8KX8=\n-----END PRIVATE KEY-----"</span>
|
||||
<span class="c1">// ...</span>
|
||||
</code></pre></div>
|
||||
<h3 id="binance-futures">Binance Futures<a class="headerlink" href="#binance-futures" title="Permanent link">¶</a></h3>
|
||||
<p>Binance has specific (unfortunately complex) <a href="https://www.binance.com/en/support/faq/4f462ebe6ff445d4a170be7d9e897272">Futures Trading Quantitative Rules</a> which need to be followed, and which prohibit a too low stake-amount (among others) for too many orders.
|
||||
Violating these rules will result in a trading restriction.</p>
|
||||
<p>When trading on Binance Futures market, orderbook must be used because there is no price ticker data for futures.</p>
|
||||
<p><code>jsonc
|
||||
"entry_pricing": {
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1,
|
||||
"check_depth_of_market": {
|
||||
"enabled": false,
|
||||
"bids_to_ask_delta": 1
|
||||
<div class="highlight"><pre><span></span><code> "entry_pricing": {
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1,
|
||||
"check_depth_of_market": {
|
||||
"enabled": false,
|
||||
"bids_to_ask_delta": 1
|
||||
}
|
||||
},
|
||||
"exit_pricing": {
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},</code></p>
|
||||
"exit_pricing": {
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},
|
||||
</code></pre></div>
|
||||
<h4 id="binance-isolated-futures-settings">Binance isolated futures settings<a class="headerlink" href="#binance-isolated-futures-settings" title="Permanent link">¶</a></h4>
|
||||
<p>Users will also have to have the futures-setting "Position Mode" set to "One-way Mode", and "Asset Mode" set to "Single-Asset Mode".
|
||||
These settings will be checked on startup, and freqtrade will show an error if this setting is wrong.</p>
|
||||
@@ -2435,15 +2935,15 @@ These settings will be checked on startup, and freqtrade will show an error if t
|
||||
<h4 id="binance-bnfcr-futures">Binance BNFCR futures<a class="headerlink" href="#binance-bnfcr-futures" title="Permanent link">¶</a></h4>
|
||||
<p>BNFCR mode are a special type of futures mode on Binance to work around regulatory issues in Europe.<br />
|
||||
To use BNFCR futures, you will have to have the following combination of settings:</p>
|
||||
<p><code>jsonc
|
||||
{
|
||||
<div class="highlight"><pre><span></span><code>{
|
||||
// ...
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "cross",
|
||||
"proxy_coin": "BNFCR",
|
||||
"stake_currency": "USDT" // or "USDC"
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "cross",
|
||||
"proxy_coin": "BNFCR",
|
||||
"stake_currency": "USDT" // or "USDC"
|
||||
// ...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<p>The <code>stake_currency</code> setting defines the markets the bot will be operating in. This choice is really arbitrary.</p>
|
||||
<p>On the exchange, you'll have to use "Multi-asset Mode" - and "Position Mode set to "One-way Mode".<br />
|
||||
Freqtrade will check these settings on startup, but won't attempt to change them.</p>
|
||||
@@ -2470,7 +2970,7 @@ The assumption for this mode is that the data is downloaded and unzipped keeping
|
||||
Duplicate content will be ignored (based on timestamp) - though the assumption is that there is no gap in the data.</p>
|
||||
<p>This means, if your "full" history ends in Q4 2022 - then both incremental updates Q1 2023 and Q2 2023 are available.
|
||||
Not having this will lead to incomplete data, and therefore invalid results while using the data.</p>
|
||||
<p><code>└── trades_csv
|
||||
<div class="highlight"><pre><span></span><code>└── trades_csv
|
||||
├── Kraken_full_history
|
||||
│ ├── BCHEUR.csv
|
||||
│ └── XBTEUR.csv
|
||||
@@ -2479,16 +2979,16 @@ Not having this will lead to incomplete data, and therefore invalid results whil
|
||||
│ └── XBTEUR.csv
|
||||
└── Kraken_Trading_History_Q2_2023
|
||||
├── BCHEUR.csv
|
||||
└── XBTEUR.csv</code></p>
|
||||
└── XBTEUR.csv
|
||||
</code></pre></div>
|
||||
<p>You can convert these files into freqtrade files:</p>
|
||||
<p>``` bash
|
||||
freqtrade convert-trade-data --exchange kraken --format-from kraken_csv --format-to feather</p>
|
||||
<h1 id="convert-trade-data-to-different-ohlcv-timeframes">Convert trade data to different ohlcv timeframes<a class="headerlink" href="#convert-trade-data-to-different-ohlcv-timeframes" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade trades-to-ohlcv -p BTC/EUR BCH/EUR --exchange kraken -t 1m 5m 15m 1h
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>convert-trade-data<span class="w"> </span>--exchange<span class="w"> </span>kraken<span class="w"> </span>--format-from<span class="w"> </span>kraken_csv<span class="w"> </span>--format-to<span class="w"> </span>feather
|
||||
<span class="c1"># Convert trade data to different ohlcv timeframes</span>
|
||||
freqtrade<span class="w"> </span>trades-to-ohlcv<span class="w"> </span>-p<span class="w"> </span>BTC/EUR<span class="w"> </span>BCH/EUR<span class="w"> </span>--exchange<span class="w"> </span>kraken<span class="w"> </span>-t<span class="w"> </span>1m<span class="w"> </span>5m<span class="w"> </span>15m<span class="w"> </span>1h
|
||||
</code></pre></div>
|
||||
<p>The converted data also makes downloading data possible, and will start the download after the latest loaded trade.</p>
|
||||
<p><code>bash
|
||||
freqtrade download-data --exchange kraken --dl-trades -p BTC/EUR BCH/EUR</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>download-data<span class="w"> </span>--exchange<span class="w"> </span>kraken<span class="w"> </span>--dl-trades<span class="w"> </span>-p<span class="w"> </span>BTC/EUR<span class="w"> </span>BCH/EUR<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Downloading data from kraken</p>
|
||||
<p>Downloading kraken data will require significantly more memory (RAM) than any other exchange, as the trades-data needs to be converted into candles on your machine.
|
||||
@@ -2501,15 +3001,15 @@ So, in order to mitigate Kraken API "Rate limit exceeded" exception, this config
|
||||
</div>
|
||||
<h2 id="kraken-futures">Kraken Futures<a class="headerlink" href="#kraken-futures" title="Permanent link">¶</a></h2>
|
||||
<p>Kraken Futures uses the exchange id <code>krakenfutures</code> and supports isolated futures mode.</p>
|
||||
<p><code>jsonc
|
||||
"exchange": {
|
||||
"name": "krakenfutures",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret"
|
||||
<div class="highlight"><pre><span></span><code>"exchange": {
|
||||
"name": "krakenfutures",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret"
|
||||
},
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated",
|
||||
"stake_currency": "USD"</code></p>
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated",
|
||||
"stake_currency": "USD"
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Stoploss on Exchange</p>
|
||||
<p>Kraken Futures supports <code>stoploss_on_exchange</code> with both <code>limit</code> and <code>market</code> stop orders.
|
||||
@@ -2526,14 +3026,14 @@ Freqtrade derives the <code>USD</code> balance from Kraken margin fields, so kee
|
||||
</div>
|
||||
<h2 id="kucoin">Kucoin<a class="headerlink" href="#kucoin" title="Permanent link">¶</a></h2>
|
||||
<p>Kucoin requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "kucoin",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"password": "your_exchange_api_key_password",
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"kucoin"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_api_key_password"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Kucoin supports <a href="../configuration/#understand-order_time_in_force">time_in_force</a> with settings "GTC" (good till cancelled), "FOK" (full-or-cancel) and "IOC" (immediate-or-cancel) settings.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Stoploss on Exchange</p>
|
||||
@@ -2550,14 +3050,14 @@ Kucoin accounts may use <code>KCS</code> for fees, and if a trade happens to be
|
||||
</div>
|
||||
<h2 id="okx">OKX<a class="headerlink" href="#okx" title="Permanent link">¶</a></h2>
|
||||
<p>OKX requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "okx",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"password": "your_exchange_api_key_password",
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"okx"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_api_key_password"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>If you've registered with OKX on the host my.okx.com (OKX EAA)- you will need to use <code>"myokx"</code> as the exchange name.
|
||||
Using the wrong exchange will result in the error "OKX Error 50119: API key doesn't exist" - as the 2 are separate entities.</p>
|
||||
<div class="admonition warning">
|
||||
@@ -2612,28 +3112,28 @@ Other configurations (multiple bots on one account, manual non-bot trades on the
|
||||
<h2 id="bitmart">Bitmart<a class="headerlink" href="#bitmart" title="Permanent link">¶</a></h2>
|
||||
<p>Bitmart requires the API key Memo (the name you give the API key) to go along with the exchange key and secret.
|
||||
It's therefore required to pass the UID as well.</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "bitmart",
|
||||
"uid": "your_bitmart_api_key_memo",
|
||||
"secret": "your_exchange_secret",
|
||||
"password": "your_exchange_api_key_password",
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bitmart"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"uid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_bitmart_api_key_memo"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_api_key_password"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Necessary Verification</p>
|
||||
<p>Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification.</p>
|
||||
</div>
|
||||
<h2 id="bitget">Bitget<a class="headerlink" href="#bitget" title="Permanent link">¶</a></h2>
|
||||
<p>Bitget requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "bitget",
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"password": "your_exchange_api_key_password",
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bitget"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_secret"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_exchange_api_key_password"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Bitget supports <a href="../configuration/#understand-order_time_in_force">time_in_force</a> with settings "GTC" (good till cancelled), "FOK" (full-or-cancel), "IOC" (immediate-or-cancel) and "PO" (Post only) settings.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Stoploss on Exchange</p>
|
||||
@@ -2656,13 +3156,13 @@ Freqtrade will attempt to detect the account type on startup - changing the acco
|
||||
</div>
|
||||
<p>Hyperliquid is a Decentralized Exchange (DEX). Decentralized exchanges work a bit different compared to normal exchanges. Instead of authenticating private API calls using an API key, private API calls need to be signed with the private key of your wallet (We recommend using an api Wallet for this, generated either on Hyperliquid or in your wallet of choice).
|
||||
This needs to be configured like this:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "hyperliquid",
|
||||
"walletAddress": "your_eth_wallet_address", // This should NOT be your API Wallet Address!
|
||||
"privateKey": "your_api_private_key",
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hyperliquid"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"walletAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_eth_wallet_address"</span><span class="p">,</span><span class="w"> </span><span class="c1">// This should NOT be your API Wallet Address!</span>
|
||||
<span class="w"> </span><span class="nt">"privateKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_api_private_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<ul>
|
||||
<li>walletAddress in hex format: <code>0x<40 hex characters></code> - Can be easily copied from your wallet - and should be your main wallet address, not your API Wallet Address.</li>
|
||||
<li>privateKey in hex format: <code>0x<64 hex characters></code> - Use the key the API Wallet shows on creation.</li>
|
||||
@@ -2688,19 +3188,19 @@ Unfortunately, hyperliquid only offers 5000 historic candles, so backtesting wil
|
||||
<h3 id="hyperliquid-vault-subaccount">Hyperliquid Vault / Subaccount<a class="headerlink" href="#hyperliquid-vault-subaccount" title="Permanent link">¶</a></h3>
|
||||
<p>Hyperliquid allows you to create either a vault or a subaccount.<br />
|
||||
To use these with Freqtrade, you will need to use the following configuration pattern:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "hyperliquid",
|
||||
"walletAddress": "your_master_wallet_address", // Your master wallet address (not the API wallet address and not the vault/subaccount address).
|
||||
"privateKey": "your_api_private_key", // API wallet private key (see https://app.hyperliquid.xyz/API). You'll only need the private key.
|
||||
"ccxt_config": {
|
||||
"options": {
|
||||
"vaultAddress": "your_vault_address", // Optional, only if you want to use a vault ...
|
||||
"subAccountAddress": "your_subaccount_address" // OR optional, only if you want to use a subaccount
|
||||
}
|
||||
},
|
||||
// ...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hyperliquid"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"walletAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_master_wallet_address"</span><span class="p">,</span><span class="w"> </span><span class="c1">// Your master wallet address (not the API wallet address and not the vault/subaccount address).</span>
|
||||
<span class="w"> </span><span class="nt">"privateKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_api_private_key"</span><span class="p">,</span><span class="w"> </span><span class="c1">// API wallet private key (see https://app.hyperliquid.xyz/API). You'll only need the private key.</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"options"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"vaultAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_vault_address"</span><span class="p">,</span><span class="w"> </span><span class="c1">// Optional, only if you want to use a vault ...</span>
|
||||
<span class="w"> </span><span class="nt">"subAccountAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_subaccount_address"</span><span class="w"> </span><span class="c1">// OR optional, only if you want to use a subaccount</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Your balance and trades will now be used from your vault / subaccount - and no longer from your main account.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2712,13 +3212,13 @@ To use these with Freqtrade, you will need to use the following configuration pa
|
||||
<p>Hyperliquid supports HIP-3 decentralized exchanges (DEXes), which are independent exchanges built on top of the Hyperliquid infrastructure.
|
||||
These DEXes operate similarly to the main Hyperliquid exchange but are community-created and managed.</p>
|
||||
<p>To trade on HIP-3 DEXes with Freqtrade, you need to add them to your configuration using the <code>hip3_dexes</code> parameter:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "hyperliquid",
|
||||
"walletAddress": "your_master_wallet_address",
|
||||
"privateKey": "your_api_private_key",
|
||||
"hip3_dexes": ["dex_name_1", "dex_name_2"]
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hyperliquid"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"walletAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_master_wallet_address"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"privateKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_api_private_key"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"hip3_dexes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"dex_name_1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"dex_name_2"</span><span class="p">]</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Replace <code>"dex_name_1"</code> and <code>"dex_name_2"</code> with the actual names of the HIP-3 DEXes you want to trade on (e.g. <code>vntl</code> and <code>xyz</code>).</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Performance and Rate Limit Impact</p>
|
||||
@@ -2737,17 +3237,17 @@ Different HIP-3 DEXes may also use different quote currencies - so make sure to
|
||||
</div>
|
||||
<h2 id="bitvavo">Bitvavo<a class="headerlink" href="#bitvavo" title="Permanent link">¶</a></h2>
|
||||
<p>If your account is required to use an operatorId, you can set it in the configuration file as follows:</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "bitvavo",
|
||||
"key": "",
|
||||
"secret": "",
|
||||
"ccxt_config": {
|
||||
"options": {
|
||||
"operatorId": "123567"
|
||||
}
|
||||
},
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bitvavo"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ccxt_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"options"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"operatorId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"123567"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Bitvavo expects the <code>operatorId</code> to be an integer.</p>
|
||||
<h2 id="all-exchanges">All exchanges<a class="headerlink" href="#all-exchanges" title="Permanent link">¶</a></h2>
|
||||
<p>Should you experience constant errors with Nonce (like <code>InvalidNonce</code>), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys.</p>
|
||||
@@ -2755,8 +3255,8 @@ Different HIP-3 DEXes may also use different quote currencies - so make sure to
|
||||
<ul>
|
||||
<li>The Ocean (exchange id: <code>theocean</code>) exchange uses Web3 functionality and requires <code>web3</code> python package to be installed:</li>
|
||||
</ul>
|
||||
<p><code>shell
|
||||
pip3 install web3</code></p>
|
||||
<div class="highlight"><pre><span></span><code>pip3<span class="w"> </span>install<span class="w"> </span>web3
|
||||
</code></pre></div>
|
||||
<h3 id="getting-latest-price-incomplete-candles">Getting latest price / Incomplete candles<a class="headerlink" href="#getting-latest-price-incomplete-candles" title="Permanent link">¶</a></h3>
|
||||
<p>Most exchanges return current incomplete candle via their OHLCV/klines API interface.
|
||||
By default, Freqtrade assumes that incomplete candle is fetched from the exchange and removes the last candle assuming it's the incomplete candle.</p>
|
||||
@@ -2767,15 +3267,15 @@ By default, Freqtrade assumes that incomplete candle is fetched from the exchang
|
||||
<p>Advanced options can be configured using the <code>_ft_has_params</code> setting, which will override Defaults and exchange-specific behavior.</p>
|
||||
<p>Available options are listed in the exchange-class as <code>_ft_has_default</code>.</p>
|
||||
<p>For example, to test the order type <code>FOK</code> with Kraken, and modify candle limit to 200 (so you only get 200 candles per API call):</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "kraken",
|
||||
"_ft_has_params": {
|
||||
"order_time_in_force": ["GTC", "FOK"],
|
||||
"ohlcv_candle_limit": 200
|
||||
}
|
||||
//...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"kraken"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"_ft_has_params"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"order_time_in_force"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"GTC"</span><span class="p">,</span><span class="w"> </span><span class="s2">"FOK"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"ohlcv_candle_limit"</span><span class="p">:</span><span class="w"> </span><span class="mi">200</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Please make sure to fully understand the impacts of these settings before modifying them.
|
||||
|
||||
+22
-25
@@ -2768,12 +2768,12 @@ While this makes the iteration slightly slower (due to the REST Api call) - it w
|
||||
<h3 id="im-getting-the-exchange-xxx-does-not-support-market-orders-message-and-cannot-run-my-strategy">I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy<a class="headerlink" href="#im-getting-the-exchange-xxx-does-not-support-market-orders-message-and-cannot-run-my-strategy" title="Permanent link">¶</a></h3>
|
||||
<p>As the message says, your exchange does not support market orders and you have one of the <a href="../configuration/#understand-order_types">order types</a> set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Gate.io).</p>
|
||||
<p>To fix this, redefine order types in the strategy to use "limit" instead of "market":</p>
|
||||
<p><code>python
|
||||
order_types = {
|
||||
...
|
||||
"stoploss": "limit",
|
||||
...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">order_types</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="o">...</span>
|
||||
<span class="s2">"stoploss"</span><span class="p">:</span> <span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="o">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>The same fix should be applied in the configuration file, if order types are defined in your custom config rather than in the strategy.</p>
|
||||
<h3 id="im-trying-to-start-the-bot-live-but-get-an-api-permission-error">I'm trying to start the bot live, but get an API permission error<a class="headerlink" href="#im-trying-to-start-the-bot-live-but-get-an-api-permission-error" title="Permanent link">¶</a></h3>
|
||||
<p>Errors like <code>Invalid API-key, IP, or permissions for action</code> mean exactly what they actually say.<br />
|
||||
@@ -2784,36 +2784,33 @@ Futures will usually have to be enabled specifically.</p>
|
||||
<p>By default, the bot writes its log into stderr stream. This is implemented this way so that you can easily separate the bot's diagnostics messages from Backtesting, Edge and Hyperopt results, output from other various Freqtrade utility sub-commands, as well as from the output of your custom <code>print()</code>'s you may have inserted into your strategy. So if you need to search the log messages with the grep utility, you need to redirect stderr to stdout and disregard stdout.</p>
|
||||
<ul>
|
||||
<li>In unix shells, this normally can be done as simple as:
|
||||
<code>shell
|
||||
$ freqtrade --some-options 2>&1 >/dev/null | grep 'something'</code>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>freqtrade<span class="w"> </span>--some-options<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span>>/dev/null<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'something'</span>
|
||||
</code></pre></div>
|
||||
(note, <code>2>&1</code> and <code>>/dev/null</code> should be written in this order)</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Bash interpreter also supports so called process substitution syntax, you can grep the log for a string with it as:
|
||||
<code>shell
|
||||
$ freqtrade --some-options 2> >(grep 'something') >/dev/null</code>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>freqtrade<span class="w"> </span>--some-options<span class="w"> </span><span class="m">2</span>><span class="w"> </span>><span class="o">(</span>grep<span class="w"> </span><span class="s1">'something'</span><span class="o">)</span><span class="w"> </span>>/dev/null
|
||||
</code></pre></div>
|
||||
or
|
||||
<code>shell
|
||||
$ freqtrade --some-options 2> >(grep -v 'something' 1>&2)</code></li>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>freqtrade<span class="w"> </span>--some-options<span class="w"> </span><span class="m">2</span>><span class="w"> </span>><span class="o">(</span>grep<span class="w"> </span>-v<span class="w"> </span><span class="s1">'something'</span><span class="w"> </span><span class="m">1</span>><span class="p">&</span><span class="m">2</span><span class="o">)</span>
|
||||
</code></pre></div></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>You can also write the copy of Freqtrade log messages to a file with the <code>--logfile</code> option:
|
||||
<code>shell
|
||||
$ freqtrade --logfile /path/to/mylogfile.log --some-options</code>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>freqtrade<span class="w"> </span>--logfile<span class="w"> </span>/path/to/mylogfile.log<span class="w"> </span>--some-options
|
||||
</code></pre></div>
|
||||
and then grep it as:
|
||||
<code>shell
|
||||
$ cat /path/to/mylogfile.log | grep 'something'</code>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>/path/to/mylogfile.log<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'something'</span>
|
||||
</code></pre></div>
|
||||
or even on the fly, as the bot works and the log file grows:
|
||||
<code>shell
|
||||
$ tail -f /path/to/mylogfile.log | grep 'something'</code>
|
||||
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>tail<span class="w"> </span>-f<span class="w"> </span>/path/to/mylogfile.log<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'something'</span>
|
||||
</code></pre></div>
|
||||
from a separate terminal window.</li>
|
||||
</ul>
|
||||
<p>On Windows, the <code>--logfile</code> option is also supported by Freqtrade and you can use the <code>findstr</code> command to search the log for the string of interest:
|
||||
```</p>
|
||||
<blockquote>
|
||||
<p>type \path\to\mylogfile.log | findstr "something"
|
||||
```</p>
|
||||
</blockquote>
|
||||
<div class="highlight"><pre><span></span><code>> type \path\to\mylogfile.log | findstr "something"
|
||||
</code></pre></div></p>
|
||||
<h2 id="hyperopt-module">Hyperopt module<a class="headerlink" href="#hyperopt-module" title="Permanent link">¶</a></h2>
|
||||
<h3 id="why-does-freqtrade-not-have-gpu-support">Why does freqtrade not have GPU support?<a class="headerlink" href="#why-does-freqtrade-not-have-gpu-support" title="Permanent link">¶</a></h3>
|
||||
<p>First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
|
||||
@@ -2831,8 +2828,8 @@ have to run it for 10000 or more. But it will take an eternity to
|
||||
compute.</p>
|
||||
<p>Since hyperopt uses Bayesian search, running for too many epochs may not produce greater results.</p>
|
||||
<p>It's therefore recommended to run between 500-1000 epochs over and over until you hit at least 10000 epochs in total (or are satisfied with the result). You can best judge by looking at the results - if the bot keeps discovering better strategies, it's best to keep on going.</p>
|
||||
<p><code>bash
|
||||
freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --strategy SampleStrategy -e 1000</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>hyperopt<span class="w"> </span>--hyperopt-loss<span class="w"> </span>SharpeHyperOptLossDaily<span class="w"> </span>--strategy<span class="w"> </span>SampleStrategy<span class="w"> </span>-e<span class="w"> </span><span class="m">1000</span>
|
||||
</code></pre></div>
|
||||
<h3 id="why-does-it-take-a-long-time-to-run-hyperopt">Why does it take a long time to run hyperopt?<a class="headerlink" href="#why-does-it-take-a-long-time-to-run-hyperopt" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
<li>Discovering a great strategy with Hyperopt takes time. Study <a href="http://www.freqtrade.io">www.freqtrade.io</a>, the Freqtrade Documentation page, join the Freqtrade <a href="https://discord.gg/p7nuUNVfP7">discord community</a>. While you patiently wait for the most advanced, free crypto bot in the world, to hand you a possible golden strategy specially designed just for you.</li>
|
||||
|
||||
@@ -2157,23 +2157,23 @@ Also, the standard disallows <code>*</code> CORS policies for requests with cred
|
||||
<p>Users can allow access from different origin URL's to the bot API via the <code>CORS_origins</code> configuration setting.
|
||||
It consists of a list of allowed URL's that are allowed to consume resources from the bot's API.</p>
|
||||
<p>Assuming your application is deployed as <code>https://frequi.freqtrade.io/home/</code> - this would mean that the following configuration becomes necessary:</p>
|
||||
<p><code>jsonc
|
||||
{
|
||||
<div class="highlight"><pre><span></span><code>{
|
||||
//...
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["https://frequi.freqtrade.io"],
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["https://frequi.freqtrade.io"],
|
||||
//...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<p>In the following (pretty common) case, FreqUI is accessible on <code>http://localhost:8080/trade</code> (this is what you see in your navbar when navigating to freqUI).
|
||||
<img alt="freqUI url" src="../assets/frequi_url.png" /></p>
|
||||
<p>The correct configuration for this case is <code>http://localhost:8080</code> - the main part of the URL including the port.</p>
|
||||
<p><code>jsonc
|
||||
{
|
||||
<div class="highlight"><pre><span></span><code>{
|
||||
//...
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["http://localhost:8080"],
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["http://localhost:8080"],
|
||||
//...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">trailing Slash</p>
|
||||
<p>The trailing slash is not allowed in the <code>CORS_origins</code> configuration (e.g. <code>"http://localhots:8080/"</code>).
|
||||
|
||||
@@ -2283,28 +2283,28 @@
|
||||
<p>FreqAI is configured through the typical <a href="../configuration/">Freqtrade config file</a> and the standard <a href="../strategy-customization/">Freqtrade strategy</a>. Examples of FreqAI config and strategy files can be found in <code>config_examples/config_freqai.example.json</code> and <code>freqtrade/templates/FreqaiExampleStrategy.py</code>, respectively.</p>
|
||||
<h2 id="setting-up-the-configuration-file">Setting up the configuration file<a class="headerlink" href="#setting-up-the-configuration-file" title="Permanent link">¶</a></h2>
|
||||
<p>Although there are plenty of additional parameters to choose from, as highlighted in the <a href="../freqai-parameter-table/#parameter-table">parameter table</a>, a FreqAI config must at minimum include the following parameters (the parameter values are only examples):</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"enabled": true,
|
||||
"purge_old_models": 2,
|
||||
"train_period_days": 30,
|
||||
"backtest_period_days": 7,
|
||||
"identifier" : "unique-id",
|
||||
"feature_parameters" : {
|
||||
"include_timeframes": ["5m","15m","4h"],
|
||||
"include_corr_pairlist": [
|
||||
"ETH/USD",
|
||||
"LINK/USD",
|
||||
"BNB/USD"
|
||||
],
|
||||
"label_period_candles": 24,
|
||||
"include_shifted_candles": 2,
|
||||
"indicator_periods_candles": [10, 20]
|
||||
},
|
||||
"data_split_parameters" : {
|
||||
"test_size": 0.25
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"purge_old_models"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"train_period_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"backtest_period_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">7</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"identifier"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"unique-id"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"include_timeframes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"5m"</span><span class="p">,</span><span class="s2">"15m"</span><span class="p">,</span><span class="s2">"4h"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"include_corr_pairlist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"ETH/USD"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"LINK/USD"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"BNB/USD"</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"label_period_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">24</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"include_shifted_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"indicator_periods_candles"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"data_split_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"test_size"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.25</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>A full example config is available in <code>config_examples/config_freqai.example.json</code>.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2312,112 +2312,110 @@
|
||||
</div>
|
||||
<h2 id="building-a-freqai-strategy">Building a FreqAI strategy<a class="headerlink" href="#building-a-freqai-strategy" title="Permanent link">¶</a></h2>
|
||||
<p>The FreqAI strategy requires including the following lines of code in the standard <a href="../strategy-customization/">Freqtrade strategy</a>:</p>
|
||||
<p>```python
|
||||
# user should define the maximum startup candle count (the largest number of candles
|
||||
# passed to any single indicator)
|
||||
startup_candle_count: int = 20</p>
|
||||
<div class="codehilite"><pre><span></span><code>def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
<div class="highlight"><pre><span></span><code> <span class="c1"># user should define the maximum startup candle count (the largest number of candles</span>
|
||||
<span class="c1"># passed to any single indicator)</span>
|
||||
<span class="n">startup_candle_count</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">20</span>
|
||||
|
||||
# the model will return all labels created by user in `set_freqai_targets()`
|
||||
# (& appended targets), an indication of whether or not the prediction should be accepted,
|
||||
# the target mean/std values for each of the labels created by user in
|
||||
# `set_freqai_targets()` for each training period.
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
<span class="c1"># the model will return all labels created by user in `set_freqai_targets()`</span>
|
||||
<span class="c1"># (& appended targets), an indication of whether or not the prediction should be accepted,</span>
|
||||
<span class="c1"># the target mean/std values for each of the labels created by user in</span>
|
||||
<span class="c1"># `set_freqai_targets()` for each training period.</span>
|
||||
|
||||
return dataframe
|
||||
<span class="n">dataframe</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">freqai</span><span class="o">.</span><span class="n">start</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
|
||||
|
||||
def feature_engineering_expand_all(self, dataframe: DataFrame, period, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined
|
||||
`indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and
|
||||
`include_corr_pairs`. In other words, a single feature defined in this function
|
||||
will automatically expand to a total of
|
||||
`indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` *
|
||||
`include_corr_pairs` numbers of features added to the model.
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_expand_all</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">period</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This function will automatically expand the defined features on the config defined</span>
|
||||
<span class="sd"> `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and</span>
|
||||
<span class="sd"> `include_corr_pairs`. In other words, a single feature defined in this function</span>
|
||||
<span class="sd"> will automatically expand to a total of</span>
|
||||
<span class="sd"> `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` *</span>
|
||||
<span class="sd"> `include_corr_pairs` numbers of features added to the model.</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
:param period: period of the indicator - usage example:
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
"""
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
|
||||
dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period)
|
||||
dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period)
|
||||
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> :param period: period of the indicator - usage example:</span>
|
||||
<span class="sd"> dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
return dataframe
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">si-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">RSI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"%-mfi-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">MFI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-a</span><span class="s2">dx-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">ADX</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-s</span><span class="s2">ma-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">SMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-e</span><span class="s2">ma-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">EMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
|
||||
def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined
|
||||
`include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.
|
||||
In other words, a single feature defined in this function
|
||||
will automatically expand to a total of
|
||||
`include_timeframes` * `include_shifted_candles` * `include_corr_pairs`
|
||||
numbers of features added to the model.
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
Features defined here will *not* be automatically duplicated on user defined
|
||||
`indicator_periods_candles`
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_expand_basic</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This function will automatically expand the defined features on the config defined</span>
|
||||
<span class="sd"> `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.</span>
|
||||
<span class="sd"> In other words, a single feature defined in this function</span>
|
||||
<span class="sd"> will automatically expand to a total of</span>
|
||||
<span class="sd"> `include_timeframes` * `include_shifted_candles` * `include_corr_pairs`</span>
|
||||
<span class="sd"> numbers of features added to the model.</span>
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<span class="sd"> Features defined here will *not* be automatically duplicated on user defined</span>
|
||||
<span class="sd"> `indicator_periods_candles`</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
dataframe["%-pct-change"] = dataframe["close"].pct_change()
|
||||
dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)
|
||||
"""
|
||||
dataframe["%-pct-change"] = dataframe["close"].pct_change()
|
||||
dataframe["%-raw_volume"] = dataframe["volume"]
|
||||
dataframe["%-raw_price"] = dataframe["close"]
|
||||
return dataframe
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This optional function will be called once with the dataframe of the base timeframe.
|
||||
This is the final function to be called, which means that the dataframe entering this
|
||||
function will contain all the features and columns created by all other
|
||||
freqai_feature_engineering_* functions.
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> dataframe["%-pct-change"] = dataframe["close"].pct_change()</span>
|
||||
<span class="sd"> dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"%-pct-change"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">pct_change</span><span class="p">()</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">aw_volume"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">aw_price"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
This function is a good place to do custom exotic feature extractions (e.g. tsfresh).
|
||||
This function is a good place for any feature that should not be auto-expanded upon
|
||||
(e.g. day of the week).
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_standard</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This optional function will be called once with the dataframe of the base timeframe.</span>
|
||||
<span class="sd"> This is the final function to be called, which means that the dataframe entering this</span>
|
||||
<span class="sd"> function will contain all the features and columns created by all other</span>
|
||||
<span class="sd"> freqai_feature_engineering_* functions.</span>
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<span class="sd"> This function is a good place to do custom exotic feature extractions (e.g. tsfresh).</span>
|
||||
<span class="sd"> This function is a good place for any feature that should not be auto-expanded upon</span>
|
||||
<span class="sd"> (e.g. day of the week).</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
|
||||
"""
|
||||
dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
|
||||
dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25
|
||||
return dataframe
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
def set_freqai_targets(self, dataframe: DataFrame, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
Required function to set the targets for the model.
|
||||
All targets must be prepended with `&` to be recognized by the FreqAI internals.
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-d</span><span class="s2">ay_of_week"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">dayofweek</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">7</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-ho</span><span class="s2">ur_of_day"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">hour</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">25</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the targets
|
||||
usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]
|
||||
"""
|
||||
dataframe["&-s_close"] = (
|
||||
dataframe["close"]
|
||||
.shift(-self.freqai_info["feature_parameters"]["label_period_candles"])
|
||||
.rolling(self.freqai_info["feature_parameters"]["label_period_candles"])
|
||||
.mean()
|
||||
/ dataframe["close"]
|
||||
- 1
|
||||
)
|
||||
return dataframe
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">set_freqai_targets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> Required function to set the targets for the model.</span>
|
||||
<span class="sd"> All targets must be prepended with `&` to be recognized by the FreqAI internals.</span>
|
||||
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the targets</span>
|
||||
<span class="sd"> usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="p">[</span><span class="s2">"feature_parameters"</span><span class="p">][</span><span class="s2">"label_period_candles"</span><span class="p">])</span>
|
||||
<span class="o">.</span><span class="n">rolling</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="p">[</span><span class="s2">"feature_parameters"</span><span class="p">][</span><span class="s2">"label_period_candles"</span><span class="p">])</span>
|
||||
<span class="o">.</span><span class="n">mean</span><span class="p">()</span>
|
||||
<span class="o">/</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>Notice how the <code>feature_engineering_*()</code> is where <a href="../freqai-feature-engineering/#feature-engineering">features</a> are added. Meanwhile <code>set_freqai_targets()</code> adds the labels/targets. A full example strategy is available in <code>templates/FreqaiExampleStrategy.py</code>.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2470,18 +2468,19 @@ will cause the algorithm to fail in live/dry mode. In order to add generalized f
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>There are instances where the TA-Lib functions actually require more data than just the passed <code>period</code> or else the feature dataset gets populated with NaNs. Anecdotally, multiplying the <code>startup_candle_count</code> by 2 always leads to a fully NaN free training dataset. Hence, it is typically safest to multiply the expected <code>startup_candle_count</code> by 2. Look out for this log message to confirm that the data is clean:</p>
|
||||
<p><code>2022-08-31 15:14:04 - freqtrade.freqai.data_kitchen - INFO - dropped 0 training points due to NaNs in populated dataset 4319.</code></p>
|
||||
<div class="highlight"><pre><span></span><code>2022-08-31 15:14:04 - freqtrade.freqai.data_kitchen - INFO - dropped 0 training points due to NaNs in populated dataset 4319.
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<h2 id="creating-a-dynamic-target-threshold">Creating a dynamic target threshold<a class="headerlink" href="#creating-a-dynamic-target-threshold" title="Permanent link">¶</a></h2>
|
||||
<p>Deciding when to enter or exit a trade can be done in a dynamic way to reflect current market conditions. FreqAI allows you to return additional information from the training of a model (more info <a href="../freqai-feature-engineering/#returning-additional-info-from-training">here</a>). For example, the <code>&*_std/mean</code> return values describe the statistical distribution of the target/label <em>during the most recent training</em>. Comparing a given prediction to these values allows you to know the rarity of the prediction. In <code>templates/FreqaiExampleStrategy.py</code>, the <code>target_roi</code> and <code>sell_roi</code> are defined to be 1.25 z-scores away from the mean which causes predictions that are closer to the mean to be filtered out.</p>
|
||||
<p><code>python
|
||||
dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25
|
||||
dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">dataframe</span><span class="p">[</span><span class="s2">"target_roi"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close_mean"</span><span class="p">]</span> <span class="o">+</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close_std"</span><span class="p">]</span> <span class="o">*</span> <span class="mf">1.25</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"sell_roi"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close_mean"</span><span class="p">]</span> <span class="o">-</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close_std"</span><span class="p">]</span> <span class="o">*</span> <span class="mf">1.25</span>
|
||||
</code></pre></div>
|
||||
<p>To consider the population of <em>historical predictions</em> for creating the dynamic target instead of information from the training as discussed above, you would set <code>fit_live_predictions_candles</code> in the config to the number of historical prediction candles you wish to use to generate target statistics.</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"fit_live_predictions_candles": 300,
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"fit_live_predictions_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>If this value is set, FreqAI will initially use the predictions from the training data and subsequently begin introducing real prediction data as it is generated. FreqAI will save this historical data to be reloaded if you stop and restart a model with the same <code>identifier</code>.</p>
|
||||
<h2 id="using-different-prediction-models">Using different prediction models<a class="headerlink" href="#using-different-prediction-models" title="Permanent link">¶</a></h2>
|
||||
<p>FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag <code>--freqaimodel</code>. These libraries include <code>LightGBM</code>, and <code>XGBoost</code> regression, classification, and multi-target models, and can be found in <code>freqai/prediction_models/</code>.</p>
|
||||
@@ -2498,22 +2497,22 @@ Make sure to use unique names to avoid overriding built-in models.</p>
|
||||
<h3 id="setting-model-targets">Setting model targets<a class="headerlink" href="#setting-model-targets" title="Permanent link">¶</a></h3>
|
||||
<h4 id="regressors">Regressors<a class="headerlink" href="#regressors" title="Permanent link">¶</a></h4>
|
||||
<p>If you are using a regressor, you need to specify a target that has continuous values. FreqAI includes a variety of regressors, such as the <code>LightGBMRegressor</code>via the flag <code>--freqaimodel LightGBMRegressor</code>. An example of how you could set a regression target for predicting the price 100 candles into the future would be</p>
|
||||
<p><code>python
|
||||
df['&s-close_price'] = df['close'].shift(-100)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">df</span><span class="p">[</span><span class="s1">'&s-close_price'</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s1">'close'</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>If you want to predict multiple targets, you need to define multiple labels using the same syntax as shown above.</p>
|
||||
<h4 id="classifiers">Classifiers<a class="headerlink" href="#classifiers" title="Permanent link">¶</a></h4>
|
||||
<p>If you are using a classifier, you need to specify a target that has discrete values. FreqAI includes a variety of classifiers, such as the <code>LightGBMClassifier</code> via the flag <code>--freqaimodel LightGBMClassifier</code>. If you elects to use a classifier, the classes need to be set using strings. For example, if you want to predict if the price 100 candles into the future goes up or down you would set</p>
|
||||
<p><code>python
|
||||
df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down')</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">df</span><span class="p">[</span><span class="s1">'&s-up_or_down'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">)</span> <span class="o">></span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">],</span> <span class="s1">'up'</span><span class="p">,</span> <span class="s1">'down'</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>If you want to predict multiple targets you must specify all labels in the same label column. You could, for example, add the label <code>same</code> to define where the price was unchanged by setting</p>
|
||||
<p><code>python
|
||||
df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down')
|
||||
df['&s-up_or_down'] = np.where( df["close"].shift(-100) == df["close"], 'same', df['&s-up_or_down'])</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">df</span><span class="p">[</span><span class="s1">'&s-up_or_down'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">)</span> <span class="o">></span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">],</span> <span class="s1">'up'</span><span class="p">,</span> <span class="s1">'down'</span><span class="p">)</span>
|
||||
<span class="n">df</span><span class="p">[</span><span class="s1">'&s-up_or_down'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">)</span> <span class="o">==</span> <span class="n">df</span><span class="p">[</span><span class="s2">"close"</span><span class="p">],</span> <span class="s1">'same'</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s1">'&s-up_or_down'</span><span class="p">])</span>
|
||||
</code></pre></div>
|
||||
<h2 id="pytorch-module">PyTorch Module<a class="headerlink" href="#pytorch-module" title="Permanent link">¶</a></h2>
|
||||
<h3 id="quick-start">Quick start<a class="headerlink" href="#quick-start" title="Permanent link">¶</a></h3>
|
||||
<p>The easiest way to quickly run a pytorch model is with the following command (for regression task):</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel PyTorchMLPRegressor --strategy-path freqtrade/templates</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--config<span class="w"> </span>config_examples/config_freqai.example.json<span class="w"> </span>--strategy<span class="w"> </span>FreqaiExampleStrategy<span class="w"> </span>--freqaimodel<span class="w"> </span>PyTorchMLPRegressor<span class="w"> </span>--strategy-path<span class="w"> </span>freqtrade/templates<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Installation/docker</p>
|
||||
<p>The PyTorch module requires large packages such as <code>torch</code>, which should be explicitly requested during <code>./setup.sh -i</code> by answering "y" to the question "Do you also want dependencies for freqai-rl or PyTorch (~700mb additional space required) [y/N]?".
|
||||
@@ -2530,69 +2529,67 @@ As long as you only load models that you have trained yourself, there is no risk
|
||||
<h3 id="structure">Structure<a class="headerlink" href="#structure" title="Permanent link">¶</a></h3>
|
||||
<h4 id="model">Model<a class="headerlink" href="#model" title="Permanent link">¶</a></h4>
|
||||
<p>You can construct your own Neural Network architecture in PyTorch by simply defining your <code>nn.Module</code> class inside your custom <a href="#using-different-prediction-models"><code>IFreqaiModel</code> file</a> and then using that class in your <code>def train()</code> function. Here is an example of logistic regression model implementation using PyTorch (should be used with nn.BCELoss criterion) for classification tasks.</p>
|
||||
<p>```python</p>
|
||||
<p>class LogisticRegression(nn.Module):
|
||||
def <strong>init</strong>(self, input_size: int):
|
||||
super().<strong>init</strong>()
|
||||
# Define your layers
|
||||
self.linear = nn.Linear(input_size, 1)
|
||||
self.activation = nn.Sigmoid()</p>
|
||||
<div class="codehilite"><pre><span></span><code>def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||
# Define the forward pass
|
||||
out = self.linear(x)
|
||||
out = self.activation(out)
|
||||
return out
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">LogisticRegression</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_size</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
|
||||
<span class="c1"># Define your layers</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">linear</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">activation</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Sigmoid</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">)</span> <span class="o">-></span> <span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">:</span>
|
||||
<span class="c1"># Define the forward pass</span>
|
||||
<span class="n">out</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">linear</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||||
<span class="n">out</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">activation</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">out</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyCoolPyTorchClassifier</span><span class="p">(</span><span class="n">BasePyTorchClassifier</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> This is a custom IFreqaiModel showing how a user might setup their own </span>
|
||||
<span class="sd"> custom Neural Network architecture for their training.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">data_convertor</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">PyTorchDataConvertor</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">DefaultPyTorchDataConvertor</span><span class="p">(</span><span class="n">target_tensor_type</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="n">config</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"model_training_parameters"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">learning_rate</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"learning_rate"</span><span class="p">,</span> <span class="mf">3e-4</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">model_kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"model_kwargs"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">trainer_kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"trainer_kwargs"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">fit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data_dictionary</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">dk</span><span class="p">:</span> <span class="n">FreqaiDataKitchen</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User sets up the training and test data to fit their desired model here</span>
|
||||
<span class="sd"> :param data_dictionary: the dictionary holding all data for train, test,</span>
|
||||
<span class="sd"> labels, weights</span>
|
||||
<span class="sd"> :param dk: The datakitchen object for the current coin/model</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">class_names</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_class_names</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">convert_label_column_to_int</span><span class="p">(</span><span class="n">data_dictionary</span><span class="p">,</span> <span class="n">dk</span><span class="p">,</span> <span class="n">class_names</span><span class="p">)</span>
|
||||
<span class="n">n_features</span> <span class="o">=</span> <span class="n">data_dictionary</span><span class="p">[</span><span class="s2">"train_features"</span><span class="p">]</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="n">model</span> <span class="o">=</span> <span class="n">LogisticRegression</span><span class="p">(</span>
|
||||
<span class="n">input_dim</span><span class="o">=</span><span class="n">n_features</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">model</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
|
||||
<span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">AdamW</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">learning_rate</span><span class="p">)</span>
|
||||
<span class="n">criterion</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">CrossEntropyLoss</span><span class="p">()</span>
|
||||
<span class="n">init_model</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_init_model</span><span class="p">(</span><span class="n">dk</span><span class="o">.</span><span class="n">pair</span><span class="p">)</span>
|
||||
<span class="n">trainer</span> <span class="o">=</span> <span class="n">PyTorchModelTrainer</span><span class="p">(</span>
|
||||
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
|
||||
<span class="n">optimizer</span><span class="o">=</span><span class="n">optimizer</span><span class="p">,</span>
|
||||
<span class="n">criterion</span><span class="o">=</span><span class="n">criterion</span><span class="p">,</span>
|
||||
<span class="n">model_meta_data</span><span class="o">=</span><span class="p">{</span><span class="s2">"class_names"</span><span class="p">:</span> <span class="n">class_names</span><span class="p">},</span>
|
||||
<span class="n">device</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">device</span><span class="p">,</span>
|
||||
<span class="n">init_model</span><span class="o">=</span><span class="n">init_model</span><span class="p">,</span>
|
||||
<span class="n">data_convertor</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">data_convertor</span><span class="p">,</span>
|
||||
<span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">trainer_kwargs</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">trainer</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">data_dictionary</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">splits</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">trainer</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>class MyCoolPyTorchClassifier(BasePyTorchClassifier):
|
||||
"""
|
||||
This is a custom IFreqaiModel showing how a user might setup their own
|
||||
custom Neural Network architecture for their training.
|
||||
"""</p>
|
||||
<div class="codehilite"><pre><span></span><code>@property
|
||||
def data_convertor(self) -> PyTorchDataConvertor:
|
||||
return DefaultPyTorchDataConvertor(target_tensor_type=torch.float)
|
||||
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
config = self.freqai_info.get("model_training_parameters", {})
|
||||
self.learning_rate: float = config.get("learning_rate", 3e-4)
|
||||
self.model_kwargs: dict[str, Any] = config.get("model_kwargs", {})
|
||||
self.trainer_kwargs: dict[str, Any] = config.get("trainer_kwargs", {})
|
||||
|
||||
def fit(self, data_dictionary: dict, dk: FreqaiDataKitchen, **kwargs) -> Any:
|
||||
"""
|
||||
User sets up the training and test data to fit their desired model here
|
||||
:param data_dictionary: the dictionary holding all data for train, test,
|
||||
labels, weights
|
||||
:param dk: The datakitchen object for the current coin/model
|
||||
"""
|
||||
|
||||
class_names = self.get_class_names()
|
||||
self.convert_label_column_to_int(data_dictionary, dk, class_names)
|
||||
n_features = data_dictionary["train_features"].shape[-1]
|
||||
model = LogisticRegression(
|
||||
input_dim=n_features
|
||||
)
|
||||
model.to(self.device)
|
||||
optimizer = torch.optim.AdamW(model.parameters(), lr=self.learning_rate)
|
||||
criterion = torch.nn.CrossEntropyLoss()
|
||||
init_model = self.get_init_model(dk.pair)
|
||||
trainer = PyTorchModelTrainer(
|
||||
model=model,
|
||||
optimizer=optimizer,
|
||||
criterion=criterion,
|
||||
model_meta_data={"class_names": class_names},
|
||||
device=self.device,
|
||||
init_model=init_model,
|
||||
data_convertor=self.data_convertor,
|
||||
**self.trainer_kwargs,
|
||||
)
|
||||
trainer.fit(data_dictionary, self.splits)
|
||||
return trainer
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<h4 id="trainer">Trainer<a class="headerlink" href="#trainer" title="Permanent link">¶</a></h4>
|
||||
<p>The <code>PyTorchModelTrainer</code> performs the idiomatic PyTorch train loop:
|
||||
Define our model, loss function, and optimizer, and then move them to the appropriate device (GPU or CPU). Inside the loop, we iterate through the batches in the dataloader, move the data to the device, compute the prediction and loss, backpropagate, and update the model parameters using the optimizer. </p>
|
||||
@@ -2610,65 +2607,61 @@ From top to bottom:</p>
|
||||
<p><img alt="image" src="../assets/freqai_pytorch-diagram.png" /></p>
|
||||
<h4 id="full-example">Full example<a class="headerlink" href="#full-example" title="Permanent link">¶</a></h4>
|
||||
<p>Building a PyTorch regressor using MLP (multilayer perceptron) model, MSELoss criterion, and AdamW optimizer.</p>
|
||||
<p>```python
|
||||
class PyTorchMLPRegressor(BasePyTorchRegressor):
|
||||
def <strong>init</strong>(self, <strong>kwargs) -> None:
|
||||
super().<strong>init</strong>(</strong>kwargs)
|
||||
config = self.freqai_info.get("model_training_parameters", {})
|
||||
self.learning_rate: float = config.get("learning_rate", 3e-4)
|
||||
self.model_kwargs: dict[str, Any] = config.get("model_kwargs", {})
|
||||
self.trainer_kwargs: dict[str, Any] = config.get("trainer_kwargs", {})</p>
|
||||
<div class="codehilite"><pre><span></span><code>def fit(self, data_dictionary: dict, dk: FreqaiDataKitchen, **kwargs) -> Any:
|
||||
n_features = data_dictionary["train_features"].shape[-1]
|
||||
model = PyTorchMLPModel(
|
||||
input_dim=n_features,
|
||||
output_dim=1,
|
||||
**self.model_kwargs
|
||||
)
|
||||
model.to(self.device)
|
||||
optimizer = torch.optim.AdamW(model.parameters(), lr=self.learning_rate)
|
||||
criterion = torch.nn.MSELoss()
|
||||
init_model = self.get_init_model(dk.pair)
|
||||
trainer = PyTorchModelTrainer(
|
||||
model=model,
|
||||
optimizer=optimizer,
|
||||
criterion=criterion,
|
||||
device=self.device,
|
||||
init_model=init_model,
|
||||
target_tensor_type=torch.float,
|
||||
**self.trainer_kwargs,
|
||||
)
|
||||
trainer.fit(data_dictionary)
|
||||
return trainer
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">PyTorchMLPRegressor</span><span class="p">(</span><span class="n">BasePyTorchRegressor</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="n">config</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"model_training_parameters"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">learning_rate</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"learning_rate"</span><span class="p">,</span> <span class="mf">3e-4</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">model_kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"model_kwargs"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">trainer_kwargs</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"trainer_kwargs"</span><span class="p">,</span> <span class="p">{})</span>
|
||||
|
||||
<p>```</p>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">fit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data_dictionary</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">dk</span><span class="p">:</span> <span class="n">FreqaiDataKitchen</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span>
|
||||
<span class="n">n_features</span> <span class="o">=</span> <span class="n">data_dictionary</span><span class="p">[</span><span class="s2">"train_features"</span><span class="p">]</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="n">model</span> <span class="o">=</span> <span class="n">PyTorchMLPModel</span><span class="p">(</span>
|
||||
<span class="n">input_dim</span><span class="o">=</span><span class="n">n_features</span><span class="p">,</span>
|
||||
<span class="n">output_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">model_kwargs</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">model</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
|
||||
<span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">AdamW</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">learning_rate</span><span class="p">)</span>
|
||||
<span class="n">criterion</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">MSELoss</span><span class="p">()</span>
|
||||
<span class="n">init_model</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_init_model</span><span class="p">(</span><span class="n">dk</span><span class="o">.</span><span class="n">pair</span><span class="p">)</span>
|
||||
<span class="n">trainer</span> <span class="o">=</span> <span class="n">PyTorchModelTrainer</span><span class="p">(</span>
|
||||
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
|
||||
<span class="n">optimizer</span><span class="o">=</span><span class="n">optimizer</span><span class="p">,</span>
|
||||
<span class="n">criterion</span><span class="o">=</span><span class="n">criterion</span><span class="p">,</span>
|
||||
<span class="n">device</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">device</span><span class="p">,</span>
|
||||
<span class="n">init_model</span><span class="o">=</span><span class="n">init_model</span><span class="p">,</span>
|
||||
<span class="n">target_tensor_type</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">,</span>
|
||||
<span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">trainer_kwargs</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">trainer</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">data_dictionary</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">trainer</span>
|
||||
</code></pre></div>
|
||||
<p>Here we create a <code>PyTorchMLPRegressor</code> class that implements the <code>fit</code> method. The <code>fit</code> method specifies the training building blocks: model, optimizer, criterion, and trainer. We inherit both <code>BasePyTorchRegressor</code> and <code>BasePyTorchModel</code>, where the former implements the <code>predict</code> method that is suitable for our regression task, and the latter implements the train method.</p>
|
||||
<details class="note">
|
||||
<summary>Setting Class Names for Classifiers</summary>
|
||||
<p>When using classifiers, the user must declare the class names (or targets) by overriding the <code>IFreqaiModel.class_names</code> attribute. This is achieved by setting <code>self.freqai.class_names</code> in the FreqAI strategy inside the <code>set_freqai_targets</code> method.</p>
|
||||
<p>For example, if you are using a binary classifier to predict price movements as up or down, you can set the class names as follows:
|
||||
```python
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
self.freqai.class_names = ["down", "up"]
|
||||
dataframe['&s-up_or_down'] = np.where(dataframe["close"].shift(-100) >
|
||||
dataframe["close"], 'up', 'down')</p>
|
||||
<div class="codehilite"><pre><span></span><code>return dataframe
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">set_freqai_targets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">freqai</span><span class="o">.</span><span class="n">class_names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"down"</span><span class="p">,</span> <span class="s2">"up"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'&s-up_or_down'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">)</span> <span class="o">></span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">],</span> <span class="s1">'up'</span><span class="p">,</span> <span class="s1">'down'</span><span class="p">)</span>
|
||||
|
||||
<p>```
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
To see a full example, you can refer to the <a href="https://github.com/freqtrade/freqtrade/blob/develop/tests/strategy/strats/freqai_test_classifier.py">classifier test strategy class</a>.</p>
|
||||
</details>
|
||||
<h4 id="improving-performance-with-torchcompile">Improving performance with <code>torch.compile()</code><a class="headerlink" href="#improving-performance-with-torchcompile" title="Permanent link">¶</a></h4>
|
||||
<p>Torch provides a <code>torch.compile()</code> method that can be used to improve performance for specific GPU hardware. More details can be found <a href="https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html">here</a>. In brief, you simply wrap your <code>model</code> in <code>torch.compile()</code>:</p>
|
||||
<p><code>python
|
||||
model = PyTorchMLPModel(
|
||||
input_dim=n_features,
|
||||
output_dim=1,
|
||||
**self.model_kwargs
|
||||
)
|
||||
model.to(self.device)
|
||||
model = torch.compile(model)</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">model</span> <span class="o">=</span> <span class="n">PyTorchMLPModel</span><span class="p">(</span>
|
||||
<span class="n">input_dim</span><span class="o">=</span><span class="n">n_features</span><span class="p">,</span>
|
||||
<span class="n">output_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">model_kwargs</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">model</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
|
||||
<span class="n">model</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>Then proceed to use the model as normal. Keep in mind that doing this will remove eager execution, which means errors and tracebacks will not be informative.</p>
|
||||
|
||||
|
||||
|
||||
@@ -2002,8 +2002,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The example file structure would look like this:</p>
|
||||
<p>```
|
||||
├── models
|
||||
<div class="highlight"><pre><span></span><code>├── models
|
||||
│ └── unique-id
|
||||
│ ├── config_freqai.example.json
|
||||
│ ├── historic_predictions.backup.pkl
|
||||
@@ -2036,8 +2035,8 @@
|
||||
│ ├── cb_ada_1662821399_pca_object.pkl
|
||||
│ ├── cb_ada_1662821399_svm_model.joblib
|
||||
│ ├── cb_ada_1662821399_trained_dates_df.pkl
|
||||
│ └── cb_ada_1662821399_trained_df.pkl</p>
|
||||
<p>```</p>
|
||||
│ └── cb_ada_1662821399_trained_df.pkl
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1088,6 +1088,78 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#migrating-a-custom-ifreqaimodel-to-the-new-pipeline" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Migrating a custom IFreqaiModel to the new Pipeline
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#outlier-detection" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Outlier detection
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Outlier detection">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-with-the-dissimilarity-index-di" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers with the Dissimilarity Index (DI)
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-using-a-support-vector-machine-svm" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers using a Support Vector Machine (SVM)
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-with-dbscan" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers with DBSCAN
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#data-dimensionality-reduction-with-principal-component-analysis" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Data dimensionality reduction with Principal Component Analysis
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1981,6 +2053,78 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#migrating-a-custom-ifreqaimodel-to-the-new-pipeline" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Migrating a custom IFreqaiModel to the new Pipeline
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#outlier-detection" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Outlier detection
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Outlier detection">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-with-the-dissimilarity-index-di" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers with the Dissimilarity Index (DI)
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-using-a-support-vector-machine-svm" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers using a Support Vector Machine (SVM)
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#identifying-outliers-with-dbscan" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Identifying outliers with DBSCAN
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#data-dimensionality-reduction-with-principal-component-analysis" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Data dimensionality reduction with Principal Component Analysis
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2044,155 +2188,157 @@
|
||||
</table>
|
||||
<p>Meanwhile, high level feature engineering is handled within <code>"feature_parameters":{}</code> in the FreqAI config. Within this file, it is possible to decide large scale feature expansions on top of the <code>base_features</code> such as "including correlated pairs" or "including informative timeframes" or even "including recent candles."</p>
|
||||
<p>It is advisable to start from the template <code>feature_engineering_*</code> functions in the source provided example strategy (found in <code>templates/FreqaiExampleStrategy.py</code>) to ensure that the feature definitions are following the correct conventions. Here is an example of how to set the indicators and labels in the strategy:</p>
|
||||
<p><code>``python
|
||||
def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined</code>indicator_periods_candles<code>,</code>include_timeframes<code>,</code>include_shifted_candles<code>, and</code>include_corr_pairs<code>. In other words, a single feature defined in this function
|
||||
will automatically expand to a total of</code>indicator_periods_candles<code>*</code>include_timeframes<code>*</code>include_shifted_candles<code>*</code>include_corr_pairs` numbers of features added to the model.</p>
|
||||
<div class="codehilite"><pre><span></span><code> All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_expand_all</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">period</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This function will automatically expand the defined features on the config defined</span>
|
||||
<span class="sd"> `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and</span>
|
||||
<span class="sd"> `include_corr_pairs`. In other words, a single feature defined in this function</span>
|
||||
<span class="sd"> will automatically expand to a total of</span>
|
||||
<span class="sd"> `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` *</span>
|
||||
<span class="sd"> `include_corr_pairs` numbers of features added to the model.</span>
|
||||
|
||||
Access metadata such as the current pair/timeframe/period with:
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
`metadata["pair"]` `metadata["tf"]` `metadata["period"]`
|
||||
<span class="sd"> Access metadata such as the current pair/timeframe/period with:</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
:param period: period of the indicator - usage example:
|
||||
:param metadata: metadata of current pair
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
"""
|
||||
<span class="sd"> `metadata["pair"]` `metadata["tf"]` `metadata["period"]`</span>
|
||||
|
||||
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
|
||||
dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period)
|
||||
dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period)
|
||||
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> :param period: period of the indicator - usage example:</span>
|
||||
<span class="sd"> :param metadata: metadata of current pair</span>
|
||||
<span class="sd"> dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
bollinger = qtpylib.bollinger_bands(
|
||||
qtpylib.typical_price(dataframe), window=period, stds=2.2
|
||||
)
|
||||
dataframe["bb_lowerband-period"] = bollinger["lower"]
|
||||
dataframe["bb_middleband-period"] = bollinger["mid"]
|
||||
dataframe["bb_upperband-period"] = bollinger["upper"]
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">si-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">RSI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"%-mfi-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">MFI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-a</span><span class="s2">dx-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">ADX</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-s</span><span class="s2">ma-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">SMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-e</span><span class="s2">ma-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">EMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
|
||||
dataframe["%-bb_width-period"] = (
|
||||
dataframe["bb_upperband-period"]
|
||||
- dataframe["bb_lowerband-period"]
|
||||
) / dataframe["bb_middleband-period"]
|
||||
dataframe["%-close-bb_lower-period"] = (
|
||||
dataframe["close"] / dataframe["bb_lowerband-period"]
|
||||
)
|
||||
<span class="n">bollinger</span> <span class="o">=</span> <span class="n">qtpylib</span><span class="o">.</span><span class="n">bollinger_bands</span><span class="p">(</span>
|
||||
<span class="n">qtpylib</span><span class="o">.</span><span class="n">typical_price</span><span class="p">(</span><span class="n">dataframe</span><span class="p">),</span> <span class="n">window</span><span class="o">=</span><span class="n">period</span><span class="p">,</span> <span class="n">stds</span><span class="o">=</span><span class="mf">2.2</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_lowerband-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s2">"lower"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_middleband-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s2">"mid"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_upperband-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s2">"upper"</span><span class="p">]</span>
|
||||
|
||||
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"%-bb_width-period"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_upperband-period"</span><span class="p">]</span>
|
||||
<span class="o">-</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_lowerband-period"</span><span class="p">]</span>
|
||||
<span class="p">)</span> <span class="o">/</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_middleband-period"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-c</span><span class="s2">lose-bb_lower-period"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span> <span class="o">/</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_lowerband-period"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
dataframe["%-relative_volume-period"] = (
|
||||
dataframe["volume"] / dataframe["volume"].rolling(period).mean()
|
||||
)
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">oc-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">ROC</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
|
||||
return dataframe
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">elative_volume-period"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span> <span class="o">/</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span><span class="o">.</span><span class="n">rolling</span><span class="p">(</span><span class="n">period</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined
|
||||
`include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.
|
||||
In other words, a single feature defined in this function
|
||||
will automatically expand to a total of
|
||||
`include_timeframes` * `include_shifted_candles` * `include_corr_pairs`
|
||||
numbers of features added to the model.
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
Features defined here will *not* be automatically duplicated on user defined
|
||||
`indicator_periods_candles`
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_expand_basic</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This function will automatically expand the defined features on the config defined</span>
|
||||
<span class="sd"> `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.</span>
|
||||
<span class="sd"> In other words, a single feature defined in this function</span>
|
||||
<span class="sd"> will automatically expand to a total of</span>
|
||||
<span class="sd"> `include_timeframes` * `include_shifted_candles` * `include_corr_pairs`</span>
|
||||
<span class="sd"> numbers of features added to the model.</span>
|
||||
|
||||
Access metadata such as the current pair/timeframe with:
|
||||
<span class="sd"> Features defined here will *not* be automatically duplicated on user defined</span>
|
||||
<span class="sd"> `indicator_periods_candles`</span>
|
||||
|
||||
`metadata["pair"]` `metadata["tf"]`
|
||||
<span class="sd"> Access metadata such as the current pair/timeframe with:</span>
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<span class="sd"> `metadata["pair"]` `metadata["tf"]`</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
:param metadata: metadata of current pair
|
||||
dataframe["%-pct-change"] = dataframe["close"].pct_change()
|
||||
dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)
|
||||
"""
|
||||
dataframe["%-pct-change"] = dataframe["close"].pct_change()
|
||||
dataframe["%-raw_volume"] = dataframe["volume"]
|
||||
dataframe["%-raw_price"] = dataframe["close"]
|
||||
return dataframe
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
def feature_engineering_standard(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This optional function will be called once with the dataframe of the base timeframe.
|
||||
This is the final function to be called, which means that the dataframe entering this
|
||||
function will contain all the features and columns created by all other
|
||||
freqai_feature_engineering_* functions.
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> :param metadata: metadata of current pair</span>
|
||||
<span class="sd"> dataframe["%-pct-change"] = dataframe["close"].pct_change()</span>
|
||||
<span class="sd"> dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"%-pct-change"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span><span class="o">.</span><span class="n">pct_change</span><span class="p">()</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">aw_volume"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">aw_price"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
This function is a good place to do custom exotic feature extractions (e.g. tsfresh).
|
||||
This function is a good place for any feature that should not be auto-expanded upon
|
||||
(e.g. day of the week).
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_standard</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> This optional function will be called once with the dataframe of the base timeframe.</span>
|
||||
<span class="sd"> This is the final function to be called, which means that the dataframe entering this</span>
|
||||
<span class="sd"> function will contain all the features and columns created by all other</span>
|
||||
<span class="sd"> freqai_feature_engineering_* functions.</span>
|
||||
|
||||
Access metadata such as the current pair with:
|
||||
<span class="sd"> This function is a good place to do custom exotic feature extractions (e.g. tsfresh).</span>
|
||||
<span class="sd"> This function is a good place for any feature that should not be auto-expanded upon</span>
|
||||
<span class="sd"> (e.g. day of the week).</span>
|
||||
|
||||
`metadata["pair"]`
|
||||
<span class="sd"> Access metadata such as the current pair with:</span>
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
<span class="sd"> `metadata["pair"]`</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the features
|
||||
:param metadata: metadata of current pair
|
||||
usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
|
||||
"""
|
||||
dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
|
||||
dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25
|
||||
return dataframe
|
||||
<span class="sd"> All features must be prepended with `%` to be recognized by FreqAI internals.</span>
|
||||
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
Required function to set the targets for the model.
|
||||
All targets must be prepended with `&` to be recognized by the FreqAI internals.
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the features</span>
|
||||
<span class="sd"> :param metadata: metadata of current pair</span>
|
||||
<span class="sd"> usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-d</span><span class="s2">ay_of_week"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">dayofweek</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">7</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-ho</span><span class="s2">ur_of_day"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">hour</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">25</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
Access metadata such as the current pair with:
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">set_freqai_targets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> Required function to set the targets for the model.</span>
|
||||
<span class="sd"> All targets must be prepended with `&` to be recognized by the FreqAI internals.</span>
|
||||
|
||||
`metadata["pair"]`
|
||||
<span class="sd"> Access metadata such as the current pair with:</span>
|
||||
|
||||
:param df: strategy dataframe which will receive the targets
|
||||
:param metadata: metadata of current pair
|
||||
usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]
|
||||
"""
|
||||
dataframe["&-s_close"] = (
|
||||
dataframe["close"]
|
||||
.shift(-self.freqai_info["feature_parameters"]["label_period_candles"])
|
||||
.rolling(self.freqai_info["feature_parameters"]["label_period_candles"])
|
||||
.mean()
|
||||
/ dataframe["close"]
|
||||
- 1
|
||||
)
|
||||
<span class="sd"> `metadata["pair"]`</span>
|
||||
|
||||
return dataframe
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the targets</span>
|
||||
<span class="sd"> :param metadata: metadata of current pair</span>
|
||||
<span class="sd"> usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-s_close"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="p">[</span><span class="s2">"feature_parameters"</span><span class="p">][</span><span class="s2">"label_period_candles"</span><span class="p">])</span>
|
||||
<span class="o">.</span><span class="n">rolling</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">freqai_info</span><span class="p">[</span><span class="s2">"feature_parameters"</span><span class="p">][</span><span class="s2">"label_period_candles"</span><span class="p">])</span>
|
||||
<span class="o">.</span><span class="n">mean</span><span class="p">()</span>
|
||||
<span class="o">/</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>In the presented example, the user does not wish to pass the <code>bb_lowerband</code> as a feature to the model,
|
||||
and has therefore not prepended it with <code>%</code>. The user does, however, wish to pass <code>bb_width</code> to the
|
||||
model for training/prediction and has therefore prepended it with <code>%</code>.</p>
|
||||
<p>After having defined the <code>base features</code>, the next step is to expand upon them using the powerful <code>feature_parameters</code> in the configuration file:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
//...
|
||||
"feature_parameters" : {
|
||||
"include_timeframes": ["5m","15m","4h"],
|
||||
"include_corr_pairlist": [
|
||||
"ETH/USD",
|
||||
"LINK/USD",
|
||||
"BNB/USD"
|
||||
],
|
||||
"label_period_candles": 24,
|
||||
"include_shifted_candles": 2,
|
||||
"indicator_periods_candles": [10, 20]
|
||||
},
|
||||
//...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"include_timeframes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"5m"</span><span class="p">,</span><span class="s2">"15m"</span><span class="p">,</span><span class="s2">"4h"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"include_corr_pairlist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"ETH/USD"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"LINK/USD"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"BNB/USD"</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"label_period_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">24</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"include_shifted_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"indicator_periods_candles"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>The <code>include_timeframes</code> in the config above are the timeframes (<code>tf</code>) of each call to <code>feature_engineering_expand_*()</code> in the strategy. In the presented case, the user is asking for the <code>5m</code>, <code>15m</code>, and <code>4h</code> timeframes of the <code>rsi</code>, <code>mfi</code>, <code>roc</code>, and <code>bb_width</code> to be included in the feature set.</p>
|
||||
<p>You can ask for each of the defined features to be included also for informative pairs using the <code>include_corr_pairlist</code>. This means that the feature set will include all the features from <code>feature_engineering_expand_*()</code> on all the <code>include_timeframes</code> for each of the correlated pairs defined in the config (<code>ETH/USD</code>, <code>LINK/USD</code>, and <code>BNB/USD</code> in the presented example).</p>
|
||||
<p><code>include_shifted_candles</code> indicates the number of previous candles to include in the feature set. For example, <code>include_shifted_candles: 2</code> tells FreqAI to include the past 2 candles for each of the features in the feature set.</p>
|
||||
@@ -2204,19 +2350,19 @@ model for training/prediction and has therefore prepended it with <code>%</code>
|
||||
</div>
|
||||
<h3 id="gain-finer-control-over-feature_engineering_-functions-with-metadata">Gain finer control over <code>feature_engineering_*</code> functions with <code>metadata</code><a class="headerlink" href="#gain-finer-control-over-feature_engineering_-functions-with-metadata" title="Permanent link">¶</a></h3>
|
||||
<p>All <code>feature_engineering_*</code> and <code>set_freqai_targets()</code> functions are passed a <code>metadata</code> dictionary which contains information about the <code>pair</code>, <code>tf</code> (timeframe), and <code>period</code> that FreqAI is automating for feature building. As such, a user can use <code>metadata</code> inside <code>feature_engineering_*</code> functions as criteria for blocking/reserving features for certain timeframes, periods, pairs etc.</p>
|
||||
<p><code>python
|
||||
def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata, **kwargs) -> DataFrame:
|
||||
if metadata["tf"] == "1h":
|
||||
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_expand_all</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">period</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">metadata</span><span class="p">[</span><span class="s2">"tf"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"1h"</span><span class="p">:</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"</span><span class="si">%-r</span><span class="s2">oc-period"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">ROC</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">period</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>This will block <code>ta.ROC()</code> from being added to any timeframes other than <code>"1h"</code>.</p>
|
||||
<h3 id="returning-additional-info-from-training">Returning additional info from training<a class="headerlink" href="#returning-additional-info-from-training" title="Permanent link">¶</a></h3>
|
||||
<p>Important metrics can be returned to the strategy at the end of each model training by assigning them to <code>dk.data['extra_returns_per_train']['my_new_value'] = XYZ</code> inside the custom prediction model class. </p>
|
||||
<p>FreqAI takes the <code>my_new_value</code> assigned in this dictionary and expands it to fit the dataframe that is returned to the strategy. You can then use the returned metrics in your strategy through <code>dataframe['my_new_value']</code>. An example of how return values can be used in FreqAI are the <code>&*_mean</code> and <code>&*_std</code> values that are used to <a href="../freqai-configuration/#creating-a-dynamic-target-threshold">created a dynamic target threshold</a>.</p>
|
||||
<p>Another example, where the user wants to use live metrics from the trade database, is shown below:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"extra_returns_per_train": {"total_profit": 4}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"extra_returns_per_train"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nt">"total_profit"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>You need to set the standard dictionary in the config so that FreqAI can return proper dataframe shapes. These values will likely be overridden by the prediction model, but in the case where the model has yet to set them, or needs a default initial value, the pre-set values are what will be returned.</p>
|
||||
<h3 id="weighting-features-for-temporal-importance">Weighting features for temporal importance<a class="headerlink" href="#weighting-features-for-temporal-importance" title="Permanent link">¶</a></h3>
|
||||
<p>FreqAI allows you to set a <code>weight_factor</code> to weight recent data more strongly than past data via an exponential function:</p>
|
||||
@@ -2235,67 +2381,66 @@ def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata,
|
||||
<p class="admonition-title">More information available</p>
|
||||
<p>FreqAI uses the <a href="https://github.com/emergentmethods/datasieve"><code>DataSieve</code></a> pipeline, which follows the SKlearn pipeline API, but adds, among other features, coherence between the X, y, and sample_weight vector point removals, feature removal, feature name following. </p>
|
||||
</div>
|
||||
<p>```python
|
||||
from datasieve.transforms import SKLearnWrapper, DissimilarityIndex
|
||||
from datasieve.pipeline import Pipeline
|
||||
from sklearn.preprocessing import QuantileTransformer, StandardScaler
|
||||
from freqai.base_models import BaseRegressionModel</p>
|
||||
<p>class MyFreqaiModel(BaseRegressionModel):
|
||||
"""
|
||||
Some cool custom model
|
||||
"""
|
||||
def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> Any:
|
||||
"""
|
||||
My custom fit function
|
||||
"""
|
||||
model = cool_model.fit()
|
||||
return model</p>
|
||||
<div class="codehilite"><pre><span></span><code>def define_data_pipeline(self) -> Pipeline:
|
||||
"""
|
||||
User defines their custom feature pipeline here (if they wish)
|
||||
"""
|
||||
feature_pipeline = Pipeline([
|
||||
('qt', SKLearnWrapper(QuantileTransformer(output_distribution='normal'))),
|
||||
('di', ds.DissimilarityIndex(di_threshold=1))
|
||||
])
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">datasieve.transforms</span><span class="w"> </span><span class="kn">import</span> <span class="n">SKLearnWrapper</span><span class="p">,</span> <span class="n">DissimilarityIndex</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">datasieve.pipeline</span><span class="w"> </span><span class="kn">import</span> <span class="n">Pipeline</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sklearn.preprocessing</span><span class="w"> </span><span class="kn">import</span> <span class="n">QuantileTransformer</span><span class="p">,</span> <span class="n">StandardScaler</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqai.base_models</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseRegressionModel</span>
|
||||
|
||||
return feature_pipeline
|
||||
|
||||
def define_label_pipeline(self) -> Pipeline:
|
||||
"""
|
||||
User defines their custom label pipeline here (if they wish)
|
||||
"""
|
||||
label_pipeline = Pipeline([
|
||||
('qt', SKLearnWrapper(StandardScaler())),
|
||||
])
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyFreqaiModel</span><span class="p">(</span><span class="n">BaseRegressionModel</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Some cool custom model</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">fit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data_dictionary</span><span class="p">:</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">dk</span><span class="p">:</span> <span class="n">FreqaiDataKitchen</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> My custom fit function</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">model</span> <span class="o">=</span> <span class="n">cool_model</span><span class="o">.</span><span class="n">fit</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">model</span>
|
||||
|
||||
return label_pipeline
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">define_data_pipeline</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Pipeline</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User defines their custom feature pipeline here (if they wish)</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">feature_pipeline</span> <span class="o">=</span> <span class="n">Pipeline</span><span class="p">([</span>
|
||||
<span class="p">(</span><span class="s1">'qt'</span><span class="p">,</span> <span class="n">SKLearnWrapper</span><span class="p">(</span><span class="n">QuantileTransformer</span><span class="p">(</span><span class="n">output_distribution</span><span class="o">=</span><span class="s1">'normal'</span><span class="p">))),</span>
|
||||
<span class="p">(</span><span class="s1">'di'</span><span class="p">,</span> <span class="n">ds</span><span class="o">.</span><span class="n">DissimilarityIndex</span><span class="p">(</span><span class="n">di_threshold</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
|
||||
<span class="p">])</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">feature_pipeline</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">define_label_pipeline</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Pipeline</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User defines their custom label pipeline here (if they wish)</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">label_pipeline</span> <span class="o">=</span> <span class="n">Pipeline</span><span class="p">([</span>
|
||||
<span class="p">(</span><span class="s1">'qt'</span><span class="p">,</span> <span class="n">SKLearnWrapper</span><span class="p">(</span><span class="n">StandardScaler</span><span class="p">())),</span>
|
||||
<span class="p">])</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">label_pipeline</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>Here, you are defining the exact pipeline that will be used for your feature set during training and prediction. You can use <em>most</em> SKLearn transformation steps by wrapping them in the <code>SKLearnWrapper</code> class as shown above. In addition, you can use any of the transformations available in the <a href="https://github.com/emergentmethods/datasieve"><code>DataSieve</code> library</a>. </p>
|
||||
<p>You can easily add your own transformation by creating a class that inherits from the datasieve <code>BaseTransform</code> and implementing your <code>fit()</code>, <code>transform()</code> and <code>inverse_transform()</code> methods:</p>
|
||||
<p>```python
|
||||
from datasieve.transforms.base_transform import BaseTransform</p>
|
||||
<h1 id="import-whatever-else-you-need">import whatever else you need<a class="headerlink" href="#import-whatever-else-you-need" title="Permanent link">¶</a></h1>
|
||||
<p>class MyCoolTransform(BaseTransform):
|
||||
def <strong>init</strong>(self, **kwargs):
|
||||
self.param1 = kwargs.get('param1', 1)</p>
|
||||
<div class="codehilite"><pre><span></span><code>def fit(self, X, y=None, sample_weight=None, feature_list=None, **kwargs):
|
||||
# do something with X, y, sample_weight, or/and feature_list
|
||||
return X, y, sample_weight, feature_list
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">datasieve.transforms.base_transform</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseTransform</span>
|
||||
<span class="c1"># import whatever else you need</span>
|
||||
|
||||
def transform(self, X, y=None, sample_weight=None,
|
||||
feature_list=None, outlier_check=False, **kwargs):
|
||||
# do something with X, y, sample_weight, or/and feature_list
|
||||
return X, y, sample_weight, feature_list
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyCoolTransform</span><span class="p">(</span><span class="n">BaseTransform</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">param1</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'param1'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
def inverse_transform(self, X, y=None, sample_weight=None, feature_list=None, **kwargs):
|
||||
# do/dont do something with X, y, sample_weight, or/and feature_list
|
||||
return X, y, sample_weight, feature_list
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">fit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">feature_list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># do something with X, y, sample_weight, or/and feature_list</span>
|
||||
<span class="k">return</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">sample_weight</span><span class="p">,</span> <span class="n">feature_list</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">transform</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">feature_list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">outlier_check</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># do something with X, y, sample_weight, or/and feature_list</span>
|
||||
<span class="k">return</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">sample_weight</span><span class="p">,</span> <span class="n">feature_list</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">inverse_transform</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">feature_list</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># do/dont do something with X, y, sample_weight, or/and feature_list</span>
|
||||
<span class="k">return</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">sample_weight</span><span class="p">,</span> <span class="n">feature_list</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Hint</p>
|
||||
<p>You can define this custom class in the same file as your <code>IFreqaiModel</code>.</p>
|
||||
@@ -2308,12 +2453,12 @@ def inverse_transform(self, X, y=None, sample_weight=None, feature_list=None, **
|
||||
<h3 id="identifying-outliers-with-the-dissimilarity-index-di">Identifying outliers with the Dissimilarity Index (DI)<a class="headerlink" href="#identifying-outliers-with-the-dissimilarity-index-di" title="Permanent link">¶</a></h3>
|
||||
<p>The Dissimilarity Index (DI) aims to quantify the uncertainty associated with each prediction made by the model. </p>
|
||||
<p>You can tell FreqAI to remove outlier data points from the training/test data sets using the DI by including the following statement in the config:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"feature_parameters" : {
|
||||
"DI_threshold": 1
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"DI_threshold"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Which will add <code>DissimilarityIndex</code> step to your <code>feature_pipeline</code> and set the threshold to 1. The DI allows predictions which are outliers (not existent in the model feature space) to be thrown out due to low levels of certainty. To do so, FreqAI measures the distance between each training data point (feature vector), <span class="arithmatex">\(X_{a}\)</span>, and all other training data points:</p>
|
||||
<div class="arithmatex">\[ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} \]</div>
|
||||
<p>where <span class="arithmatex">\(d_{ab}\)</span> is the distance between the normalized points <span class="arithmatex">\(a\)</span> and <span class="arithmatex">\(b\)</span>, and <span class="arithmatex">\(p\)</span> is the number of features, i.e., the length of the vector <span class="arithmatex">\(X\)</span>. The characteristic distance, <span class="arithmatex">\(\overline{d}\)</span>, for a set of training data points is simply the mean of the average distances:</p>
|
||||
@@ -2327,36 +2472,36 @@ def inverse_transform(self, X, y=None, sample_weight=None, feature_list=None, **
|
||||
<p><img alt="DI" src="../assets/freqai_DI.jpg" /></p>
|
||||
<h3 id="identifying-outliers-using-a-support-vector-machine-svm">Identifying outliers using a Support Vector Machine (SVM)<a class="headerlink" href="#identifying-outliers-using-a-support-vector-machine-svm" title="Permanent link">¶</a></h3>
|
||||
<p>You can tell FreqAI to remove outlier data points from the training/test data sets using a Support Vector Machine (SVM) by including the following statement in the config:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"feature_parameters" : {
|
||||
"use_SVM_to_remove_outliers": true
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"use_SVM_to_remove_outliers"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Which will add <code>SVMOutlierExtractor</code> step to your <code>feature_pipeline</code>. The SVM will be trained on the training data and any data point that the SVM deems to be beyond the feature space will be removed.</p>
|
||||
<p>You can elect to provide additional parameters for the SVM, such as <code>shuffle</code>, and <code>nu</code> via the <code>feature_parameters.svm_params</code> dictionary in the config.</p>
|
||||
<p>The parameter <code>shuffle</code> is by default set to <code>False</code> to ensure consistent results. If it is set to <code>True</code>, running the SVM multiple times on the same data set might result in different outcomes due to <code>max_iter</code> being to low for the algorithm to reach the demanded <code>tol</code>. Increasing <code>max_iter</code> solves this issue but causes the procedure to take longer time.</p>
|
||||
<p>The parameter <code>nu</code>, <em>very</em> broadly, is the amount of data points that should be considered outliers and should be between 0 and 1.</p>
|
||||
<h3 id="identifying-outliers-with-dbscan">Identifying outliers with DBSCAN<a class="headerlink" href="#identifying-outliers-with-dbscan" title="Permanent link">¶</a></h3>
|
||||
<p>You can configure FreqAI to use DBSCAN to cluster and remove outliers from the training/test data set or incoming outliers from predictions, by activating <code>use_DBSCAN_to_remove_outliers</code> in the config:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"feature_parameters" : {
|
||||
"use_DBSCAN_to_remove_outliers": true
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"use_DBSCAN_to_remove_outliers"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Which will add the <code>DataSieveDBSCAN</code> step to your <code>feature_pipeline</code>. This is an unsupervised machine learning algorithm that clusters data without needing to know how many clusters there should be.</p>
|
||||
<p>Given a number of data points <span class="arithmatex">\(N\)</span>, and a distance <span class="arithmatex">\(\varepsilon\)</span>, DBSCAN clusters the data set by setting all data points that have <span class="arithmatex">\(N-1\)</span> other data points within a distance of <span class="arithmatex">\(\varepsilon\)</span> as <em>core points</em>. A data point that is within a distance of <span class="arithmatex">\(\varepsilon\)</span> from a <em>core point</em> but that does not have <span class="arithmatex">\(N-1\)</span> other data points within a distance of <span class="arithmatex">\(\varepsilon\)</span> from itself is considered an <em>edge point</em>. A cluster is then the collection of <em>core points</em> and <em>edge points</em>. Data points that have no other data points at a distance <span class="arithmatex">\(<\varepsilon\)</span> are considered outliers. The figure below shows a cluster with <span class="arithmatex">\(N = 3\)</span>.</p>
|
||||
<p><img alt="dbscan" src="../assets/freqai_dbscan.jpg" /></p>
|
||||
<p>FreqAI uses <code>sklearn.cluster.DBSCAN</code> (details are available on scikit-learn's webpage <a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html">here</a> (external website)) with <code>min_samples</code> (<span class="arithmatex">\(N\)</span>) taken as ¼ of the no. of time points (candles) in the feature set. <code>eps</code> (<span class="arithmatex">\(\varepsilon\)</span>) is computed automatically as the elbow point in the <em>k-distance graph</em> computed from the nearest neighbors in the pairwise distances of all data points in the feature set.</p>
|
||||
<h3 id="data-dimensionality-reduction-with-principal-component-analysis">Data dimensionality reduction with Principal Component Analysis<a class="headerlink" href="#data-dimensionality-reduction-with-principal-component-analysis" title="Permanent link">¶</a></h3>
|
||||
<p>You can reduce the dimensionality of your features by activating the principal_component_analysis in the config:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"feature_parameters" : {
|
||||
"principal_component_analysis": true
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"feature_parameters"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"principal_component_analysis"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>This will perform PCA on the features and reduce their dimensionality so that the explained variance of the data set is >= 0.999. Reducing data dimensionality makes training the model faster and hence allows for more up-to-date models.</p>
|
||||
|
||||
|
||||
|
||||
@@ -2108,88 +2108,84 @@ Users who prefer docker should ensure they use the docker image appended with <c
|
||||
<p>As explained above, the agent is "trained" in an artificial trading "environment". In our case, that environment may seem quite similar to a real Freqtrade backtesting environment, but it is <em>NOT</em>. In fact, the RL training environment is much more simplified. It does not incorporate any of the complicated strategy logic, such as callbacks like <code>custom_exit</code>, <code>custom_stoploss</code>, leverage controls, etc. The RL environment is instead a very "raw" representation of the true market, where the agent has free will to learn the policy (read: stoploss, take profit, etc.) which is enforced by the <code>calculate_reward()</code>. Thus, it is important to consider that the agent training environment is not identical to the real world.</p>
|
||||
<h2 id="running-reinforcement-learning">Running Reinforcement Learning<a class="headerlink" href="#running-reinforcement-learning" title="Permanent link">¶</a></h2>
|
||||
<p>Setting up and running a Reinforcement Learning model is the same as running a Regressor or Classifier. The same two flags, <code>--freqaimodel</code> and <code>--strategy</code>, must be defined on the command line:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --freqaimodel ReinforcementLearner --strategy MyRLStrategy --config config.json</code></p>
|
||||
<p>where <code>ReinforcementLearner</code> will use the templated <code>ReinforcementLearner</code> from <code>freqai/prediction_models/ReinforcementLearner</code> (or a custom user defined one located in <code>user_data/freqaimodels</code>). The strategy, on the other hand, follows the same base <a href="../freqai-feature-engineering/">feature engineering</a> with <code>feature_engineering_*</code> as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesn't require them. However, FreqAI requires a default (neutral) value to be set in the action column:</p>
|
||||
<p><code>``python
|
||||
def set_freqai_targets(self, dataframe, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
Required function to set the targets for the model.
|
||||
All targets must be prepended with</code>&` to be recognized by the FreqAI internals.</p>
|
||||
<div class="codehilite"><pre><span></span><code> More details about feature engineering available:
|
||||
|
||||
https://www.freqtrade.io/en/stable/freqai-feature-engineering
|
||||
|
||||
:param df: strategy dataframe which will receive the targets
|
||||
usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]
|
||||
"""
|
||||
# For RL, there are no direct targets to set. This is filler (neutral)
|
||||
# until the agent sends an action.
|
||||
dataframe["&-action"] = 0
|
||||
return dataframe
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--freqaimodel<span class="w"> </span>ReinforcementLearner<span class="w"> </span>--strategy<span class="w"> </span>MyRLStrategy<span class="w"> </span>--config<span class="w"> </span>config.json
|
||||
</code></pre></div>
|
||||
<p>where <code>ReinforcementLearner</code> will use the templated <code>ReinforcementLearner</code> from <code>freqai/prediction_models/ReinforcementLearner</code> (or a custom user defined one located in <code>user_data/freqaimodels</code>). The strategy, on the other hand, follows the same base <a href="../freqai-feature-engineering/">feature engineering</a> with <code>feature_engineering_*</code> as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesn't require them. However, FreqAI requires a default (neutral) value to be set in the action column:</p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">def</span><span class="w"> </span><span class="nf">set_freqai_targets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> *Only functional with FreqAI enabled strategies*</span>
|
||||
<span class="sd"> Required function to set the targets for the model.</span>
|
||||
<span class="sd"> All targets must be prepended with `&` to be recognized by the FreqAI internals.</span>
|
||||
|
||||
<p>```</p>
|
||||
<span class="sd"> More details about feature engineering available:</span>
|
||||
|
||||
<span class="sd"> https://www.freqtrade.io/en/stable/freqai-feature-engineering</span>
|
||||
|
||||
<span class="sd"> :param df: strategy dataframe which will receive the targets</span>
|
||||
<span class="sd"> usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="c1"># For RL, there are no direct targets to set. This is filler (neutral)</span>
|
||||
<span class="c1"># until the agent sends an action.</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"&-action"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
<p>Most of the function remains the same as for typical Regressors, however, the function below shows how the strategy must pass the raw price data to the agent so that it has access to raw OHLCV in the training environment:</p>
|
||||
<p><code>python
|
||||
def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame:
|
||||
# The following features are necessary for RL models
|
||||
dataframe[f"%-raw_close"] = dataframe["close"]
|
||||
dataframe[f"%-raw_open"] = dataframe["open"]
|
||||
dataframe[f"%-raw_high"] = dataframe["high"]
|
||||
dataframe[f"%-raw_low"] = dataframe["low"]
|
||||
return dataframe</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">def</span><span class="w"> </span><span class="nf">feature_engineering_standard</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># The following features are necessary for RL models</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="sa">f</span><span class="s2">"%-raw_close"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="sa">f</span><span class="s2">"%-raw_open"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"open"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="sa">f</span><span class="s2">"%-raw_high"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"high"</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="sa">f</span><span class="s2">"%-raw_low"</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"low"</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
<p>Finally, there is no explicit "label" to make - instead it is necessary to assign the <code>&-action</code> column which will contain the agent's actions when accessed in <code>populate_entry/exit_trends()</code>. In the present example, the neutral action to 0. This value should align with the environment used. FreqAI provides two environments, both use 0 as the neutral action.</p>
|
||||
<p>After users realize there are no labels to set, they will soon understand that the agent is making its "own" entry and exit decisions. This makes strategy construction rather simple. The entry and exit signals come from the agent in the form of an integer - which are used directly to decide entries and exits in the strategy:</p>
|
||||
<p>```python
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:</p>
|
||||
<div class="codehilite"><pre><span></span><code> enter_long_conditions = [df["do_predict"] == 1, df["&-action"] == 1]
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">def</span><span class="w"> </span><span class="nf">populate_entry_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">df</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
|
||||
if enter_long_conditions:
|
||||
df.loc[
|
||||
reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"]
|
||||
] = (1, "long")
|
||||
<span class="n">enter_long_conditions</span> <span class="o">=</span> <span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"do_predict"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s2">"&-action"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">]</span>
|
||||
|
||||
enter_short_conditions = [df["do_predict"] == 1, df["&-action"] == 3]
|
||||
<span class="k">if</span> <span class="n">enter_long_conditions</span><span class="p">:</span>
|
||||
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="n">reduce</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">,</span> <span class="n">enter_long_conditions</span><span class="p">),</span> <span class="p">[</span><span class="s2">"enter_long"</span><span class="p">,</span> <span class="s2">"enter_tag"</span><span class="p">]</span>
|
||||
<span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s2">"long"</span><span class="p">)</span>
|
||||
|
||||
if enter_short_conditions:
|
||||
df.loc[
|
||||
reduce(lambda x, y: x & y, enter_short_conditions), ["enter_short", "enter_tag"]
|
||||
] = (1, "short")
|
||||
<span class="n">enter_short_conditions</span> <span class="o">=</span> <span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"do_predict"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s2">"&-action"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span><span class="p">]</span>
|
||||
|
||||
return df
|
||||
<span class="k">if</span> <span class="n">enter_short_conditions</span><span class="p">:</span>
|
||||
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="n">reduce</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">,</span> <span class="n">enter_short_conditions</span><span class="p">),</span> <span class="p">[</span><span class="s2">"enter_short"</span><span class="p">,</span> <span class="s2">"enter_tag"</span><span class="p">]</span>
|
||||
<span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s2">"short"</span><span class="p">)</span>
|
||||
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
exit_long_conditions = [df["do_predict"] == 1, df["&-action"] == 2]
|
||||
if exit_long_conditions:
|
||||
df.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1
|
||||
<span class="k">return</span> <span class="n">df</span>
|
||||
|
||||
exit_short_conditions = [df["do_predict"] == 1, df["&-action"] == 4]
|
||||
if exit_short_conditions:
|
||||
df.loc[reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"] = 1
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_exit_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">df</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="n">exit_long_conditions</span> <span class="o">=</span> <span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"do_predict"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s2">"&-action"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">exit_long_conditions</span><span class="p">:</span>
|
||||
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">reduce</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">,</span> <span class="n">exit_long_conditions</span><span class="p">),</span> <span class="s2">"exit_long"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
return df
|
||||
<span class="n">exit_short_conditions</span> <span class="o">=</span> <span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"do_predict"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s2">"&-action"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">4</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">exit_short_conditions</span><span class="p">:</span>
|
||||
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">reduce</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">,</span> <span class="n">exit_short_conditions</span><span class="p">),</span> <span class="s2">"exit_short"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">df</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>It is important to consider that <code>&-action</code> depends on which environment they choose to use. The example above shows 5 actions, where 0 is neutral, 1 is enter long, 2 is exit long, 3 is enter short and 4 is exit short.</p>
|
||||
<h2 id="configuring-the-reinforcement-learner">Configuring the Reinforcement Learner<a class="headerlink" href="#configuring-the-reinforcement-learner" title="Permanent link">¶</a></h2>
|
||||
<p>In order to configure the <code>Reinforcement Learner</code> the following dictionary must exist in the <code>freqai</code> config:</p>
|
||||
<p><code>json
|
||||
"rl_config": {
|
||||
"train_cycles": 25,
|
||||
"add_state_info": true,
|
||||
"max_trade_duration_candles": 300,
|
||||
"max_training_drawdown_pct": 0.02,
|
||||
"cpu_count": 8,
|
||||
"model_type": "PPO",
|
||||
"policy_type": "MlpPolicy",
|
||||
"model_reward_parameters": {
|
||||
"rr": 1,
|
||||
"profit_aim": 0.025
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"rl_config"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"train_cycles"</span><span class="p">:</span><span class="w"> </span><span class="mi">25</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"add_state_info"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_trade_duration_candles"</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_training_drawdown_pct"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.02</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"cpu_count"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"model_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PPO"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"policy_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MlpPolicy"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"model_reward_parameters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"rr"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"profit_aim"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.025</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>Parameter details can be found <a href="../freqai-parameter-table/">here</a>, but in general the <code>train_cycles</code> decides how many times the agent should cycle through the candle data in its artificial environment to train weights in the model. <code>model_type</code> is a string which selects one of the available models in <a href="https://stable-baselines3.readthedocs.io/en/master/">stable_baselines</a>(external link).</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2210,113 +2206,112 @@ The reward function provided with the Freqtrade source code is a showcase of fun
|
||||
<p class="admonition-title">Hint</p>
|
||||
<p>The best reward functions are ones that are continuously differentiable, and well scaled. In other words, adding a single large negative penalty to a rare event is not a good idea, and the neural net will not be able to learn that function. Instead, it is better to add a small negative penalty to a common event. This will help the agent learn faster. Not only this, but you can help improve the continuity of your rewards/penalties by having them scale with severity according to some linear/exponential functions. In other words, you'd slowly scale the penalty as the duration of the trade increases. This is better than a single large penalty occurring at a single point in time.</p>
|
||||
</div>
|
||||
<p>```python
|
||||
from freqtrade.freqai.prediction_models.ReinforcementLearner import ReinforcementLearner
|
||||
from freqtrade.freqai.RL.Base5ActionRLEnv import Actions, Base5ActionRLEnv, Positions</p>
|
||||
<p>class MyCoolRLModel(ReinforcementLearner):
|
||||
"""
|
||||
User created RL prediction model.</p>
|
||||
<div class="codehilite"><pre><span></span><code>Save this file to `freqtrade/user_data/freqaimodels`
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.freqai.prediction_models.ReinforcementLearner</span><span class="w"> </span><span class="kn">import</span> <span class="n">ReinforcementLearner</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.freqai.RL.Base5ActionRLEnv</span><span class="w"> </span><span class="kn">import</span> <span class="n">Actions</span><span class="p">,</span> <span class="n">Base5ActionRLEnv</span><span class="p">,</span> <span class="n">Positions</span>
|
||||
|
||||
then use it with:
|
||||
|
||||
freqtrade trade --freqaimodel MyCoolRLModel --config config.json --strategy SomeCoolStrat
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyCoolRLModel</span><span class="p">(</span><span class="n">ReinforcementLearner</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User created RL prediction model.</span>
|
||||
|
||||
Here the users can override any of the functions
|
||||
available in the `IFreqaiModel` inheritance tree. Most importantly for RL, this
|
||||
is where the user overrides `MyRLEnv` (see below), to define custom
|
||||
`calculate_reward()` function, or to override any other parts of the environment.
|
||||
<span class="sd"> Save this file to `freqtrade/user_data/freqaimodels`</span>
|
||||
|
||||
This class also allows users to override any other part of the IFreqaiModel tree.
|
||||
For example, the user can override `def fit()` or `def train()` or `def predict()`
|
||||
to take fine-tuned control over these processes.
|
||||
<span class="sd"> then use it with:</span>
|
||||
|
||||
Another common override may be `def data_cleaning_predict()` where the user can
|
||||
take fine-tuned control over the data handling pipeline.
|
||||
"""
|
||||
class MyRLEnv(Base5ActionRLEnv):
|
||||
"""
|
||||
User made custom environment. This class inherits from BaseEnvironment and gym.Env.
|
||||
Users can override any functions from those parent classes. Here is an example
|
||||
of a user customized `calculate_reward()` function.
|
||||
<span class="sd"> freqtrade trade --freqaimodel MyCoolRLModel --config config.json --strategy SomeCoolStrat</span>
|
||||
|
||||
Warning!
|
||||
This is function is a showcase of functionality designed to show as many possible
|
||||
environment control features as possible. It is also designed to run quickly
|
||||
on small computers. This is a benchmark, it is *not* for live production.
|
||||
"""
|
||||
def calculate_reward(self, action: int) -> float:
|
||||
# first, penalize if the action is not valid
|
||||
if not self._is_valid(action):
|
||||
return -2
|
||||
pnl = self.get_unrealized_profit()
|
||||
<span class="sd"> Here the users can override any of the functions</span>
|
||||
<span class="sd"> available in the `IFreqaiModel` inheritance tree. Most importantly for RL, this</span>
|
||||
<span class="sd"> is where the user overrides `MyRLEnv` (see below), to define custom</span>
|
||||
<span class="sd"> `calculate_reward()` function, or to override any other parts of the environment.</span>
|
||||
|
||||
factor = 100
|
||||
<span class="sd"> This class also allows users to override any other part of the IFreqaiModel tree.</span>
|
||||
<span class="sd"> For example, the user can override `def fit()` or `def train()` or `def predict()`</span>
|
||||
<span class="sd"> to take fine-tuned control over these processes.</span>
|
||||
|
||||
pair = self.pair.replace(':', '')
|
||||
<span class="sd"> Another common override may be `def data_cleaning_predict()` where the user can</span>
|
||||
<span class="sd"> take fine-tuned control over the data handling pipeline.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyRLEnv</span><span class="p">(</span><span class="n">Base5ActionRLEnv</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User made custom environment. This class inherits from BaseEnvironment and gym.Env.</span>
|
||||
<span class="sd"> Users can override any functions from those parent classes. Here is an example</span>
|
||||
<span class="sd"> of a user customized `calculate_reward()` function.</span>
|
||||
|
||||
# you can use feature values from dataframe
|
||||
# Assumes the shifted RSI indicator has been generated in the strategy.
|
||||
rsi_now = self.raw_features[f"%-rsi-period_10_shift-1_{pair}_"
|
||||
f"{self.config['timeframe']}"].iloc[self._current_tick]
|
||||
<span class="sd"> Warning!</span>
|
||||
<span class="sd"> This is function is a showcase of functionality designed to show as many possible</span>
|
||||
<span class="sd"> environment control features as possible. It is also designed to run quickly</span>
|
||||
<span class="sd"> on small computers. This is a benchmark, it is *not* for live production.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">calculate_reward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||||
<span class="c1"># first, penalize if the action is not valid</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span><span class="p">(</span><span class="n">action</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="o">-</span><span class="mi">2</span>
|
||||
<span class="n">pnl</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_unrealized_profit</span><span class="p">()</span>
|
||||
|
||||
# reward agent for entering trades
|
||||
if (action in (Actions.Long_enter.value, Actions.Short_enter.value)
|
||||
and self._position == Positions.Neutral):
|
||||
if rsi_now < 40:
|
||||
factor = 40 / rsi_now
|
||||
else:
|
||||
factor = 1
|
||||
return 25 * factor
|
||||
<span class="n">factor</span> <span class="o">=</span> <span class="mi">100</span>
|
||||
|
||||
# discourage agent from not entering trades
|
||||
if action == Actions.Neutral.value and self._position == Positions.Neutral:
|
||||
return -1
|
||||
max_trade_duration = self.rl_config.get('max_trade_duration_candles', 300)
|
||||
trade_duration = self._current_tick - self._last_trade_tick
|
||||
if trade_duration <= max_trade_duration:
|
||||
factor *= 1.5
|
||||
elif trade_duration > max_trade_duration:
|
||||
factor *= 0.5
|
||||
# discourage sitting in position
|
||||
if self._position in (Positions.Short, Positions.Long) and \
|
||||
action == Actions.Neutral.value:
|
||||
return -1 * trade_duration / max_trade_duration
|
||||
# close long
|
||||
if action == Actions.Long_exit.value and self._position == Positions.Long:
|
||||
if pnl > self.profit_aim * self.rr:
|
||||
factor *= self.rl_config['model_reward_parameters'].get('win_reward_factor', 2)
|
||||
return float(pnl * factor)
|
||||
# close short
|
||||
if action == Actions.Short_exit.value and self._position == Positions.Short:
|
||||
if pnl > self.profit_aim * self.rr:
|
||||
factor *= self.rl_config['model_reward_parameters'].get('win_reward_factor', 2)
|
||||
return float(pnl * factor)
|
||||
return 0.
|
||||
<span class="n">pair</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pair</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">':'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># you can use feature values from dataframe</span>
|
||||
<span class="c1"># Assumes the shifted RSI indicator has been generated in the strategy.</span>
|
||||
<span class="n">rsi_now</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">raw_features</span><span class="p">[</span><span class="sa">f</span><span class="s2">"%-rsi-period_10_shift-1_</span><span class="si">{</span><span class="n">pair</span><span class="si">}</span><span class="s2">_"</span>
|
||||
<span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'timeframe'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">]</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_current_tick</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># reward agent for entering trades</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="n">action</span> <span class="ow">in</span> <span class="p">(</span><span class="n">Actions</span><span class="o">.</span><span class="n">Long_enter</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="n">Actions</span><span class="o">.</span><span class="n">Short_enter</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_position</span> <span class="o">==</span> <span class="n">Positions</span><span class="o">.</span><span class="n">Neutral</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">rsi_now</span> <span class="o"><</span> <span class="mi">40</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">=</span> <span class="mi">40</span> <span class="o">/</span> <span class="n">rsi_now</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">25</span> <span class="o">*</span> <span class="n">factor</span>
|
||||
|
||||
<span class="c1"># discourage agent from not entering trades</span>
|
||||
<span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="n">Actions</span><span class="o">.</span><span class="n">Neutral</span><span class="o">.</span><span class="n">value</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_position</span> <span class="o">==</span> <span class="n">Positions</span><span class="o">.</span><span class="n">Neutral</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span>
|
||||
<span class="n">max_trade_duration</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rl_config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'max_trade_duration_candles'</span><span class="p">,</span> <span class="mi">300</span><span class="p">)</span>
|
||||
<span class="n">trade_duration</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_current_tick</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">_last_trade_tick</span>
|
||||
<span class="k">if</span> <span class="n">trade_duration</span> <span class="o"><=</span> <span class="n">max_trade_duration</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">*=</span> <span class="mf">1.5</span>
|
||||
<span class="k">elif</span> <span class="n">trade_duration</span> <span class="o">></span> <span class="n">max_trade_duration</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">*=</span> <span class="mf">0.5</span>
|
||||
<span class="c1"># discourage sitting in position</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_position</span> <span class="ow">in</span> <span class="p">(</span><span class="n">Positions</span><span class="o">.</span><span class="n">Short</span><span class="p">,</span> <span class="n">Positions</span><span class="o">.</span><span class="n">Long</span><span class="p">)</span> <span class="ow">and</span> \
|
||||
<span class="n">action</span> <span class="o">==</span> <span class="n">Actions</span><span class="o">.</span><span class="n">Neutral</span><span class="o">.</span><span class="n">value</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span> <span class="o">*</span> <span class="n">trade_duration</span> <span class="o">/</span> <span class="n">max_trade_duration</span>
|
||||
<span class="c1"># close long</span>
|
||||
<span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="n">Actions</span><span class="o">.</span><span class="n">Long_exit</span><span class="o">.</span><span class="n">value</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_position</span> <span class="o">==</span> <span class="n">Positions</span><span class="o">.</span><span class="n">Long</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">pnl</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">profit_aim</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">rr</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">*=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rl_config</span><span class="p">[</span><span class="s1">'model_reward_parameters'</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'win_reward_factor'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">pnl</span> <span class="o">*</span> <span class="n">factor</span><span class="p">)</span>
|
||||
<span class="c1"># close short</span>
|
||||
<span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="n">Actions</span><span class="o">.</span><span class="n">Short_exit</span><span class="o">.</span><span class="n">value</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_position</span> <span class="o">==</span> <span class="n">Positions</span><span class="o">.</span><span class="n">Short</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">pnl</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">profit_aim</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">rr</span><span class="p">:</span>
|
||||
<span class="n">factor</span> <span class="o">*=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rl_config</span><span class="p">[</span><span class="s1">'model_reward_parameters'</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'win_reward_factor'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">pnl</span> <span class="o">*</span> <span class="n">factor</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="mf">0.</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<h2 id="using-tensorboard">Using Tensorboard<a class="headerlink" href="#using-tensorboard" title="Permanent link">¶</a></h2>
|
||||
<p>Reinforcement Learning models benefit from tracking training metrics. FreqAI has integrated Tensorboard to allow users to track training and evaluation performance across all coins and across all retrainings. Tensorboard is activated via the following command:</p>
|
||||
<p><code>bash
|
||||
tensorboard --logdir user_data/models/unique-id</code></p>
|
||||
<div class="highlight"><pre><span></span><code>tensorboard<span class="w"> </span>--logdir<span class="w"> </span>user_data/models/unique-id
|
||||
</code></pre></div>
|
||||
<p>where <code>unique-id</code> is the <code>identifier</code> set in the <code>freqai</code> configuration file. This command must be run in a separate shell to view the output in the browser at 127.0.0.1:6006 (6006 is the default port used by Tensorboard).</p>
|
||||
<p><img alt="tensorboard" src="../assets/tensorboard.jpg" /></p>
|
||||
<h2 id="custom-logging">Custom logging<a class="headerlink" href="#custom-logging" title="Permanent link">¶</a></h2>
|
||||
<p>FreqAI also provides a built in episodic summary logger called <code>self.tensorboard_log</code> for adding custom information to the Tensorboard log. By default, this function is already called once per step inside the environment to record the agent actions. All values accumulated for all steps in a single episode are reported at the conclusion of each episode, followed by a full reset of all metrics to 0 in preparation for the subsequent episode.</p>
|
||||
<p><code>self.tensorboard_log</code> can also be used anywhere inside the environment, for example, it can be added to the <code>calculate_reward</code> function to collect more detailed information about how often various parts of the reward were called:</p>
|
||||
<p><code>``python
|
||||
class MyRLEnv(Base5ActionRLEnv):
|
||||
"""
|
||||
User made custom environment. This class inherits from BaseEnvironment and gym.Env.
|
||||
Users can override any functions from those parent classes. Here is an example
|
||||
of a user customized</code>calculate_reward()` function.
|
||||
"""
|
||||
def calculate_reward(self, action: int) -> float:
|
||||
if not self._is_valid(action):
|
||||
self.tensorboard_log("invalid")
|
||||
return -2</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="k">class</span><span class="w"> </span><span class="nc">MyRLEnv</span><span class="p">(</span><span class="n">Base5ActionRLEnv</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> User made custom environment. This class inherits from BaseEnvironment and gym.Env.</span>
|
||||
<span class="sd"> Users can override any functions from those parent classes. Here is an example</span>
|
||||
<span class="sd"> of a user customized `calculate_reward()` function.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">calculate_reward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span><span class="p">(</span><span class="n">action</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">tensorboard_log</span><span class="p">(</span><span class="s2">"invalid"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="o">-</span><span class="mi">2</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code>self.tensorboard_log()</code> function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. <code>self.tensorboard_log("float_metric1", 0.23)</code>. In this case the metric values are not incremented.</p>
|
||||
|
||||
@@ -2194,16 +2194,16 @@
|
||||
<p><img alt="freqai-window" src="../assets/freqai_moving-window.jpg" /></p>
|
||||
<h2 id="live-deployments">Live deployments<a class="headerlink" href="#live-deployments" title="Permanent link">¶</a></h2>
|
||||
<p>FreqAI can be run dry/live using the following command:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMRegressor</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--strategy<span class="w"> </span>FreqaiExampleStrategy<span class="w"> </span>--config<span class="w"> </span>config_freqai.example.json<span class="w"> </span>--freqaimodel<span class="w"> </span>LightGBMRegressor
|
||||
</code></pre></div>
|
||||
<p>When launched, FreqAI will start training a new model, with a new <code>identifier</code>, based on the config settings. Following training, the model will be used to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the coin pairs to try to keep all models equally up to date. FreqAI will always use the most recently trained model to make predictions on incoming live data. If you do not want FreqAI to retrain new models as often as possible, you can set <code>live_retrain_hours</code> to tell FreqAI to wait at least that number of hours before training a new model. Additionally, you can set <code>expired_hours</code> to tell FreqAI to avoid making predictions on models that are older than that number of hours.</p>
|
||||
<p>Trained models are by default saved to disk to allow for reuse during backtesting or after a crash. You can opt to <a href="#purging-old-model-data">purge old models</a> to save disk space by setting <code>"purge_old_models": true</code> in the config.</p>
|
||||
<p>To start a dry/live run from a saved backtest model (or from a previously crashed dry/live session), you only need to specify the <code>identifier</code> of the specific model:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"identifier": "example",
|
||||
"live_retrain_hours": 0.5
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"identifier"</span><span class="p">:</span><span class="w"> </span><span class="s2">"example"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"live_retrain_hours"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>In this case, although FreqAI will initiate with a pre-trained model, it will still check to see how much time has elapsed since the model was trained. If a full <code>live_retrain_hours</code> has elapsed since the end of the loaded model, FreqAI will start training a new model.</p>
|
||||
<h3 id="automatic-data-download">Automatic data download<a class="headerlink" href="#automatic-data-download" title="Permanent link">¶</a></h3>
|
||||
<p>FreqAI automatically downloads the proper amount of data needed to ensure training of a model through the defined <code>train_period_days</code> and <code>startup_candle_count</code> (see the <a href="../freqai-parameter-table/">parameter table</a> for detailed descriptions of these parameters). </p>
|
||||
@@ -2211,15 +2211,15 @@ freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.
|
||||
<p>All predictions made during the lifetime of a specific <code>identifier</code> model are stored in <code>historic_predictions.pkl</code> to allow for reloading after a crash or changes made to the config.</p>
|
||||
<h3 id="purging-old-model-data">Purging old model data<a class="headerlink" href="#purging-old-model-data" title="Permanent link">¶</a></h3>
|
||||
<p>FreqAI stores new model files after each successful training. These files become obsolete as new models are generated to adapt to new market conditions. If you are planning to leave FreqAI running for extended periods of time with high frequency retraining, you should enable <code>purge_old_models</code> in the config:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"purge_old_models": 4,
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"purge_old_models"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>This will automatically purge all models older than the four most recently trained ones to save disk space. Inputing "0" will never purge any models.</p>
|
||||
<h2 id="backtesting">Backtesting<a class="headerlink" href="#backtesting" title="Permanent link">¶</a></h2>
|
||||
<p>The FreqAI backtesting module can be executed with the following command:</p>
|
||||
<p><code>bash
|
||||
freqtrade backtesting --strategy FreqaiExampleStrategy --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --freqaimodel LightGBMRegressor --timerange 20210501-20210701</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>backtesting<span class="w"> </span>--strategy<span class="w"> </span>FreqaiExampleStrategy<span class="w"> </span>--strategy-path<span class="w"> </span>freqtrade/templates<span class="w"> </span>--config<span class="w"> </span>config_examples/config_freqai.example.json<span class="w"> </span>--freqaimodel<span class="w"> </span>LightGBMRegressor<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20210501</span>-20210701
|
||||
</code></pre></div>
|
||||
<p>If this command has never been executed with the existing config file, FreqAI will train a new model
|
||||
for each pair, for each backtesting window within the expanded <code>--timerange</code>.</p>
|
||||
<p>Backtesting mode requires <a href="#downloading-data-to-cover-the-full-backtest-period">downloading the necessary data</a> before deployment (unlike in dry/live mode where FreqAI handles the data downloading automatically). You should be careful to consider that the time range of the downloaded data is more than the backtesting time range. This is because FreqAI needs data prior to the desired backtesting time range in order to train a model to be ready to make predictions on the first candle of the set backtesting time range. More details on how to calculate the data to download can be found <a href="#deciding-the-size-of-the-sliding-training-window-and-backtesting-duration">here</a>.</p>
|
||||
@@ -2267,10 +2267,10 @@ a float to indicate sub-daily retraining in live/dry mode). In the presented <a
|
||||
</div>
|
||||
<h2 id="defining-model-expirations">Defining model expirations<a class="headerlink" href="#defining-model-expirations" title="Permanent link">¶</a></h2>
|
||||
<p>During dry/live mode, FreqAI trains each coin pair sequentially (on separate threads/GPU from the main Freqtrade bot). This means that there is always an age discrepancy between models. If you are training on 50 pairs, and each pair requires 5 minutes to train, the oldest model will be over 4 hours old. This may be undesirable if the characteristic time scale (the trade duration target) for a strategy is less than 4 hours. You can decide to only make trade entries if the model is less than a certain number of hours old by setting the <code>expiration_hours</code> in the config file:</p>
|
||||
<p><code>json
|
||||
"freqai": {
|
||||
"expiration_hours": 0.5,
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"freqai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"expiration_hours"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>In the presented example config, the user will only allow predictions on models that are less than ½ hours old.</p>
|
||||
<h2 id="controlling-the-model-learning-process">Controlling the model learning process<a class="headerlink" href="#controlling-the-model-learning-process" title="Permanent link">¶</a></h2>
|
||||
<p>Model training parameters are unique to the selected machine learning library. FreqAI allows you to set any parameter for any library using the <code>model_training_parameters</code> dictionary in the config. The example config (found in <code>config_examples/config_freqai.example.json</code>) shows some of the example parameters associated with <code>Catboost</code> and <code>LightGBM</code>, but you can add any parameters available in those libraries or any other machine learning library you choose to implement.</p>
|
||||
@@ -2288,8 +2288,8 @@ a float to indicate sub-daily retraining in live/dry mode). In the presented <a
|
||||
</details>
|
||||
<h2 id="hyperopt">Hyperopt<a class="headerlink" href="#hyperopt" title="Permanent link">¶</a></h2>
|
||||
<p>You can hyperopt using the same command as for <a href="../hyperopt/">typical Freqtrade hyperopt</a>:</p>
|
||||
<p><code>bash
|
||||
freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20220428-20220507</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>hyperopt<span class="w"> </span>--hyperopt-loss<span class="w"> </span>SharpeHyperOptLoss<span class="w"> </span>--strategy<span class="w"> </span>FreqaiExampleStrategy<span class="w"> </span>--freqaimodel<span class="w"> </span>LightGBMRegressor<span class="w"> </span>--strategy-path<span class="w"> </span>freqtrade/templates<span class="w"> </span>--config<span class="w"> </span>config_examples/config_freqai.example.json<span class="w"> </span>--timerange<span class="w"> </span><span class="m">20220428</span>-20220507
|
||||
</code></pre></div>
|
||||
<p><code>hyperopt</code> requires you to have the data pre-downloaded in the same fashion as if you were doing <a href="#backtesting">backtesting</a>. In addition, you must consider some restrictions when trying to hyperopt FreqAI strategies:</p>
|
||||
<ul>
|
||||
<li>The <code>--analyze-per-epoch</code> hyperopt parameter is not compatible with FreqAI.</li>
|
||||
@@ -2298,9 +2298,9 @@ freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleSt
|
||||
</ul>
|
||||
<p>The best method for combining hyperopt and FreqAI is to focus on hyperopting entry/exit thresholds/criteria. You need to focus on hyperopting parameters that are not used in your features. For example, you should not try to hyperopt rolling window lengths in the feature creation, or any part of the FreqAI config which changes predictions. In order to efficiently hyperopt the FreqAI strategy, FreqAI stores predictions as dataframes and reuses them. Hence the requirement to hyperopt entry/exit thresholds/criteria only.</p>
|
||||
<p>A good example of a hyperoptable parameter in FreqAI is a threshold for the <a href="../freqai-feature-engineering/#identifying-outliers-with-the-dissimilarity-index-di">Dissimilarity Index (DI)</a> <code>DI_values</code> beyond which we consider data points as outliers:</p>
|
||||
<p><code>python
|
||||
di_max = IntParameter(low=1, high=20, default=10, space='buy', optimize=True, load=True)
|
||||
dataframe['outlier'] = np.where(dataframe['DI_values'] > self.di_max.value/10, 1, 0)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">di_max</span> <span class="o">=</span> <span class="n">IntParameter</span><span class="p">(</span><span class="n">low</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">high</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">space</span><span class="o">=</span><span class="s1">'buy'</span><span class="p">,</span> <span class="n">optimize</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">load</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'outlier'</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'DI_values'</span><span class="p">]</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">di_max</span><span class="o">.</span><span class="n">value</span><span class="o">/</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>This specific hyperopt would help you understand the appropriate <code>DI_values</code> for your particular parameter space.</p>
|
||||
<h2 id="using-tensorboard">Using Tensorboard<a class="headerlink" href="#using-tensorboard" title="Permanent link">¶</a></h2>
|
||||
<div class="admonition note">
|
||||
@@ -2312,9 +2312,9 @@ dataframe['outlier'] = np.where(dataframe['DI_values'] > self.di_max.value/10
|
||||
<p>Tensorboard logging requires the FreqAI torch installation/docker image.</p>
|
||||
</div>
|
||||
<p>The easiest way to use tensorboard is to ensure <code>freqai.activate_tensorboard</code> is set to <code>True</code> (default setting) in your configuration file, run FreqAI, then open a separate shell and run:</p>
|
||||
<p><code>bash
|
||||
cd freqtrade
|
||||
tensorboard --logdir user_data/models/unique-id</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>freqtrade
|
||||
tensorboard<span class="w"> </span>--logdir<span class="w"> </span>user_data/models/unique-id
|
||||
</code></pre></div>
|
||||
<p>where <code>unique-id</code> is the <code>identifier</code> set in the <code>freqai</code> configuration file. This command must be run in a separate shell if you wish to view the output in your browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard).</p>
|
||||
<p><img alt="tensorboard" src="../assets/tensorboard.jpg" /></p>
|
||||
<div class="admonition note">
|
||||
|
||||
@@ -2170,8 +2170,8 @@
|
||||
</ul>
|
||||
<h2 id="quick-start">Quick start<a class="headerlink" href="#quick-start" title="Permanent link">¶</a></h2>
|
||||
<p>The easiest way to quickly test FreqAI is to run it in dry mode with the following command:</p>
|
||||
<p><code>bash
|
||||
freqtrade trade --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>trade<span class="w"> </span>--config<span class="w"> </span>config_examples/config_freqai.example.json<span class="w"> </span>--strategy<span class="w"> </span>FreqaiExampleStrategy<span class="w"> </span>--freqaimodel<span class="w"> </span>LightGBMRegressor<span class="w"> </span>--strategy-path<span class="w"> </span>freqtrade/templates
|
||||
</code></pre></div>
|
||||
<p>You will see the boot-up process of automatic data downloading, followed by simultaneous training and trading. </p>
|
||||
<div class="admonition danger">
|
||||
<p class="admonition-title">Not for production</p>
|
||||
@@ -2193,8 +2193,8 @@ freqtrade trade --config config_examples/config_freqai.example.json --strategy F
|
||||
<p><strong>Inferencing</strong> - the process of feeding a trained model new unseen data on which it will make a prediction. </p>
|
||||
<h2 id="install-prerequisites">Install prerequisites<a class="headerlink" href="#install-prerequisites" title="Permanent link">¶</a></h2>
|
||||
<p>The normal Freqtrade install process will ask if you wish to install FreqAI dependencies. You should reply "yes" to this question if you wish to use FreqAI. If you did not reply yes, you can manually install these dependencies after the install with:</p>
|
||||
<p><code>bash
|
||||
pip install -r requirements-freqai.txt</code></p>
|
||||
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements-freqai.txt
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Catboost will not be installed on low-powered arm devices (raspberry), since it does not provide wheels for this platform.</p>
|
||||
@@ -2209,15 +2209,15 @@ pip install -r requirements-freqai.txt</code></p>
|
||||
<p>Forecasting chaotic time-series based systems, such as equity/cryptocurrency markets, requires a broad set of tools geared toward testing a wide range of hypotheses. Fortunately, a recent maturation of robust machine learning libraries (e.g. <code>scikit-learn</code>) has opened up a wide range of research possibilities. Scientists from a diverse range of fields can now easily prototype their studies on an abundance of established machine learning algorithms. Similarly, these user-friendly libraries enable "citizen scientists" to use their basic Python skills for data exploration. However, leveraging these machine learning libraries on historical and live chaotic data sources can be logistically difficult and expensive. Additionally, robust data collection, storage, and handling presents a disparate challenge. <a href="#freqai"><code>FreqAI</code></a> aims to provide a generalized and extensible open-sourced framework geared toward live deployments of adaptive modeling for market forecasting. The <code>FreqAI</code> framework is effectively a sandbox for the rich world of open source machine learning libraries. Inside the <code>FreqAI</code> sandbox, users find they can combine a wide variety of third-party libraries to test creative hypotheses on a free live 24/7 chaotic data source - cryptocurrency exchange data. </p>
|
||||
<h3 id="citing-freqai">Citing FreqAI<a class="headerlink" href="#citing-freqai" title="Permanent link">¶</a></h3>
|
||||
<p>FreqAI is <a href="https://joss.theoj.org/papers/10.21105/joss.04864">published in the Journal of Open Source Software</a>. If you find FreqAI useful in your research, please use the following citation:</p>
|
||||
<p><code>bibtex
|
||||
@article{Caulk2022,
|
||||
doi = {10.21105/joss.04864},
|
||||
url = {https://doi.org/10.21105/joss.04864},
|
||||
year = {2022}, publisher = {The Open Journal},
|
||||
volume = {7}, number = {80}, pages = {4864},
|
||||
author = {Robert A. Caulk and Elin Törnquist and Matthias Voppichler and Andrew R. Lawless and Ryan McMullan and Wagner Costa Santos and Timothy C. Pogue and Johan van der Vlugt and Stefan P. Gehring and Pascal Schmidt},
|
||||
title = {FreqAI: generalizing adaptive modeling for chaotic time-series market forecasts},
|
||||
journal = {Journal of Open Source Software} }</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nc">@article</span><span class="p">{</span><span class="nl">Caulk2022</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="na">doi</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{10.21105/joss.04864}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">url</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{https://doi.org/10.21105/joss.04864}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">year</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{2022}</span><span class="p">,</span><span class="w"> </span><span class="na">publisher</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{The Open Journal}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">volume</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{7}</span><span class="p">,</span><span class="w"> </span><span class="na">number</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{80}</span><span class="p">,</span><span class="w"> </span><span class="na">pages</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{4864}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">author</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{Robert A. Caulk and Elin Törnquist and Matthias Voppichler and Andrew R. Lawless and Ryan McMullan and Wagner Costa Santos and Timothy C. Pogue and Johan van der Vlugt and Stefan P. Gehring and Pascal Schmidt}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">title</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{FreqAI: generalizing adaptive modeling for chaotic time-series market forecasts}</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="na">journal</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">{Journal of Open Source Software}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<h2 id="common-pitfalls">Common pitfalls<a class="headerlink" href="#common-pitfalls" title="Permanent link">¶</a></h2>
|
||||
<p>FreqAI cannot be combined with dynamic <code>VolumePairlists</code> (or any pairlist filter that adds and removes pairs dynamically).
|
||||
This is for performance reasons - FreqAI relies on making quick predictions/retrains. To do this effectively,
|
||||
|
||||
+1265
-403
File diff suppressed because it is too large
Load Diff
+844
-130
File diff suppressed because it is too large
Load Diff
@@ -2317,9 +2317,9 @@ Also, never risk more than what you can afford to lose.</p>
|
||||
<p>In addition to the gains/losses from the change in price of the futures contract, traders also exchange <em>funding fees</em>, 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.</p>
|
||||
<p>To trade in futures markets, you'll have to set <code>trading_mode</code> to "futures".
|
||||
You will also have to pick a "margin mode" (explanation below).</p>
|
||||
<p><code>json
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"trading_mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"futures"</span><span class="p">,</span>
|
||||
<span class="nt">"margin_mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"isolated"</span>
|
||||
</code></pre></div>
|
||||
<h5 id="pair-namings">Pair namings<a class="headerlink" href="#pair-namings" title="Permanent link">¶</a></h5>
|
||||
<p>Freqtrade follows the <a href="https://docs.ccxt.com/#/README?id=perpetual-swap-perpetual-future">ccxt naming conventions for futures</a>.
|
||||
A futures pair will therefore have the naming of <code>base/quote:settle</code> (e.g. <code>ETH/USDT:USDT</code>).</p>
|
||||
@@ -2329,12 +2329,12 @@ While freqtrade currently only supports one margin mode, this will change, and b
|
||||
<p>The possible values are: <code>isolated</code>, or <code>cross</code>.</p>
|
||||
<h4 id="isolated-margin-mode">Isolated margin mode<a class="headerlink" href="#isolated-margin-mode" title="Permanent link">¶</a></h4>
|
||||
<p>Each market(trading pair), keeps collateral in a separate account</p>
|
||||
<p><code>json
|
||||
"margin_mode": "isolated"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"margin_mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"isolated"</span>
|
||||
</code></pre></div>
|
||||
<h4 id="cross-margin-mode">Cross margin mode<a class="headerlink" href="#cross-margin-mode" title="Permanent link">¶</a></h4>
|
||||
<p>One account is used to share collateral between markets (trading pairs). Margin is taken from total account balance to avoid liquidation when needed.</p>
|
||||
<p><code>json
|
||||
"margin_mode": "cross"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"margin_mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cross"</span>
|
||||
</code></pre></div>
|
||||
<p>Please read the <a href="../exchanges/">exchange specific notes</a> for exchanges that support this mode and how they differ.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Increased risk of liquidation</p>
|
||||
|
||||
@@ -2045,122 +2045,124 @@ This is done by not looking at the strategy code itself, but at changed indicato
|
||||
</ul>
|
||||
<p>These are set to avoid users accidentally generating false positives.</p>
|
||||
<h2 id="lookahead-analysis-command-reference">Lookahead-analysis command reference<a class="headerlink" href="#lookahead-analysis-command-reference" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade lookahead-analysis [-h] [-v] [--no-color] [--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,feather,parquet}]
|
||||
[--max-open-trades INT]
|
||||
[--stake-amount STAKE_AMOUNT]
|
||||
[--fee FLOAT] [-p PAIRS [PAIRS ...]]
|
||||
[--enable-protections]
|
||||
[--enable-dynamic-pairlist]
|
||||
[--dry-run-wallet DRY_RUN_WALLET]
|
||||
[--timeframe-detail TIMEFRAME_DETAIL]
|
||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||
[--export {none,trades,signals}]
|
||||
[--backtest-filename PATH]
|
||||
[--backtest-directory PATH]
|
||||
[--freqai-backtest-live-models]
|
||||
[--minimum-trade-amount INT]
|
||||
[--targeted-trade-amount INT]
|
||||
[--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME]
|
||||
[--allow-limit-orders]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-i, --timeframe TIMEFRAME
|
||||
Specify timeframe (<code>1m</code>, <code>5m</code>, <code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
--data-format-ohlcv {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
--max-open-trades INT
|
||||
Override the value of the <code>max_open_trades</code>
|
||||
configuration setting.
|
||||
--stake-amount STAKE_AMOUNT
|
||||
Override the value of the <code>stake_amount</code> configuration
|
||||
setting.
|
||||
--fee FLOAT Specify fee ratio. Will be applied twice (on trade
|
||||
entry and exit).
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--enable-protections, --enableprotections
|
||||
Enable protections for backtesting. Will slow
|
||||
backtesting down by a considerable amount, but will
|
||||
include configured protections
|
||||
--enable-dynamic-pairlist
|
||||
Enables dynamic pairlist refreshes in backtesting. The
|
||||
pairlist will be generated for each new candle if
|
||||
you're using a pairlist handler that supports this
|
||||
feature, for example, ShuffleFilter.
|
||||
--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 (<code>1m</code>, <code>5m</code>,
|
||||
<code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--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.
|
||||
--export {none,trades,signals}
|
||||
Export backtest results (default: trades).
|
||||
--backtest-filename, --export-filename PATH
|
||||
Use this filename for backtest results.Example:
|
||||
<code>--backtest-
|
||||
filename=backtest_results_2020-09-27_16-20-48.json</code>.
|
||||
Assumes either <code>user_data/backtest_results/</code> or
|
||||
<code>--export-directory</code> as base directory.
|
||||
--backtest-directory, --export-directory PATH
|
||||
Directory to use for backtest results. Example:
|
||||
<code>--export-directory=user_data/backtest_results/</code>.
|
||||
--freqai-backtest-live-models
|
||||
Run backtest with ready models.
|
||||
--minimum-trade-amount INT
|
||||
Minimum trade amount for lookahead-analysis
|
||||
--targeted-trade-amount INT
|
||||
Targeted trade amount for lookahead analysis
|
||||
--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME
|
||||
Use this csv-filename to store lookahead-analysis-
|
||||
results
|
||||
--allow-limit-orders Allow limit orders in lookahead analysis (could cause
|
||||
false positives in lookahead analysis results).</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade lookahead-analysis [-h] [-v] [--no-color] [--logfile FILE]</span>
|
||||
<span class="go"> [-V] [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-s NAME] [--strategy-path PATH]</span>
|
||||
<span class="go"> [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME]</span>
|
||||
<span class="go"> [--freqaimodel-path PATH] [-i TIMEFRAME]</span>
|
||||
<span class="go"> [--timerange TIMERANGE]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [--max-open-trades INT]</span>
|
||||
<span class="go"> [--stake-amount STAKE_AMOUNT]</span>
|
||||
<span class="go"> [--fee FLOAT] [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> [--enable-protections]</span>
|
||||
<span class="go"> [--enable-dynamic-pairlist]</span>
|
||||
<span class="go"> [--dry-run-wallet DRY_RUN_WALLET]</span>
|
||||
<span class="go"> [--timeframe-detail TIMEFRAME_DETAIL]</span>
|
||||
<span class="go"> [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]</span>
|
||||
<span class="go"> [--export {none,trades,signals}]</span>
|
||||
<span class="go"> [--backtest-filename PATH]</span>
|
||||
<span class="go"> [--backtest-directory PATH]</span>
|
||||
<span class="go"> [--freqai-backtest-live-models]</span>
|
||||
<span class="go"> [--minimum-trade-amount INT]</span>
|
||||
<span class="go"> [--targeted-trade-amount INT]</span>
|
||||
<span class="go"> [--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME]</span>
|
||||
<span class="go"> [--allow-limit-orders]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -i, --timeframe TIMEFRAME</span>
|
||||
<span class="go"> Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> --max-open-trades INT</span>
|
||||
<span class="go"> Override the value of the `max_open_trades`</span>
|
||||
<span class="go"> configuration setting.</span>
|
||||
<span class="go"> --stake-amount STAKE_AMOUNT</span>
|
||||
<span class="go"> Override the value of the `stake_amount` configuration</span>
|
||||
<span class="go"> setting.</span>
|
||||
<span class="go"> --fee FLOAT Specify fee ratio. Will be applied twice (on trade</span>
|
||||
<span class="go"> entry and exit).</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --enable-protections, --enableprotections</span>
|
||||
<span class="go"> Enable protections for backtesting. Will slow</span>
|
||||
<span class="go"> backtesting down by a considerable amount, but will</span>
|
||||
<span class="go"> include configured protections</span>
|
||||
<span class="go"> --enable-dynamic-pairlist</span>
|
||||
<span class="go"> Enables dynamic pairlist refreshes in backtesting. The</span>
|
||||
<span class="go"> pairlist will be generated for each new candle if</span>
|
||||
<span class="go"> you're using a pairlist handler that supports this</span>
|
||||
<span class="go"> feature, for example, ShuffleFilter.</span>
|
||||
<span class="go"> --dry-run-wallet, --starting-balance DRY_RUN_WALLET</span>
|
||||
<span class="go"> Starting balance, used for backtesting / hyperopt and</span>
|
||||
<span class="go"> dry-runs.</span>
|
||||
<span class="go"> --timeframe-detail TIMEFRAME_DETAIL</span>
|
||||
<span class="go"> Specify detail timeframe for backtesting (`1m`, `5m`,</span>
|
||||
<span class="go"> `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --strategy-list STRATEGY_LIST [STRATEGY_LIST ...]</span>
|
||||
<span class="go"> Provide a space-separated list of strategies to</span>
|
||||
<span class="go"> backtest. Please note that timeframe needs to be set</span>
|
||||
<span class="go"> either in config or via command line.</span>
|
||||
<span class="go"> --export {none,trades,signals}</span>
|
||||
<span class="go"> Export backtest results (default: trades).</span>
|
||||
<span class="go"> --backtest-filename, --export-filename PATH</span>
|
||||
<span class="go"> Use this filename for backtest results.Example:</span>
|
||||
<span class="go"> `--backtest-</span>
|
||||
<span class="go"> filename=backtest_results_2020-09-27_16-20-48.json`.</span>
|
||||
<span class="go"> Assumes either `user_data/backtest_results/` or</span>
|
||||
<span class="go"> `--export-directory` as base directory.</span>
|
||||
<span class="go"> --backtest-directory, --export-directory PATH</span>
|
||||
<span class="go"> Directory to use for backtest results. Example:</span>
|
||||
<span class="go"> `--export-directory=user_data/backtest_results/`.</span>
|
||||
<span class="go"> --freqai-backtest-live-models</span>
|
||||
<span class="go"> Run backtest with ready models.</span>
|
||||
<span class="go"> --minimum-trade-amount INT</span>
|
||||
<span class="go"> Minimum trade amount for lookahead-analysis</span>
|
||||
<span class="go"> --targeted-trade-amount INT</span>
|
||||
<span class="go"> Targeted trade amount for lookahead analysis</span>
|
||||
<span class="go"> --lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME</span>
|
||||
<span class="go"> Use this csv-filename to store lookahead-analysis-</span>
|
||||
<span class="go"> results</span>
|
||||
<span class="go"> --allow-limit-orders Allow limit orders in lookahead analysis (could cause</span>
|
||||
<span class="go"> false positives in lookahead analysis results).</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The above output was reduced to options that <code>lookahead-analysis</code> adds on top of regular backtesting commands.</p>
|
||||
|
||||
+242
-241
@@ -2022,8 +2022,8 @@ This is mostly for the performance problems even medium sized plots can cause, b
|
||||
</div>
|
||||
<h2 id="installation-setup">Installation / Setup<a class="headerlink" href="#installation-setup" title="Permanent link">¶</a></h2>
|
||||
<p>Plotting modules use the Plotly library. You can install / upgrade this by running the following command:</p>
|
||||
<p><code>bash
|
||||
pip install -U -r requirements-plot.txt</code></p>
|
||||
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span>-r<span class="w"> </span>requirements-plot.txt
|
||||
</code></pre></div>
|
||||
<h2 id="plot-price-and-indicators">Plot price and indicators<a class="headerlink" href="#plot-price-and-indicators" title="Permanent link">¶</a></h2>
|
||||
<p>The <code>freqtrade plot-dataframe</code> subcommand shows an interactive graph with three subplots:</p>
|
||||
<ul>
|
||||
@@ -2033,89 +2033,91 @@ pip install -U -r requirements-plot.txt</code></p>
|
||||
</ul>
|
||||
<p><img alt="plot-dataframe" src="../assets/plot-dataframe.png" /></p>
|
||||
<p>Possible arguments:</p>
|
||||
<p>``` output
|
||||
usage: freqtrade plot-dataframe [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH] [-s NAME]
|
||||
[--strategy-path PATH]
|
||||
[--recursive-strategy-search]
|
||||
[--freqaimodel NAME] [--freqaimodel-path PATH]
|
||||
[-p PAIRS [PAIRS ...]]
|
||||
[--indicators1 INDICATORS1 [INDICATORS1 ...]]
|
||||
[--indicators2 INDICATORS2 [INDICATORS2 ...]]
|
||||
[--plot-limit INT] [--db-url PATH]
|
||||
[--trade-source {DB,file}]
|
||||
[--export {none,trades,signals}]
|
||||
[--backtest-filename PATH]
|
||||
[--timerange TIMERANGE] [-i TIMEFRAME]
|
||||
[--no-trades]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--indicators1 INDICATORS1 [INDICATORS1 ...]
|
||||
Set indicators from your strategy you want in the
|
||||
first row of the graph. Space-separated list. Example:
|
||||
<code>ema3 ema5</code>. Default: <code>['sma', 'ema3', 'ema5']</code>.
|
||||
--indicators2 INDICATORS2 [INDICATORS2 ...]
|
||||
Set indicators from your strategy you want in the
|
||||
third row of the graph. Space-separated list. Example:
|
||||
<code>fastd fastk</code>. Default: <code>['macd', 'macdsignal']</code>.
|
||||
--plot-limit INT Specify tick limit for plotting. Notice: too high
|
||||
values cause huge files. Default: 750.
|
||||
--db-url PATH Override trades database URL, this is useful in custom
|
||||
deployments (default: <code>sqlite:///tradesv3.sqlite</code> for
|
||||
Live Run mode, <code>sqlite:///tradesv3.dryrun.sqlite</code> for
|
||||
Dry Run).
|
||||
--trade-source {DB,file}
|
||||
Specify the source for trades (Can be DB or file
|
||||
(backtest file)) Default: file
|
||||
--export {none,trades,signals}
|
||||
Export backtest results (default: trades).
|
||||
--backtest-filename, --export-filename PATH
|
||||
Use this filename for backtest results.Example:
|
||||
<code>--backtest-
|
||||
filename=backtest_results_2020-09-27_16-20-48.json</code>.
|
||||
Assumes either <code>user_data/backtest_results/</code> or
|
||||
<code>--export-directory</code> as base directory.
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
-i, --timeframe TIMEFRAME
|
||||
Specify timeframe (<code>1m</code>, <code>5m</code>, <code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--no-trades Skip using trades from backtesting file and DB.</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade plot-dataframe [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH] [-s NAME]</span>
|
||||
<span class="go"> [--strategy-path PATH]</span>
|
||||
<span class="go"> [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME] [--freqaimodel-path PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> [--indicators1 INDICATORS1 [INDICATORS1 ...]]</span>
|
||||
<span class="go"> [--indicators2 INDICATORS2 [INDICATORS2 ...]]</span>
|
||||
<span class="go"> [--plot-limit INT] [--db-url PATH]</span>
|
||||
<span class="go"> [--trade-source {DB,file}]</span>
|
||||
<span class="go"> [--export {none,trades,signals}]</span>
|
||||
<span class="go"> [--backtest-filename PATH]</span>
|
||||
<span class="go"> [--timerange TIMERANGE] [-i TIMEFRAME]</span>
|
||||
<span class="go"> [--no-trades]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --indicators1 INDICATORS1 [INDICATORS1 ...]</span>
|
||||
<span class="go"> Set indicators from your strategy you want in the</span>
|
||||
<span class="go"> first row of the graph. Space-separated list. Example:</span>
|
||||
<span class="go"> `ema3 ema5`. Default: `['sma', 'ema3', 'ema5']`.</span>
|
||||
<span class="go"> --indicators2 INDICATORS2 [INDICATORS2 ...]</span>
|
||||
<span class="go"> Set indicators from your strategy you want in the</span>
|
||||
<span class="go"> third row of the graph. Space-separated list. Example:</span>
|
||||
<span class="go"> `fastd fastk`. Default: `['macd', 'macdsignal']`.</span>
|
||||
<span class="go"> --plot-limit INT Specify tick limit for plotting. Notice: too high</span>
|
||||
<span class="go"> values cause huge files. Default: 750.</span>
|
||||
<span class="go"> --db-url PATH Override trades database URL, this is useful in custom</span>
|
||||
<span class="go"> deployments (default: `sqlite:///tradesv3.sqlite` for</span>
|
||||
<span class="go"> Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for</span>
|
||||
<span class="go"> Dry Run).</span>
|
||||
<span class="go"> --trade-source {DB,file}</span>
|
||||
<span class="go"> Specify the source for trades (Can be DB or file</span>
|
||||
<span class="go"> (backtest file)) Default: file</span>
|
||||
<span class="go"> --export {none,trades,signals}</span>
|
||||
<span class="go"> Export backtest results (default: trades).</span>
|
||||
<span class="go"> --backtest-filename, --export-filename PATH</span>
|
||||
<span class="go"> Use this filename for backtest results.Example:</span>
|
||||
<span class="go"> `--backtest-</span>
|
||||
<span class="go"> filename=backtest_results_2020-09-27_16-20-48.json`.</span>
|
||||
<span class="go"> Assumes either `user_data/backtest_results/` or</span>
|
||||
<span class="go"> `--export-directory` as base directory.</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> -i, --timeframe TIMEFRAME</span>
|
||||
<span class="go"> Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --no-trades Skip using trades from backtesting file and DB.</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<p>Example:</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe -p BTC/ETH --strategy AwesomeStrategy</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy
|
||||
</code></pre></div>
|
||||
<p>The <code>-p/--pairs</code> argument can be used to specify pairs you would like to plot.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2123,21 +2125,21 @@ freqtrade plot-dataframe -p BTC/ETH --strategy AwesomeStrategy</code></p>
|
||||
</div>
|
||||
<p>Specify custom indicators.
|
||||
Use <code>--indicators1</code> for the main plot and <code>--indicators2</code> for the subplot below (if values are in a different range than prices).</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --indicators1 sma ema --indicators2 macd</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>--indicators1<span class="w"> </span>sma<span class="w"> </span>ema<span class="w"> </span>--indicators2<span class="w"> </span>macd
|
||||
</code></pre></div>
|
||||
<h3 id="further-usage-examples">Further usage examples<a class="headerlink" href="#further-usage-examples" title="Permanent link">¶</a></h3>
|
||||
<p>To plot multiple pairs, separate them with a space:</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH XRP/ETH</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>XRP/ETH
|
||||
</code></pre></div>
|
||||
<p>To plot a timerange (to zoom in)</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --timerange=20180801-20180805</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>--timerange<span class="o">=</span><span class="m">20180801</span>-20180805
|
||||
</code></pre></div>
|
||||
<p>To plot trades stored in a database use <code>--db-url</code> in combination with <code>--trade-source DB</code>:</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe --strategy AwesomeStrategy --db-url sqlite:///tradesv3.dry_run.sqlite -p BTC/ETH --trade-source DB</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///tradesv3.dry_run.sqlite<span class="w"> </span>-p<span class="w"> </span>BTC/ETH<span class="w"> </span>--trade-source<span class="w"> </span>DB
|
||||
</code></pre></div>
|
||||
<p>To plot trades from a backtesting result, use <code>--export-filename <filename></code></p>
|
||||
<p><code>bash
|
||||
freqtrade plot-dataframe --strategy AwesomeStrategy --export-filename user_data/backtest_results/backtest-result.json -p BTC/ETH</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-dataframe<span class="w"> </span>--strategy<span class="w"> </span>AwesomeStrategy<span class="w"> </span>--export-filename<span class="w"> </span>user_data/backtest_results/backtest-result.json<span class="w"> </span>-p<span class="w"> </span>BTC/ETH
|
||||
</code></pre></div>
|
||||
<h3 id="plot-dataframe-basics">Plot dataframe basics<a class="headerlink" href="#plot-dataframe-basics" title="Permanent link">¶</a></h3>
|
||||
<p><img alt="plot-dataframe2" src="../assets/plot-dataframe2.png" /></p>
|
||||
<p>The <code>plot-dataframe</code> subcommand requires backtesting data, a strategy and either a backtesting-results file or a database, containing trades corresponding to the strategy.</p>
|
||||
@@ -2173,87 +2175,84 @@ It also allows multiple subplots to display both MACD and RSI at the same time.<
|
||||
</ul>
|
||||
<p>Extra parameters to <code>plotly.graph_objects.*</code> constructor can be specified in <code>plotly</code> dict.</p>
|
||||
<p>Sample configuration with inline comments explaining the process:</p>
|
||||
<p>``` python
|
||||
@property
|
||||
def plot_config(self):
|
||||
"""
|
||||
There are a lot of solutions how to build the return dictionary.
|
||||
The only important point is the return value.
|
||||
Example:
|
||||
plot_config = {'main_plot': {}, 'subplots': {}}</p>
|
||||
<div class="codehilite"><pre><span></span><code>"""
|
||||
plot_config = {}
|
||||
plot_config['main_plot'] = {
|
||||
# Configuration for main plot indicators.
|
||||
# Assumes 2 parameters, emashort and emalong to be specified.
|
||||
f'ema_{self.emashort.value}': {'color': 'red'},
|
||||
f'ema_{self.emalong.value}': {'color': '#CCCCCC'},
|
||||
# By omitting color, a random color is selected.
|
||||
'sar': {},
|
||||
# fill area between senkou_a and senkou_b
|
||||
'senkou_a': {
|
||||
'color': 'green', #optional
|
||||
'fill_to': 'senkou_b',
|
||||
'fill_label': 'Ichimoku Cloud', #optional
|
||||
'fill_color': 'rgba(255,76,46,0.2)', #optional
|
||||
},
|
||||
# plot senkou_b, too. Not only the area to it.
|
||||
'senkou_b': {}
|
||||
}
|
||||
plot_config['subplots'] = {
|
||||
# Create subplot MACD
|
||||
"MACD": {
|
||||
'macd': {'color': 'blue', 'fill_to': 'macdhist'},
|
||||
'macdsignal': {'color': 'orange'},
|
||||
'macdhist': {'type': 'bar', 'plotly': {'opacity': 0.9}}
|
||||
},
|
||||
# Additional subplot RSI
|
||||
"RSI": {
|
||||
'rsi': {'color': 'red'}
|
||||
}
|
||||
}
|
||||
<div class="highlight"><pre><span></span><code><span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">plot_config</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> There are a lot of solutions how to build the return dictionary.</span>
|
||||
<span class="sd"> The only important point is the return value.</span>
|
||||
<span class="sd"> Example:</span>
|
||||
<span class="sd"> plot_config = {'main_plot': {}, 'subplots': {}}</span>
|
||||
|
||||
return plot_config
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">plot_config</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="n">plot_config</span><span class="p">[</span><span class="s1">'main_plot'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="c1"># Configuration for main plot indicators.</span>
|
||||
<span class="c1"># Assumes 2 parameters, emashort and emalong to be specified.</span>
|
||||
<span class="sa">f</span><span class="s1">'ema_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">emashort</span><span class="o">.</span><span class="n">value</span><span class="si">}</span><span class="s1">'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'red'</span><span class="p">},</span>
|
||||
<span class="sa">f</span><span class="s1">'ema_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">emalong</span><span class="o">.</span><span class="n">value</span><span class="si">}</span><span class="s1">'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'#CCCCCC'</span><span class="p">},</span>
|
||||
<span class="c1"># By omitting color, a random color is selected.</span>
|
||||
<span class="s1">'sar'</span><span class="p">:</span> <span class="p">{},</span>
|
||||
<span class="c1"># fill area between senkou_a and senkou_b</span>
|
||||
<span class="s1">'senkou_a'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'color'</span><span class="p">:</span> <span class="s1">'green'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="s1">'fill_to'</span><span class="p">:</span> <span class="s1">'senkou_b'</span><span class="p">,</span>
|
||||
<span class="s1">'fill_label'</span><span class="p">:</span> <span class="s1">'Ichimoku Cloud'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="s1">'fill_color'</span><span class="p">:</span> <span class="s1">'rgba(255,76,46,0.2)'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="p">},</span>
|
||||
<span class="c1"># plot senkou_b, too. Not only the area to it.</span>
|
||||
<span class="s1">'senkou_b'</span><span class="p">:</span> <span class="p">{}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">plot_config</span><span class="p">[</span><span class="s1">'subplots'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="c1"># Create subplot MACD</span>
|
||||
<span class="s2">"MACD"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'macd'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'blue'</span><span class="p">,</span> <span class="s1">'fill_to'</span><span class="p">:</span> <span class="s1">'macdhist'</span><span class="p">},</span>
|
||||
<span class="s1">'macdsignal'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'orange'</span><span class="p">},</span>
|
||||
<span class="s1">'macdhist'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'type'</span><span class="p">:</span> <span class="s1">'bar'</span><span class="p">,</span> <span class="s1">'plotly'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'opacity'</span><span class="p">:</span> <span class="mf">0.9</span><span class="p">}}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="c1"># Additional subplot RSI</span>
|
||||
<span class="s2">"RSI"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'rsi'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'red'</span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">plot_config</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<details class="note">
|
||||
<summary>As attribute (former method)</summary>
|
||||
<p>Assigning plot_config is also possible as Attribute (this used to be the default way).
|
||||
This has the disadvantage that strategy parameters are not available, preventing certain configurations from working.</p>
|
||||
<p><code>`` python
|
||||
plot_config = {
|
||||
'main_plot': {
|
||||
# Configuration for main plot indicators.
|
||||
# Specifies</code>ema10<code>to be red, and</code>ema50` to be a shade of gray
|
||||
'ema10': {'color': 'red'},
|
||||
'ema50': {'color': '#CCCCCC'},
|
||||
# By omitting color, a random color is selected.
|
||||
'sar': {},
|
||||
# fill area between senkou_a and senkou_b
|
||||
'senkou_a': {
|
||||
'color': 'green', #optional
|
||||
'fill_to': 'senkou_b',
|
||||
'fill_label': 'Ichimoku Cloud', #optional
|
||||
'fill_color': 'rgba(255,76,46,0.2)', #optional
|
||||
},
|
||||
# plot senkou_b, too. Not only the area to it.
|
||||
'senkou_b': {}
|
||||
},
|
||||
'subplots': {
|
||||
# Create subplot MACD
|
||||
"MACD": {
|
||||
'macd': {'color': 'blue', 'fill_to': 'macdhist'},
|
||||
'macdsignal': {'color': 'orange'},
|
||||
'macdhist': {'type': 'bar', 'plotly': {'opacity': 0.9}}
|
||||
},
|
||||
# Additional subplot RSI
|
||||
"RSI": {
|
||||
'rsi': {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">plot_config</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s1">'main_plot'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="c1"># Configuration for main plot indicators.</span>
|
||||
<span class="c1"># Specifies `ema10` to be red, and `ema50` to be a shade of gray</span>
|
||||
<span class="s1">'ema10'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'red'</span><span class="p">},</span>
|
||||
<span class="s1">'ema50'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'#CCCCCC'</span><span class="p">},</span>
|
||||
<span class="c1"># By omitting color, a random color is selected.</span>
|
||||
<span class="s1">'sar'</span><span class="p">:</span> <span class="p">{},</span>
|
||||
<span class="c1"># fill area between senkou_a and senkou_b</span>
|
||||
<span class="s1">'senkou_a'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'color'</span><span class="p">:</span> <span class="s1">'green'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="s1">'fill_to'</span><span class="p">:</span> <span class="s1">'senkou_b'</span><span class="p">,</span>
|
||||
<span class="s1">'fill_label'</span><span class="p">:</span> <span class="s1">'Ichimoku Cloud'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="s1">'fill_color'</span><span class="p">:</span> <span class="s1">'rgba(255,76,46,0.2)'</span><span class="p">,</span> <span class="c1">#optional</span>
|
||||
<span class="p">},</span>
|
||||
<span class="c1"># plot senkou_b, too. Not only the area to it.</span>
|
||||
<span class="s1">'senkou_b'</span><span class="p">:</span> <span class="p">{}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s1">'subplots'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="c1"># Create subplot MACD</span>
|
||||
<span class="s2">"MACD"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'macd'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'blue'</span><span class="p">,</span> <span class="s1">'fill_to'</span><span class="p">:</span> <span class="s1">'macdhist'</span><span class="p">},</span>
|
||||
<span class="s1">'macdsignal'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'orange'</span><span class="p">},</span>
|
||||
<span class="s1">'macdhist'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'type'</span><span class="p">:</span> <span class="s1">'bar'</span><span class="p">,</span> <span class="s1">'plotly'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'opacity'</span><span class="p">:</span> <span class="mf">0.9</span><span class="p">}}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="c1"># Additional subplot RSI</span>
|
||||
<span class="s2">"RSI"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'rsi'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'color'</span><span class="p">:</span> <span class="s1">'red'</span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</details>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2286,82 +2285,84 @@ This graph will also highlight the start (and end) of the Max drawdown period.</
|
||||
<p>The third graph can be useful to spot outliers, events in pairs that cause profit spikes.</p>
|
||||
<p>The forth graph can help you analyze trade parallelism, showing how often max_open_trades have been maxed out.</p>
|
||||
<p>Possible options for the <code>freqtrade plot-profit</code> subcommand:</p>
|
||||
<p>``` output
|
||||
usage: freqtrade plot-profit [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[-c PATH] [-d PATH] [--userdir PATH] [-s NAME]
|
||||
[--strategy-path PATH]
|
||||
[--recursive-strategy-search]
|
||||
[--freqaimodel NAME] [--freqaimodel-path PATH]
|
||||
[-p PAIRS [PAIRS ...]] [--timerange TIMERANGE]
|
||||
[--export {none,trades,signals}]
|
||||
[--backtest-filename PATH] [--db-url PATH]
|
||||
[--trade-source {DB,file}] [-i TIMEFRAME]
|
||||
[--auto-open]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
--export {none,trades,signals}
|
||||
Export backtest results (default: trades).
|
||||
--backtest-filename, --export-filename PATH
|
||||
Use this filename for backtest results.Example:
|
||||
<code>--backtest-
|
||||
filename=backtest_results_2020-09-27_16-20-48.json</code>.
|
||||
Assumes either <code>user_data/backtest_results/</code> or
|
||||
<code>--export-directory</code> as base directory.
|
||||
--db-url PATH Override trades database URL, this is useful in custom
|
||||
deployments (default: <code>sqlite:///tradesv3.sqlite</code> for
|
||||
Live Run mode, <code>sqlite:///tradesv3.dryrun.sqlite</code> for
|
||||
Dry Run).
|
||||
--trade-source {DB,file}
|
||||
Specify the source for trades (Can be DB or file
|
||||
(backtest file)) Default: file
|
||||
-i, --timeframe TIMEFRAME
|
||||
Specify timeframe (<code>1m</code>, <code>5m</code>, <code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--auto-open Automatically open generated plot.</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade plot-profit [-h] [-v] [--no-color] [--logfile FILE] [-V]</span>
|
||||
<span class="go"> [-c PATH] [-d PATH] [--userdir PATH] [-s NAME]</span>
|
||||
<span class="go"> [--strategy-path PATH]</span>
|
||||
<span class="go"> [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME] [--freqaimodel-path PATH]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]] [--timerange TIMERANGE]</span>
|
||||
<span class="go"> [--export {none,trades,signals}]</span>
|
||||
<span class="go"> [--backtest-filename PATH] [--db-url PATH]</span>
|
||||
<span class="go"> [--trade-source {DB,file}] [-i TIMEFRAME]</span>
|
||||
<span class="go"> [--auto-open]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> --export {none,trades,signals}</span>
|
||||
<span class="go"> Export backtest results (default: trades).</span>
|
||||
<span class="go"> --backtest-filename, --export-filename PATH</span>
|
||||
<span class="go"> Use this filename for backtest results.Example:</span>
|
||||
<span class="go"> `--backtest-</span>
|
||||
<span class="go"> filename=backtest_results_2020-09-27_16-20-48.json`.</span>
|
||||
<span class="go"> Assumes either `user_data/backtest_results/` or</span>
|
||||
<span class="go"> `--export-directory` as base directory.</span>
|
||||
<span class="go"> --db-url PATH Override trades database URL, this is useful in custom</span>
|
||||
<span class="go"> deployments (default: `sqlite:///tradesv3.sqlite` for</span>
|
||||
<span class="go"> Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for</span>
|
||||
<span class="go"> Dry Run).</span>
|
||||
<span class="go"> --trade-source {DB,file}</span>
|
||||
<span class="go"> Specify the source for trades (Can be DB or file</span>
|
||||
<span class="go"> (backtest file)) Default: file</span>
|
||||
<span class="go"> -i, --timeframe TIMEFRAME</span>
|
||||
<span class="go"> Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --auto-open Automatically open generated plot.</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<p>The <code>-p/--pairs</code> argument, can be used to limit the pairs that are considered for this calculation.</p>
|
||||
<p>Examples:</p>
|
||||
<p>Use custom backtest-export file</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-profit -p LTC/BTC --export-filename user_data/backtest_results/backtest-result.json</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-profit<span class="w"> </span>-p<span class="w"> </span>LTC/BTC<span class="w"> </span>--export-filename<span class="w"> </span>user_data/backtest_results/backtest-result.json
|
||||
</code></pre></div>
|
||||
<p>Use custom database</p>
|
||||
<p><code>bash
|
||||
freqtrade plot-profit -p LTC/BTC --db-url sqlite:///tradesv3.sqlite --trade-source DB</code></p>
|
||||
<p><code>bash
|
||||
freqtrade --datadir user_data/data/binance_save/ plot-profit -p LTC/BTC</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>plot-profit<span class="w"> </span>-p<span class="w"> </span>LTC/BTC<span class="w"> </span>--db-url<span class="w"> </span>sqlite:///tradesv3.sqlite<span class="w"> </span>--trade-source<span class="w"> </span>DB
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade<span class="w"> </span>--datadir<span class="w"> </span>user_data/data/binance_save/<span class="w"> </span>plot-profit<span class="w"> </span>-p<span class="w"> </span>LTC/BTC
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
+326
-328
@@ -2638,23 +2638,23 @@ You may also use something like <code>.*DOWN/BTC</code> or <code>.*UP/BTC</code>
|
||||
<p>By default, the <code>StaticPairList</code> method is used, which uses a statically defined pair whitelist from the configuration. The pairlist also supports wildcards (in regex-style) - so <code>.*/BTC</code> will include all pairs with BTC as a stake.</p>
|
||||
<p>It uses configuration from <code>exchange.pair_whitelist</code> and <code>exchange.pair_blacklist</code>, which in the below example, will trade BTC/USDT and ETH/USDT - and will prevent BNB/USDT trading.</p>
|
||||
<p>Both <code>pair_*list</code> parameters support regex - so values like <code>.*/USDT</code> would enable trading all pairs that are not in the blacklist.</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"name": "...",
|
||||
// ...
|
||||
"pair_whitelist": [
|
||||
"BTC/USDT",
|
||||
"ETH/USDT",
|
||||
// ...
|
||||
],
|
||||
"pair_blacklist": [
|
||||
"BNB/USDT",
|
||||
// ...
|
||||
]
|
||||
},
|
||||
"pairlists": [
|
||||
{"method": "StaticPairList"}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ... </span>
|
||||
<span class="w"> </span><span class="nt">"pair_whitelist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"BTC/USDT"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"ETH/USDT"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"pair_blacklist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="s2">"BNB/USDT"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
<span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"StaticPairList"</span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<p>By default, only currently enabled pairs are allowed.
|
||||
To skip pair validation against active markets, set <code>"allow_inactive": true</code> within the <code>StaticPairList</code> configuration.
|
||||
This can be useful for backtesting expired pairs (like quarterly spot-markets).</p>
|
||||
@@ -2670,33 +2670,33 @@ Filtering instances (not the first position in the list) will not apply any cach
|
||||
<ul>
|
||||
<li>The <code>quoteVolume</code> is the amount of quote (stake) currency traded (bought or sold) in last 24 hours.</li>
|
||||
</ul>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"max_value": 8000000,
|
||||
"refresh_period": 1800
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolumePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"quoteVolume"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">8000000</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">1800</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<p>You can define a minimum volume with <code>min_value</code> - 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 <code>max_value</code> - which will filter out pairs with a volume higher than the specified value in the specified timerange.</p>
|
||||
<h5 id="volumepairlist-advanced-mode">VolumePairList Advanced mode<a class="headerlink" href="#volumepairlist-advanced-mode" title="Permanent link">¶</a></h5>
|
||||
<p><code>VolumePairList</code> can also operate in an advanced mode to build volume over a given timerange of specified candle size. It utilizes exchange historical candle data, builds a typical price (calculated by (open+high+low)/3) and multiplies the typical price with every candle's volume. The sum is the <code>quoteVolume</code> over the given range. This allows different scenarios, for a more smoothened volume, when using longer ranges with larger candle sizes, or the opposite when using a short range with small candles.</p>
|
||||
<p>For convenience <code>lookback_days</code> 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:</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"refresh_period": 86400,
|
||||
"lookback_days": 7
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolumePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"quoteVolume"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">7</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Range look back and refresh period</p>
|
||||
<p>When used in conjunction with <code>lookback_days</code> and <code>lookback_timeframe</code> the <code>refresh_period</code> can not be smaller than the candle size in seconds. As this will result in unnecessary requests to the exchanges API.</p>
|
||||
@@ -2710,31 +2710,31 @@ In addition to that, you can also define a maximum volume with <code>max_value</
|
||||
<p>On some exchanges (like Gemini), regular VolumePairList does not work as the api does not natively provide 24h volume. This can be worked around by using candle data to build the volume.
|
||||
To roughly simulate 24h volume, you can use the following configuration.
|
||||
Please note that These pairlists will only refresh once per day.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"refresh_period": 86400,
|
||||
"lookback_days": 1
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolumePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"quoteVolume"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
</details>
|
||||
<p>More sophisticated approach can be used, by using <code>lookback_timeframe</code> for candle size and <code>lookback_period</code> which specifies the amount of candles. This example will build the volume pairs based on a rolling period of 3 days of 1h candles:</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"refresh_period": 3600,
|
||||
"lookback_timeframe": "1h",
|
||||
"lookback_period": 72
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolumePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"quoteVolume"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">3600</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_timeframe"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1h"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">72</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p><code>VolumePairList</code> does not support backtesting mode.</p>
|
||||
@@ -2758,45 +2758,45 @@ The percentage change is calculated as the change in price over the last 24 hour
|
||||
<details class="note">
|
||||
<summary>Unsupported exchanges</summary>
|
||||
<p>On some exchanges (like HTX), regular PercentChangePairList does not work as the api does not natively provide 24h percent change in price. This can be worked around by using candle data to calculate the percentage change. To roughly simulate 24h percent change, you can use the following configuration. Please note that these pairlists will only refresh once per day.
|
||||
<code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "PercentChangePairList",
|
||||
"number_assets": 20,
|
||||
"min_value": 0,
|
||||
"refresh_period": 86400,
|
||||
"lookback_days": 1
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PercentChangePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div></p>
|
||||
</details>
|
||||
<p><strong>Example Configuration to Read from Ticker</strong></p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "PercentChangePairList",
|
||||
"number_assets": 15,
|
||||
"min_value": -10,
|
||||
"max_value": 50
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PercentChangePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">-10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<p>In this configuration:</p>
|
||||
<ol>
|
||||
<li>The top 15 pairs are selected based on the highest percentage change in price over the last 24 hours.</li>
|
||||
<li>Only pairs with a percentage change between -10% and 50% are considered.</li>
|
||||
</ol>
|
||||
<p><strong>Example Configuration to Read from Candles</strong></p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "PercentChangePairList",
|
||||
"number_assets": 15,
|
||||
"sort_key": "percentage",
|
||||
"min_value": 0,
|
||||
"refresh_period": 3600,
|
||||
"lookback_timeframe": "1h",
|
||||
"lookback_period": 72
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PercentChangePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"percentage"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_value"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">3600</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_timeframe"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1h"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">72</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<p>This example builds the percent change pairs based on a rolling period of 3 days of 1-hour candles by using <code>lookback_timeframe</code> for candle size and <code>lookback_period</code> which specifies the number of candles.</p>
|
||||
<p>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:</p>
|
||||
<div class="arithmatex">\[ Percent Change = (\frac{Current Close - Previous Close}{Previous Close}) * 100 \]</div>
|
||||
@@ -2817,14 +2817,14 @@ The percentage change is calculated as the change in price over the last 24 hour
|
||||
<p><a href="../producer-consumer/">Consumer mode</a> is required for this pairlist to work.</p>
|
||||
<p>The pairlist will perform a check on active pairs against the current exchange configuration to avoid attempting to trade on invalid markets.</p>
|
||||
<p>You can limit the length of the pairlist with the optional parameter <code>number_assets</code>. Using <code>"number_assets"=0</code> or omitting this key will result in the reuse of all producer pairs valid for the current setup.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "ProducerPairList",
|
||||
"number_assets": 5,
|
||||
"producer_name": "default",
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ProducerPairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"producer_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"default"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Combining pairlists</p>
|
||||
<p>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.
|
||||
@@ -2834,21 +2834,21 @@ Obviously in complex such configurations, the Producer may not provide data for
|
||||
<h4 id="remotepairlist">RemotePairList<a class="headerlink" href="#remotepairlist" title="Permanent link">¶</a></h4>
|
||||
<p>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.</p>
|
||||
<p>The RemotePairList is defined in the pairlists section of the configuration settings. It uses the following configuration options:</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "RemotePairList",
|
||||
"mode": "whitelist",
|
||||
"processing_mode": "filter",
|
||||
"pairlist_url": "https://example.com/pairlist",
|
||||
"number_assets": 10,
|
||||
"refresh_period": 1800,
|
||||
"keep_pairlist_on_failure": true,
|
||||
"read_timeout": 60,
|
||||
"bearer_token": "my-bearer-token",
|
||||
"save_to_file": "user_data/filename.json"
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RemotePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"whitelist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"processing_mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"filter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"pairlist_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://example.com/pairlist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">1800</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"keep_pairlist_on_failure"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"read_timeout"</span><span class="p">:</span><span class="w"> </span><span class="mi">60</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"bearer_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"my-bearer-token"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"save_to_file"</span><span class="p">:</span><span class="w"> </span><span class="s2">"user_data/filename.json"</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p>The optional <code>mode</code> option specifies if the pairlist should be used as a <code>blacklist</code> or as a <code>whitelist</code>. The default value is "whitelist".</p>
|
||||
<p>The optional <code>processing_mode</code> option in the RemotePairList configuration determines how the retrieved pairlist is processed. It can have two values: "filter" or "append". The default value is "filter".</p>
|
||||
<p>The optional <code>number_assets</code> option in the RemotePairList configuration determines how many pairs will be returned if used in whitelist <code>mode</code>. By default, all pairs will be returned. In blacklist <code>mode</code>, this option will be ignored.</p>
|
||||
@@ -2859,38 +2859,38 @@ Obviously in complex such configurations, the Producer may not provide data for
|
||||
<details class="example">
|
||||
<summary>Multi bot with shared pairlist example</summary>
|
||||
<p><code>save_to_file</code> can be used to save the pairlist to a file with Bot1:</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "RemotePairList",
|
||||
"mode": "whitelist",
|
||||
"pairlist_url": "https://example.com/pairlist",
|
||||
"number_assets": 10,
|
||||
"refresh_period": 1800,
|
||||
"keep_pairlist_on_failure": true,
|
||||
"read_timeout": 60,
|
||||
"save_to_file": "user_data/filename.json"
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RemotePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"whitelist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"pairlist_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://example.com/pairlist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">1800</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"keep_pairlist_on_failure"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"read_timeout"</span><span class="p">:</span><span class="w"> </span><span class="mi">60</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"save_to_file"</span><span class="p">:</span><span class="w"> </span><span class="s2">"user_data/filename.json"</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p>This saved pairlist file can be loaded by Bot2, or any additional bot with this configuration:</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "RemotePairList",
|
||||
"mode": "whitelist",
|
||||
"pairlist_url": "file:///user_data/filename.json",
|
||||
"number_assets": 10,
|
||||
"refresh_period": 10,
|
||||
"keep_pairlist_on_failure": true,
|
||||
}
|
||||
]</code> </p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RemotePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"whitelist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"pairlist_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:///user_data/filename.json"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"keep_pairlist_on_failure"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
</details>
|
||||
<p>The user is responsible for providing a server or local file that returns a JSON object with the following structure:</p>
|
||||
<p><code>json
|
||||
{
|
||||
"pairs": ["XRP/USDT", "ETH/USDT", "LTC/USDT"],
|
||||
"refresh_period": 1800
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"pairs"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"XRP/USDT"</span><span class="p">,</span><span class="w"> </span><span class="s2">"ETH/USDT"</span><span class="p">,</span><span class="w"> </span><span class="s2">"LTC/USDT"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">1800</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>The <code>pairs</code> property should contain a list of strings with the trading pairs to be used by the bot. The <code>refresh_period</code> property is optional and specifies the number of seconds that the pairlist should be cached before being refreshed.</p>
|
||||
<p>The optional <code>keep_pairlist_on_failure</code> specifies whether the previous received pairlist should be used if the remote server is not reachable or returns an error. The default value is true.</p>
|
||||
<p>The optional <code>read_timeout</code> specifies the maximum amount of time (in seconds) to wait for a response from the remote source, The default value is 60.</p>
|
||||
@@ -2901,17 +2901,17 @@ Obviously in complex such configurations, the Producer may not provide data for
|
||||
</div>
|
||||
<h4 id="marketcappairlist">MarketCapPairList<a class="headerlink" href="#marketcappairlist" title="Permanent link">¶</a></h4>
|
||||
<p><code>MarketCapPairList</code> employs sorting/filtering of pairs by their marketcap rank based of CoinGecko. The returned pairlist will be sorted based of their marketcap ranks if used in whitelist <code>mode</code>.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "MarketCapPairList",
|
||||
"number_assets": 20,
|
||||
"max_rank": 50,
|
||||
"refresh_period": 86400,
|
||||
"mode": "whitelist",
|
||||
"categories": ["layer-1"]
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MarketCapPairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_rank"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"whitelist"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"categories"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"layer-1"</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p><code>number_assets</code> defines the maximum number of pairs returned by the pairlist if used in whitelist <code>mode</code>. In blacklist <code>mode</code>, this setting will be ignored.</p>
|
||||
<p><code>max_rank</code> will determine the maximum rank used in creating/filtering the pairlist. It's expected that some coins within the top <code>max_rank</code> 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.<br />
|
||||
While using a <code>max_rank</code> bigger than 250 is supported, it's not recommended, as it'll cause multiple API calls to CoinGecko, which can lead to rate limit issues.</p>
|
||||
@@ -2959,15 +2959,15 @@ be caught out buying before the pair has finished dropping in price.</p>
|
||||
<p>Offsets an incoming pairlist by a given <code>offset</code> value.</p>
|
||||
<p>As an example it can be used in conjunction with <code>VolumeFilter</code> to remove the top X volume pairs. Or to split a larger pairlist on two bot instances.</p>
|
||||
<p>Example to remove the first 10 pairs from the pairlist, and takes the next 20 (taking items 10-30 of the initial list):</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
// ...
|
||||
{
|
||||
"method": "OffsetFilter",
|
||||
"offset": 10,
|
||||
"number_assets": 20
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"OffsetFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"offset"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>When <code>OffsetFilter</code> is used to split a larger pairlist among multiple bots in combination with <code>VolumeFilter</code>
|
||||
@@ -2991,15 +2991,15 @@ Not defining this parameter (or setting it to 0) will use all-time performance.<
|
||||
<p>The optional <code>min_profit</code> (as ratio -> a setting of <code>0.01</code> 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 <code>minutes</code> is highly discouraged, as it can lead to an empty pairlist without a way to recover.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
// ...
|
||||
{
|
||||
"method": "PerformanceFilter",
|
||||
"minutes": 1440, // rolling 24h
|
||||
"min_profit": 0.01 // minimal profit 1%
|
||||
}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="c1">// ...</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PerformanceFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"minutes"</span><span class="p">:</span><span class="w"> </span><span class="mi">1440</span><span class="p">,</span><span class="w"> </span><span class="c1">// rolling 24h</span>
|
||||
<span class="w"> </span><span class="nt">"min_profit"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="w"> </span><span class="c1">// minimal profit 1%</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<p>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.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Backtesting</p>
|
||||
@@ -3045,13 +3045,12 @@ This option is disabled by default, and will only apply if set to > 0.</p>
|
||||
<p>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.</p>
|
||||
<p>By default, ShuffleFilter will shuffle pairs once per candle.
|
||||
To shuffle on every iteration, set <code>"shuffle_frequency"</code> to <code>"iteration"</code> instead of the default of <code>"candle"</code>.</p>
|
||||
<p>``` json
|
||||
{
|
||||
"method": "ShuffleFilter",
|
||||
"shuffle_frequency": "candle",
|
||||
"seed": 42
|
||||
}</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ShuffleFilter"</span><span class="p">,</span><span class="w"> </span>
|
||||
<span class="w"> </span><span class="nt">"shuffle_frequency"</span><span class="p">:</span><span class="w"> </span><span class="s2">"candle"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"seed"</span><span class="p">:</span><span class="w"> </span><span class="mi">42</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>You may set the <code>seed</code> value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If <code>seed</code> is not set, the pairs are shuffled in the non-repeatable random order. ShuffleFilter will automatically detect runmodes and apply the <code>seed</code> only for backtesting modes - if a <code>seed</code> value is set.</p>
|
||||
@@ -3064,16 +3063,16 @@ To shuffle on every iteration, set <code>"shuffle_frequency"</code> to <code>"it
|
||||
<p>Removes pairs where the difference between lowest low and highest high over <code>lookback_days</code> days is below <code>min_rate_of_change</code> or above <code>max_rate_of_change</code>. Since this is a filter that requires additional data, the results are cached for <code>refresh_period</code>.</p>
|
||||
<p>In the below example:
|
||||
If the trading range over the last 10 days is <1% or >99%, remove the pair from the whitelist.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "RangeStabilityFilter",
|
||||
"lookback_days": 10,
|
||||
"min_rate_of_change": 0.01,
|
||||
"max_rate_of_change": 0.99,
|
||||
"refresh_period": 86400
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RangeStabilityFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_rate_of_change"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_rate_of_change"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.99</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p>Adding <code>"sort_direction": "asc"</code> or <code>"sort_direction": "desc"</code> enables sorting for this pairlist.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
@@ -3086,53 +3085,53 @@ Additionally, it can also be used to automatically remove pairs with extreme hig
|
||||
<p>This filter can be used to narrow down your pairs to a certain volatility or avoid very volatile pairs.</p>
|
||||
<p>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.</p>
|
||||
<p><code>json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolatilityFilter",
|
||||
"lookback_days": 10,
|
||||
"min_volatility": 0.05,
|
||||
"max_volatility": 0.50,
|
||||
"refresh_period": 86400
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolatilityFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_volatility"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.05</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_volatility"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.50</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<p>Adding <code>"sort_direction": "asc"</code> or <code>"sort_direction": "desc"</code> enables sorting mode for this pairlist.</p>
|
||||
<h3 id="full-example-of-pairlist-handlers">Full example of Pairlist Handlers<a class="headerlink" href="#full-example-of-pairlist-handlers" title="Permanent link">¶</a></h3>
|
||||
<p>The below example blacklists <code>BNB/BTC</code>, uses <code>VolumePairList</code> with <code>20</code> assets, sorting pairs by <code>quoteVolume</code>, then filter future delisted pairs using <a href="#delistfilter"><code>DelistFilter</code></a> and <a href="#agefilter"><code>AgeFilter</code></a> to remove pairs that are listed less than 10 days ago. After that <a href="#precisionfilter"><code>PrecisionFilter</code></a> and <a href="#pricefilter"><code>PriceFilter</code></a> are applied, filtering all assets where 1 price unit is > 1%. Then the <a href="#spreadfilter"><code>SpreadFilter</code></a> and <a href="#volatilityfilter"><code>VolatilityFilter</code></a> are applied and pairs are finally shuffled with the random seed set to some predefined value.</p>
|
||||
<p><code>json
|
||||
"exchange": {
|
||||
"pair_whitelist": [],
|
||||
"pair_blacklist": ["BNB/BTC"]
|
||||
},
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume"
|
||||
},
|
||||
{
|
||||
"method": "DelistFilter",
|
||||
"max_days_from_now": 0,
|
||||
},
|
||||
{"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}
|
||||
],</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"exchange"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"pair_whitelist"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span>
|
||||
<span class="w"> </span><span class="nt">"pair_blacklist"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"BNB/BTC"</span><span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
<span class="nt">"pairlists"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolumePairList"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"number_assets"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"sort_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"quoteVolume"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"DelistFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_days_from_now"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AgeFilter"</span><span class="p">,</span><span class="w"> </span><span class="nt">"min_days_listed"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PrecisionFilter"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PriceFilter"</span><span class="p">,</span><span class="w"> </span><span class="nt">"low_price_ratio"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SpreadFilter"</span><span class="p">,</span><span class="w"> </span><span class="nt">"max_spread_ratio"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.005</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"RangeStabilityFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_rate_of_change"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"VolatilityFilter"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"lookback_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"min_volatility"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.05</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"max_volatility"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.50</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"refresh_period"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ShuffleFilter"</span><span class="p">,</span><span class="w"> </span><span class="nt">"seed"</span><span class="p">:</span><span class="w"> </span><span class="mi">42</span><span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
</code></pre></div>
|
||||
<h2 id="protections">Protections<a class="headerlink" href="#protections" title="Permanent link">¶</a></h2>
|
||||
<p>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.</p>
|
||||
@@ -3203,20 +3202,20 @@ If <code>trade_limit</code> or more trades resulted in stoploss, trading will st
|
||||
<p>Similarly, this protection will by default look at all trades (long and short). For futures bots, setting <code>only_per_side</code> 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.</p>
|
||||
<p><code>required_profit</code> 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.</p>
|
||||
<p>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.</p>
|
||||
<p><code>python
|
||||
@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
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">protections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"StoplossGuard"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">24</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="s2">"required_profit"</span><span class="p">:</span> <span class="mf">0.0</span><span class="p">,</span>
|
||||
<span class="s2">"only_per_pair"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
|
||||
<span class="s2">"only_per_side"</span><span class="p">:</span> <span class="kc">False</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p><code>StoplossGuard</code> considers all trades with the results <code>"stop_loss"</code>, <code>"stoploss_on_exchange"</code> and <code>"trailing_stop_loss"</code> if the resulting profit was negative.
|
||||
@@ -3233,49 +3232,49 @@ It supports 2 calculation modes:</p>
|
||||
<p>For new setups, <code>calculation_mode: "equity"</code> is recommended. Prefer <code>calculation_mode: "ratios"</code> only when you intentionally rely on legacy behavior, especially with fixed stake amount configurations where ratio-based behavior is easier to reason about.</p>
|
||||
<p>If the observed drawdown exceeds <code>max_allowed_drawdown</code>, trading will stop for <code>stop_duration</code> after the last trade - assuming that the bot needs some time to let markets recover.</p>
|
||||
<p>The below sample stops trading for 12 candles if max-drawdown is > 20% considering all pairs - with a minimum of <code>trade_limit</code> trades - within the last 48 candles. If desired, <code>lookback_period</code> and/or <code>stop_duration</code> can be used.</p>
|
||||
<p><code>python
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"calculation_mode": "equity",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 20,
|
||||
"stop_duration_candles": 12,
|
||||
"max_allowed_drawdown": 0.2
|
||||
},
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">protections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"MaxDrawdown"</span><span class="p">,</span>
|
||||
<span class="s2">"calculation_mode"</span><span class="p">:</span> <span class="s2">"equity"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">48</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">12</span><span class="p">,</span>
|
||||
<span class="s2">"max_allowed_drawdown"</span><span class="p">:</span> <span class="mf">0.2</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<h4 id="low-profit-pairs">Low Profit Pairs<a class="headerlink" href="#low-profit-pairs" title="Permanent link">¶</a></h4>
|
||||
<p><code>LowProfitPairs</code> uses all trades for a pair within <code>lookback_period</code> in minutes (or in candles when using <code>lookback_period_candles</code>) to determine the overall profit ratio.
|
||||
If that ratio is below <code>required_profit</code>, that pair will be locked for <code>stop_duration</code> in minutes (or in candles when using <code>stop_duration_candles</code>, or until the set time when using <code>unlock_at</code>).</p>
|
||||
<p>For futures bots, setting <code>only_per_side</code> 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.</p>
|
||||
<p>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.</p>
|
||||
<p><code>python
|
||||
@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,
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">protections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"LowProfitPairs"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration"</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
|
||||
<span class="s2">"required_profit"</span><span class="p">:</span> <span class="mf">0.02</span><span class="p">,</span>
|
||||
<span class="s2">"only_per_pair"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<h4 id="cooldown-period">Cooldown Period<a class="headerlink" href="#cooldown-period" title="Permanent link">¶</a></h4>
|
||||
<p><code>CooldownPeriod</code> locks a pair for <code>stop_duration</code> in minutes (or in candles when using <code>stop_duration_candles</code>, or until the set time when using <code>unlock_at</code>) after exiting, avoiding a re-entry for this pair for <code>stop_duration</code> minutes.</p>
|
||||
<p>The below example will stop trading a pair for 2 candles after closing a trade, allowing this pair to "cool down".</p>
|
||||
<p><code>python
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 2
|
||||
}
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">protections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"CooldownPeriod"</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">2</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>This Protection applies only at pair-level, and will never lock all pairs globally.
|
||||
@@ -3292,51 +3291,50 @@ All protections are evaluated in the sequence they are defined.</p>
|
||||
<li>Locks all pairs that had 2 Trades within the last 6 hours (<code>6 * 1h candles</code>) with a combined profit ratio of below 0.02 (<2%) (<code>LowProfitPairs</code>).</li>
|
||||
<li>Locks all pairs for 2 candles that had a profit of below 0.01 (<1%) within the last 24h (<code>24 * 1h candles</code>), a minimum of 4 trades.</li>
|
||||
</ul>
|
||||
<p>``` python
|
||||
from freqtrade.strategy import IStrategy</p>
|
||||
<p>class AwesomeStrategy(IStrategy)
|
||||
timeframe = '1h'</p>
|
||||
<div class="codehilite"><pre><span></span><code>@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 5
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"calculation_mode": "equity",
|
||||
"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
|
||||
}
|
||||
]
|
||||
# ...
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.strategy</span><span class="w"> </span><span class="kn">import</span> <span class="n">IStrategy</span>
|
||||
|
||||
<p>```</p>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">AwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">)</span>
|
||||
<span class="n">timeframe</span> <span class="o">=</span> <span class="s1">'1h'</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">protections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"CooldownPeriod"</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">5</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"MaxDrawdown"</span><span class="p">,</span>
|
||||
<span class="s2">"calculation_mode"</span><span class="p">:</span> <span class="s2">"equity"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">48</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="s2">"max_allowed_drawdown"</span><span class="p">:</span> <span class="mf">0.2</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"StoplossGuard"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">24</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="s2">"only_per_pair"</span><span class="p">:</span> <span class="kc">False</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"LowProfitPairs"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
|
||||
<span class="s2">"required_profit"</span><span class="p">:</span> <span class="mf">0.02</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"method"</span><span class="p">:</span> <span class="s2">"LowProfitPairs"</span><span class="p">,</span>
|
||||
<span class="s2">"lookback_period_candles"</span><span class="p">:</span> <span class="mi">24</span><span class="p">,</span>
|
||||
<span class="s2">"trade_limit"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="s2">"stop_duration_candles"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="s2">"required_profit"</span><span class="p">:</span> <span class="mf">0.01</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="c1"># ...</span>
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1966,29 +1966,29 @@
|
||||
</div>
|
||||
<h2 id="configuration">Configuration<a class="headerlink" href="#configuration" title="Permanent link">¶</a></h2>
|
||||
<p>Enable subscribing to an instance by adding the <code>external_message_consumer</code> section to the consumer's config file.</p>
|
||||
<p><code>json
|
||||
{
|
||||
//...
|
||||
"external_message_consumer": {
|
||||
"enabled": true,
|
||||
"producers": [
|
||||
{
|
||||
"name": "default", // This can be any name you'd like, default is "default"
|
||||
"host": "127.0.0.1", // The host from your producer's api_server config
|
||||
"port": 8080, // The port from your producer's api_server config
|
||||
"secure": false, // Use a secure websockets connection, default false
|
||||
"ws_token": "sercet_Ws_t0ken" // The ws_token from your producer's api_server config
|
||||
}
|
||||
],
|
||||
// The following configurations are optional, and usually not required
|
||||
// "wait_timeout": 300,
|
||||
// "ping_timeout": 10,
|
||||
// "sleep_time": 10,
|
||||
// "remove_entry_exit_signals": false,
|
||||
// "message_size_limit": 8
|
||||
}
|
||||
//...
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="nt">"external_message_consumer"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"producers"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"default"</span><span class="p">,</span><span class="w"> </span><span class="c1">// This can be any name you'd like, default is "default"</span>
|
||||
<span class="w"> </span><span class="nt">"host"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1"</span><span class="p">,</span><span class="w"> </span><span class="c1">// The host from your producer's api_server config</span>
|
||||
<span class="w"> </span><span class="nt">"port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span><span class="w"> </span><span class="c1">// The port from your producer's api_server config</span>
|
||||
<span class="w"> </span><span class="nt">"secure"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"> </span><span class="c1">// Use a secure websockets connection, default false</span>
|
||||
<span class="w"> </span><span class="nt">"ws_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sercet_Ws_t0ken"</span><span class="w"> </span><span class="c1">// The ws_token from your producer's api_server config</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="c1">// The following configurations are optional, and usually not required</span>
|
||||
<span class="w"> </span><span class="c1">// "wait_timeout": 300,</span>
|
||||
<span class="w"> </span><span class="c1">// "ping_timeout": 10,</span>
|
||||
<span class="w"> </span><span class="c1">// "sleep_time": 10,</span>
|
||||
<span class="w"> </span><span class="c1">// "remove_entry_exit_signals": false,</span>
|
||||
<span class="w"> </span><span class="c1">// "message_size_limit": 8</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2060,103 +2060,99 @@
|
||||
<h2 id="examples">Examples<a class="headerlink" href="#examples" title="Permanent link">¶</a></h2>
|
||||
<h3 id="example-producer-strategy">Example - Producer Strategy<a class="headerlink" href="#example-producer-strategy" title="Permanent link">¶</a></h3>
|
||||
<p>A simple strategy with multiple indicators. No special considerations are required in the strategy itself.</p>
|
||||
<p>```py
|
||||
class ProducerStrategy(IStrategy):
|
||||
#...
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Calculate indicators in the standard freqtrade way which can then be broadcast to other instances
|
||||
"""
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||
dataframe['bb_lowerband'] = bollinger['lower']
|
||||
dataframe['bb_middleband'] = bollinger['mid']
|
||||
dataframe['bb_upperband'] = bollinger['upper']
|
||||
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)</p>
|
||||
<div class="codehilite"><pre><span></span><code> return dataframe
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">ProducerStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="c1">#...</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Calculate indicators in the standard freqtrade way which can then be broadcast to other instances</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">RSI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">)</span>
|
||||
<span class="n">bollinger</span> <span class="o">=</span> <span class="n">qtpylib</span><span class="o">.</span><span class="n">bollinger_bands</span><span class="p">(</span><span class="n">qtpylib</span><span class="o">.</span><span class="n">typical_price</span><span class="p">(</span><span class="n">dataframe</span><span class="p">),</span> <span class="n">window</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">stds</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'bb_lowerband'</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s1">'lower'</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'bb_middleband'</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s1">'mid'</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'bb_upperband'</span><span class="p">]</span> <span class="o">=</span> <span class="n">bollinger</span><span class="p">[</span><span class="s1">'upper'</span><span class="p">]</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">TEMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="mi">9</span><span class="p">)</span>
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Populates the entry signal for the given dataframe
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value)) &
|
||||
(dataframe['tema'] <= dataframe['bb_middleband']) &
|
||||
(dataframe['tema'] > dataframe['tema'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'enter_long'] = 1
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
return dataframe
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_entry_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Populates the entry signal for the given dataframe</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span>
|
||||
<span class="p">(</span><span class="n">qtpylib</span><span class="o">.</span><span class="n">crossed_above</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">buy_rsi</span><span class="o">.</span><span class="n">value</span><span class="p">))</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema'</span><span class="p">]</span> <span class="o"><=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s1">'bb_middleband'</span><span class="p">])</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema'</span><span class="p">]</span> <span class="o">></span> <span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema'</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'volume'</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="p">),</span>
|
||||
<span class="s1">'enter_long'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">FreqAI</p>
|
||||
<p>You can use this to setup <a href="../freqai/">FreqAI</a> on a powerful machine, while you run consumers on simple machines like raspberries, which can interpret the signals generated from the producer in different ways.</p>
|
||||
</div>
|
||||
<h3 id="example-consumer-strategy">Example - Consumer Strategy<a class="headerlink" href="#example-consumer-strategy" title="Permanent link">¶</a></h3>
|
||||
<p>A logically equivalent strategy which calculates no indicators itself, but will have the same analyzed dataframes available to make trading decisions based on the indicators calculated in the producer. In this example the consumer has the same entry criteria, however this is not necessary. The consumer may use different logic to enter/exit trades, and only use the indicators as specified.</p>
|
||||
<p>```py
|
||||
class ConsumerStrategy(IStrategy):
|
||||
#...
|
||||
process_only_new_candles = False # required for consumers</p>
|
||||
<div class="codehilite"><pre><span></span><code>_columns_to_expect = ['rsi_default', 'tema_default', 'bb_middleband_default']
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">ConsumerStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="c1">#...</span>
|
||||
<span class="n">process_only_new_candles</span> <span class="o">=</span> <span class="kc">False</span> <span class="c1"># required for consumers</span>
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Use the websocket api to get pre-populated indicators from another freqtrade instance.
|
||||
Use `self.dp.get_producer_df(pair)` to get the dataframe
|
||||
"""
|
||||
pair = metadata['pair']
|
||||
timeframe = self.timeframe
|
||||
<span class="n">_columns_to_expect</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'rsi_default'</span><span class="p">,</span> <span class="s1">'tema_default'</span><span class="p">,</span> <span class="s1">'bb_middleband_default'</span><span class="p">]</span>
|
||||
|
||||
producer_pairs = self.dp.get_producer_pairs()
|
||||
# You can specify which producer to get pairs from via:
|
||||
# self.dp.get_producer_pairs("my_other_producer")
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Use the websocket api to get pre-populated indicators from another freqtrade instance.</span>
|
||||
<span class="sd"> Use `self.dp.get_producer_df(pair)` to get the dataframe</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">pair</span> <span class="o">=</span> <span class="n">metadata</span><span class="p">[</span><span class="s1">'pair'</span><span class="p">]</span>
|
||||
<span class="n">timeframe</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">timeframe</span>
|
||||
|
||||
# This func returns the analyzed dataframe, and when it was analyzed
|
||||
producer_dataframe, _ = self.dp.get_producer_df(pair)
|
||||
# You can get other data if the producer makes it available:
|
||||
# self.dp.get_producer_df(
|
||||
# pair,
|
||||
# timeframe="1h",
|
||||
# candle_type=CandleType.SPOT,
|
||||
# producer_name="my_other_producer"
|
||||
# )
|
||||
<span class="n">producer_pairs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dp</span><span class="o">.</span><span class="n">get_producer_pairs</span><span class="p">()</span>
|
||||
<span class="c1"># You can specify which producer to get pairs from via:</span>
|
||||
<span class="c1"># self.dp.get_producer_pairs("my_other_producer")</span>
|
||||
|
||||
if not producer_dataframe.empty:
|
||||
# If you plan on passing the producer's entry/exit signal directly,
|
||||
# specify ffill=False or it will have unintended results
|
||||
merged_dataframe = merge_informative_pair(dataframe, producer_dataframe,
|
||||
timeframe, timeframe,
|
||||
append_timeframe=False,
|
||||
suffix="default")
|
||||
return merged_dataframe
|
||||
else:
|
||||
dataframe[self._columns_to_expect] = 0
|
||||
<span class="c1"># This func returns the analyzed dataframe, and when it was analyzed</span>
|
||||
<span class="n">producer_dataframe</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dp</span><span class="o">.</span><span class="n">get_producer_df</span><span class="p">(</span><span class="n">pair</span><span class="p">)</span>
|
||||
<span class="c1"># You can get other data if the producer makes it available:</span>
|
||||
<span class="c1"># self.dp.get_producer_df(</span>
|
||||
<span class="c1"># pair,</span>
|
||||
<span class="c1"># timeframe="1h",</span>
|
||||
<span class="c1"># candle_type=CandleType.SPOT,</span>
|
||||
<span class="c1"># producer_name="my_other_producer"</span>
|
||||
<span class="c1"># )</span>
|
||||
|
||||
return dataframe
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">producer_dataframe</span><span class="o">.</span><span class="n">empty</span><span class="p">:</span>
|
||||
<span class="c1"># If you plan on passing the producer's entry/exit signal directly,</span>
|
||||
<span class="c1"># specify ffill=False or it will have unintended results</span>
|
||||
<span class="n">merged_dataframe</span> <span class="o">=</span> <span class="n">merge_informative_pair</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">producer_dataframe</span><span class="p">,</span>
|
||||
<span class="n">timeframe</span><span class="p">,</span> <span class="n">timeframe</span><span class="p">,</span>
|
||||
<span class="n">append_timeframe</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">suffix</span><span class="o">=</span><span class="s2">"default"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">merged_dataframe</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_columns_to_expect</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Populates the entry signal for the given dataframe
|
||||
"""
|
||||
# Use the dataframe columns as if we calculated them ourselves
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(dataframe['rsi_default'], self.buy_rsi.value)) &
|
||||
(dataframe['tema_default'] <= dataframe['bb_middleband_default']) &
|
||||
(dataframe['tema_default'] > dataframe['tema_default'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'enter_long'] = 1
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
return dataframe
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_entry_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Populates the entry signal for the given dataframe</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="c1"># Use the dataframe columns as if we calculated them ourselves</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span>
|
||||
<span class="p">(</span><span class="n">qtpylib</span><span class="o">.</span><span class="n">crossed_above</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi_default'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">buy_rsi</span><span class="o">.</span><span class="n">value</span><span class="p">))</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema_default'</span><span class="p">]</span> <span class="o"><=</span> <span class="n">dataframe</span><span class="p">[</span><span class="s1">'bb_middleband_default'</span><span class="p">])</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema_default'</span><span class="p">]</span> <span class="o">></span> <span class="n">dataframe</span><span class="p">[</span><span class="s1">'tema_default'</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'volume'</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="p">),</span>
|
||||
<span class="s1">'enter_long'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Using upstream signals</p>
|
||||
<p>By setting <code>remove_entry_exit_signals=false</code>, you can also use the producer's signals directly. They should be available as <code>enter_long_default</code> (assuming <code>suffix="default"</code> was used) - and can be used as either signal directly, or as additional indicator.</p>
|
||||
|
||||
@@ -1997,62 +1997,64 @@ This does not backtest the strategy itself, but rather only calculates the indic
|
||||
</ul>
|
||||
<p>In addition to the recursive formula check, this command also carries out a simple lookahead bias check on the indicator values only. For a full lookahead check, use <a href="../lookahead-analysis/">Lookahead-analysis</a>.</p>
|
||||
<h2 id="recursive-analysis-command-reference">Recursive-analysis command reference<a class="headerlink" href="#recursive-analysis-command-reference" title="Permanent link">¶</a></h2>
|
||||
<p>``` output
|
||||
usage: freqtrade recursive-analysis [-h] [-v] [--no-color] [--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,feather,parquet}]
|
||||
[-p PAIRS [PAIRS ...]]
|
||||
[--startup-candle STARTUP_CANDLE [STARTUP_CANDLE ...]]</p>
|
||||
<p>options:
|
||||
-h, --help show this help message and exit
|
||||
-i, --timeframe TIMEFRAME
|
||||
Specify timeframe (<code>1m</code>, <code>5m</code>, <code>30m</code>, <code>1h</code>, <code>1d</code>).
|
||||
--timerange TIMERANGE
|
||||
Specify what timerange of data to use.
|
||||
--data-format-ohlcv {json,jsongz,feather,parquet}
|
||||
Storage format for downloaded candle (OHLCV) data.
|
||||
(default: <code>feather</code>).
|
||||
-p, --pairs PAIRS [PAIRS ...]
|
||||
Limit command to these pairs. Pairs are space-
|
||||
separated.
|
||||
--startup-candle STARTUP_CANDLE [STARTUP_CANDLE ...]
|
||||
Specify startup candles to be checked (<code>199</code>, <code>499</code>,
|
||||
<code>999</code>, <code>1999</code>).</p>
|
||||
<p>Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
--no-color Disable colorization of hyperopt results. May be
|
||||
useful if you are redirecting output to a file.
|
||||
--logfile, --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, --config PATH Specify configuration file (default:
|
||||
<code>userdir/config.json</code> or <code>config.json</code> whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to <code>-</code> to read config from stdin.
|
||||
-d, --datadir, --data-dir PATH
|
||||
Path to the base directory of the exchange with
|
||||
historical backtesting data. To see futures data, use
|
||||
trading-mode additionally.
|
||||
--userdir, --user-data-dir PATH
|
||||
Path to userdata directory.</p>
|
||||
<p>Strategy arguments:
|
||||
-s, --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.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">usage: freqtrade recursive-analysis [-h] [-v] [--no-color] [--logfile FILE]</span>
|
||||
<span class="go"> [-V] [-c PATH] [-d PATH] [--userdir PATH]</span>
|
||||
<span class="go"> [-s NAME] [--strategy-path PATH]</span>
|
||||
<span class="go"> [--recursive-strategy-search]</span>
|
||||
<span class="go"> [--freqaimodel NAME]</span>
|
||||
<span class="go"> [--freqaimodel-path PATH] [-i TIMEFRAME]</span>
|
||||
<span class="go"> [--timerange TIMERANGE]</span>
|
||||
<span class="go"> [--data-format-ohlcv {json,jsongz,feather,parquet}]</span>
|
||||
<span class="go"> [-p PAIRS [PAIRS ...]]</span>
|
||||
<span class="go"> [--startup-candle STARTUP_CANDLE [STARTUP_CANDLE ...]]</span>
|
||||
|
||||
<span class="go">options:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -i, --timeframe TIMEFRAME</span>
|
||||
<span class="go"> Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).</span>
|
||||
<span class="go"> --timerange TIMERANGE</span>
|
||||
<span class="go"> Specify what timerange of data to use.</span>
|
||||
<span class="go"> --data-format-ohlcv {json,jsongz,feather,parquet}</span>
|
||||
<span class="go"> Storage format for downloaded candle (OHLCV) data.</span>
|
||||
<span class="go"> (default: `feather`).</span>
|
||||
<span class="go"> -p, --pairs PAIRS [PAIRS ...]</span>
|
||||
<span class="go"> Limit command to these pairs. Pairs are space-</span>
|
||||
<span class="go"> separated.</span>
|
||||
<span class="go"> --startup-candle STARTUP_CANDLE [STARTUP_CANDLE ...]</span>
|
||||
<span class="go"> Specify startup candles to be checked (`199`, `499`,</span>
|
||||
<span class="go"> `999`, `1999`).</span>
|
||||
|
||||
<span class="go">Common arguments:</span>
|
||||
<span class="go"> -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).</span>
|
||||
<span class="go"> --no-color Disable colorization of hyperopt results. May be</span>
|
||||
<span class="go"> useful if you are redirecting output to a file.</span>
|
||||
<span class="go"> --logfile, --log-file FILE</span>
|
||||
<span class="go"> Log to the file specified. Special values are:</span>
|
||||
<span class="go"> 'syslog', 'journald'. See the documentation for more</span>
|
||||
<span class="go"> details.</span>
|
||||
<span class="go"> -V, --version show program's version number and exit</span>
|
||||
<span class="go"> -c, --config PATH Specify configuration file (default:</span>
|
||||
<span class="go"> `userdir/config.json` or `config.json` whichever</span>
|
||||
<span class="go"> exists). Multiple --config options may be used. Can be</span>
|
||||
<span class="go"> set to `-` to read config from stdin.</span>
|
||||
<span class="go"> -d, --datadir, --data-dir PATH</span>
|
||||
<span class="go"> Path to the base directory of the exchange with</span>
|
||||
<span class="go"> historical backtesting data. To see futures data, use</span>
|
||||
<span class="go"> trading-mode additionally.</span>
|
||||
<span class="go"> --userdir, --user-data-dir PATH</span>
|
||||
<span class="go"> Path to userdata directory.</span>
|
||||
|
||||
<span class="go">Strategy arguments:</span>
|
||||
<span class="go"> -s, --strategy NAME Specify strategy class name which will be used by the</span>
|
||||
<span class="go"> bot.</span>
|
||||
<span class="go"> --strategy-path PATH Specify additional strategy lookup path.</span>
|
||||
<span class="go"> --recursive-strategy-search</span>
|
||||
<span class="go"> Recursively search for a strategy in the strategies</span>
|
||||
<span class="go"> folder.</span>
|
||||
<span class="go"> --freqaimodel NAME Specify a custom freqaimodels.</span>
|
||||
<span class="go"> --freqaimodel-path PATH</span>
|
||||
<span class="go"> Specify additional lookup path for freqaimodels.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="why-are-odd-numbered-default-startup-candles-used">Why are odd-numbered default startup candles used?<a class="headerlink" href="#why-are-odd-numbered-default-startup-candles-used" title="Permanent link">¶</a></h3>
|
||||
<p>The default value for startup candles are odd numbers. When the bot fetches candle data from the exchange's API, the last candle is the one being checked by the bot and the rest of the data are the "startup candles".</p>
|
||||
<p>For example, Binance allows 1000 candles per API call. When the bot receives 1000 candles, the last candle is the "current candle", and the preceding 999 candles are the "startup candles". By setting the startup candle count as 1000 instead of 999, the bot will try to fetch 1001 candles instead. The exchange API will then send candle data in a paginated form, i.e. in case of the Binance API, this will be two groups- one of length 1000 and another of length 1. This results in the bot thinking the strategy needs 1001 candles of data, and so it will download 2000 candles worth of data instead, which means there will be 1 "current candle" and 1999 "startup candles".</p>
|
||||
@@ -2066,10 +2068,11 @@ usage: freqtrade recursive-analysis [-h] [-v] [--no-color] [--logfile FILE]
|
||||
</ul>
|
||||
<h2 id="understanding-the-recursive-analysis-output">Understanding the recursive-analysis output<a class="headerlink" href="#understanding-the-recursive-analysis-output" title="Permanent link">¶</a></h2>
|
||||
<p>This is an example of an output results table where at least one indicator has a recursive formula issue:</p>
|
||||
<p><code>| indicators | 20 | 40 | 80 | 100 | 150 | 300 | 999 |
|
||||
<div class="highlight"><pre><span></span><code>| indicators | 20 | 40 | 80 | 100 | 150 | 300 | 999 |
|
||||
|--------------+---------+---------+--------+--------+---------+---------+--------|
|
||||
| rsi_30 | nan% | -6.025% | 0.612% | 0.828% | -0.140% | 0.000% | 0.000% |
|
||||
| rsi_14 | 24.141% | -0.876% | 0.070% | 0.007% | -0.000% | -0.000% | - |</code></p>
|
||||
| rsi_14 | 24.141% | -0.876% | 0.070% | 0.007% | -0.000% | -0.000% | - |
|
||||
</code></pre></div>
|
||||
<p>The column headers indicate the different <code>startup_candle_count</code> used in the analysis. The values in the table indicate the variance of the calculated indicators compared to the benchmark value.</p>
|
||||
<p><code>nan%</code> means the value of that indicator cannot be calculated due to lack of data. In this example, you cannot calculate RSI with length 30 with just 21 candles (1 current candle + 20 startup candles).</p>
|
||||
<p>Users should assess the table per indicator to decide if the specified <code>startup_candle_count</code> results in a sufficiently small variance so that the indicator does not have any effect on entries and/or exits.</p>
|
||||
|
||||
+514
-279
@@ -827,14 +827,108 @@
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
<li class="md-nav__item">
|
||||
<a href="#freqtrade-client-available-commands" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Freqtrade client- available commands
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#available-endpoints" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Available endpoints
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#message-websocket" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Message WebSocket
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Message WebSocket">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#using-the-websocket" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Using the WebSocket
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reverse-proxy-setup" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Reverse Proxy setup
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#openapi-interface" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
OpenAPI interface
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-api-usage-using-jwt-tokens" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced API usage using JWT tokens
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#cors" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
CORS
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2012,14 +2106,108 @@
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
<li class="md-nav__item">
|
||||
<a href="#freqtrade-client-available-commands" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Freqtrade client- available commands
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#available-endpoints" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Available endpoints
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#message-websocket" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Message WebSocket
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Message WebSocket">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#using-the-websocket" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Using the WebSocket
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reverse-proxy-setup" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Reverse Proxy setup
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#openapi-interface" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
OpenAPI interface
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#advanced-api-usage-using-jwt-tokens" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Advanced API usage using JWT tokens
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#cors" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
CORS
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2053,19 +2241,19 @@
|
||||
<h2 id="configuration">Configuration<a class="headerlink" href="#configuration" title="Permanent link">¶</a></h2>
|
||||
<p>Enable the rest API by adding the api_server section to your configuration and setting <code>api_server.enabled</code> to <code>true</code>.</p>
|
||||
<p>Sample configuration:</p>
|
||||
<p><code>json
|
||||
"api_server": {
|
||||
"enabled": true,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": 8080,
|
||||
"verbosity": "error",
|
||||
"enable_openapi": false,
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": [],
|
||||
"username": "Freqtrader",
|
||||
"password": "SuperSecret1!",
|
||||
"ws_token": "sercet_Ws_t0ken"
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"api_server"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_ip_address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"verbosity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"enable_openapi"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"jwt_secret_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"somethingRandomSomethingRandom123"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"CORS_origins"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span>
|
||||
<span class="w"> </span><span class="nt">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Freqtrader"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SuperSecret1!"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ws_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sercet_Ws_t0ken"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition danger">
|
||||
<p class="admonition-title">Security warning</p>
|
||||
<p>By default, the configuration listens on localhost only (so it's not reachable from other systems). We strongly recommend to not expose this API to the internet and choose a strong, unique password, since others will potentially be able to control your bot.</p>
|
||||
@@ -2078,14 +2266,14 @@ Setup of these tools is not part of this tutorial, however many good tutorials c
|
||||
</details>
|
||||
<p>You can then access the API by going to <code>http://127.0.0.1:8080/api/v1/ping</code> in a browser to check if the API is running correctly.
|
||||
This should return the response:</p>
|
||||
<p><code>output
|
||||
{"status":"pong"}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">{"status":"pong"}</span>
|
||||
</code></pre></div>
|
||||
<p>All other endpoints return sensitive info and require authentication and are therefore not available through a web browser.</p>
|
||||
<h3 id="security">Security<a class="headerlink" href="#security" title="Permanent link">¶</a></h3>
|
||||
<p>To generate a secure password, best use a password manager, or use the below code.</p>
|
||||
<p><code>python
|
||||
import secrets
|
||||
secrets.token_hex()</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">secrets</span>
|
||||
<span class="n">secrets</span><span class="o">.</span><span class="n">token_hex</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition hint">
|
||||
<p class="admonition-title">JWT token</p>
|
||||
<p>Use the same method to also generate a JWT secret key (<code>jwt_secret_key</code>).</p>
|
||||
@@ -2097,19 +2285,19 @@ Also change <code>jwt_secret_key</code> to something random (no need to remember
|
||||
</div>
|
||||
<h3 id="configuration-with-docker">Configuration with docker<a class="headerlink" href="#configuration-with-docker" title="Permanent link">¶</a></h3>
|
||||
<p>If you run your bot using docker, you'll need to have the bot listen to incoming connections. The security is then handled by docker.</p>
|
||||
<p><code>json
|
||||
"api_server": {
|
||||
"enabled": true,
|
||||
"listen_ip_address": "0.0.0.0",
|
||||
"listen_port": 8080,
|
||||
"username": "Freqtrader",
|
||||
"password": "SuperSecret1!",
|
||||
//...
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"api_server"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_ip_address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.0.0"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Freqtrader"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SuperSecret1!"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>Make sure that the following 2 lines are available in your docker-compose file:</p>
|
||||
<p><code>yml
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"</code></p>
|
||||
<div class="highlight"><pre><span></span><code> ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
</code></pre></div>
|
||||
<div class="admonition danger">
|
||||
<p class="admonition-title">Security warning</p>
|
||||
<p>By using <code>"8080:8080"</code> (or <code>"0.0.0.0:8080:8080"</code>) in the docker port mapping, the API will be available to everyone connecting to the server under the correct port, so others may be able to control your bot.
|
||||
@@ -2120,184 +2308,246 @@ This <strong>may</strong> be safe if you're running the bot in a secure environm
|
||||
<p>We advise consuming the API by using the supported <code>freqtrade-client</code> package (also available as <code>scripts/rest_client.py</code>).</p>
|
||||
<p>This command can be installed independent of any running freqtrade bot by using <code>pip install freqtrade-client</code>.</p>
|
||||
<p>This module is designed to be lightweight, and only depends on the <code>requests</code> and <code>python-rapidjson</code> modules, skipping all heavy dependencies freqtrade otherwise needs.</p>
|
||||
<p><code>bash
|
||||
freqtrade-client <command> [optional parameters]</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade-client<span class="w"> </span><command><span class="w"> </span><span class="o">[</span>optional<span class="w"> </span>parameters<span class="o">]</span>
|
||||
</code></pre></div>
|
||||
<p>By default, the script assumes <code>127.0.0.1</code> (localhost) and port <code>8080</code> to be used, however you can specify a configuration file to override this behaviour.</p>
|
||||
<h4 id="minimalistic-client-config">Minimalistic client config<a class="headerlink" href="#minimalistic-client-config" title="Permanent link">¶</a></h4>
|
||||
<p><code>json
|
||||
{
|
||||
"api_server": {
|
||||
"enabled": true,
|
||||
"listen_ip_address": "0.0.0.0",
|
||||
"listen_port": 8080,
|
||||
"username": "Freqtrader",
|
||||
"password": "SuperSecret1!",
|
||||
//...
|
||||
}
|
||||
}</code></p>
|
||||
<p><code>bash
|
||||
freqtrade-client --config rest_config.json <command> [optional parameters]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"api_server"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_ip_address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.0.0"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Freqtrader"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SuperSecret1!"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">//...</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade-client<span class="w"> </span>--config<span class="w"> </span>rest_config.json<span class="w"> </span><command><span class="w"> </span><span class="o">[</span>optional<span class="w"> </span>parameters<span class="o">]</span>
|
||||
</code></pre></div>
|
||||
<p>Commands with many arguments may require keyword arguments (for clarity) - which can be provided as follows:</p>
|
||||
<p><code>bash
|
||||
freqtrade-client --config rest_config.json forceenter BTC/USDT long enter_tag=GutFeeling</code></p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade-client<span class="w"> </span>--config<span class="w"> </span>rest_config.json<span class="w"> </span>forceenter<span class="w"> </span>BTC/USDT<span class="w"> </span>long<span class="w"> </span><span class="nv">enter_tag</span><span class="o">=</span>GutFeeling
|
||||
</code></pre></div>
|
||||
<p>This method will work for all arguments - check the "show" command for a list of available parameters.</p>
|
||||
<details class="note">
|
||||
<summary>Programmatic use</summary>
|
||||
<p>The <code>freqtrade-client</code> package (installable independent of freqtrade) can be used in your own scripts to interact with the freqtrade API.
|
||||
to do so, please use the following:</p>
|
||||
<p>``` python
|
||||
from freqtrade_client import FtRestClient</p>
|
||||
<p>client = FtRestClient(server_url, username, password)</p>
|
||||
<h1 id="get-the-status-of-the-bot">Get the status of the bot<a class="headerlink" href="#get-the-status-of-the-bot" title="Permanent link">¶</a></h1>
|
||||
<p>ping = client.ping()
|
||||
print(ping)</p>
|
||||
<h1 id="add-pairs-to-blacklist">Add pairs to blacklist<a class="headerlink" href="#add-pairs-to-blacklist" title="Permanent link">¶</a></h1>
|
||||
<p>client.blacklist("BTC/USDT", "ETH/USDT")</p>
|
||||
<h1 id="add-pairs-to-blacklist-by-supplying-a-list">Add pairs to blacklist by supplying a list<a class="headerlink" href="#add-pairs-to-blacklist-by-supplying-a-list" title="Permanent link">¶</a></h1>
|
||||
<p>client.blacklist(*listPairs)</p>
|
||||
<h1 id="_1">...<a class="headerlink" href="#_1" title="Permanent link">¶</a></h1>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade_client</span><span class="w"> </span><span class="kn">import</span> <span class="n">FtRestClient</span>
|
||||
|
||||
|
||||
<span class="n">client</span> <span class="o">=</span> <span class="n">FtRestClient</span><span class="p">(</span><span class="n">server_url</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Get the status of the bot</span>
|
||||
<span class="n">ping</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">ping</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">ping</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Add pairs to blacklist</span>
|
||||
<span class="n">client</span><span class="o">.</span><span class="n">blacklist</span><span class="p">(</span><span class="s2">"BTC/USDT"</span><span class="p">,</span> <span class="s2">"ETH/USDT"</span><span class="p">)</span>
|
||||
<span class="c1"># Add pairs to blacklist by supplying a list</span>
|
||||
<span class="n">client</span><span class="o">.</span><span class="n">blacklist</span><span class="p">(</span><span class="o">*</span><span class="n">listPairs</span><span class="p">)</span>
|
||||
<span class="c1"># ... </span>
|
||||
</code></pre></div>
|
||||
<p>For a full list of available commands, please refer to the list below.</p>
|
||||
</details>
|
||||
<h4 id="freqtrade-client-available-commands">Freqtrade client- available commands<a class="headerlink" href="#freqtrade-client-available-commands" title="Permanent link">¶</a></h4>
|
||||
<p>Possible commands can be listed from the rest-client script using the <code>help</code> command.</p>
|
||||
<p><code>bash
|
||||
freqtrade-client help</code></p>
|
||||
<p>``` output
|
||||
Possible commands:</p>
|
||||
<p>available_pairs
|
||||
Return available pair (backtest data) based on timeframe / stake_currency selection</p>
|
||||
<p>:param timeframe: Only pairs with this timeframe available.
|
||||
:param stake_currency: Only pairs that include this stake currency.</p>
|
||||
<p>balance
|
||||
Get the account balance.</p>
|
||||
<p>blacklist
|
||||
Show the current blacklist.</p>
|
||||
<p>:param add: List of coins to add (example: "BNB/BTC")</p>
|
||||
<p>cancel_open_order
|
||||
Cancel open order for trade.</p>
|
||||
<p>:param trade_id: Cancels open orders for this trade.</p>
|
||||
<p>count
|
||||
Return the amount of open trades.</p>
|
||||
<p>daily
|
||||
Return the profits for each day, and amount of trades.</p>
|
||||
<p>delete_lock
|
||||
Delete (disable) lock from the database.</p>
|
||||
<p>:param lock_id: ID for the lock to delete</p>
|
||||
<p>delete_trade
|
||||
Delete trade from the database.
|
||||
Tries to close open orders. Requires manual handling of this asset on the exchange.</p>
|
||||
<p>:param trade_id: Deletes the trade with this ID from the database.</p>
|
||||
<p>entries
|
||||
Returns List of dicts containing all Trades, based on buy tag performance
|
||||
Can either be average for all pairs or a specific pair provided</p>
|
||||
<p>exits
|
||||
Returns List of dicts containing all Trades, based on exit reason performance
|
||||
Can either be average for all pairs or a specific pair provided</p>
|
||||
<p>forcebuy
|
||||
Buy an asset.</p>
|
||||
<p>:param pair: Pair to buy (ETH/BTC)
|
||||
:param price: Optional - price to buy</p>
|
||||
<p>forceenter
|
||||
Force entering a trade</p>
|
||||
<p>:param pair: Pair to buy (ETH/BTC)
|
||||
:param side: 'long' or 'short'
|
||||
:param price: Optional - price to buy
|
||||
:param order_type: Optional keyword argument - 'limit' or 'market'
|
||||
:param stake_amount: Optional keyword argument - stake amount (as float)
|
||||
:param leverage: Optional keyword argument - leverage (as float)
|
||||
:param enter_tag: Optional keyword argument - entry tag (as string, default: 'force_enter')</p>
|
||||
<p>forceexit
|
||||
Force-exit a trade.</p>
|
||||
<p>:param tradeid: Id of the trade (can be received via status command)
|
||||
:param ordertype: Order type to use (must be market or limit)
|
||||
:param amount: Amount to sell. Full sell if not given</p>
|
||||
<p>health
|
||||
Provides a quick health check of the running bot.</p>
|
||||
<p>list_custom_data
|
||||
List custom-data of the running bot for a specific trade.</p>
|
||||
<p>:param trade_id: ID of the trade
|
||||
:param key: str, optional - Key of the custom-data</p>
|
||||
<p>list_open_trades_custom_data
|
||||
List open trades custom-data of the running bot.</p>
|
||||
<p>:param key: str, optional - Key of the custom-data
|
||||
:param limit: limit of trades
|
||||
:param offset: trades offset for pagination</p>
|
||||
<p>lock_add
|
||||
Lock pair</p>
|
||||
<p>:param pair: Pair to lock
|
||||
:param until: Lock until this date (format "2024-03-30 16:00:00Z")
|
||||
:param side: Side to lock (long, short, *)
|
||||
:param reason: Reason for the lock</p>
|
||||
<p>locks
|
||||
Return current locks</p>
|
||||
<p>logs
|
||||
Show latest logs.</p>
|
||||
<p>:param limit: Limits log messages to the last <limit> logs. No limit to get the entire log.</p>
|
||||
<p>mix_tags
|
||||
Returns List of dicts containing all Trades, based on entry_tag + exit_reason performance
|
||||
Can either be average for all pairs or a specific pair provided</p>
|
||||
<p>monthly
|
||||
Return the profits for each month, and amount of trades.</p>
|
||||
<p>pair_candles
|
||||
Return live dataframe for <pair><timeframe>.</p>
|
||||
<p>:param pair: Pair to get data for
|
||||
:param timeframe: Only pairs with this timeframe available.
|
||||
:param limit: Limit result to the last n candles.
|
||||
:param columns: List of dataframe columns to return. Empty list will return OHLCV.</p>
|
||||
<p>pair_history
|
||||
Return historic, analyzed dataframe</p>
|
||||
<p>:param pair: Pair to get data for
|
||||
:param timeframe: Only pairs with this timeframe available.
|
||||
:param strategy: Strategy to analyze and get values for
|
||||
:param freqaimodel: FreqAI model to use for analysis
|
||||
:param timerange: Timerange to get data for (same format than --timerange endpoints)</p>
|
||||
<p>pairlists_available
|
||||
Lists available pairlist providers</p>
|
||||
<p>performance
|
||||
Return the performance of the different coins.</p>
|
||||
<p>ping
|
||||
simple ping</p>
|
||||
<p>plot_config
|
||||
Return plot configuration if the strategy defines one.</p>
|
||||
<p>profit
|
||||
Return the profit summary.</p>
|
||||
<p>reload_config
|
||||
Reload configuration.</p>
|
||||
<p>show_config
|
||||
Returns part of the configuration, relevant for trading operations.</p>
|
||||
<p>start
|
||||
Start the bot if it's in the stopped state.</p>
|
||||
<p>stats
|
||||
Return the stats report (durations, sell-reasons).</p>
|
||||
<p>status
|
||||
Get the status of open trades.</p>
|
||||
<p>stop
|
||||
Stop the bot. Use <code>start</code> to restart.</p>
|
||||
<p>stopbuy
|
||||
Stop buying (but handle sells gracefully). Use <code>reload_config</code> to reset.</p>
|
||||
<p>strategies
|
||||
Lists available strategies</p>
|
||||
<p>strategy
|
||||
Get strategy details</p>
|
||||
<p>:param strategy: Strategy class name</p>
|
||||
<p>sysinfo
|
||||
Provides system information (CPU, RAM usage)</p>
|
||||
<p>trade
|
||||
Return specific trade</p>
|
||||
<p>:param trade_id: Specify which trade to get.</p>
|
||||
<p>trades
|
||||
Return trades history, sorted by id (or by latest timestamp if order_by_id=False)</p>
|
||||
<p>:param limit: Limits trades to the X last trades. Max 500 trades.
|
||||
:param offset: Offset by this amount of trades.
|
||||
:param order_by_id: Sort trades by id (default: True). If False, sorts by latest timestamp.</p>
|
||||
<p>version
|
||||
Return the version of the bot.</p>
|
||||
<p>weekly
|
||||
Return the profits for each week, and amount of trades.</p>
|
||||
<p>whitelist
|
||||
Show the current whitelist.</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code>freqtrade-client<span class="w"> </span><span class="nb">help</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="go">Possible commands:</span>
|
||||
|
||||
<span class="go">available_pairs</span>
|
||||
<span class="go"> Return available pair (backtest data) based on timeframe / stake_currency selection</span>
|
||||
|
||||
<span class="go">:param timeframe: Only pairs with this timeframe available.</span>
|
||||
<span class="go">:param stake_currency: Only pairs that include this stake currency.</span>
|
||||
|
||||
<span class="go">balance</span>
|
||||
<span class="go"> Get the account balance.</span>
|
||||
|
||||
<span class="go">blacklist</span>
|
||||
<span class="go"> Show the current blacklist.</span>
|
||||
|
||||
<span class="go">:param add: List of coins to add (example: "BNB/BTC")</span>
|
||||
|
||||
<span class="go">cancel_open_order</span>
|
||||
<span class="go"> Cancel open order for trade.</span>
|
||||
|
||||
<span class="go">:param trade_id: Cancels open orders for this trade.</span>
|
||||
|
||||
<span class="go">count</span>
|
||||
<span class="go"> Return the amount of open trades.</span>
|
||||
|
||||
<span class="go">daily</span>
|
||||
<span class="go"> Return the profits for each day, and amount of trades.</span>
|
||||
|
||||
<span class="go">delete_lock</span>
|
||||
<span class="go"> Delete (disable) lock from the database.</span>
|
||||
|
||||
<span class="go">:param lock_id: ID for the lock to delete</span>
|
||||
|
||||
<span class="go">delete_trade</span>
|
||||
<span class="go"> Delete trade from the database.</span>
|
||||
<span class="go">Tries to close open orders. Requires manual handling of this asset on the exchange.</span>
|
||||
|
||||
<span class="go">:param trade_id: Deletes the trade with this ID from the database.</span>
|
||||
|
||||
<span class="go">entries</span>
|
||||
<span class="go"> Returns List of dicts containing all Trades, based on buy tag performance</span>
|
||||
<span class="go">Can either be average for all pairs or a specific pair provided</span>
|
||||
|
||||
<span class="go">exits</span>
|
||||
<span class="go"> Returns List of dicts containing all Trades, based on exit reason performance</span>
|
||||
<span class="go">Can either be average for all pairs or a specific pair provided</span>
|
||||
|
||||
<span class="go">forcebuy</span>
|
||||
<span class="go"> Buy an asset.</span>
|
||||
|
||||
<span class="go">:param pair: Pair to buy (ETH/BTC)</span>
|
||||
<span class="go">:param price: Optional - price to buy</span>
|
||||
|
||||
<span class="go">forceenter</span>
|
||||
<span class="go"> Force entering a trade</span>
|
||||
|
||||
<span class="go">:param pair: Pair to buy (ETH/BTC)</span>
|
||||
<span class="go">:param side: 'long' or 'short'</span>
|
||||
<span class="go">:param price: Optional - price to buy</span>
|
||||
<span class="go">:param order_type: Optional keyword argument - 'limit' or 'market'</span>
|
||||
<span class="go">:param stake_amount: Optional keyword argument - stake amount (as float)</span>
|
||||
<span class="go">:param leverage: Optional keyword argument - leverage (as float)</span>
|
||||
<span class="go">:param enter_tag: Optional keyword argument - entry tag (as string, default: 'force_enter')</span>
|
||||
|
||||
<span class="go">forceexit</span>
|
||||
<span class="go"> Force-exit a trade.</span>
|
||||
|
||||
<span class="go">:param tradeid: Id of the trade (can be received via status command)</span>
|
||||
<span class="go">:param ordertype: Order type to use (must be market or limit)</span>
|
||||
<span class="go">:param amount: Amount to sell. Full sell if not given</span>
|
||||
|
||||
<span class="go">health</span>
|
||||
<span class="go"> Provides a quick health check of the running bot.</span>
|
||||
|
||||
<span class="go">list_custom_data</span>
|
||||
<span class="go"> List custom-data of the running bot for a specific trade.</span>
|
||||
|
||||
<span class="go">:param trade_id: ID of the trade</span>
|
||||
<span class="go">:param key: str, optional - Key of the custom-data</span>
|
||||
|
||||
<span class="go">list_open_trades_custom_data</span>
|
||||
<span class="go"> List open trades custom-data of the running bot.</span>
|
||||
|
||||
<span class="go">:param key: str, optional - Key of the custom-data</span>
|
||||
<span class="go">:param limit: limit of trades</span>
|
||||
<span class="go">:param offset: trades offset for pagination</span>
|
||||
|
||||
<span class="go">lock_add</span>
|
||||
<span class="go"> Lock pair</span>
|
||||
|
||||
<span class="go">:param pair: Pair to lock</span>
|
||||
<span class="go">:param until: Lock until this date (format "2024-03-30 16:00:00Z")</span>
|
||||
<span class="go">:param side: Side to lock (long, short, *)</span>
|
||||
<span class="go">:param reason: Reason for the lock</span>
|
||||
|
||||
<span class="go">locks</span>
|
||||
<span class="go"> Return current locks</span>
|
||||
|
||||
<span class="go">logs</span>
|
||||
<span class="go"> Show latest logs.</span>
|
||||
|
||||
<span class="go">:param limit: Limits log messages to the last <limit> logs. No limit to get the entire log.</span>
|
||||
|
||||
<span class="go">mix_tags</span>
|
||||
<span class="go"> Returns List of dicts containing all Trades, based on entry_tag + exit_reason performance</span>
|
||||
<span class="go">Can either be average for all pairs or a specific pair provided</span>
|
||||
|
||||
<span class="go">monthly</span>
|
||||
<span class="go"> Return the profits for each month, and amount of trades.</span>
|
||||
|
||||
<span class="go">pair_candles</span>
|
||||
<span class="go"> Return live dataframe for <pair><timeframe>.</span>
|
||||
|
||||
<span class="go">:param pair: Pair to get data for</span>
|
||||
<span class="go">:param timeframe: Only pairs with this timeframe available.</span>
|
||||
<span class="go">:param limit: Limit result to the last n candles.</span>
|
||||
<span class="go">:param columns: List of dataframe columns to return. Empty list will return OHLCV.</span>
|
||||
|
||||
<span class="go">pair_history</span>
|
||||
<span class="go"> Return historic, analyzed dataframe</span>
|
||||
|
||||
<span class="go">:param pair: Pair to get data for</span>
|
||||
<span class="go">:param timeframe: Only pairs with this timeframe available.</span>
|
||||
<span class="go">:param strategy: Strategy to analyze and get values for</span>
|
||||
<span class="go">:param freqaimodel: FreqAI model to use for analysis</span>
|
||||
<span class="go">:param timerange: Timerange to get data for (same format than --timerange endpoints)</span>
|
||||
|
||||
<span class="go">pairlists_available</span>
|
||||
<span class="go"> Lists available pairlist providers</span>
|
||||
|
||||
<span class="go">performance</span>
|
||||
<span class="go"> Return the performance of the different coins.</span>
|
||||
|
||||
<span class="go">ping</span>
|
||||
<span class="go"> simple ping</span>
|
||||
|
||||
<span class="go">plot_config</span>
|
||||
<span class="go"> Return plot configuration if the strategy defines one.</span>
|
||||
|
||||
<span class="go">profit</span>
|
||||
<span class="go"> Return the profit summary.</span>
|
||||
|
||||
<span class="go">reload_config</span>
|
||||
<span class="go"> Reload configuration.</span>
|
||||
|
||||
<span class="go">show_config</span>
|
||||
<span class="go"> Returns part of the configuration, relevant for trading operations.</span>
|
||||
|
||||
<span class="go">start</span>
|
||||
<span class="go"> Start the bot if it's in the stopped state.</span>
|
||||
|
||||
<span class="go">stats</span>
|
||||
<span class="go"> Return the stats report (durations, sell-reasons).</span>
|
||||
|
||||
<span class="go">status</span>
|
||||
<span class="go"> Get the status of open trades.</span>
|
||||
|
||||
<span class="go">stop</span>
|
||||
<span class="go"> Stop the bot. Use `start` to restart.</span>
|
||||
|
||||
<span class="go">stopbuy</span>
|
||||
<span class="go"> Stop buying (but handle sells gracefully). Use `reload_config` to reset.</span>
|
||||
|
||||
<span class="go">strategies</span>
|
||||
<span class="go"> Lists available strategies</span>
|
||||
|
||||
<span class="go">strategy</span>
|
||||
<span class="go"> Get strategy details</span>
|
||||
|
||||
<span class="go">:param strategy: Strategy class name</span>
|
||||
|
||||
<span class="go">sysinfo</span>
|
||||
<span class="go"> Provides system information (CPU, RAM usage)</span>
|
||||
|
||||
<span class="go">trade</span>
|
||||
<span class="go"> Return specific trade</span>
|
||||
|
||||
<span class="go">:param trade_id: Specify which trade to get.</span>
|
||||
|
||||
<span class="go">trades</span>
|
||||
<span class="go"> Return trades history, sorted by id (or by latest timestamp if order_by_id=False)</span>
|
||||
|
||||
<span class="go">:param limit: Limits trades to the X last trades. Max 500 trades.</span>
|
||||
<span class="go">:param offset: Offset by this amount of trades.</span>
|
||||
<span class="go">:param order_by_id: Sort trades by id (default: True). If False, sorts by latest timestamp.</span>
|
||||
|
||||
<span class="go">version</span>
|
||||
<span class="go"> Return the version of the bot.</span>
|
||||
|
||||
<span class="go">weekly</span>
|
||||
<span class="go"> Return the profits for each week, and amount of trades.</span>
|
||||
|
||||
<span class="go">whitelist</span>
|
||||
<span class="go"> Show the current whitelist.</span>
|
||||
</code></pre></div>
|
||||
<h3 id="available-endpoints">Available endpoints<a class="headerlink" href="#available-endpoints" title="Permanent link">¶</a></h3>
|
||||
<p>If you wish to call the REST API manually via another route, e.g. directly via <code>curl</code>, the table below shows the relevant URL endpoints and parameters.
|
||||
All endpoints in the below table need to be prefixed with the base URL of the API, e.g. <code>http://127.0.0.1:8080/api/v1/</code> - so the command becomes <code>http://127.0.0.1:8080/api/v1/<command></code>.</p>
|
||||
@@ -2548,31 +2798,24 @@ This can be used to consume real-time data from your bot, such as entry/exit fil
|
||||
<p>Assuming your rest API is set to <code>127.0.0.1</code> on port <code>8080</code>, the endpoint is available at <code>http://localhost:8080/api/v1/message/ws</code>.</p>
|
||||
<p>To access the websocket endpoint, the <code>ws_token</code> is required as a query parameter in the endpoint URL.</p>
|
||||
<p>To generate a safe <code>ws_token</code> you can run the following code:</p>
|
||||
<p>``` python</p>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<p>import secrets
|
||||
secrets.token_urlsafe(25)
|
||||
'hZ-y58LXyX_HZ8O1cJzVyN6ePWrLpNQv4Q'
|
||||
```</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="kn">import</span><span class="w"> </span><span class="nn">secrets</span>
|
||||
<span class="o">>>></span> <span class="n">secrets</span><span class="o">.</span><span class="n">token_urlsafe</span><span class="p">(</span><span class="mi">25</span><span class="p">)</span>
|
||||
<span class="s1">'hZ-y58LXyX_HZ8O1cJzVyN6ePWrLpNQv4Q'</span>
|
||||
</code></pre></div>
|
||||
<p>You would then add that token under <code>ws_token</code> in your <code>api_server</code> config. Like so:</p>
|
||||
<p><code>json
|
||||
"api_server": {
|
||||
"enabled": true,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": 8080,
|
||||
"verbosity": "error",
|
||||
"enable_openapi": false,
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": [],
|
||||
"username": "Freqtrader",
|
||||
"password": "SuperSecret1!",
|
||||
"ws_token": "hZ-y58LXyX_HZ8O1cJzVyN6ePWrLpNQv4Q" // <-----
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"api_server"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_ip_address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"listen_port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8080</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"verbosity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"enable_openapi"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"jwt_secret_key"</span><span class="p">:</span><span class="w"> </span><span class="s2">"somethingRandomSomethingRandom123"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"CORS_origins"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span>
|
||||
<span class="w"> </span><span class="nt">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Freqtrader"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SuperSecret1!"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"ws_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hZ-y58LXyX_HZ8O1cJzVyN6ePWrLpNQv4Q"</span><span class="w"> </span><span class="c1">// <-----</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>You can now connect to the endpoint at <code>http://localhost:8080/api/v1/message/ws?token=hZ-y58LXyX_HZ8O1cJzVyN6ePWrLpNQv4Q</code>.</p>
|
||||
<div class="admonition danger">
|
||||
<p class="admonition-title">Reuse of example tokens</p>
|
||||
@@ -2580,48 +2823,46 @@ secrets.token_urlsafe(25)
|
||||
</div>
|
||||
<h4 id="using-the-websocket">Using the WebSocket<a class="headerlink" href="#using-the-websocket" title="Permanent link">¶</a></h4>
|
||||
<p>Once connected to the WebSocket, the bot will broadcast RPC messages to anyone who is subscribed to them. To subscribe to a list of messages, you must send a JSON request through the WebSocket like the one below. The <code>data</code> key must be a list of message type strings.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"data": ["whitelist", "analyzed_df"] // A list of string message types
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"subscribe"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"whitelist"</span><span class="p">,</span><span class="w"> </span><span class="s2">"analyzed_df"</span><span class="p">]</span><span class="w"> </span><span class="c1">// A list of string message types</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>For a list of message types, please refer to the RPCMessageType enum in <code>freqtrade/enums/rpcmessagetype.py</code></p>
|
||||
<p>Now anytime those types of RPC messages are sent in the bot, you will receive them through the WebSocket as long as the connection is active. They typically take the same form as the request:</p>
|
||||
<p><code>json
|
||||
{
|
||||
"type": "analyzed_df",
|
||||
"data": {
|
||||
"key": ["NEO/BTC", "5m", "spot"],
|
||||
"df": {}, // The dataframe
|
||||
"la": "2022-09-08 22:14:41.457786+00:00"
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"analyzed_df"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"key"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"NEO/BTC"</span><span class="p">,</span><span class="w"> </span><span class="s2">"5m"</span><span class="p">,</span><span class="w"> </span><span class="s2">"spot"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"df"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="c1">// The dataframe</span>
|
||||
<span class="w"> </span><span class="nt">"la"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-09-08 22:14:41.457786+00:00"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<h4 id="reverse-proxy-setup">Reverse Proxy setup<a class="headerlink" href="#reverse-proxy-setup" title="Permanent link">¶</a></h4>
|
||||
<p>When using <a href="https://nginx.org/en/docs/">Nginx</a>, the following configuration is required for WebSockets to work (Note this configuration is incomplete, it's missing some information and can not be used as is):</p>
|
||||
<p>Please make sure to replace <code><freqtrade_listen_ip></code> (and the subsequent port) with the IP and Port matching your configuration/setup.</p>
|
||||
<p>```
|
||||
http {
|
||||
<div class="highlight"><pre><span></span><code>http {
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}</p>
|
||||
<div class="codehilite"><pre><span></span><code>#...
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
#...
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://<freqtrade_listen_ip>:8080;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
server {
|
||||
#...
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://<freqtrade_listen_ip>:8080;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre></div>
|
||||
|
||||
<p>}
|
||||
```</p>
|
||||
<p>To properly configure your reverse proxy (securely), please consult it's documentation for proxying websockets.</p>
|
||||
<ul>
|
||||
<li><strong>Traefik</strong>: Traefik supports websockets out of the box, see the <a href="https://doc.traefik.io/traefik/">documentation</a></li>
|
||||
@@ -2642,23 +2883,17 @@ This will enable the Swagger UI at the <code>/docs</code> endpoint. By default,
|
||||
</div>
|
||||
<p>Freqtrade's REST API also offers JWT (JSON Web Tokens).
|
||||
You can login using the following command, and subsequently use the resulting access_token.</p>
|
||||
<p>``` bash</p>
|
||||
<blockquote>
|
||||
<p _access_token_:_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiMmEwYmY0NWUtMjhmOS00YTUzLTlmNzItMmM5ZWVlYThkNzc2IiwiZXhwIjoxNTg5MTIwNTgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qt6MAXYIa-l556OM7arBvYJ0SDI9J8bIk3_glDujF5g_refresh_token_:_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiZWQ1ZWI3YjAtYjMwMy00YzAyLTg2N2MtNWViMjIxNWQ2YTMxIiwiZXhwIjoxNTkxNzExNjgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJ0eXBlIjoicmVmcmVzaCJ9.d1AT_jYICyTAjD0fiQAr52rkRqtxCjUGEMwlNuuzgNQ_=""access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiMmEwYmY0NWUtMjhmOS00YTUzLTlmNzItMmM5ZWVlYThkNzc2IiwiZXhwIjoxNTg5MTIwNTgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qt6MAXYIa-l556OM7arBvYJ0SDI9J8bIk3_glDujF5g","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiZWQ1ZWI3YjAtYjMwMy00YzAyLTg2N2MtNWViMjIxNWQ2YTMxIiwiZXhwIjoxNTkxNzExNjgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJ0eXBlIjoicmVmcmVzaCJ9.d1AT_jYICyTAjD0fiQAr52rkRqtxCjUGEMwlNuuzgNQ"">curl -X POST --user Freqtrader <a href="http://localhost:8080/api/v1/token/login">http://localhost:8080/api/v1/token/login</a></p>
|
||||
<p>access_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiMmEwYmY0NWUtMjhmOS00YTUzLTlmNzItMmM5ZWVlYThkNzc2IiwiZXhwIjoxNTg5MTIwNTgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qt6MAXYIa-l556OM7arBvYJ0SDI9J8bIk3_glDujF5g"</p>
|
||||
</blockquote>
|
||||
<h1 id="use-access_token-for-authentication">Use access_token for authentication<a class="headerlink" href="#use-access_token-for-authentication" title="Permanent link">¶</a></h1>
|
||||
<blockquote>
|
||||
<p>curl -X GET --header "Authorization: Bearer ${access_token}" <a href="http://localhost:8080/api/v1/count">http://localhost:8080/api/v1/count</a></p>
|
||||
</blockquote>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code>><span class="w"> </span>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>--user<span class="w"> </span>Freqtrader<span class="w"> </span>http://localhost:8080/api/v1/token/login
|
||||
<span class="o">{</span><span class="s2">"access_token"</span>:<span class="s2">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiMmEwYmY0NWUtMjhmOS00YTUzLTlmNzItMmM5ZWVlYThkNzc2IiwiZXhwIjoxNTg5MTIwNTgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qt6MAXYIa-l556OM7arBvYJ0SDI9J8bIk3_glDujF5g"</span>,<span class="s2">"refresh_token"</span>:<span class="s2">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiZWQ1ZWI3YjAtYjMwMy00YzAyLTg2N2MtNWViMjIxNWQ2YTMxIiwiZXhwIjoxNTkxNzExNjgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJ0eXBlIjoicmVmcmVzaCJ9.d1AT_jYICyTAjD0fiQAr52rkRqtxCjUGEMwlNuuzgNQ"</span><span class="o">}</span>
|
||||
|
||||
><span class="w"> </span><span class="nv">access_token</span><span class="o">=</span><span class="s2">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk2ODEsIm5iZiI6MTU4OTExOTY4MSwianRpIjoiMmEwYmY0NWUtMjhmOS00YTUzLTlmNzItMmM5ZWVlYThkNzc2IiwiZXhwIjoxNTg5MTIwNTgxLCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qt6MAXYIa-l556OM7arBvYJ0SDI9J8bIk3_glDujF5g"</span>
|
||||
<span class="c1"># Use access_token for authentication</span>
|
||||
><span class="w"> </span>curl<span class="w"> </span>-X<span class="w"> </span>GET<span class="w"> </span>--header<span class="w"> </span><span class="s2">"Authorization: Bearer </span><span class="si">${</span><span class="nv">access_token</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>http://localhost:8080/api/v1/count
|
||||
</code></pre></div>
|
||||
<p>Since the access token has a short timeout (15 min) - the <code>token/refresh</code> request should be used periodically to get a fresh access token:</p>
|
||||
<p>``` bash</p>
|
||||
<blockquote>
|
||||
<p>curl -X POST --header "Authorization: Bearer ${refresh_token}"<a href="http://localhost:8080/api/v1/token/refresh">http://localhost:8080/api/v1/token/refresh</a>
|
||||
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk5NzQsIm5iZiI6MTU4OTExOTk3NCwianRpIjoiMDBjNTlhMWUtMjBmYS00ZTk0LTliZjAtNWQwNTg2MTdiZDIyIiwiZXhwIjoxNTg5MTIwODc0LCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.1seHlII3WprjjclY6DpRhen0rqdF4j6jbvxIhUFaSbs"}
|
||||
```</p>
|
||||
</blockquote>
|
||||
<div class="highlight"><pre><span></span><code>><span class="w"> </span>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>--header<span class="w"> </span><span class="s2">"Authorization: Bearer </span><span class="si">${</span><span class="nv">refresh_token</span><span class="si">}</span><span class="s2">"</span>http://localhost:8080/api/v1/token/refresh
|
||||
<span class="o">{</span><span class="s2">"access_token"</span>:<span class="s2">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk5NzQsIm5iZiI6MTU4OTExOTk3NCwianRpIjoiMDBjNTlhMWUtMjBmYS00ZTk0LTliZjAtNWQwNTg2MTdiZDIyIiwiZXhwIjoxNTg5MTIwODc0LCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.1seHlII3WprjjclY6DpRhen0rqdF4j6jbvxIhUFaSbs"</span><span class="o">}</span>
|
||||
</code></pre></div>
|
||||
<h2 id="cors">CORS<a class="headerlink" href="#cors" title="Permanent link">¶</a></h2>
|
||||
<p>This whole section is only necessary in cross-origin cases (where you multiple bot API's running on <code>localhost:8081</code>, <code>localhost:8082</code>, ...), and want to combine them into one FreqUI instance.</p>
|
||||
<details class="info">
|
||||
@@ -2670,23 +2905,23 @@ Also, the standard disallows <code>*</code> CORS policies for requests with cred
|
||||
<p>Users can allow access from different origin URL's to the bot API via the <code>CORS_origins</code> configuration setting.
|
||||
It consists of a list of allowed URL's that are allowed to consume resources from the bot's API.</p>
|
||||
<p>Assuming your application is deployed as <code>https://frequi.freqtrade.io/home/</code> - this would mean that the following configuration becomes necessary:</p>
|
||||
<p><code>jsonc
|
||||
{
|
||||
<div class="highlight"><pre><span></span><code>{
|
||||
//...
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["https://frequi.freqtrade.io"],
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["https://frequi.freqtrade.io"],
|
||||
//...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<p>In the following (pretty common) case, FreqUI is accessible on <code>http://localhost:8080/trade</code> (this is what you see in your navbar when navigating to freqUI).
|
||||
<img alt="freqUI url" src="../assets/frequi_url.png" /></p>
|
||||
<p>The correct configuration for this case is <code>http://localhost:8080</code> - the main part of the URL including the port.</p>
|
||||
<p><code>jsonc
|
||||
{
|
||||
<div class="highlight"><pre><span></span><code>{
|
||||
//...
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["http://localhost:8080"],
|
||||
"jwt_secret_key": "somethingRandomSomethingRandom123",
|
||||
"CORS_origins": ["http://localhost:8080"],
|
||||
//...
|
||||
}</code></p>
|
||||
}
|
||||
</code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">trailing Slash</p>
|
||||
<p>The trailing slash is not allowed in the <code>CORS_origins</code> configuration (e.g. <code>"http://localhots:8080/"</code>).
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2184,27 +2184,27 @@ Always make sure to have a backup of your database before running any queries.</
|
||||
<p>Sqlite3 is a terminal based sqlite application.
|
||||
Feel free to use a visual Database editor like SqliteBrowser if you feel more comfortable with that.</p>
|
||||
<h3 id="ubuntudebian-installation">Ubuntu/Debian installation<a class="headerlink" href="#ubuntudebian-installation" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
sudo apt-get install sqlite3</code></p>
|
||||
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>sqlite3
|
||||
</code></pre></div>
|
||||
<h3 id="using-sqlite3-via-docker">Using sqlite3 via docker<a class="headerlink" href="#using-sqlite3-via-docker" title="Permanent link">¶</a></h3>
|
||||
<p>The freqtrade docker image does contain sqlite3, so you can edit the database without having to install anything on the host system.</p>
|
||||
<p><code>bash
|
||||
docker compose exec freqtrade /bin/bash
|
||||
sqlite3 <database-file>.sqlite</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>freqtrade<span class="w"> </span>/bin/bash
|
||||
sqlite3<span class="w"> </span><database-file>.sqlite
|
||||
</code></pre></div>
|
||||
<h2 id="open-the-db">Open the DB<a class="headerlink" href="#open-the-db" title="Permanent link">¶</a></h2>
|
||||
<p><code>bash
|
||||
sqlite3
|
||||
.open <filepath></code></p>
|
||||
<div class="highlight"><pre><span></span><code>sqlite3
|
||||
.open<span class="w"> </span><filepath>
|
||||
</code></pre></div>
|
||||
<h2 id="table-structure">Table structure<a class="headerlink" href="#table-structure" title="Permanent link">¶</a></h2>
|
||||
<h3 id="list-tables">List tables<a class="headerlink" href="#list-tables" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
.tables</code></p>
|
||||
<div class="highlight"><pre><span></span><code>.tables
|
||||
</code></pre></div>
|
||||
<h3 id="display-table-structure">Display table structure<a class="headerlink" href="#display-table-structure" title="Permanent link">¶</a></h3>
|
||||
<p><code>bash
|
||||
.schema <table_name></code></p>
|
||||
<div class="highlight"><pre><span></span><code>.schema<span class="w"> </span><table_name>
|
||||
</code></pre></div>
|
||||
<h3 id="get-all-trades-in-the-table">Get all trades in the table<a class="headerlink" href="#get-all-trades-in-the-table" title="Permanent link">¶</a></h3>
|
||||
<p><code>sql
|
||||
SELECT * FROM trades;</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">trades</span><span class="p">;</span>
|
||||
</code></pre></div>
|
||||
<h2 id="destructive-queries">Destructive queries<a class="headerlink" href="#destructive-queries" title="Permanent link">¶</a></h2>
|
||||
<p>Queries that write to the database.
|
||||
These queries should usually not be necessary as freqtrade tries to handle all database operations itself - or exposes them via API or telegram commands.</p>
|
||||
@@ -2227,25 +2227,25 @@ It is strongly advised to backup your database file before making any manual cha
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>This should not be necessary after /forceexit, as force_exit orders are closed automatically by the bot on the next iteration.</p>
|
||||
</div>
|
||||
<p><code>sql
|
||||
UPDATE trades
|
||||
SET is_open=0,
|
||||
close_date=<close_date>,
|
||||
close_rate=<close_rate>,
|
||||
close_profit = close_rate / open_rate - 1,
|
||||
close_profit_abs = (amount * <close_rate> * (1 - fee_close) - (amount * (open_rate * (1 - fee_open)))),
|
||||
exit_reason=<exit_reason>
|
||||
WHERE id=<trade_ID_to_update>;</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">UPDATE</span><span class="w"> </span><span class="n">trades</span>
|
||||
<span class="k">SET</span><span class="w"> </span><span class="n">is_open</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_date</span><span class="o">=<</span><span class="n">close_date</span><span class="o">></span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_rate</span><span class="o">=<</span><span class="n">close_rate</span><span class="o">></span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_profit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">close_rate</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">open_rate</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_profit_abs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">amount</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="o"><</span><span class="n">close_rate</span><span class="o">></span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">fee_close</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">amount</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">open_rate</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">fee_open</span><span class="p">)))),</span>
|
||||
<span class="w"> </span><span class="n">exit_reason</span><span class="o">=<</span><span class="n">exit_reason</span><span class="o">></span>
|
||||
<span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="o">=<</span><span class="n">trade_ID_to_update</span><span class="o">></span><span class="p">;</span>
|
||||
</code></pre></div>
|
||||
<h4 id="example">Example<a class="headerlink" href="#example" title="Permanent link">¶</a></h4>
|
||||
<p><code>sql
|
||||
UPDATE trades
|
||||
SET is_open=0,
|
||||
close_date='2020-06-20 03:08:45.103418',
|
||||
close_rate=0.19638016,
|
||||
close_profit=0.0496,
|
||||
close_profit_abs = (amount * 0.19638016 * (1 - fee_close) - (amount * (open_rate * (1 - fee_open)))),
|
||||
exit_reason='force_exit'
|
||||
WHERE id=31;</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">UPDATE</span><span class="w"> </span><span class="n">trades</span>
|
||||
<span class="k">SET</span><span class="w"> </span><span class="n">is_open</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_date</span><span class="o">=</span><span class="s1">'2020-06-20 03:08:45.103418'</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_rate</span><span class="o">=</span><span class="mi">0</span><span class="p">.</span><span class="mi">19638016</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_profit</span><span class="o">=</span><span class="mi">0</span><span class="p">.</span><span class="mi">0496</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="n">close_profit_abs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">amount</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">0</span><span class="p">.</span><span class="mi">19638016</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">fee_close</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">amount</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">open_rate</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">fee_open</span><span class="p">)))),</span>
|
||||
<span class="w"> </span><span class="n">exit_reason</span><span class="o">=</span><span class="s1">'force_exit'</span><span class="w"> </span>
|
||||
<span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="o">=</span><span class="mi">31</span><span class="p">;</span>
|
||||
</code></pre></div>
|
||||
<h3 id="remove-trade-from-the-database">Remove trade from the database<a class="headerlink" href="#remove-trade-from-the-database" title="Permanent link">¶</a></h3>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Use RPC Methods to delete trades</p>
|
||||
@@ -2256,14 +2256,15 @@ WHERE id=31;</code></p>
|
||||
<p class="admonition-title">Danger</p>
|
||||
<p>Some systems (Ubuntu) disable foreign keys in their sqlite3 packaging. When using sqlite - please ensure that foreign keys are on by running <code>PRAGMA foreign_keys = ON</code> before the above query.</p>
|
||||
</div>
|
||||
<p>```sql
|
||||
DELETE FROM trades WHERE id = <tradeid>;
|
||||
DELETE FROM orders WHERE ft_trade_id = <tradeid>;
|
||||
DELETE FROM trade_custom_data WHERE ft_trade_id = <tradeid>;</p>
|
||||
<p>DELETE FROM trades WHERE id = 31;
|
||||
DELETE FROM orders WHERE ft_trade_id = 31;
|
||||
DELETE FROM trade_custom_data WHERE ft_trade_id = 31;
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">trades</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o"><</span><span class="n">tradeid</span><span class="o">></span><span class="p">;</span>
|
||||
<span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">ft_trade_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o"><</span><span class="n">tradeid</span><span class="o">></span><span class="p">;</span>
|
||||
<span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">trade_custom_data</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">ft_trade_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o"><</span><span class="n">tradeid</span><span class="o">></span><span class="p">;</span>
|
||||
|
||||
|
||||
<span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">trades</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">31</span><span class="p">;</span>
|
||||
<span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">orders</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">ft_trade_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">31</span><span class="p">;</span>
|
||||
<span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">trade_custom_data</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">ft_trade_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">31</span><span class="p">;</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This will remove the specified trade from the database. Please make sure you got the correct id and <strong>NEVER</strong> run this query without the <code>where</code> clause.</p>
|
||||
|
||||
@@ -2234,11 +2234,11 @@ Stoploss calculations do include fees, so a stoploss of -10% is placed exactly 1
|
||||
<h2 id="stop-loss-on-exchangefreqtrade">Stop Loss On-Exchange/Freqtrade<a class="headerlink" href="#stop-loss-on-exchangefreqtrade" title="Permanent link">¶</a></h2>
|
||||
<p>Those stoploss modes can be <em>on exchange</em> or <em>off exchange</em>.</p>
|
||||
<p>These modes can be configured with these values:</p>
|
||||
<p><code>python
|
||||
'emergency_exit': 'market',
|
||||
'stoploss_on_exchange': False
|
||||
'stoploss_on_exchange_interval': 60,
|
||||
'stoploss_on_exchange_limit_ratio': 0.99</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="s1">'emergency_exit'</span><span class="p">:</span> <span class="s1">'market'</span><span class="p">,</span>
|
||||
<span class="s1">'stoploss_on_exchange'</span><span class="p">:</span> <span class="kc">False</span>
|
||||
<span class="s1">'stoploss_on_exchange_interval'</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
|
||||
<span class="s1">'stoploss_on_exchange_limit_ratio'</span><span class="p">:</span> <span class="mf">0.99</span>
|
||||
</code></pre></div>
|
||||
<p>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.</p>
|
||||
<details class="info">
|
||||
@@ -2418,16 +2418,16 @@ The naming for these prices in exchange terminology often varies, but is usually
|
||||
<p><code>emergency_exit</code> is an optional value, which defaults to <code>market</code> 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.</p>
|
||||
<p>Example from strategy file:</p>
|
||||
<p><code>python
|
||||
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
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">order_types</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"entry"</span><span class="p">:</span> <span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="s2">"exit"</span><span class="p">:</span> <span class="s2">"limit"</span><span class="p">,</span>
|
||||
<span class="s2">"emergency_exit"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss"</span><span class="p">:</span> <span class="s2">"market"</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange_interval"</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
|
||||
<span class="s2">"stoploss_on_exchange_limit_ratio"</span><span class="p">:</span> <span class="mf">0.99</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<h2 id="stop-loss-types">Stop Loss Types<a class="headerlink" href="#stop-loss-types" title="Permanent link">¶</a></h2>
|
||||
<p>At this stage the bot contains the following stoploss support modes:</p>
|
||||
<ol>
|
||||
@@ -2440,8 +2440,8 @@ order_types = {
|
||||
<h3 id="static-stop-loss">Static Stop Loss<a class="headerlink" href="#static-stop-loss" title="Permanent link">¶</a></h3>
|
||||
<p>This is very simple, you define a stop loss of x (as a ratio of price, i.e. x * 100% of price). This will try to sell the asset once the loss exceeds the defined loss.</p>
|
||||
<p>Example of stop loss:</p>
|
||||
<p><code>python
|
||||
stoploss = -0.10</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
</code></pre></div>
|
||||
<p>For example, simplified math:</p>
|
||||
<ul>
|
||||
<li>the bot buys an asset at a price of 100$</li>
|
||||
@@ -2451,9 +2451,9 @@ order_types = {
|
||||
<h3 id="trailing-stop-loss">Trailing Stop Loss<a class="headerlink" href="#trailing-stop-loss" title="Permanent link">¶</a></h3>
|
||||
<p>The initial value for this is <code>stoploss</code>, just as you would define your static Stop loss.
|
||||
To enable trailing stoploss:</p>
|
||||
<p><code>python
|
||||
stoploss = -0.10
|
||||
trailing_stop = True</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
<span class="n">trailing_stop</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
</code></pre></div>
|
||||
<p>This will now activate an algorithm, which automatically moves the stop loss up every time the price of your asset increases.</p>
|
||||
<p>For example, simplified math:</p>
|
||||
<ul>
|
||||
@@ -2473,12 +2473,12 @@ For example, your default stop loss is -10%, but once you have reached profitabi
|
||||
<p>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 <a href="#trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset">offset enabled</a>.</p>
|
||||
</div>
|
||||
<p>Both values require <code>trailing_stop</code> to be set to true and <code>trailing_stop_positive</code> with a value.</p>
|
||||
<p><code>python
|
||||
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</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
<span class="n">trailing_stop</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">trailing_stop_positive</span> <span class="o">=</span> <span class="mf">0.02</span>
|
||||
<span class="n">trailing_stop_positive_offset</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
<span class="n">trailing_only_offset_is_reached</span> <span class="o">=</span> <span class="kc">False</span> <span class="c1"># Default - not necessary for this example</span>
|
||||
</code></pre></div>
|
||||
<p>For example, simplified math:</p>
|
||||
<ul>
|
||||
<li>the bot buys an asset at a price of 100$</li>
|
||||
@@ -2494,11 +2494,11 @@ Before this, <code>stoploss</code> is used for the trailing stoploss.</p>
|
||||
<p class="admonition-title">Use an offset to change your stoploss</p>
|
||||
<p>Use <code>trailing_stop_positive_offset</code> to ensure that your new trailing stoploss will be in profit by setting <code>trailing_stop_positive_offset</code> higher than <code>trailing_stop_positive</code>. Your first new stoploss value will then already have locked in profits.</p>
|
||||
<p>Example with simplified math:</p>
|
||||
<p><code>python
|
||||
stoploss = -0.10
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.02
|
||||
trailing_stop_positive_offset = 0.03</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
<span class="n">trailing_stop</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">trailing_stop_positive</span> <span class="o">=</span> <span class="mf">0.02</span>
|
||||
<span class="n">trailing_stop_positive_offset</span> <span class="o">=</span> <span class="mf">0.03</span>
|
||||
</code></pre></div>
|
||||
<ul>
|
||||
<li>the bot buys an asset at a price of 100$</li>
|
||||
<li>the stop loss is defined at -10%, so the stop loss would get triggered once the asset drops below 90$</li>
|
||||
@@ -2515,12 +2515,12 @@ Before this, <code>stoploss</code> is used for the trailing stoploss.</p>
|
||||
Leaving this value as <code>trailing_only_offset_is_reached=False</code> will allow the trailing stoploss to start trailing as soon as the asset price increases above the initial entry price.</p>
|
||||
<p>This option can be used with or without <code>trailing_stop_positive</code>, but uses <code>trailing_stop_positive_offset</code> as offset.</p>
|
||||
<p>Configuration (offset is buy-price + 3%):</p>
|
||||
<p><code>python
|
||||
stoploss = -0.10
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.02
|
||||
trailing_stop_positive_offset = 0.03
|
||||
trailing_only_offset_is_reached = True</code></p>
|
||||
<div class="highlight"><pre><span></span><code> <span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
<span class="n">trailing_stop</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">trailing_stop_positive</span> <span class="o">=</span> <span class="mf">0.02</span>
|
||||
<span class="n">trailing_stop_positive_offset</span> <span class="o">=</span> <span class="mf">0.03</span>
|
||||
<span class="n">trailing_only_offset_is_reached</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
</code></pre></div>
|
||||
<p>For example, simplified math:</p>
|
||||
<ul>
|
||||
<li>the bot buys an asset at a price of 100$</li>
|
||||
|
||||
@@ -2224,8 +2224,8 @@
|
||||
<p>The <code>populate_indicators</code> function adds columns to the dataframe that represent the technical analysis indicator values.</p>
|
||||
<p>Examples of common indicators include Relative Strength Index, Bollinger Bands, Money Flow Index, Moving Average, and Average True Range.</p>
|
||||
<p>Columns are added to the dataframe by calling technical analysis functions, e.g. ta-lib's RSI function <code>ta.RSI()</code>, and assigning them to a column name, e.g. <code>rsi</code></p>
|
||||
<p><code>python
|
||||
dataframe['rsi'] = ta.RSI(dataframe)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">RSI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<details class="hint">
|
||||
<summary>Technical Analysis libraries</summary>
|
||||
<p>Different libraries work in different ways to generate indicator values. Please check the documentation of each library to understand
|
||||
@@ -2247,43 +2247,42 @@ how to integrate it into your strategy. You can also check the <a href="https://
|
||||
</details>
|
||||
<h2 id="a-simple-strategy">A simple strategy<a class="headerlink" href="#a-simple-strategy" title="Permanent link">¶</a></h2>
|
||||
<p>Here is a minimal example of a Freqtrade strategy:</p>
|
||||
<p>```python
|
||||
from freqtrade.strategy import IStrategy
|
||||
from pandas import DataFrame
|
||||
import talib.abstract as ta</p>
|
||||
<p>class MyStrategy(IStrategy):</p>
|
||||
<div class="codehilite"><pre><span></span><code>timeframe = '15m'
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.strategy</span><span class="w"> </span><span class="kn">import</span> <span class="n">IStrategy</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">pandas</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataFrame</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">talib.abstract</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">ta</span>
|
||||
|
||||
# set the initial stoploss to -10%
|
||||
stoploss = -0.10
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
|
||||
# exit profitable positions at any time when the profit is greater than 1%
|
||||
minimal_roi = {"0": 0.01}
|
||||
<span class="n">timeframe</span> <span class="o">=</span> <span class="s1">'15m'</span>
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# generate values for technical analysis indicators
|
||||
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||
<span class="c1"># set the initial stoploss to -10%</span>
|
||||
<span class="n">stoploss</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.10</span>
|
||||
|
||||
return dataframe
|
||||
<span class="c1"># exit profitable positions at any time when the profit is greater than 1%</span>
|
||||
<span class="n">minimal_roi</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"0"</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">}</span>
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# generate entry signals based on indicator values
|
||||
dataframe.loc[
|
||||
(dataframe['rsi'] < 30),
|
||||
'enter_long'] = 1
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># generate values for technical analysis indicators</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">RSI</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
|
||||
|
||||
return dataframe
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# generate exit signals based on indicator values
|
||||
dataframe.loc[
|
||||
(dataframe['rsi'] > 70),
|
||||
'exit_long'] = 1
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_entry_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># generate entry signals based on indicator values</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">]</span> <span class="o"><</span> <span class="mi">30</span><span class="p">),</span>
|
||||
<span class="s1">'enter_long'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
return dataframe
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_exit_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># generate exit signals based on indicator values</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'rsi'</span><span class="p">]</span> <span class="o">></span> <span class="mi">70</span><span class="p">),</span>
|
||||
<span class="s1">'exit_long'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<h2 id="making-trades">Making trades<a class="headerlink" href="#making-trades" title="Permanent link">¶</a></h2>
|
||||
<p>When a signal is found (a <code>1</code> in an entry or exit column), Freqtrade will attempt to make an order, i.e. a <code>trade</code> or <code>position</code>.</p>
|
||||
<p>Each new trade position takes up a <code>slot</code>. Slots represent the maximum number of concurrent new trades that can be opened.</p>
|
||||
|
||||
@@ -2106,66 +2106,65 @@ If you're just getting started, please familiarize yourself with the <a href="..
|
||||
<p>Using a trade object, information can be stored using <code>trade.set_custom_data(key='my_key', value=my_value)</code> and retrieved using <code>trade.get_custom_data(key='my_key')</code>. Each data entry is associated with a trade and a user supplied key (of type <code>string</code>). This means that this can only be used in callbacks that also provide a trade object.</p>
|
||||
<p>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.</p>
|
||||
<p>```python
|
||||
from freqtrade.persistence import Trade
|
||||
from datetime import timedelta</p>
|
||||
<p>class AwesomeStrategy(IStrategy):</p>
|
||||
<div class="codehilite"><pre><span></span><code>def bot_loop_start(self, **kwargs) -> None:
|
||||
for trade in Trade.get_open_order_trades():
|
||||
fills = trade.select_filled_orders(trade.entry_side)
|
||||
if trade.pair == 'ETH/USDT':
|
||||
trade_entry_type = trade.get_custom_data(key='entry_type')
|
||||
if trade_entry_type is None:
|
||||
trade_entry_type = 'breakout' if 'entry_1' in trade.enter_tag else 'dip'
|
||||
elif len(fills) > 1:
|
||||
trade_entry_type = 'buy_up'
|
||||
trade.set_custom_data(key='entry_type', value=trade_entry_type)
|
||||
return super().bot_loop_start(**kwargs)
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">timedelta</span>
|
||||
|
||||
def adjust_entry_price(self, trade: Trade, order: Order | None, pair: str,
|
||||
current_time: datetime, proposed_rate: float, current_order_rate: float,
|
||||
entry_tag: str | None, side: str, **kwargs) -> float:
|
||||
# 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
|
||||
and order.filled == 0.0
|
||||
):
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
|
||||
current_candle = dataframe.iloc[-1].squeeze()
|
||||
# store information about entry adjustment
|
||||
existing_count = trade.get_custom_data('num_entry_adjustments', default=0)
|
||||
if not existing_count:
|
||||
existing_count = 1
|
||||
else:
|
||||
existing_count += 1
|
||||
trade.set_custom_data(key='num_entry_adjustments', value=existing_count)
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">AwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
|
||||
# adjust order price
|
||||
return current_candle['sma_200']
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">bot_loop_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">trade</span> <span class="ow">in</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_open_order_trades</span><span class="p">():</span>
|
||||
<span class="n">fills</span> <span class="o">=</span> <span class="n">trade</span><span class="o">.</span><span class="n">select_filled_orders</span><span class="p">(</span><span class="n">trade</span><span class="o">.</span><span class="n">entry_side</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">trade</span><span class="o">.</span><span class="n">pair</span> <span class="o">==</span> <span class="s1">'ETH/USDT'</span><span class="p">:</span>
|
||||
<span class="n">trade_entry_type</span> <span class="o">=</span> <span class="n">trade</span><span class="o">.</span><span class="n">get_custom_data</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s1">'entry_type'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">trade_entry_type</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">trade_entry_type</span> <span class="o">=</span> <span class="s1">'breakout'</span> <span class="k">if</span> <span class="s1">'entry_1'</span> <span class="ow">in</span> <span class="n">trade</span><span class="o">.</span><span class="n">enter_tag</span> <span class="k">else</span> <span class="s1">'dip'</span>
|
||||
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">fills</span><span class="p">)</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="n">trade_entry_type</span> <span class="o">=</span> <span class="s1">'buy_up'</span>
|
||||
<span class="n">trade</span><span class="o">.</span><span class="n">set_custom_data</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s1">'entry_type'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">trade_entry_type</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">bot_loop_start</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
|
||||
# default: maintain existing order
|
||||
return current_order_rate
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">adjust_entry_price</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trade</span><span class="p">:</span> <span class="n">Trade</span><span class="p">,</span> <span class="n">order</span><span class="p">:</span> <span class="n">Order</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">pair</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
||||
<span class="n">current_time</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">proposed_rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">current_order_rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
|
||||
<span class="n">entry_tag</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">side</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||||
<span class="c1"># Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair.</span>
|
||||
<span class="k">if</span> <span class="p">(</span>
|
||||
<span class="n">pair</span> <span class="o">==</span> <span class="s1">'BTC/USDT'</span>
|
||||
<span class="ow">and</span> <span class="n">entry_tag</span> <span class="o">==</span> <span class="s1">'long_sma200'</span>
|
||||
<span class="ow">and</span> <span class="n">side</span> <span class="o">==</span> <span class="s1">'long'</span>
|
||||
<span class="ow">and</span> <span class="p">(</span><span class="n">current_time</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">10</span><span class="p">))</span> <span class="o">></span> <span class="n">trade</span><span class="o">.</span><span class="n">open_date_utc</span>
|
||||
<span class="ow">and</span> <span class="n">order</span><span class="o">.</span><span class="n">filled</span> <span class="o">==</span> <span class="mf">0.0</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">dataframe</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dp</span><span class="o">.</span><span class="n">get_analyzed_dataframe</span><span class="p">(</span><span class="n">pair</span><span class="o">=</span><span class="n">pair</span><span class="p">,</span> <span class="n">timeframe</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">timeframe</span><span class="p">)</span>
|
||||
<span class="n">current_candle</span> <span class="o">=</span> <span class="n">dataframe</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">squeeze</span><span class="p">()</span>
|
||||
<span class="c1"># store information about entry adjustment</span>
|
||||
<span class="n">existing_count</span> <span class="o">=</span> <span class="n">trade</span><span class="o">.</span><span class="n">get_custom_data</span><span class="p">(</span><span class="s1">'num_entry_adjustments'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">existing_count</span><span class="p">:</span>
|
||||
<span class="n">existing_count</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">existing_count</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
<span class="n">trade</span><span class="o">.</span><span class="n">set_custom_data</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s1">'num_entry_adjustments'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="n">existing_count</span><span class="p">)</span>
|
||||
|
||||
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs):
|
||||
<span class="c1"># adjust order price</span>
|
||||
<span class="k">return</span> <span class="n">current_candle</span><span class="p">[</span><span class="s1">'sma_200'</span><span class="p">]</span>
|
||||
|
||||
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
|
||||
<span class="c1"># default: maintain existing order</span>
|
||||
<span class="k">return</span> <span class="n">current_order_rate</span>
|
||||
|
||||
return False, None
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">custom_exit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pair</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">trade</span><span class="p">:</span> <span class="n">Trade</span><span class="p">,</span> <span class="n">current_time</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">current_rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">current_profit</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
|
||||
<span class="n">entry_adjustment_count</span> <span class="o">=</span> <span class="n">trade</span><span class="o">.</span><span class="n">get_custom_data</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s1">'num_entry_adjustments'</span><span class="p">)</span>
|
||||
<span class="n">trade_entry_type</span> <span class="o">=</span> <span class="n">trade</span><span class="o">.</span><span class="n">get_custom_data</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s1">'entry_type'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">entry_adjustment_count</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">current_profit</span> <span class="o">></span> <span class="mf">0.01</span> <span class="ow">and</span> <span class="p">(</span><span class="n">current_time</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span> <span class="o">></span> <span class="n">trade</span><span class="o">.</span><span class="n">open_date_utc</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'exit_1'</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">if</span> <span class="n">entry_adjustment_count</span> <span class="o">></span> <span class="mi">0</span> <span class="ow">and</span> <span class="k">if</span> <span class="n">current_profit</span> <span class="o">></span> <span class="mf">0.05</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'exit_2'</span>
|
||||
<span class="k">if</span> <span class="n">trade_entry_type</span> <span class="o">==</span> <span class="s1">'breakout'</span> <span class="ow">and</span> <span class="n">current_profit</span> <span class="o">></span> <span class="mf">0.1</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'exit_3</span>
|
||||
|
||||
<span class="k">return</span> <span class="kc">False</span><span class="p">,</span> <span class="kc">None</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<p>The above is a simple example - there are simpler ways to retrieve trade data like entry-adjustments.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2197,23 +2196,21 @@ Please use <a href="#storing-information-persistent">Persistent Storage</a> inst
|
||||
<summary>Storing information</summary>
|
||||
<p>Storing information can be accomplished by creating a new dictionary within the strategy class.</p>
|
||||
<p>The name of the variable can be chosen at will, but should be prefixed with <code>custom_</code> to avoid naming collisions with predefined strategy variables.</p>
|
||||
<p>```python
|
||||
class AwesomeStrategy(IStrategy):
|
||||
# Create custom dictionary
|
||||
custom_info = {}</p>
|
||||
<div class="codehilite"><pre><span></span><code>def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# Check if the entry already exists
|
||||
if not metadata["pair"] in self.custom_info:
|
||||
# Create empty entry for this pair
|
||||
self.custom_info[metadata["pair"]] = {}
|
||||
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">AwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="c1"># Create custom dictionary</span>
|
||||
<span class="n">custom_info</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
if "crosstime" in self.custom_info[metadata["pair"]]:
|
||||
self.custom_info[metadata["pair"]]["crosstime"] += 1
|
||||
else:
|
||||
self.custom_info[metadata["pair"]]["crosstime"] = 1
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">populate_indicators</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="c1"># Check if the entry already exists</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">metadata</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">custom_info</span><span class="p">:</span>
|
||||
<span class="c1"># Create empty entry for this pair</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">custom_info</span><span class="p">[</span><span class="n">metadata</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"crosstime"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">custom_info</span><span class="p">[</span><span class="n">metadata</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]]:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">custom_info</span><span class="p">[</span><span class="n">metadata</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]][</span><span class="s2">"crosstime"</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">custom_info</span><span class="p">[</span><span class="n">metadata</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]][</span><span class="s2">"crosstime"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>The data is not persisted after a bot-restart (or config-reload). Also, the amount of data should be kept smallish (no DataFrames and such), otherwise the bot will start to consume a lot of memory and eventually run out of memory and crash.</p>
|
||||
@@ -2225,31 +2222,30 @@ class AwesomeStrategy(IStrategy):
|
||||
</details>
|
||||
<h2 id="dataframe-access">Dataframe access<a class="headerlink" href="#dataframe-access" title="Permanent link">¶</a></h2>
|
||||
<p>You may access dataframe in various strategy functions by querying it from dataprovider.</p>
|
||||
<p>``` python
|
||||
from freqtrade.exchange import timeframe_to_prev_date</p>
|
||||
<p>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, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)</p>
|
||||
<div class="codehilite"><pre><span></span><code> # Obtain last available candle. Do not use current_time to look up latest candle, because
|
||||
# current_time points to current incomplete candle whose data is not available.
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
# <...>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.exchange</span><span class="w"> </span><span class="kn">import</span> <span class="n">timeframe_to_prev_date</span>
|
||||
|
||||
# In dry/live runs trade open date will not match candle open date therefore it must be
|
||||
# rounded.
|
||||
trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
|
||||
# Look up trade candle.
|
||||
trade_candle = dataframe.loc[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()
|
||||
# <...>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">AwesomeStrategy</span><span class="p">(</span><span class="n">IStrategy</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">confirm_trade_exit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pair</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">trade</span><span class="p">:</span> <span class="s1">'Trade'</span><span class="p">,</span> <span class="n">order_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">amount</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
|
||||
<span class="n">rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">time_in_force</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">exit_reason</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
||||
<span class="n">current_time</span><span class="p">:</span> <span class="s1">'datetime'</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
|
||||
<span class="c1"># Obtain pair dataframe.</span>
|
||||
<span class="n">dataframe</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dp</span><span class="o">.</span><span class="n">get_analyzed_dataframe</span><span class="p">(</span><span class="n">pair</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">timeframe</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Obtain last available candle. Do not use current_time to look up latest candle, because </span>
|
||||
<span class="c1"># current_time points to current incomplete candle whose data is not available.</span>
|
||||
<span class="n">last_candle</span> <span class="o">=</span> <span class="n">dataframe</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">squeeze</span><span class="p">()</span>
|
||||
<span class="c1"># <...></span>
|
||||
|
||||
<span class="c1"># In dry/live runs trade open date will not match candle open date therefore it must be </span>
|
||||
<span class="c1"># rounded.</span>
|
||||
<span class="n">trade_date</span> <span class="o">=</span> <span class="n">timeframe_to_prev_date</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">timeframe</span><span class="p">,</span> <span class="n">trade</span><span class="o">.</span><span class="n">open_date_utc</span><span class="p">)</span>
|
||||
<span class="c1"># Look up trade candle.</span>
|
||||
<span class="n">trade_candle</span> <span class="o">=</span> <span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">dataframe</span><span class="p">[</span><span class="s1">'date'</span><span class="p">]</span> <span class="o">==</span> <span class="n">trade_date</span><span class="p">]</span>
|
||||
<span class="c1"># trade_candle may be empty for trades that just opened as it is still incomplete.</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">trade_candle</span><span class="o">.</span><span class="n">empty</span><span class="p">:</span>
|
||||
<span class="n">trade_candle</span> <span class="o">=</span> <span class="n">trade_candle</span><span class="o">.</span><span class="n">squeeze</span><span class="p">()</span>
|
||||
<span class="c1"># <...></span>
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Using .iloc[-1]</p>
|
||||
<p>You can use <code>.iloc[-1]</code> here because <code>get_analyzed_dataframe()</code> only returns candles that backtesting is allowed to see.
|
||||
@@ -2260,38 +2256,37 @@ Also, this will only work starting with version 2021.5.</p>
|
||||
<h2 id="enter-tag">Enter Tag<a class="headerlink" href="#enter-tag" title="Permanent link">¶</a></h2>
|
||||
<p>When your strategy has multiple entry signals, you can name the signal that triggered.
|
||||
Then you can access your entry signal on <code>custom_exit</code></p>
|
||||
<p>```python
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe["enter_tag"] = ""
|
||||
signal_rsi = (qtpylib.crossed_above(dataframe["rsi"], 35))
|
||||
signal_bblower = (dataframe["bb_lowerband"] < dataframe["close"])
|
||||
# Additional conditions
|
||||
dataframe.loc[
|
||||
(
|
||||
signal_rsi
|
||||
| signal_bblower
|
||||
# ... additional signals to enter a long position
|
||||
)
|
||||
& (dataframe["volume"] > 0)
|
||||
, "enter_long"
|
||||
] = 1
|
||||
# Concatenate the tags so all signals are kept
|
||||
dataframe.loc[signal_rsi, "enter_tag"] += "long_signal_rsi "
|
||||
dataframe.loc[signal_bblower, "enter_tag"] += "long_signal_bblower "</p>
|
||||
<div class="codehilite"><pre><span></span><code>return dataframe
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">populate_entry_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"enter_tag"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<span class="n">signal_rsi</span> <span class="o">=</span> <span class="p">(</span><span class="n">qtpylib</span><span class="o">.</span><span class="n">crossed_above</span><span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"rsi"</span><span class="p">],</span> <span class="mi">35</span><span class="p">))</span>
|
||||
<span class="n">signal_bblower</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"bb_lowerband"</span><span class="p">]</span> <span class="o"><</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"close"</span><span class="p">])</span>
|
||||
<span class="c1"># Additional conditions</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span>
|
||||
<span class="n">signal_rsi</span>
|
||||
<span class="o">|</span> <span class="n">signal_bblower</span>
|
||||
<span class="c1"># ... additional signals to enter a long position</span>
|
||||
<span class="p">)</span>
|
||||
<span class="o">&</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="p">,</span> <span class="s2">"enter_long"</span>
|
||||
<span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
<span class="c1"># Concatenate the tags so all signals are kept</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">signal_rsi</span><span class="p">,</span> <span class="s2">"enter_tag"</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">"long_signal_rsi "</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">signal_bblower</span><span class="p">,</span> <span class="s2">"enter_tag"</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">"long_signal_bblower "</span>
|
||||
|
||||
<p>def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
|
||||
current_profit: float, **kwargs):
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if "long_signal_rsi" in trade.enter_tag and last_candle["rsi"] > 80:
|
||||
return "exit_signal_rsi"
|
||||
if "long_signal_bblower" in trade.enter_tag and last_candle["high"] > last_candle["bb_upperband"]:
|
||||
return "exit_signal_bblower"
|
||||
# ...
|
||||
return None</p>
|
||||
<p>```</p>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">custom_exit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pair</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">trade</span><span class="p">:</span> <span class="n">Trade</span><span class="p">,</span> <span class="n">current_time</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">current_rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
|
||||
<span class="n">current_profit</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="n">dataframe</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dp</span><span class="o">.</span><span class="n">get_analyzed_dataframe</span><span class="p">(</span><span class="n">pair</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">timeframe</span><span class="p">)</span>
|
||||
<span class="n">last_candle</span> <span class="o">=</span> <span class="n">dataframe</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">squeeze</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="s2">"long_signal_rsi"</span> <span class="ow">in</span> <span class="n">trade</span><span class="o">.</span><span class="n">enter_tag</span> <span class="ow">and</span> <span class="n">last_candle</span><span class="p">[</span><span class="s2">"rsi"</span><span class="p">]</span> <span class="o">></span> <span class="mi">80</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="s2">"exit_signal_rsi"</span>
|
||||
<span class="k">if</span> <span class="s2">"long_signal_bblower"</span> <span class="ow">in</span> <span class="n">trade</span><span class="o">.</span><span class="n">enter_tag</span> <span class="ow">and</span> <span class="n">last_candle</span><span class="p">[</span><span class="s2">"high"</span><span class="p">]</span> <span class="o">></span> <span class="n">last_candle</span><span class="p">[</span><span class="s2">"bb_upperband"</span><span class="p">]:</span>
|
||||
<span class="k">return</span> <span class="s2">"exit_signal_bblower"</span>
|
||||
<span class="c1"># ...</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p><code>enter_tag</code> is limited to 255 characters, remaining data will be truncated.</p>
|
||||
@@ -2305,28 +2300,26 @@ These results are a consequence of the strategy overwriting prior tags - where t
|
||||
</div>
|
||||
<h2 id="exit-tag">Exit tag<a class="headerlink" href="#exit-tag" title="Permanent link">¶</a></h2>
|
||||
<p>Similar to <a href="#enter-tag">Entry Tagging</a>, you can also specify an exit tag.</p>
|
||||
<p>``` python
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe["exit_tag"] = ""
|
||||
rsi_exit_signal = (dataframe["rsi"] > 70)
|
||||
ema_exit_signal = (dataframe["ema20"] < dataframe["ema50"])
|
||||
# Additional conditions
|
||||
dataframe.loc[
|
||||
(
|
||||
rsi_exit_signal
|
||||
| ema_exit_signal
|
||||
# ... additional signals to exit a long position
|
||||
) &
|
||||
(dataframe["volume"] > 0)
|
||||
,
|
||||
"exit_long"] = 1
|
||||
# Concatenate the tags so all signals are kept
|
||||
dataframe.loc[rsi_exit_signal, "exit_tag"] += "exit_signal_rsi "
|
||||
dataframe.loc[rsi_exit_signal2, "exit_tag"] += "exit_signal_rsi "</p>
|
||||
<div class="codehilite"><pre><span></span><code>return dataframe
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">populate_exit_trend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">:</span> <span class="n">DataFrame</span><span class="p">,</span> <span class="n">metadata</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">DataFrame</span><span class="p">:</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="s2">"exit_tag"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<span class="n">rsi_exit_signal</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"rsi"</span><span class="p">]</span> <span class="o">></span> <span class="mi">70</span><span class="p">)</span>
|
||||
<span class="n">ema_exit_signal</span> <span class="o">=</span> <span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"ema20"</span><span class="p">]</span> <span class="o"><</span> <span class="n">dataframe</span><span class="p">[</span><span class="s2">"ema50"</span><span class="p">])</span>
|
||||
<span class="c1"># Additional conditions</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span>
|
||||
<span class="p">(</span>
|
||||
<span class="n">rsi_exit_signal</span>
|
||||
<span class="o">|</span> <span class="n">ema_exit_signal</span>
|
||||
<span class="c1"># ... additional signals to exit a long position</span>
|
||||
<span class="p">)</span> <span class="o">&</span>
|
||||
<span class="p">(</span><span class="n">dataframe</span><span class="p">[</span><span class="s2">"volume"</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="p">,</span>
|
||||
<span class="s2">"exit_long"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
<span class="c1"># Concatenate the tags so all signals are kept</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">rsi_exit_signal</span><span class="p">,</span> <span class="s2">"exit_tag"</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">"exit_signal_rsi "</span>
|
||||
<span class="n">dataframe</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">rsi_exit_signal2</span><span class="p">,</span> <span class="s2">"exit_tag"</span><span class="p">]</span> <span class="o">+=</span> <span class="s2">"exit_signal_rsi "</span>
|
||||
|
||||
<p>```</p>
|
||||
<span class="k">return</span> <span class="n">dataframe</span>
|
||||
</code></pre></div>
|
||||
<p>The provided exit-tag is then used as exit-reason - and shown as such in backtest results.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
@@ -2334,12 +2327,12 @@ def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFr
|
||||
</div>
|
||||
<h2 id="strategy-version">Strategy version<a class="headerlink" href="#strategy-version" title="Permanent link">¶</a></h2>
|
||||
<p>You can implement custom strategy versioning by using the "version" method, and returning the version you would like this strategy to have.</p>
|
||||
<p><code>python
|
||||
def version(self) -> str:
|
||||
"""
|
||||
Returns version of the strategy.
|
||||
"""
|
||||
return "1.1"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">version</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""</span>
|
||||
<span class="sd"> Returns version of the strategy.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="s2">"1.1"</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>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.</p>
|
||||
@@ -2368,15 +2361,15 @@ This is done by utilizing BASE64 encoding and providing this string at the strat
|
||||
in your chosen config file.</p>
|
||||
<h3 id="encoding-a-string-as-base64">Encoding a string as BASE64<a class="headerlink" href="#encoding-a-string-as-base64" title="Permanent link">¶</a></h3>
|
||||
<p>This is a quick example, how to generate the BASE64 string in python</p>
|
||||
<p>```python
|
||||
from base64 import urlsafe_b64encode</p>
|
||||
<p>with open(file, 'r') as f:
|
||||
content = f.read()
|
||||
content = urlsafe_b64encode(content.encode('utf-8'))
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">base64</span><span class="w"> </span><span class="kn">import</span> <span class="n">urlsafe_b64encode</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
<span class="n">content</span> <span class="o">=</span> <span class="n">urlsafe_b64encode</span><span class="p">(</span><span class="n">content</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">))</span>
|
||||
</code></pre></div>
|
||||
<p>The variable 'content', will contain the strategy file in a BASE64 encoded form. Which can now be set in your configurations file as following</p>
|
||||
<p><code>json
|
||||
"strategy": "NameOfStrategy:BASE64String"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"strategy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"NameOfStrategy:BASE64String"</span>
|
||||
</code></pre></div>
|
||||
<p>Please ensure that 'NameOfStrategy' is identical to the strategy name!</p>
|
||||
<h2 id="performance-warning">Performance warning<a class="headerlink" href="#performance-warning" title="Permanent link">¶</a></h2>
|
||||
<p>When executing a strategy, one can sometimes be greeted by the following in the logs</p>
|
||||
@@ -2387,19 +2380,19 @@ content = urlsafe_b64encode(content.encode('utf-8'))
|
||||
use <code>pd.concat(axis=1)</code>.
|
||||
This can have slight performance implications, which are usually only visible during hyperopt (when optimizing an indicator).</p>
|
||||
<p>For example:</p>
|
||||
<p><code>python
|
||||
for val in self.buy_ema_short.range:
|
||||
dataframe[f'ema_short_{val}'] = ta.EMA(dataframe, timeperiod=val)</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">buy_ema_short</span><span class="o">.</span><span class="n">range</span><span class="p">:</span>
|
||||
<span class="n">dataframe</span><span class="p">[</span><span class="sa">f</span><span class="s1">'ema_short_</span><span class="si">{</span><span class="n">val</span><span class="si">}</span><span class="s1">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ta</span><span class="o">.</span><span class="n">EMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">val</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>should be rewritten to</p>
|
||||
<p>```python
|
||||
frames = [dataframe]
|
||||
for val in self.buy_ema_short.range:
|
||||
frames.append(DataFrame({
|
||||
f'ema_short_{val}': ta.EMA(dataframe, timeperiod=val)
|
||||
}))</p>
|
||||
<h1 id="combine-all-dataframes-and-reassign-the-original-dataframe-column">Combine all dataframes, and reassign the original dataframe column<a class="headerlink" href="#combine-all-dataframes-and-reassign-the-original-dataframe-column" title="Permanent link">¶</a></h1>
|
||||
<p>dataframe = pd.concat(frames, axis=1)
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="n">frames</span> <span class="o">=</span> <span class="p">[</span><span class="n">dataframe</span><span class="p">]</span>
|
||||
<span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">buy_ema_short</span><span class="o">.</span><span class="n">range</span><span class="p">:</span>
|
||||
<span class="n">frames</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">DataFrame</span><span class="p">({</span>
|
||||
<span class="sa">f</span><span class="s1">'ema_short_</span><span class="si">{</span><span class="n">val</span><span class="si">}</span><span class="s1">'</span><span class="p">:</span> <span class="n">ta</span><span class="o">.</span><span class="n">EMA</span><span class="p">(</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">timeperiod</span><span class="o">=</span><span class="n">val</span><span class="p">)</span>
|
||||
<span class="p">}))</span>
|
||||
|
||||
<span class="c1"># Combine all dataframes, and reassign the original dataframe column</span>
|
||||
<span class="n">dataframe</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">concat</span><span class="p">(</span><span class="n">frames</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>Freqtrade does however also counter this by running <code>dataframe.copy()</code> on the dataframe right after the <code>populate_indicators()</code> method - so performance implications of this should be low to non-existent.</p>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1340,11 +1340,139 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#configure-freqtrade-environment" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Configure Freqtrade environment
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-and-run-strategy" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load and run strategy
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Load and run strategy">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#display-the-trade-details" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Display the trade details
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-existing-objects-into-a-jupyter-notebook" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load existing objects into a Jupyter notebook
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Load existing objects into a Jupyter notebook">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-backtest-results-to-pandas-dataframe" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load backtest results to pandas dataframe
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plotting-daily-profit-equity-line" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plotting daily profit / equity line
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Plotting daily profit / equity line">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-live-trading-results-into-a-pandas-dataframe" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load live trading results into a pandas dataframe
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#analyze-the-loaded-trades-for-trade-parallelism" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Analyze the loaded trades for trade parallelism
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plot-results" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plot results
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plot-average-profit-per-trade-as-distribution-graph" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plot average profit per trade as distribution graph
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1881,11 +2009,139 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#configure-freqtrade-environment" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Configure Freqtrade environment
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-and-run-strategy" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load and run strategy
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Load and run strategy">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#display-the-trade-details" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Display the trade details
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-existing-objects-into-a-jupyter-notebook" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load existing objects into a Jupyter notebook
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Load existing objects into a Jupyter notebook">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-backtest-results-to-pandas-dataframe" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load backtest results to pandas dataframe
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plotting-daily-profit-equity-line" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plotting daily profit / equity line
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Plotting daily profit / equity line">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#load-live-trading-results-into-a-pandas-dataframe" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Load live trading results into a pandas dataframe
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#analyze-the-loaded-trades-for-trade-parallelism" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Analyze the loaded trades for trade parallelism
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plot-results" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plot results
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#plot-average-profit-per-trade-as-distribution-graph" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Plot average profit per trade as distribution graph
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1919,73 +2175,81 @@ The following assumes you work with SampleStrategy, data for 5m timeframe from B
|
||||
Please follow the <a href="https://www.freqtrade.io/en/stable/data-download/">documentation</a> for more details.</p>
|
||||
<h2 id="setup">Setup<a class="headerlink" href="#setup" title="Permanent link">¶</a></h2>
|
||||
<h3 id="change-working-directory-to-repository-root">Change Working directory to repository root<a class="headerlink" href="#change-working-directory-to-repository-root" title="Permanent link">¶</a></h3>
|
||||
<p>```python
|
||||
import os
|
||||
from pathlib import Path</p>
|
||||
<h1 id="change-directory">Change directory<a class="headerlink" href="#change-directory" title="Permanent link">¶</a></h1>
|
||||
<h1 id="modify-this-cell-to-insure-that-the-output-shows-the-correct-path">Modify this cell to insure that the output shows the correct path.<a class="headerlink" href="#modify-this-cell-to-insure-that-the-output-shows-the-correct-path" title="Permanent link">¶</a></h1>
|
||||
<h1 id="define-all-paths-relative-to-the-project-root-shown-in-the-cell-output">Define all paths relative to the project root shown in the cell output<a class="headerlink" href="#define-all-paths-relative-to-the-project-root-shown-in-the-cell-output" title="Permanent link">¶</a></h1>
|
||||
<p>project_root = "somedir/freqtrade"
|
||||
i = 0
|
||||
try:
|
||||
os.chdir(project_root)
|
||||
if not Path("LICENSE").is_file():
|
||||
i = 0
|
||||
while i < 4 and (not Path("LICENSE").is_file()):
|
||||
os.chdir(Path(Path.cwd(), "../"))
|
||||
i += 1
|
||||
project_root = Path.cwd()
|
||||
except FileNotFoundError:
|
||||
print("Please define the project root relative to the current directory")
|
||||
print(Path.cwd())
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>
|
||||
|
||||
|
||||
<span class="c1"># Change directory</span>
|
||||
<span class="c1"># Modify this cell to insure that the output shows the correct path.</span>
|
||||
<span class="c1"># Define all paths relative to the project root shown in the cell output</span>
|
||||
<span class="n">project_root</span> <span class="o">=</span> <span class="s2">"somedir/freqtrade"</span>
|
||||
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">project_root</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">Path</span><span class="p">(</span><span class="s2">"LICENSE"</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
|
||||
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">4</span> <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="n">Path</span><span class="p">(</span><span class="s2">"LICENSE"</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">()):</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">Path</span><span class="p">(</span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">(),</span> <span class="s2">"../"</span><span class="p">))</span>
|
||||
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
<span class="n">project_root</span> <span class="o">=</span> <span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">()</span>
|
||||
<span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Please define the project root relative to the current directory"</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">())</span>
|
||||
</code></pre></div>
|
||||
<h3 id="configure-freqtrade-environment">Configure Freqtrade environment<a class="headerlink" href="#configure-freqtrade-environment" title="Permanent link">¶</a></h3>
|
||||
<p>```python
|
||||
from freqtrade.configuration import Configuration</p>
|
||||
<h1 id="customize-these-according-to-your-needs">Customize these according to your needs.<a class="headerlink" href="#customize-these-according-to-your-needs" title="Permanent link">¶</a></h1>
|
||||
<h1 id="initialize-empty-configuration-object">Initialize empty configuration object<a class="headerlink" href="#initialize-empty-configuration-object" title="Permanent link">¶</a></h1>
|
||||
<p>config = Configuration.from_files([])</p>
|
||||
<h1 id="optionally-recommended-use-existing-configuration-file">Optionally (recommended), use existing configuration file<a class="headerlink" href="#optionally-recommended-use-existing-configuration-file" title="Permanent link">¶</a></h1>
|
||||
<h1 id="config-configurationfrom_filesuser_dataconfigjson">config = Configuration.from_files(["user_data/config.json"])<a class="headerlink" href="#config-configurationfrom_filesuser_dataconfigjson" title="Permanent link">¶</a></h1>
|
||||
<h1 id="define-some-constants">Define some constants<a class="headerlink" href="#define-some-constants" title="Permanent link">¶</a></h1>
|
||||
<p>config["timeframe"] = "5m"</p>
|
||||
<h1 id="name-of-the-strategy-class">Name of the strategy class<a class="headerlink" href="#name-of-the-strategy-class" title="Permanent link">¶</a></h1>
|
||||
<p>config["strategy"] = "SampleStrategy"</p>
|
||||
<h1 id="location-of-the-data">Location of the data<a class="headerlink" href="#location-of-the-data" title="Permanent link">¶</a></h1>
|
||||
<p>data_location = config["datadir"]</p>
|
||||
<h1 id="pair-to-analyze-only-use-one-pair-here">Pair to analyze - Only use one pair here<a class="headerlink" href="#pair-to-analyze-only-use-one-pair-here" title="Permanent link">¶</a></h1>
|
||||
<p>pair = "BTC/USDT"
|
||||
```</p>
|
||||
<p>```python</p>
|
||||
<h1 id="load-data-using-values-set-above">Load data using values set above<a class="headerlink" href="#load-data-using-values-set-above" title="Permanent link">¶</a></h1>
|
||||
<p>from freqtrade.data.history import load_pair_history
|
||||
from freqtrade.enums import CandleType</p>
|
||||
<p>candles = load_pair_history(
|
||||
datadir=data_location,
|
||||
timeframe=config["timeframe"],
|
||||
pair=pair,
|
||||
data_format="json", # Make sure to update this to your data
|
||||
candle_type=CandleType.SPOT,
|
||||
)</p>
|
||||
<h1 id="confirm-success">Confirm success<a class="headerlink" href="#confirm-success" title="Permanent link">¶</a></h1>
|
||||
<p>print(f"Loaded {len(candles)} rows of data for {pair} from {data_location}")
|
||||
candles.head()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">Configuration</span>
|
||||
|
||||
|
||||
<span class="c1"># Customize these according to your needs.</span>
|
||||
|
||||
<span class="c1"># Initialize empty configuration object</span>
|
||||
<span class="n">config</span> <span class="o">=</span> <span class="n">Configuration</span><span class="o">.</span><span class="n">from_files</span><span class="p">([])</span>
|
||||
<span class="c1"># Optionally (recommended), use existing configuration file</span>
|
||||
<span class="c1"># config = Configuration.from_files(["user_data/config.json"])</span>
|
||||
|
||||
<span class="c1"># Define some constants</span>
|
||||
<span class="n">config</span><span class="p">[</span><span class="s2">"timeframe"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"5m"</span>
|
||||
<span class="c1"># Name of the strategy class</span>
|
||||
<span class="n">config</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"SampleStrategy"</span>
|
||||
<span class="c1"># Location of the data</span>
|
||||
<span class="n">data_location</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s2">"datadir"</span><span class="p">]</span>
|
||||
<span class="c1"># Pair to analyze - Only use one pair here</span>
|
||||
<span class="n">pair</span> <span class="o">=</span> <span class="s2">"BTC/USDT"</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Load data using values set above</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.history</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_pair_history</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.enums</span><span class="w"> </span><span class="kn">import</span> <span class="n">CandleType</span>
|
||||
|
||||
|
||||
<span class="n">candles</span> <span class="o">=</span> <span class="n">load_pair_history</span><span class="p">(</span>
|
||||
<span class="n">datadir</span><span class="o">=</span><span class="n">data_location</span><span class="p">,</span>
|
||||
<span class="n">timeframe</span><span class="o">=</span><span class="n">config</span><span class="p">[</span><span class="s2">"timeframe"</span><span class="p">],</span>
|
||||
<span class="n">pair</span><span class="o">=</span><span class="n">pair</span><span class="p">,</span>
|
||||
<span class="n">data_format</span><span class="o">=</span><span class="s2">"json"</span><span class="p">,</span> <span class="c1"># Make sure to update this to your data</span>
|
||||
<span class="n">candle_type</span><span class="o">=</span><span class="n">CandleType</span><span class="o">.</span><span class="n">SPOT</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># Confirm success</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Loaded </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">candles</span><span class="p">)</span><span class="si">}</span><span class="s2"> rows of data for </span><span class="si">{</span><span class="n">pair</span><span class="si">}</span><span class="s2"> from </span><span class="si">{</span><span class="n">data_location</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">candles</span><span class="o">.</span><span class="n">head</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="load-and-run-strategy">Load and run strategy<a class="headerlink" href="#load-and-run-strategy" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li>Rerun each time the strategy file is changed</li>
|
||||
</ul>
|
||||
<p>```python</p>
|
||||
<h1 id="load-strategy-using-values-set-above">Load strategy using values set above<a class="headerlink" href="#load-strategy-using-values-set-above" title="Permanent link">¶</a></h1>
|
||||
<p>from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.resolvers import StrategyResolver</p>
|
||||
<p>strategy = StrategyResolver.load_strategy(config)
|
||||
strategy.dp = DataProvider(config, None, None)
|
||||
strategy.ft_bot_start()</p>
|
||||
<h1 id="generate-buysell-signals-using-strategy">Generate buy/sell signals using strategy<a class="headerlink" href="#generate-buysell-signals-using-strategy" title="Permanent link">¶</a></h1>
|
||||
<p>df = strategy.analyze_ticker(candles, {"pair": pair})
|
||||
df.tail()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Load strategy using values set above</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.dataprovider</span><span class="w"> </span><span class="kn">import</span> <span class="n">DataProvider</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.resolvers</span><span class="w"> </span><span class="kn">import</span> <span class="n">StrategyResolver</span>
|
||||
|
||||
|
||||
<span class="n">strategy</span> <span class="o">=</span> <span class="n">StrategyResolver</span><span class="o">.</span><span class="n">load_strategy</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
|
||||
<span class="n">strategy</span><span class="o">.</span><span class="n">dp</span> <span class="o">=</span> <span class="n">DataProvider</span><span class="p">(</span><span class="n">config</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="n">strategy</span><span class="o">.</span><span class="n">ft_bot_start</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Generate buy/sell signals using strategy</span>
|
||||
<span class="n">df</span> <span class="o">=</span> <span class="n">strategy</span><span class="o">.</span><span class="n">analyze_ticker</span><span class="p">(</span><span class="n">candles</span><span class="p">,</span> <span class="p">{</span><span class="s2">"pair"</span><span class="p">:</span> <span class="n">pair</span><span class="p">})</span>
|
||||
<span class="n">df</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h3 id="display-the-trade-details">Display the trade details<a class="headerlink" href="#display-the-trade-details" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
<li>Note that using <code>data.head()</code> would also work, however most indicators have some "startup" data at the top of the dataframe.</li>
|
||||
@@ -1996,119 +2260,136 @@ df.tail()
|
||||
* having 200 buy signals as output for one pair from <code>analyze_ticker()</code> does not necessarily mean that 200 trades will be made during backtesting.
|
||||
* Assuming you use only one condition such as, <code>df['rsi'] < 30</code> as buy condition, this will generate multiple "buy" signals for each pair in sequence (until rsi returns > 29). The bot will only buy on the first of these signals (and also only if a trade-slot ("max_open_trades") is still available), or on one of the middle signals, as soon as a "slot" becomes available. </li>
|
||||
</ul>
|
||||
<p>```python</p>
|
||||
<h1 id="report-results">Report results<a class="headerlink" href="#report-results" title="Permanent link">¶</a></h1>
|
||||
<p>print(f"Generated {df['enter_long'].sum()} entry signals")
|
||||
data = df.set_index("date", drop=False)
|
||||
data.tail()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Report results</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Generated </span><span class="si">{</span><span class="n">df</span><span class="p">[</span><span class="s1">'enter_long'</span><span class="p">]</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span><span class="si">}</span><span class="s2"> entry signals"</span><span class="p">)</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">set_index</span><span class="p">(</span><span class="s2">"date"</span><span class="p">,</span> <span class="n">drop</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">data</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="load-existing-objects-into-a-jupyter-notebook">Load existing objects into a Jupyter notebook<a class="headerlink" href="#load-existing-objects-into-a-jupyter-notebook" title="Permanent link">¶</a></h2>
|
||||
<p>The following cells assume that you have already generated data using the cli.<br />
|
||||
They will allow you to drill deeper into your results, and perform analysis which otherwise would make the output very difficult to digest due to information overload.</p>
|
||||
<h3 id="load-backtest-results-to-pandas-dataframe">Load backtest results to pandas dataframe<a class="headerlink" href="#load-backtest-results-to-pandas-dataframe" title="Permanent link">¶</a></h3>
|
||||
<p>Analyze a trades dataframe (also used below for plotting)</p>
|
||||
<p>```python
|
||||
from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats</p>
|
||||
<h1 id="if-backtest_dir-points-to-a-directory-itll-automatically-load-the-last-backtest-file">if backtest_dir points to a directory, it'll automatically load the last backtest file.<a class="headerlink" href="#if-backtest_dir-points-to-a-directory-itll-automatically-load-the-last-backtest-file" title="Permanent link">¶</a></h1>
|
||||
<p>backtest_dir = config["user_data_dir"] / "backtest_results"</p>
|
||||
<h1 id="backtest_dir-can-also-point-to-a-specific-file">backtest_dir can also point to a specific file<a class="headerlink" href="#backtest_dir-can-also-point-to-a-specific-file" title="Permanent link">¶</a></h1>
|
||||
<h1 id="backtest_dir">backtest_dir = (<a class="headerlink" href="#backtest_dir" title="Permanent link">¶</a></h1>
|
||||
<h1 id="configuser_data_dir-backtest_resultsbacktest-result-2020-07-01_20-04-22json">config["user_data_dir"] / "backtest_results/backtest-result-2020-07-01_20-04-22.json"<a class="headerlink" href="#configuser_data_dir-backtest_resultsbacktest-result-2020-07-01_20-04-22json" title="Permanent link">¶</a></h1>
|
||||
<h1 id="_1">)<a class="headerlink" href="#_1" title="Permanent link">¶</a></h1>
|
||||
<p>```</p>
|
||||
<p>```python</p>
|
||||
<h1 id="you-can-get-the-full-backtest-statistics-by-using-the-following-command">You can get the full backtest statistics by using the following command.<a class="headerlink" href="#you-can-get-the-full-backtest-statistics-by-using-the-following-command" title="Permanent link">¶</a></h1>
|
||||
<h1 id="this-contains-all-information-used-to-generate-the-backtest-result">This contains all information used to generate the backtest result.<a class="headerlink" href="#this-contains-all-information-used-to-generate-the-backtest-result" title="Permanent link">¶</a></h1>
|
||||
<p>stats = load_backtest_stats(backtest_dir)</p>
|
||||
<p>strategy = "SampleStrategy"</p>
|
||||
<h1 id="all-statistics-are-available-per-strategy-so-if-strategy-list-was-used-during-backtest">All statistics are available per strategy, so if <code>--strategy-list</code> was used during backtest,<a class="headerlink" href="#all-statistics-are-available-per-strategy-so-if-strategy-list-was-used-during-backtest" title="Permanent link">¶</a></h1>
|
||||
<h1 id="this-will-be-reflected-here-as-well">this will be reflected here as well.<a class="headerlink" href="#this-will-be-reflected-here-as-well" title="Permanent link">¶</a></h1>
|
||||
<h1 id="example-usages">Example usages:<a class="headerlink" href="#example-usages" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy"][strategy]["results_per_pair"])</p>
|
||||
<h1 id="get-pairlist-used-for-this-backtest">Get pairlist used for this backtest<a class="headerlink" href="#get-pairlist-used-for-this-backtest" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy"][strategy]["pairlist"])</p>
|
||||
<h1 id="get-market-change-average-change-of-all-pairs-from-start-to-end-of-the-backtest-period">Get market change (average change of all pairs from start to end of the backtest period)<a class="headerlink" href="#get-market-change-average-change-of-all-pairs-from-start-to-end-of-the-backtest-period" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy"][strategy]["market_change"])</p>
|
||||
<h1 id="maximum-drawdown">Maximum drawdown ()<a class="headerlink" href="#maximum-drawdown" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy"][strategy]["max_drawdown_abs"])</p>
|
||||
<h1 id="maximum-drawdown-start-and-end">Maximum drawdown start and end<a class="headerlink" href="#maximum-drawdown-start-and-end" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy"][strategy]["drawdown_start"])
|
||||
print(stats["strategy"][strategy]["drawdown_end"])</p>
|
||||
<h1 id="get-strategy-comparison-only-relevant-if-multiple-strategies-were-compared">Get strategy comparison (only relevant if multiple strategies were compared)<a class="headerlink" href="#get-strategy-comparison-only-relevant-if-multiple-strategies-were-compared" title="Permanent link">¶</a></h1>
|
||||
<p>print(stats["strategy_comparison"])
|
||||
```</p>
|
||||
<p>```python</p>
|
||||
<h1 id="load-backtested-trades-as-dataframe">Load backtested trades as dataframe<a class="headerlink" href="#load-backtested-trades-as-dataframe" title="Permanent link">¶</a></h1>
|
||||
<p>trades = load_backtest_data(backtest_dir)</p>
|
||||
<h1 id="show-value-counts-per-pair">Show value-counts per pair<a class="headerlink" href="#show-value-counts-per-pair" title="Permanent link">¶</a></h1>
|
||||
<p>trades.groupby("pair")["exit_reason"].value_counts()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.btanalysis</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_backtest_data</span><span class="p">,</span> <span class="n">load_backtest_stats</span>
|
||||
|
||||
|
||||
<span class="c1"># if backtest_dir points to a directory, it'll automatically load the last backtest file.</span>
|
||||
<span class="n">backtest_dir</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="s2">"user_data_dir"</span><span class="p">]</span> <span class="o">/</span> <span class="s2">"backtest_results"</span>
|
||||
<span class="c1"># backtest_dir can also point to a specific file</span>
|
||||
<span class="c1"># backtest_dir = (</span>
|
||||
<span class="c1"># config["user_data_dir"] / "backtest_results/backtest-result-2020-07-01_20-04-22.json"</span>
|
||||
<span class="c1"># )</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># You can get the full backtest statistics by using the following command.</span>
|
||||
<span class="c1"># This contains all information used to generate the backtest result.</span>
|
||||
<span class="n">stats</span> <span class="o">=</span> <span class="n">load_backtest_stats</span><span class="p">(</span><span class="n">backtest_dir</span><span class="p">)</span>
|
||||
|
||||
<span class="n">strategy</span> <span class="o">=</span> <span class="s2">"SampleStrategy"</span>
|
||||
<span class="c1"># All statistics are available per strategy, so if `--strategy-list` was used during backtest,</span>
|
||||
<span class="c1"># this will be reflected here as well.</span>
|
||||
<span class="c1"># Example usages:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"results_per_pair"</span><span class="p">])</span>
|
||||
<span class="c1"># Get pairlist used for this backtest</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"pairlist"</span><span class="p">])</span>
|
||||
<span class="c1"># Get market change (average change of all pairs from start to end of the backtest period)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"market_change"</span><span class="p">])</span>
|
||||
<span class="c1"># Maximum drawdown ()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"max_drawdown_abs"</span><span class="p">])</span>
|
||||
<span class="c1"># Maximum drawdown start and end</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"drawdown_start"</span><span class="p">])</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">][</span><span class="s2">"drawdown_end"</span><span class="p">])</span>
|
||||
|
||||
|
||||
<span class="c1"># Get strategy comparison (only relevant if multiple strategies were compared)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">stats</span><span class="p">[</span><span class="s2">"strategy_comparison"</span><span class="p">])</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Load backtested trades as dataframe</span>
|
||||
<span class="n">trades</span> <span class="o">=</span> <span class="n">load_backtest_data</span><span class="p">(</span><span class="n">backtest_dir</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Show value-counts per pair</span>
|
||||
<span class="n">trades</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="s2">"pair"</span><span class="p">)[</span><span class="s2">"exit_reason"</span><span class="p">]</span><span class="o">.</span><span class="n">value_counts</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="plotting-daily-profit-equity-line">Plotting daily profit / equity line<a class="headerlink" href="#plotting-daily-profit-equity-line" title="Permanent link">¶</a></h2>
|
||||
<p>```python</p>
|
||||
<h1 id="plotting-equity-line-starting-with-0-on-day-1-and-adding-daily-profit-for-each-backtested-day">Plotting equity line (starting with 0 on day 1 and adding daily profit for each backtested day)<a class="headerlink" href="#plotting-equity-line-starting-with-0-on-day-1-and-adding-daily-profit-for-each-backtested-day" title="Permanent link">¶</a></h1>
|
||||
<p>import pandas as pd
|
||||
import plotly.express as px</p>
|
||||
<p>from freqtrade.configuration import Configuration
|
||||
from freqtrade.data.btanalysis import load_backtest_stats</p>
|
||||
<h1 id="strategy-samplestrategy">strategy = 'SampleStrategy'<a class="headerlink" href="#strategy-samplestrategy" title="Permanent link">¶</a></h1>
|
||||
<h1 id="config-configurationfrom_filesuser_dataconfigjson_1">config = Configuration.from_files(["user_data/config.json"])<a class="headerlink" href="#config-configurationfrom_filesuser_dataconfigjson_1" title="Permanent link">¶</a></h1>
|
||||
<h1 id="backtest_dir-configuser_data_dir-backtest_results">backtest_dir = config["user_data_dir"] / "backtest_results"<a class="headerlink" href="#backtest_dir-configuser_data_dir-backtest_results" title="Permanent link">¶</a></h1>
|
||||
<p>stats = load_backtest_stats(backtest_dir)
|
||||
strategy_stats = stats["strategy"][strategy]</p>
|
||||
<p>df = pd.DataFrame(columns=["dates", "equity"], data=strategy_stats["daily_profit"])
|
||||
df["equity_daily"] = df["equity"].cumsum()</p>
|
||||
<p>fig = px.line(df, x="dates", y="equity_daily")
|
||||
fig.show()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Plotting equity line (starting with 0 on day 1 and adding daily profit for each backtested day)</span>
|
||||
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">pandas</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">pd</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">plotly.express</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">px</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.configuration</span><span class="w"> </span><span class="kn">import</span> <span class="n">Configuration</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.btanalysis</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_backtest_stats</span>
|
||||
|
||||
|
||||
<span class="c1"># strategy = 'SampleStrategy'</span>
|
||||
<span class="c1"># config = Configuration.from_files(["user_data/config.json"])</span>
|
||||
<span class="c1"># backtest_dir = config["user_data_dir"] / "backtest_results"</span>
|
||||
|
||||
<span class="n">stats</span> <span class="o">=</span> <span class="n">load_backtest_stats</span><span class="p">(</span><span class="n">backtest_dir</span><span class="p">)</span>
|
||||
<span class="n">strategy_stats</span> <span class="o">=</span> <span class="n">stats</span><span class="p">[</span><span class="s2">"strategy"</span><span class="p">][</span><span class="n">strategy</span><span class="p">]</span>
|
||||
|
||||
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">columns</span><span class="o">=</span><span class="p">[</span><span class="s2">"dates"</span><span class="p">,</span> <span class="s2">"equity"</span><span class="p">],</span> <span class="n">data</span><span class="o">=</span><span class="n">strategy_stats</span><span class="p">[</span><span class="s2">"daily_profit"</span><span class="p">])</span>
|
||||
<span class="n">df</span><span class="p">[</span><span class="s2">"equity_daily"</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s2">"equity"</span><span class="p">]</span><span class="o">.</span><span class="n">cumsum</span><span class="p">()</span>
|
||||
|
||||
<span class="n">fig</span> <span class="o">=</span> <span class="n">px</span><span class="o">.</span><span class="n">line</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="s2">"dates"</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="s2">"equity_daily"</span><span class="p">)</span>
|
||||
<span class="n">fig</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h3 id="load-live-trading-results-into-a-pandas-dataframe">Load live trading results into a pandas dataframe<a class="headerlink" href="#load-live-trading-results-into-a-pandas-dataframe" title="Permanent link">¶</a></h3>
|
||||
<p>In case you did already some trading and want to analyze your performance</p>
|
||||
<p>```python
|
||||
from freqtrade.data.btanalysis import load_trades_from_db</p>
|
||||
<h1 id="fetch-trades-from-database">Fetch trades from database<a class="headerlink" href="#fetch-trades-from-database" title="Permanent link">¶</a></h1>
|
||||
<p>trades = load_trades_from_db("sqlite:///tradesv3.sqlite")</p>
|
||||
<h1 id="display-results">Display results<a class="headerlink" href="#display-results" title="Permanent link">¶</a></h1>
|
||||
<p>trades.groupby("pair")["exit_reason"].value_counts()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.btanalysis</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_trades_from_db</span>
|
||||
|
||||
|
||||
<span class="c1"># Fetch trades from database</span>
|
||||
<span class="n">trades</span> <span class="o">=</span> <span class="n">load_trades_from_db</span><span class="p">(</span><span class="s2">"sqlite:///tradesv3.sqlite"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Display results</span>
|
||||
<span class="n">trades</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="s2">"pair"</span><span class="p">)[</span><span class="s2">"exit_reason"</span><span class="p">]</span><span class="o">.</span><span class="n">value_counts</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="analyze-the-loaded-trades-for-trade-parallelism">Analyze the loaded trades for trade parallelism<a class="headerlink" href="#analyze-the-loaded-trades-for-trade-parallelism" title="Permanent link">¶</a></h2>
|
||||
<p>This can be useful to find the best <code>max_open_trades</code> parameter, when used with backtesting in conjunction with a very high <code>max_open_trades</code> setting.</p>
|
||||
<p><code>analyze_trade_parallelism()</code> returns a timeseries dataframe with an "open_trades" column, specifying the number of open trades for each candle.</p>
|
||||
<p>```python
|
||||
from freqtrade.data.btanalysis import analyze_trade_parallelism</p>
|
||||
<h1 id="analyze-the-above">Analyze the above<a class="headerlink" href="#analyze-the-above" title="Permanent link">¶</a></h1>
|
||||
<p>parallel_trades = analyze_trade_parallelism(trades, "5m")</p>
|
||||
<p>parallel_trades.plot()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.data.btanalysis</span><span class="w"> </span><span class="kn">import</span> <span class="n">analyze_trade_parallelism</span>
|
||||
|
||||
|
||||
<span class="c1"># Analyze the above</span>
|
||||
<span class="n">parallel_trades</span> <span class="o">=</span> <span class="n">analyze_trade_parallelism</span><span class="p">(</span><span class="n">trades</span><span class="p">,</span> <span class="s2">"5m"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">parallel_trades</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="plot-results">Plot results<a class="headerlink" href="#plot-results" title="Permanent link">¶</a></h2>
|
||||
<p>Freqtrade offers interactive plotting capabilities based on plotly.</p>
|
||||
<p>```python
|
||||
from freqtrade.plot.plotting import generate_candlestick_graph</p>
|
||||
<h1 id="limit-graph-period-to-keep-plotly-quick-and-reactive">Limit graph period to keep plotly quick and reactive<a class="headerlink" href="#limit-graph-period-to-keep-plotly-quick-and-reactive" title="Permanent link">¶</a></h1>
|
||||
<h1 id="filter-trades-to-one-pair">Filter trades to one pair<a class="headerlink" href="#filter-trades-to-one-pair" title="Permanent link">¶</a></h1>
|
||||
<p>trades_red = trades.loc[trades["pair"] == pair]</p>
|
||||
<p>data_red = data["2019-06-01":"2019-06-10"]</p>
|
||||
<h1 id="generate-candlestick-graph">Generate candlestick graph<a class="headerlink" href="#generate-candlestick-graph" title="Permanent link">¶</a></h1>
|
||||
<p>graph = generate_candlestick_graph(
|
||||
pair=pair,
|
||||
data=data_red,
|
||||
trades=trades_red,
|
||||
indicators1=["sma20", "ema50", "ema55"],
|
||||
indicators2=["rsi", "macd", "macdsignal", "macdhist"],
|
||||
)
|
||||
```</p>
|
||||
<p>```python</p>
|
||||
<h1 id="show-graph-inline">Show graph inline<a class="headerlink" href="#show-graph-inline" title="Permanent link">¶</a></h1>
|
||||
<h1 id="graphshow">graph.show()<a class="headerlink" href="#graphshow" title="Permanent link">¶</a></h1>
|
||||
<h1 id="render-graph-in-a-separate-window">Render graph in a separate window<a class="headerlink" href="#render-graph-in-a-separate-window" title="Permanent link">¶</a></h1>
|
||||
<p>graph.show(renderer="browser")
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.plot.plotting</span><span class="w"> </span><span class="kn">import</span> <span class="n">generate_candlestick_graph</span>
|
||||
|
||||
|
||||
<span class="c1"># Limit graph period to keep plotly quick and reactive</span>
|
||||
|
||||
<span class="c1"># Filter trades to one pair</span>
|
||||
<span class="n">trades_red</span> <span class="o">=</span> <span class="n">trades</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">trades</span><span class="p">[</span><span class="s2">"pair"</span><span class="p">]</span> <span class="o">==</span> <span class="n">pair</span><span class="p">]</span>
|
||||
|
||||
<span class="n">data_red</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">"2019-06-01"</span><span class="p">:</span><span class="s2">"2019-06-10"</span><span class="p">]</span>
|
||||
<span class="c1"># Generate candlestick graph</span>
|
||||
<span class="n">graph</span> <span class="o">=</span> <span class="n">generate_candlestick_graph</span><span class="p">(</span>
|
||||
<span class="n">pair</span><span class="o">=</span><span class="n">pair</span><span class="p">,</span>
|
||||
<span class="n">data</span><span class="o">=</span><span class="n">data_red</span><span class="p">,</span>
|
||||
<span class="n">trades</span><span class="o">=</span><span class="n">trades_red</span><span class="p">,</span>
|
||||
<span class="n">indicators1</span><span class="o">=</span><span class="p">[</span><span class="s2">"sma20"</span><span class="p">,</span> <span class="s2">"ema50"</span><span class="p">,</span> <span class="s2">"ema55"</span><span class="p">],</span>
|
||||
<span class="n">indicators2</span><span class="o">=</span><span class="p">[</span><span class="s2">"rsi"</span><span class="p">,</span> <span class="s2">"macd"</span><span class="p">,</span> <span class="s2">"macdsignal"</span><span class="p">,</span> <span class="s2">"macdhist"</span><span class="p">],</span>
|
||||
<span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<div class="highlight"><pre><span></span><code><span class="c1"># Show graph inline</span>
|
||||
<span class="c1"># graph.show()</span>
|
||||
|
||||
<span class="c1"># Render graph in a separate window</span>
|
||||
<span class="n">graph</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="n">renderer</span><span class="o">=</span><span class="s2">"browser"</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<h2 id="plot-average-profit-per-trade-as-distribution-graph">Plot average profit per trade as distribution graph<a class="headerlink" href="#plot-average-profit-per-trade-as-distribution-graph" title="Permanent link">¶</a></h2>
|
||||
<p>```python
|
||||
import plotly.figure_factory as ff</p>
|
||||
<p>hist_data = [trades.profit_ratio]
|
||||
group_labels = ["profit_ratio"] # name of the dataset</p>
|
||||
<p>fig = ff.create_distplot(hist_data, group_labels, bin_size=0.01)
|
||||
fig.show()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">plotly.figure_factory</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">ff</span>
|
||||
|
||||
|
||||
<span class="n">hist_data</span> <span class="o">=</span> <span class="p">[</span><span class="n">trades</span><span class="o">.</span><span class="n">profit_ratio</span><span class="p">]</span>
|
||||
<span class="n">group_labels</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"profit_ratio"</span><span class="p">]</span> <span class="c1"># name of the dataset</span>
|
||||
|
||||
<span class="n">fig</span> <span class="o">=</span> <span class="n">ff</span><span class="o">.</span><span class="n">create_distplot</span><span class="p">(</span><span class="n">hist_data</span><span class="p">,</span> <span class="n">group_labels</span><span class="p">,</span> <span class="n">bin_size</span><span class="o">=</span><span class="mf">0.01</span><span class="p">)</span>
|
||||
<span class="n">fig</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<p>Feel free to submit an issue or Pull Request enhancing this document if you would like to share ideas on how to best analyze the data.</p>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2611,16 +2611,16 @@ Telegram user id.</p>
|
||||
This will return the group id to you, without having to use some random bot.
|
||||
While "chat_id" is still required, it doesn't need to be set to this particular group id for this command.</p>
|
||||
<p>The response will also contain the "topic_id" if necessary - both in a format ready to copy/paste into your configuration.</p>
|
||||
<p><code>json
|
||||
{
|
||||
"enabled": true,
|
||||
"token": "********",
|
||||
"chat_id": "-1001332619709",
|
||||
"topic_id": "122"
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"********"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-1001332619709"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"topic_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"122"</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>For the Freqtrade configuration, you can then use the full value (including <code>-</code> ) as string:</p>
|
||||
<p><code>json
|
||||
"chat_id": "-1001332619709"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-1001332619709"</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Using telegram groups</p>
|
||||
<p>When using telegram groups, you're giving every member of the telegram group access to your freqtrade bot and to all commands possible via telegram. Please make sure that you can trust everyone in the telegram group to avoid unpleasant surprises.</p>
|
||||
@@ -2628,18 +2628,18 @@ While "chat_id" is still required, it doesn't need to be set to this particular
|
||||
<h5 id="group-topic-id">Group Topic ID<a class="headerlink" href="#group-topic-id" title="Permanent link">¶</a></h5>
|
||||
<p>To use a specific topic in a group, you can use the <code>topic_id</code> parameter in the configuration. This will allow you to use the bot in a specific topic in a group.<br />
|
||||
Without this, the bot will always respond to the general channel in the group if topics are enabled for a group chat.</p>
|
||||
<p><code>json
|
||||
"chat_id": "-1001332619709",
|
||||
"topic_id": "3"</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-1001332619709"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"topic_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3"</span>
|
||||
</code></pre></div>
|
||||
<p>Similar to the group-id - you can use <code>/tg_info</code> from the topic/thread to get the correct topic-id.</p>
|
||||
<h4 id="authorized-users">Authorized users<a class="headerlink" href="#authorized-users" title="Permanent link">¶</a></h4>
|
||||
<p>For groups, it can be useful to limit who can send commands to the bot.</p>
|
||||
<p>If <code>"authorized_users": []</code> is present and empty, no user will be allowed to control the bot.
|
||||
In the below example, only the user with the id "1234567" is allowed to control the bot - all other users will only be able to receive messages.</p>
|
||||
<p><code>json
|
||||
"chat_id": "-1001332619709",
|
||||
"topic_id": "3",
|
||||
"authorized_users": ["1234567"]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-1001332619709"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"topic_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"authorized_users"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"1234567"</span><span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<h2 id="control-telegram-noise">Control telegram noise<a class="headerlink" href="#control-telegram-noise" title="Permanent link">¶</a></h2>
|
||||
<p>Freqtrade provides means to control the verbosity of your telegram bot.
|
||||
Each setting has the following possible values:</p>
|
||||
@@ -2649,43 +2649,43 @@ Each setting has the following possible values:</p>
|
||||
<li><code>off</code> - Skip sending a message-type all together.</li>
|
||||
</ul>
|
||||
<p>Example configuration showing the different settings:</p>
|
||||
<p><code>json
|
||||
"telegram": {
|
||||
"enabled": true,
|
||||
"token": "your_telegram_token",
|
||||
"chat_id": "your_telegram_chat_id",
|
||||
"allow_custom_messages": true,
|
||||
"notification_settings": {
|
||||
"status": "silent",
|
||||
"warning": "on",
|
||||
"startup": "off",
|
||||
"entry": "silent",
|
||||
"entry_fill": "on",
|
||||
"entry_cancel": "silent",
|
||||
"exit": {
|
||||
"roi": "silent",
|
||||
"emergency_exit": "on",
|
||||
"force_exit": "on",
|
||||
"exit_signal": "silent",
|
||||
"trailing_stop_loss": "on",
|
||||
"stop_loss": "on",
|
||||
"stoploss_on_exchange": "on",
|
||||
"custom_exit": "silent", // custom_exit without specifying an exit reason
|
||||
"partial_exit": "on",
|
||||
// "custom_exit_message": "silent", // Disable individual custom exit reasons
|
||||
"*": "off" // Disable all other exit reasons
|
||||
},
|
||||
// "exit": "off", // Simplistic configuration to disable all exit messages
|
||||
"exit_cancel": "on",
|
||||
"exit_fill": "off",
|
||||
"protection_trigger": "off",
|
||||
"protection_trigger_global": "on",
|
||||
"strategy_msg": "off",
|
||||
"show_candle": "off"
|
||||
},
|
||||
"reload": true,
|
||||
"balance_dust_level": 0.01
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_telegram_token"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_telegram_chat_id"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"allow_custom_messages"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"notification_settings"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"warning"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"startup"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"entry"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"entry_fill"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"entry_cancel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"exit"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"roi"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"emergency_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"force_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"exit_signal"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"trailing_stop_loss"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"stop_loss"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"stoploss_on_exchange"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"custom_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="p">,</span><span class="w"> </span><span class="c1">// custom_exit without specifying an exit reason</span>
|
||||
<span class="w"> </span><span class="nt">"partial_exit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="c1">// "custom_exit_message": "silent", // Disable individual custom exit reasons</span>
|
||||
<span class="w"> </span><span class="nt">"*"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span><span class="w"> </span><span class="c1">// Disable all other exit reasons</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="c1">// "exit": "off", // Simplistic configuration to disable all exit messages</span>
|
||||
<span class="w"> </span><span class="nt">"exit_cancel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"exit_fill"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"protection_trigger"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"protection_trigger_global"</span><span class="p">:</span><span class="w"> </span><span class="s2">"on"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"strategy_msg"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"show_candle"</span><span class="p">:</span><span class="w"> </span><span class="s2">"off"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"reload"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"balance_dust_level"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.01</span>
|
||||
<span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<ul>
|
||||
<li><code>entry</code> notifications are sent when the order is placed, while <code>entry_fill</code> notifications are sent when the order is filled on the exchange. </li>
|
||||
<li><code>exit</code> notifications are sent when the order is placed, while <code>exit_fill</code> notifications are sent when the order is filled on the exchange.<br />
|
||||
@@ -2701,25 +2701,25 @@ Each setting has the following possible values:</p>
|
||||
<h2 id="create-a-custom-keyboard-command-shortcut-buttons">Create a custom keyboard (command shortcut buttons)<a class="headerlink" href="#create-a-custom-keyboard-command-shortcut-buttons" title="Permanent link">¶</a></h2>
|
||||
<p>Telegram allows us to create a custom keyboard with buttons for commands.
|
||||
The default custom keyboard looks like this.</p>
|
||||
<p><code>python
|
||||
[
|
||||
["/daily", "/profit", "/balance"], # row 1, 3 commands
|
||||
["/status", "/status table", "/performance"], # row 2, 3 commands
|
||||
["/count", "/start", "/stop", "/help"] # row 3, 4 commands
|
||||
]</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">[</span>
|
||||
<span class="p">[</span><span class="s2">"/daily"</span><span class="p">,</span> <span class="s2">"/profit"</span><span class="p">,</span> <span class="s2">"/balance"</span><span class="p">],</span> <span class="c1"># row 1, 3 commands</span>
|
||||
<span class="p">[</span><span class="s2">"/status"</span><span class="p">,</span> <span class="s2">"/status table"</span><span class="p">,</span> <span class="s2">"/performance"</span><span class="p">],</span> <span class="c1"># row 2, 3 commands</span>
|
||||
<span class="p">[</span><span class="s2">"/count"</span><span class="p">,</span> <span class="s2">"/start"</span><span class="p">,</span> <span class="s2">"/stop"</span><span class="p">,</span> <span class="s2">"/help"</span><span class="p">]</span> <span class="c1"># row 3, 4 commands</span>
|
||||
<span class="p">]</span>
|
||||
</code></pre></div>
|
||||
<h3 id="usage">Usage<a class="headerlink" href="#usage" title="Permanent link">¶</a></h3>
|
||||
<p>You can create your own keyboard in <code>config.json</code>:</p>
|
||||
<p><code>json
|
||||
"telegram": {
|
||||
"enabled": true,
|
||||
"token": "your_telegram_token",
|
||||
"chat_id": "your_telegram_chat_id",
|
||||
"keyboard": [
|
||||
["/daily", "/stats", "/balance", "/profit"],
|
||||
["/status table", "/performance"],
|
||||
["/reload_config", "/count", "/logs"]
|
||||
]
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_telegram_token"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"chat_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"your_telegram_chat_id"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"keyboard"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">[</span><span class="s2">"/daily"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/stats"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/balance"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/profit"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="p">[</span><span class="s2">"/status table"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/performance"</span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="p">[</span><span class="s2">"/reload_config"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/count"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/logs"</span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Supported Commands</p>
|
||||
<p>Only the following commands are allowed. Command arguments are not supported!</p>
|
||||
@@ -2953,19 +2953,17 @@ Enter Tag is configurable via Strategy.</p>
|
||||
</blockquote>
|
||||
<h3 id="status-table">/status table<a class="headerlink" href="#status-table" title="Permanent link">¶</a></h3>
|
||||
<p>Return the status of all open trades in a table format.</p>
|
||||
<p><code>ID L/S Pair Since Profit
|
||||
<div class="highlight"><pre><span></span><code>ID L/S Pair Since Profit
|
||||
---- -------- ------- --------
|
||||
67 L SC/BTC 1 d 13.33%
|
||||
123 S CVC/BTC 1 h 12.95%</code></p>
|
||||
123 S CVC/BTC 1 h 12.95%
|
||||
</code></pre></div>
|
||||
<h3 id="count">/count<a class="headerlink" href="#count" title="Permanent link">¶</a></h3>
|
||||
<p>Return the number of trades used and available.</p>
|
||||
<p>```
|
||||
current max</p>
|
||||
<hr />
|
||||
<div class="codehilite"><pre><span></span><code> 2 10
|
||||
<div class="highlight"><pre><span></span><code>current max
|
||||
--------- -----
|
||||
2 10
|
||||
</code></pre></div>
|
||||
|
||||
<p>```</p>
|
||||
<h3 id="profit">/profit<a class="headerlink" href="#profit" title="Permanent link">¶</a></h3>
|
||||
<p>Also available as <code>/profit_long</code> and <code>/profit_short</code> to show profit for long or short trades only.</p>
|
||||
<p>Return a summary of your profit/loss and performance.</p>
|
||||
@@ -3045,34 +3043,35 @@ Trades created through <code>/forcelong</code> will have the buy-tag of <code>fo
|
||||
<blockquote>
|
||||
<p><strong>Daily Profit over the last 3 days:</strong></p>
|
||||
</blockquote>
|
||||
<p>```
|
||||
Day (count) USDT USD Profit %</p>
|
||||
<hr />
|
||||
<p>2022-06-11 (1) -0.746 USDT -0.75 USD -0.08%
|
||||
<div class="highlight"><pre><span></span><code>Day (count) USDT USD Profit %
|
||||
-------------- ------------ ---------- ----------
|
||||
2022-06-11 (1) -0.746 USDT -0.75 USD -0.08%
|
||||
2022-06-10 (0) 0 USDT 0.00 USD 0.00%
|
||||
2022-06-09 (5) 20 USDT 20.10 USD 5.00%
|
||||
```</p>
|
||||
</code></pre></div>
|
||||
<h3 id="weekly">/weekly <n><a class="headerlink" href="#weekly" title="Permanent link">¶</a></h3>
|
||||
<p>Per default <code>/weekly</code> will return the 8 last weeks, including the current week. Each week starts
|
||||
from Monday. The example below if for <code>/weekly 3</code>:</p>
|
||||
<blockquote>
|
||||
<p><strong>Weekly Profit over the last 3 weeks (starting from Monday):</strong></p>
|
||||
</blockquote>
|
||||
<p><code>Monday (count) Profit BTC Profit USD Profit %
|
||||
<div class="highlight"><pre><span></span><code>Monday (count) Profit BTC Profit USD Profit %
|
||||
------------- -------------- ------------ ----------
|
||||
2018-01-03 (5) 0.00224175 BTC 29,142 USD 4.98%
|
||||
2017-12-27 (1) 0.00033131 BTC 4,307 USD 0.00%
|
||||
2017-12-20 (4) 0.00269130 BTC 34.986 USD 5.12%</code></p>
|
||||
2017-12-20 (4) 0.00269130 BTC 34.986 USD 5.12%
|
||||
</code></pre></div>
|
||||
<h3 id="monthly">/monthly <n><a class="headerlink" href="#monthly" title="Permanent link">¶</a></h3>
|
||||
<p>Per default <code>/monthly</code> will return the 6 last months, including the current month. The example below
|
||||
if for <code>/monthly 3</code>:</p>
|
||||
<blockquote>
|
||||
<p><strong>Monthly Profit over the last 3 months:</strong>
|
||||
<code>Month (count) Profit BTC Profit USD Profit %
|
||||
<div class="highlight"><pre><span></span><code>Month (count) Profit BTC Profit USD Profit %
|
||||
------------- -------------- ------------ ----------
|
||||
2018-01 (20) 0.00224175 BTC 29,142 USD 4.98%
|
||||
2017-12 (5) 0.00033131 BTC 4,307 USD 0.00%
|
||||
2017-11 (10) 0.00269130 BTC 34.986 USD 5.10%</code></p>
|
||||
2017-11 (10) 0.00269130 BTC 34.986 USD 5.10%
|
||||
</code></pre></div></p>
|
||||
</blockquote>
|
||||
<h3 id="whitelist">/whitelist<a class="headerlink" href="#whitelist" title="Permanent link">¶</a></h3>
|
||||
<p>Shows the current whitelist</p>
|
||||
@@ -3096,9 +3095,11 @@ Use <code>/reload_config</code> to reset the blacklist.</p>
|
||||
<h3 id="marketdir">/marketdir<a class="headerlink" href="#marketdir" title="Permanent link">¶</a></h3>
|
||||
<p>If a market direction is provided the command updates the user managed variable that represents the current market direction.
|
||||
This variable is not set to any valid market direction on bot startup and must be set by the user. The example below is for <code>/marketdir long</code>:</p>
|
||||
<p><code>Successfully updated marketdirection from none to long.</code></p>
|
||||
<div class="highlight"><pre><span></span><code>Successfully updated marketdirection from none to long.
|
||||
</code></pre></div>
|
||||
<p>If no market direction is provided the command outputs the currently set market directions. The example below is for <code>/marketdir</code>:</p>
|
||||
<p><code>Currently set marketdirection: even</code></p>
|
||||
<div class="highlight"><pre><span></span><code>Currently set marketdirection: even
|
||||
</code></pre></div>
|
||||
<p>You can use the market direction in your strategy via <code>self.market_direction</code>.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Bot restarts</p>
|
||||
|
||||
@@ -1528,6 +1528,106 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_open_trade_count" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_open_trade_count
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_total_closed_profit" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_total_closed_profit
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#total_open_trades_stakes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
total_open_trades_stakes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#class-methods-not-supported-in-backtestinghyperopt" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Class methods not supported in backtesting/hyperopt
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Class methods not supported in backtesting/hyperopt">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_overall_performance" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_overall_performance
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_trading_volume" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_trading_volume
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#order-object" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Order Object
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Order Object">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#order-available-attributes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Order - Available attributes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1981,6 +2081,106 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_open_trade_count" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_open_trade_count
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_total_closed_profit" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_total_closed_profit
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#total_open_trades_stakes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
total_open_trades_stakes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#class-methods-not-supported-in-backtestinghyperopt" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Class methods not supported in backtesting/hyperopt
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Class methods not supported in backtesting/hyperopt">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_overall_performance" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_overall_performance
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#get_trading_volume" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
get_trading_volume
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#order-object" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Order Object
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Order Object">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#order-available-attributes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Order - Available attributes
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -2341,12 +2541,12 @@ During backtesting, it's limited to usage in <a href="../strategy-callbacks/">st
|
||||
<h3 id="get_trades_proxy">get_trades_proxy<a class="headerlink" href="#get_trades_proxy" title="Permanent link">¶</a></h3>
|
||||
<p>When your strategy needs some information on existing (open or close) trades - it's best to use <code>Trade.get_trades_proxy()</code>.</p>
|
||||
<p>Usage:</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade
|
||||
from datetime import timedelta</p>
|
||||
<h1 id="_1">...<a class="headerlink" href="#_1" title="Permanent link">¶</a></h1>
|
||||
<p>trade_hist = Trade.get_trades_proxy(pair='ETH/USDT', is_open=False, open_date=current_date - timedelta(days=2))</p>
|
||||
<p>```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">timedelta</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
<span class="n">trade_hist</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_trades_proxy</span><span class="p">(</span><span class="n">pair</span><span class="o">=</span><span class="s1">'ETH/USDT'</span><span class="p">,</span> <span class="n">is_open</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">open_date</span><span class="o">=</span><span class="n">current_date</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
|
||||
</code></pre></div>
|
||||
<p><code>get_trades_proxy()</code> supports the following keyword arguments. All arguments are optional - calling <code>get_trades_proxy()</code> without arguments will return a list of all trades in the database.</p>
|
||||
<ul>
|
||||
<li><code>pair</code> e.g. <code>pair='ETH/USDT'</code></li>
|
||||
@@ -2356,46 +2556,45 @@ from datetime import timedelta</p>
|
||||
</ul>
|
||||
<h3 id="get_open_trade_count">get_open_trade_count<a class="headerlink" href="#get_open_trade_count" title="Permanent link">¶</a></h3>
|
||||
<p>Get the number of currently open trades</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade</p>
|
||||
<h1 id="_2">...<a class="headerlink" href="#_2" title="Permanent link">¶</a></h1>
|
||||
<p>open_trades = Trade.get_open_trade_count()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
<span class="c1"># ...</span>
|
||||
<span class="n">open_trades</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_open_trade_count</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h3 id="get_total_closed_profit">get_total_closed_profit<a class="headerlink" href="#get_total_closed_profit" title="Permanent link">¶</a></h3>
|
||||
<p>Retrieve the total profit the bot has generated so far.
|
||||
Aggregates <code>close_profit_abs</code> for all closed trades.</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade</p>
|
||||
<h1 id="_3">...<a class="headerlink" href="#_3" title="Permanent link">¶</a></h1>
|
||||
<p>profit = Trade.get_total_closed_profit()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
<span class="n">profit</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_total_closed_profit</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h3 id="total_open_trades_stakes">total_open_trades_stakes<a class="headerlink" href="#total_open_trades_stakes" title="Permanent link">¶</a></h3>
|
||||
<p>Retrieve the total stake_amount that's currently in trades.</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade</p>
|
||||
<h1 id="_4">...<a class="headerlink" href="#_4" title="Permanent link">¶</a></h1>
|
||||
<p>profit = Trade.total_open_trades_stakes()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
<span class="n">profit</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">total_open_trades_stakes</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="class-methods-not-supported-in-backtestinghyperopt">Class methods not supported in backtesting/hyperopt<a class="headerlink" href="#class-methods-not-supported-in-backtestinghyperopt" title="Permanent link">¶</a></h2>
|
||||
<p>The following class methods are not supported in backtesting/hyperopt mode.</p>
|
||||
<h3 id="get_overall_performance">get_overall_performance<a class="headerlink" href="#get_overall_performance" title="Permanent link">¶</a></h3>
|
||||
<p>Retrieve the overall performance - similar to the <code>/performance</code> telegram command.</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade</p>
|
||||
<h1 id="_5">...<a class="headerlink" href="#_5" title="Permanent link">¶</a></h1>
|
||||
<p>if self.config['runmode'].value in ('live', 'dry_run'):
|
||||
performance = Trade.get_overall_performance()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'runmode'</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">'live'</span><span class="p">,</span> <span class="s1">'dry_run'</span><span class="p">):</span>
|
||||
<span class="n">performance</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_overall_performance</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<p>Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of 0.015).</p>
|
||||
<p><code>json
|
||||
{"pair": "ETH/BTC", "profit": 0.015, "count": 5}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="nt">"pair"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ETH/BTC"</span><span class="p">,</span><span class="w"> </span><span class="nt">"profit"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.015</span><span class="p">,</span><span class="w"> </span><span class="nt">"count"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<h3 id="get_trading_volume">get_trading_volume<a class="headerlink" href="#get_trading_volume" title="Permanent link">¶</a></h3>
|
||||
<p>Get total trading volume based on orders.</p>
|
||||
<p>``` python
|
||||
from freqtrade.persistence import Trade</p>
|
||||
<h1 id="_6">...<a class="headerlink" href="#_6" title="Permanent link">¶</a></h1>
|
||||
<p>volume = Trade.get_trading_volume()
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">freqtrade.persistence</span><span class="w"> </span><span class="kn">import</span> <span class="n">Trade</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
<span class="n">volume</span> <span class="o">=</span> <span class="n">Trade</span><span class="o">.</span><span class="n">get_trading_volume</span><span class="p">()</span>
|
||||
</code></pre></div>
|
||||
<h2 id="order-object">Order Object<a class="headerlink" href="#order-object" title="Permanent link">¶</a></h2>
|
||||
<p>An <code>Order</code> object represents an order on the exchange (or a simulated order in dry-run mode).
|
||||
An <code>Order</code> object will always be tied to it's corresponding <a href="#trade-object"><code>Trade</code></a>, and only really makes sense in the context of a trade.</p>
|
||||
|
||||
@@ -1782,6 +1782,17 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#problems-updating" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Problems updating
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1916,6 +1927,17 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#problems-updating" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
Problems updating
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1959,25 +1981,25 @@ To ensure ongoing compatibility, please make sure to update your bot regularly.<
|
||||
<p class="admonition-title">Legacy installations using the <code>master</code> image</p>
|
||||
<p>We're switching from master to stable for the release Images - please adjust your docker-file and replace <code>freqtradeorg/freqtrade:master</code> with <code>freqtradeorg/freqtrade:stable</code></p>
|
||||
</div>
|
||||
<p><code>bash
|
||||
docker compose pull
|
||||
docker compose up -d</code></p>
|
||||
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>pull
|
||||
docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d
|
||||
</code></pre></div>
|
||||
<h2 id="installation-via-setup-script">Installation via setup script<a class="headerlink" href="#installation-via-setup-script" title="Permanent link">¶</a></h2>
|
||||
<p><code>bash
|
||||
./setup.sh --update</code></p>
|
||||
<div class="highlight"><pre><span></span><code>./setup.sh<span class="w"> </span>--update
|
||||
</code></pre></div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Make sure to run this command with your virtual environment disabled!</p>
|
||||
</div>
|
||||
<h2 id="plain-native-installation">Plain native installation<a class="headerlink" href="#plain-native-installation" title="Permanent link">¶</a></h2>
|
||||
<p>Please ensure that you're also updating dependencies - otherwise things might break without you noticing.</p>
|
||||
<p>``` bash
|
||||
git pull
|
||||
pip install -U -r requirements.txt
|
||||
pip install -e .</p>
|
||||
<h1 id="ensure-frequi-is-at-the-latest-version">Ensure freqUI is at the latest version<a class="headerlink" href="#ensure-frequi-is-at-the-latest-version" title="Permanent link">¶</a></h1>
|
||||
<p>freqtrade install-ui
|
||||
```</p>
|
||||
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>pull
|
||||
pip<span class="w"> </span>install<span class="w"> </span>-U<span class="w"> </span>-r<span class="w"> </span>requirements.txt
|
||||
pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span>.
|
||||
|
||||
<span class="c1"># Ensure freqUI is at the latest version</span>
|
||||
freqtrade<span class="w"> </span>install-ui<span class="w"> </span>
|
||||
</code></pre></div>
|
||||
<h2 id="problems-updating">Problems updating<a class="headerlink" href="#problems-updating" title="Permanent link">¶</a></h2>
|
||||
<p>Update-problems usually come missing dependencies (you didn't follow the above instructions) - or from dependencies which fail to install.
|
||||
We try to make sure that heavy dependencies have wheels available for major platforms, but sometimes this is not possible.</p>
|
||||
|
||||
+668
-646
File diff suppressed because it is too large
Load Diff
@@ -2105,111 +2105,111 @@
|
||||
<h2 id="configuration">Configuration<a class="headerlink" href="#configuration" title="Permanent link">¶</a></h2>
|
||||
<p>Enable webhooks by adding a webhook-section to your configuration file, and setting <code>webhook.enabled</code> to <code>true</code>.</p>
|
||||
<p>Sample configuration (tested using IFTTT).</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://maker.ifttt.com/trigger/<YOUREVENT>/with/key/<YOURKEY>/",
|
||||
"entry": {
|
||||
"value1": "Buying {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "{stake_amount:8f} {stake_currency}"
|
||||
},
|
||||
"entry_cancel": {
|
||||
"value1": "Cancelling Open Buy Order for {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "{stake_amount:8f} {stake_currency}"
|
||||
},
|
||||
"entry_fill": {
|
||||
"value1": "Buy Order for {pair} filled",
|
||||
"value2": "at {open_rate:8f}",
|
||||
"value3": ""
|
||||
},
|
||||
"exit": {
|
||||
"value1": "Exiting {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"
|
||||
},
|
||||
"exit_cancel": {
|
||||
"value1": "Cancelling Open Exit Order for {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"
|
||||
},
|
||||
"exit_fill": {
|
||||
"value1": "Exit Order for {pair} filled",
|
||||
"value2": "at {close_rate:8f}.",
|
||||
"value3": ""
|
||||
},
|
||||
"status": {
|
||||
"value1": "Status: {status}",
|
||||
"value2": "",
|
||||
"value3": ""
|
||||
}
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://maker.ifttt.com/trigger/<YOUREVENT>/with/key/<YOURKEY>/"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"entry"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Buying {pair}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit {limit:8f}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{stake_amount:8f} {stake_currency}"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"entry_cancel"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Cancelling Open Buy Order for {pair}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit {limit:8f}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{stake_amount:8f} {stake_currency}"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"entry_fill"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Buy Order for {pair} filled"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"at {open_rate:8f}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"exit"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Exiting {pair}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit {limit:8f}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"exit_cancel"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Cancelling Open Exit Order for {pair}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"limit {limit:8f}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"profit: {profit_amount:8f} {stake_currency} ({profit_ratio})"</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"exit_fill"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Exit Order for {pair} filled"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"at {close_rate:8f}."</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"value1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Status: {status}"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value2"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"value3"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>The url in <code>webhook.url</code> should point to the correct url for your webhook. If you're using <a href="https://ifttt.com">IFTTT</a> (as shown in the sample above) please insert your event and key to the url.</p>
|
||||
<p>You can set the POST body format to Form-Encoded (default), JSON-Encoded, or raw data. Use <code>"format": "form"</code>, <code>"format": "json"</code>, or <code>"format": "raw"</code> respectively. Example configuration for Mattermost Cloud integration:</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://<YOURSUBDOMAIN>.cloud.mattermost.com/hooks/<YOURHOOK>",
|
||||
"format": "json",
|
||||
"status": {
|
||||
"text": "Status: {status}"
|
||||
}
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://<YOURSUBDOMAIN>.cloud.mattermost.com/hooks/<YOURHOOK>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"json"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"text"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Status: {status}"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>The result would be a POST request with e.g. <code>{"text":"Status: running"}</code> body and <code>Content-Type: application/json</code> header which results <code>Status: running</code> message in the Mattermost channel.</p>
|
||||
<p>When using the Form-Encoded or JSON-Encoded configuration you can configure any number of payload values, and both the key and value will be output in the POST request. However, when using the raw data format you can only configure one value and it <strong>must</strong> be named <code>"data"</code>. In this instance the data key will not be output in the POST request, only the value. For example:</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://<YOURHOOKURL>",
|
||||
"format": "raw",
|
||||
"webhookstatus": {
|
||||
"data": "Status: {status}"
|
||||
}
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://<YOURHOOKURL>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"raw"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"webhookstatus"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Status: {status}"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>The result would be a POST request with e.g. <code>Status: running</code> body and <code>Content-Type: text/plain</code> header.</p>
|
||||
<h3 id="nested-webhook-configuration">Nested Webhook Configuration<a class="headerlink" href="#nested-webhook-configuration" title="Permanent link">¶</a></h3>
|
||||
<p>Some webhook targets require a nested structure.
|
||||
This can be accomplished by setting the content as dictionary or list instead of as text directly. </p>
|
||||
<p>This is only supported for the JSON format.</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://<yourhookurl>",
|
||||
"format": "json",
|
||||
"status": {
|
||||
"msgtype": "text",
|
||||
"text": {
|
||||
"content": "Status update: {status}"
|
||||
}
|
||||
}
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://<yourhookurl>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"json"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"msgtype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"text"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"text"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"content"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Status update: {status}"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>The result would be a POST request with e.g. <code>{"msgtype":"text","text":{"content":"Status update: running"}}</code> body and <code>Content-Type: application/json</code> header.</p>
|
||||
<h2 id="additional-configurations">Additional configurations<a class="headerlink" href="#additional-configurations" title="Permanent link">¶</a></h2>
|
||||
<p>The <code>webhook.retries</code> parameter can be set for the maximum number of retries the webhook request should attempt if it is unsuccessful (i.e. HTTP response status is not 200). By default this is set to <code>0</code> which is disabled. An additional <code>webhook.retry_delay</code> parameter can be set to specify the time in seconds between retry attempts. By default this is set to <code>0.1</code> (i.e. 100ms). Note that increasing the number of retries or retry delay may slow down the trader if there are connectivity issues with the webhook.
|
||||
You can also specify <code>webhook.timeout</code> - which defines how long the bot will wait until it assumes the other host as unresponsive (defaults to 10s).</p>
|
||||
<p>Example configuration for retries:</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://<YOURHOOKURL>",
|
||||
"timeout": 10,
|
||||
"retries": 3,
|
||||
"retry_delay": 0.2,
|
||||
"status": {
|
||||
"status": "Status: {status}"
|
||||
}
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://<YOURHOOKURL>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"timeout"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"retries"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"retry_delay"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.2</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Status: {status}"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>Custom messages can be sent to Webhook endpoints via the <code>self.dp.send_msg()</code> function from within the strategy. To enable this, set the <code>allow_custom_messages</code> option to <code>true</code>:</p>
|
||||
<p><code>json
|
||||
"webhook": {
|
||||
"enabled": true,
|
||||
"url": "https://<YOURHOOKURL>",
|
||||
"allow_custom_messages": true,
|
||||
"strategy_msg": {
|
||||
"status": "StrategyMessage: {msg}"
|
||||
}
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"webhook"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://<YOURHOOKURL>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"allow_custom_messages"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"strategy_msg"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"StrategyMessage: {msg}"</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
<p>Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called.</p>
|
||||
<h2 id="webhook-message-types">Webhook Message types<a class="headerlink" href="#webhook-message-types" title="Permanent link">¶</a></h2>
|
||||
<h3 id="entry-entry-fill">Entry / Entry fill<a class="headerlink" href="#entry-entry-fill" title="Permanent link">¶</a></h3>
|
||||
@@ -2314,51 +2314,51 @@ Possible parameters are:</p>
|
||||
<h2 id="discord">Discord<a class="headerlink" href="#discord" title="Permanent link">¶</a></h2>
|
||||
<p>A special form of webhooks is available for discord.
|
||||
You can configure this as follows:</p>
|
||||
<p><code>json
|
||||
"discord": {
|
||||
"enabled": true,
|
||||
"webhook_url": "https://discord.com/api/webhooks/<Your webhook URL ...>",
|
||||
"exit_fill": [
|
||||
{"Trade ID": "{trade_id}"},
|
||||
{"Exchange": "{exchange}"},
|
||||
{"Pair": "{pair}"},
|
||||
{"Direction": "{direction}"},
|
||||
{"Open rate": "{open_rate}"},
|
||||
{"Close rate": "{close_rate}"},
|
||||
{"Amount": "{amount}"},
|
||||
{"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"},
|
||||
{"Close date": "{close_date:%Y-%m-%d %H:%M:%S}"},
|
||||
{"Profit": "{profit_amount} {stake_currency}"},
|
||||
{"Profitability": "{profit_ratio:.2%}"},
|
||||
{"Enter tag": "{enter_tag}"},
|
||||
{"Exit Reason": "{exit_reason}"},
|
||||
{"Strategy": "{strategy}"},
|
||||
{"Timeframe": "{timeframe}"},
|
||||
],
|
||||
"entry_fill": [
|
||||
{"Trade ID": "{trade_id}"},
|
||||
{"Exchange": "{exchange}"},
|
||||
{"Pair": "{pair}"},
|
||||
{"Direction": "{direction}"},
|
||||
{"Open rate": "{open_rate}"},
|
||||
{"Amount": "{amount}"},
|
||||
{"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"},
|
||||
{"Enter tag": "{enter_tag}"},
|
||||
{"Strategy": "{strategy} {timeframe}"},
|
||||
]
|
||||
}</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="nt">"discord"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"webhook_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://discord.com/api/webhooks/<Your webhook URL ...>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"exit_fill"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Trade ID"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{trade_id}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Exchange"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{exchange}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Pair"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{pair}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{direction}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Open rate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{open_rate}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Close rate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{close_rate}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Amount"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{amount}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Open date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{open_date:%Y-%m-%d %H:%M:%S}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Close date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{close_date:%Y-%m-%d %H:%M:%S}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Profit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{profit_amount} {stake_currency}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Profitability"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{profit_ratio:.2%}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Enter tag"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{enter_tag}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Exit Reason"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{exit_reason}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Strategy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{strategy}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Timeframe"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{timeframe}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">],</span>
|
||||
<span class="w"> </span><span class="nt">"entry_fill"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Trade ID"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{trade_id}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Exchange"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{exchange}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Pair"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{pair}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{direction}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Open rate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{open_rate}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Amount"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{amount}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Open date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{open_date:%Y-%m-%d %H:%M:%S}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Enter tag"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{enter_tag}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">{</span><span class="nt">"Strategy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{strategy} {timeframe}"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="p">]</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre></div>
|
||||
<p>The above represents the default (<code>exit_fill</code> and <code>entry_fill</code> are optional and will default to the above configuration) - modifications are obviously possible.
|
||||
To disable either of the two default values (<code>entry_fill</code> / <code>exit_fill</code>), you can assign them an empty array (<code>exit_fill: []</code>).</p>
|
||||
<p>Available fields correspond to the fields for webhooks and are documented in the corresponding webhook sections.</p>
|
||||
<p>The notifications will look as follows by default.</p>
|
||||
<p><img alt="discord-notification" src="../assets/discord_notification.png" /></p>
|
||||
<p>Custom messages can be sent from a strategy to Discord endpoints via the dataprovider.send_msg() function. To enable this, set the <code>allow_custom_messages</code> option to <code>true</code>:</p>
|
||||
<p><code>json
|
||||
"discord": {
|
||||
"enabled": true,
|
||||
"webhook_url": "https://discord.com/api/webhooks/<Your webhook URL ...>",
|
||||
"allow_custom_messages": true,
|
||||
},</code></p>
|
||||
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">"discord"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nt">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"webhook_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://discord.com/api/webhooks/<Your webhook URL ...>"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="nt">"allow_custom_messages"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="p">},</span>
|
||||
</code></pre></div>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user