From a5853681e3713e892364130a5af154780ad89287 Mon Sep 17 00:00:00 2001 From: Gerald Lonlas Date: Wed, 17 Jan 2018 23:06:37 -0800 Subject: [PATCH] Update documentation --- docs/bot-optimization.md | 98 +++++++++------ docs/bot-usage.md | 45 +++++-- docs/configuration.md | 12 +- docs/hyperopt.md | 46 +++---- user_data/strategies/test_strategy.py | 167 ++++++++++++++++++++++++++ 5 files changed, 297 insertions(+), 71 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index 424bab989..f94bb5206 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -3,21 +3,55 @@ This page explains where to customize your strategies, and add new indicators. ## Table of Contents -- [Change your strategy](#change-your-strategy) +- [Install a custom strategy file](#install-a-custom-strategy-file) +- [Customize your strategy](#change-your-strategy) - [Add more Indicator](#add-more-indicator) +- [Where is the default strategy](#where-is-the-default-strategy) + +Since the version `0.16.0` the bot allows using custom strategy file. + +## Install a custom strategy file +This is very simple. Copy paste your strategy file into the folder +`user_data/strategies`. + +Let guess you have a strategy file `awesome-strategy.py`: +1. Move your file into `user_data/strategies` (you should have `user_data/strategies/awesome-strategy.py` +2. Start the bot with the param `--strategy awesome-strategy` (the parameter is the name of the file without '.py') + +```bash +python3 ./freqtrade/main.py --strategy awesome_strategy +``` ## Change your strategy -The bot is using buy and sell strategies to buy and sell your trades. -Both are customizable. +The bot includes a default strategy file. However, we recommend you to +use your own file to not have to lose your parameters everytime the default +strategy file will be updated on Github. Put your custom strategy file +into the folder `user_data/strategies`. -### Buy strategy -The default buy strategy is located in the file -[freqtrade/analyze.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/analyze.py#L73-L92). -Edit the function `populate_buy_trend()` to update your buy strategy. +A strategy file contains all the information needed to build a good strategy: +- Buy strategy rules +- Sell strategy rules +- Minimal ROI recommended +- Stoploss recommended +- Hyperopt parameter -Sample: +The bot also include a sample strategy you can update: `user_data/strategies/test_strategy.py`. +You can test it with the parameter: `--strategy test_strategy` + +```bash +python3 ./freqtrade/main.py --strategy awesome_strategy +``` + +**For the following section we will use the [user_data/strategies/test_strategy.py](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py) +file as reference.** + +### Buy strategy +Edit the method `populate_buy_trend()` into your strategy file to +update your buy strategy. + +Sample from `user_data/strategies/test_strategy.py`: ```python -def populate_buy_trend(dataframe: DataFrame) -> DataFrame: +def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame @@ -25,14 +59,9 @@ def populate_buy_trend(dataframe: DataFrame) -> DataFrame: """ dataframe.loc[ ( - (dataframe['rsi'] < 35) & - (dataframe['fastd'] < 35) & (dataframe['adx'] > 30) & - (dataframe['plus_di'] > 0.5) - ) | - ( - (dataframe['adx'] > 65) & - (dataframe['plus_di'] > 0.5) + (dataframe['tema'] <= dataframe['blower']) & + (dataframe['tema'] > dataframe['tema'].shift(1)) ), 'buy'] = 1 @@ -40,41 +69,31 @@ def populate_buy_trend(dataframe: DataFrame) -> DataFrame: ``` ### Sell strategy -The default buy strategy is located in the file -[freqtrade/analyze.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/analyze.py#L95-L115) -Edit the function `populate_sell_trend()` to update your buy strategy. +Edit the method `populate_sell_trend()` into your strategy file to +update your sell strategy. -Sample: +Sample from `user_data/strategies/test_strategy.py`: ```python -def populate_sell_trend(dataframe: DataFrame) -> DataFrame: +def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ dataframe.loc[ - ( - ( - (crossed_above(dataframe['rsi'], 70)) | - (crossed_above(dataframe['fastd'], 70)) - ) & - (dataframe['adx'] > 10) & - (dataframe['minus_di'] > 0) - ) | ( (dataframe['adx'] > 70) & - (dataframe['minus_di'] > 0.5) + (dataframe['tema'] > dataframe['blower']) & + (dataframe['tema'] < dataframe['tema'].shift(1)) ), 'sell'] = 1 return dataframe ``` ## Add more Indicator -As you have seen, buy and sell strategies need indicators. You can see -the indicators in the file -[freqtrade/analyze.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/analyze.py#L95-L115). -Of course you can add more indicators by extending the list contained in -the function `populate_indicators()`. +As you have seen, buy and sell strategies need indicators. You can add +more indicators by extending the list contained in +the method `populate_indicators()` from your strategy file. Sample: ```python @@ -111,6 +130,15 @@ def populate_indicators(dataframe: DataFrame) -> DataFrame: return dataframe ``` +**Want more indicators example?** +Look into the [user_data/strategies/test_strategy.py](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py). +Then uncomment indicateur you need. + + +### Where is the default strategy? +The default buy strategy is located in the file +[freqtrade/default_strategy.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/strategy/default_strategy.py). + ## Next step Now you have a perfect strategy you probably want to backtesting it. diff --git a/docs/bot-usage.md b/docs/bot-usage.md index d3dcf8659..ca92d74c4 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -22,19 +22,21 @@ positional arguments: optional arguments: -h, --help show this help message and exit - -c PATH, --config PATH - specify configuration file (default: config.json) -v, --verbose be verbose --version show program's version number and exit - -dd PATH, --datadir PATH - Path is from where backtesting and hyperopt will load the - ticker data files (default freqdata/tests/testdata). - --dynamic-whitelist [INT] - dynamically generate and update whitelist based on 24h - BaseVolume (Default 20 currencies) + -c PATH, --config PATH + specify configuration file (default: config.json) + -s PATH, --strategy PATH + specify strategy file (default: + freqtrade/strategy/default_strategy.py) --dry-run-db Force dry run to use a local DB "tradesv3.dry_run.sqlite" instead of memory DB. Work only if dry_run is enabled. + -dd PATH, --datadir PATH + path to backtest data (default freqdata/tests/testdata + --dynamic-whitelist [INT] + dynamically generate and update whitelist based on 24h + BaseVolume (Default 20 currencies) ``` ### How to use a different config file? @@ -45,6 +47,33 @@ default, the bot will load the file `./config.json` python3 ./freqtrade/main.py -c path/far/far/away/config.json ``` +### How to use --strategy? +This parameter will allow you to load your custom strategy file. Per +default without `--strategy` or `-s` the bol will load the +`default_strategy` included with the bot (`freqtrade/strategy/default_strategy.py`). + +The bot will search your strategy file into `user_data/strategies` and +`freqtrade/strategy`. + +To load a strategy, simply pass the file name (without .py) in this +parameters. + +**Example:** +In `user_data/strategies` you have a file `my_awesome_strategy.py` to +load it: +```bash +python3 ./freqtrade/main.py --strategy my_awesome_strategy +``` + +If the bot does not find your strategy file, it will fallback to the +`default_strategy`. + +Learn more about strategy file in [optimize your bot](https://github.com/gcarq/freqtrade/blob/develop/docs/bot-optimization.md). + +#### How to install a strategy? +This is very simple. Copy paste your strategy file into the folder +`user_data/strategies`. And voila, the bot is ready to use it. + ### How to use --dynamic-whitelist? Per default `--dynamic-whitelist` will retrieve the 20 currencies based on BaseVolume. This value can be changed when you run the script. diff --git a/docs/configuration.md b/docs/configuration.md index 5d1204efd..84c8f53ba 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -20,8 +20,8 @@ The table below will list all configuration parameters. | `ticker_interval` | [1, 5, 30, 60, 1440] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Defaut is 5 minutes | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. -| `minimal_roi` | See below | Yes | Set the threshold in percent the bot will use to sell a trade. More information below. -| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. +| `minimal_roi` | See below | No | Set the threshold in percent the bot will use to sell a trade. More information below. If set, this parameter will override `minimal_roi` from your strategy file. +| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file. | `unfilledtimeout` | 0 | No | How long (in minutes) the bot will wait for an unfilled order to complete, after which the order will be cancelled. | `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. | `exchange.name` | bittrex | Yes | Name of the exchange class to use. @@ -53,11 +53,19 @@ See the example below: }, ``` +Most of the strategy files already include the optimal `minimal_roi` +value. This parameter is optional. If you use it, it will take over the +`minimal_roi` value from the strategy file. + ### Understand stoploss `stoploss` is loss in percentage that should trigger a sale. For example value `-0.10` will cause immediate sell if the profit dips below -10% for a given trade. This parameter is optional. +Most of the strategy files already include the optimal `stoploss` +value. This parameter is optional. If you use it, it will take over the +`stoploss` value from the strategy file. + ### Understand initial_state `initial_state` is an optional field that defines the initial application state. Possible values are `running` or `stopped`. (default=`running`) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index af564f0b6..3c3cb7d25 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -14,14 +14,13 @@ parameters with Hyperopt. ## Prepare Hyperopt Before we start digging in Hyperopt, we recommend you to take a look at -out Hyperopt file -[freqtrade/optimize/hyperopt.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py) +your strategy file located into [user_data/strategies/](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py) ### 1. Configure your Guards and Triggers -There are two places you need to change to add a new buy strategy for -testing: -- Inside the [populate_buy_trend()](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L167-L207). -- Inside the [SPACE dict](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L47-L94). +There are two places you need to change in your strategy file to add a +new buy strategy for testing: +- Inside [populate_buy_trend()](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py#L278-L294). +- Inside [hyperopt_space()](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py#L244-L297) known as `SPACE`. There you have two different type of indicators: 1. `guards` and 2. `triggers`. @@ -38,10 +37,10 @@ ADX > 10*". If you have updated the buy strategy, means change the content of -`populate_buy_trend()` function you have to update the `guards` and +`populate_buy_trend()` method you have to update the `guards` and `triggers` hyperopts must used. -As for an example if your `populate_buy_trend()` function is: +As for an example if your `populate_buy_trend()` method is: ```python def populate_buy_trend(dataframe: DataFrame) -> DataFrame: dataframe.loc[ @@ -56,10 +55,10 @@ Your hyperopt file must contains `guards` to find the right value for `(dataframe['adx'] > 65)` & and `(dataframe['plus_di'] > 0.5)`. That means you will need to enable/disable triggers. -In our case the `SPACE` and `populate_buy_trend` in hyperopt.py file +In our case the `SPACE` and `populate_buy_trend` in your strategy file will be look like: ```python -SPACE = { +space = { 'rsi': hp.choice('rsi', [ {'enabled': False}, {'enabled': True, 'value': hp.quniform('rsi-value', 20, 40, 1)} @@ -82,7 +81,7 @@ SPACE = { ... -def populate_buy_trend(dataframe: DataFrame) -> DataFrame: +def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: conditions = [] # GUARDS AND TRENDS if params['adx']['enabled']: @@ -111,13 +110,13 @@ cannot use your config file. It is also made on purpose to allow you testing your strategy with different configurations. The Hyperopt configuration is located in -[freqtrade/optimize/hyperopt_conf.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt_conf.py). +[user_data/hyperopt_conf.py](https://github.com/gcarq/freqtrade/blob/develop/user_data/hyperopt_conf.py). ## Advanced notions ### Understand the Guards and Triggers When you need to add the new guards and triggers to be hyperopt -parameters, you do this by adding them into the [SPACE dict](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L47-L94). +parameters, you do this by adding them into the [hyperopt_space()](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py#L244-L297). If it's a trigger, you add one line to the 'trigger' choice group and that's it. @@ -149,9 +148,8 @@ for best working algo. ### Add a new Indicators If you want to test an indicator that isn't used by the bot currently, -you need to add it to -[freqtrade/analyze.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/analyze.py#L40-L70) -inside the `populate_indicators` function. +you need to add it to your strategy file (example: [user_data/strategies/test_strategy.py](https://github.com/gcarq/freqtrade/blob/develop/user_data/strategies/test_strategy.py)) +inside the `populate_indicators()` method. ## Execute Hyperopt Once you have updated your hyperopt configuration you can run it. @@ -165,8 +163,8 @@ python3 ./freqtrade/main.py -c config.json hyperopt ### Execute hyperopt with different ticker-data source If you would like to learn parameters using an alternate ticke-data that -you have on-disk, use the --datadir PATH option. Default hyperopt will -use data from directory freqtrade/tests/testdata. +you have on-disk, use the `--datadir PATH` option. Default hyperopt will +use data from directory `user_data/data`. ### Running hyperopt with smaller testset @@ -270,15 +268,11 @@ customizable value. - and so on... -You have to look from -[freqtrade/optimize/hyperopt.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L170-L200) -what those values match to. +You have to look inside your strategy file into `buy_strategy_generator()` +method, what those values match to. So for example you had `adx:` with the `value: 15.0` so we would look -at `adx`-block from -[freqtrade/optimize/hyperopt.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L178-L179). -That translates to the following code block to -[analyze.populate_buy_trend()](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/analyze.py#L73) +at `adx`-block, that translates to the following code block: ``` (dataframe['adx'] > 15.0) ``` @@ -286,7 +280,7 @@ That translates to the following code block to So translating your whole hyperopt result to as the new buy-signal would be the following: ``` -def populate_buy_trend(dataframe: DataFrame) -> DataFrame: +def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: dataframe.loc[ ( (dataframe['adx'] > 15.0) & # adx-value diff --git a/user_data/strategies/test_strategy.py b/user_data/strategies/test_strategy.py index 728cc6328..69c0f4bcd 100644 --- a/user_data/strategies/test_strategy.py +++ b/user_data/strategies/test_strategy.py @@ -9,15 +9,20 @@ from pandas import DataFrame # Add your lib to import here import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy # noqa # Update this variable if you change the class name class_name = 'TestStrategy' +# This class is a sample. Feel free to customize it. class TestStrategy(IStrategy): """ This is a test strategy to inspire you. + More information in https://github.com/gcarq/freqtrade/blob/develop/docs/bot-optimization.md + You can: - Rename the class name (Do not forget to update class_name) - Add any methods you want to build your strategy @@ -51,10 +56,171 @@ class TestStrategy(IStrategy): or your hyperopt configuration, otherwise you will waste your memory and CPU usage. """ + # Momentum Indicator + # ------------------------------------ + + # ADX dataframe['adx'] = ta.ADX(dataframe) + + """ + # Awesome oscillator + dataframe['ao'] = qtpylib.awesome_oscillator(dataframe) + + # Commodity Channel Index: values Oversold:<-100, Overbought:>100 + dataframe['cci'] = ta.CCI(dataframe) + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # ROC + dataframe['roc'] = ta.ROC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] - 50) + dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) + + # Inverse Fisher transform on RSI normalized, value [0.0, 100.0] (https://goo.gl/2JGGoy) + dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # Stoch + stoch = ta.STOCH(dataframe) + dataframe['slowd'] = stoch['slowd'] + dataframe['slowk'] = stoch['slowk'] + + # Stoch fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # Stoch RSI + stoch_rsi = ta.STOCHRSI(dataframe) + dataframe['fastd_rsi'] = stoch_rsi['fastd'] + dataframe['fastk_rsi'] = stoch_rsi['fastk'] + """ + + # Overlap Studies + # ------------------------------------ + + """ + # Previous Bollinger bands + # Because ta.BBANDS implementation is broken with small numbers, it actually + # returns middle band for all the three bands. Switch to qtpylib.bollinger_bands + # and use middle band instead. + dataframe['blower'] = ta.BBANDS(dataframe, nbdevup=2, nbdevdn=2)['lowerband'] + """ + + # Bollinger bands + 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'] + + """ + # EMA - Exponential Moving Average + dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # SAR Parabol + dataframe['sar'] = ta.SAR(dataframe) + + # SMA - Simple Moving Average + dataframe['sma'] = ta.SMA(dataframe, timeperiod=40) + """ + + # TEMA - Triple Exponential Moving Average dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9) + # Cycle Indicator + # ------------------------------------ + # Hilbert Transform Indicator - SineWave + hilbert = ta.HT_SINE(dataframe) + dataframe['htsine'] = hilbert['sine'] + dataframe['htleadsine'] = hilbert['leadsine'] + + # Pattern Recognition - Bullish candlestick patterns + # ------------------------------------ + """ + # Hammer: values [0, 100] + dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + # Inverted Hammer: values [0, 100] + dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe) + # Dragonfly Doji: values [0, 100] + dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe) + # Piercing Line: values [0, 100] + dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100] + # Morningstar: values [0, 100] + dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100] + # Three White Soldiers: values [0, 100] + dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100] + """ + + # Pattern Recognition - Bearish candlestick patterns + # ------------------------------------ + """ + # Hanging Man: values [0, 100] + dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe) + # Shooting Star: values [0, 100] + dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe) + # Gravestone Doji: values [0, 100] + dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe) + # Dark Cloud Cover: values [0, 100] + dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe) + # Evening Doji Star: values [0, 100] + dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe) + # Evening Star: values [0, 100] + dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe) + """ + + # Pattern Recognition - Bullish/Bearish candlestick patterns + # ------------------------------------ + """ + # Three Line Strike: values [0, -100, 100] + dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe) + # Spinning Top: values [0, -100, 100] + dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100] + # Engulfing: values [0, -100, 100] + dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100] + # Harami: values [0, -100, 100] + dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100] + # Three Outside Up/Down: values [0, -100, 100] + dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100] + # Three Inside Up/Down: values [0, -100, 100] + dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100] + """ + + # Chart type + # ------------------------------------ + """ + # Heikinashi stategy + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['ha_open'] = heikinashi['open'] + dataframe['ha_close'] = heikinashi['close'] + dataframe['ha_high'] = heikinashi['high'] + dataframe['ha_low'] = heikinashi['low'] + """ + return dataframe def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: @@ -91,6 +257,7 @@ class TestStrategy(IStrategy): def hyperopt_space(self) -> List[Dict]: """ Define your Hyperopt space for the strategy + :return: Dict """ space = { 'adx': hp.choice('adx', [