diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 38c1e7fa5..af4033c8d 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -713,3 +713,4 @@ class AwesomeStrategy(IStrategy): :return: A leverage amount, which is between 1.0 and max_leverage. """ return 1.0 +``` diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index fb598282e..c6d347dc8 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -908,7 +908,7 @@ In some situations it may be confusing to deal with stops relative to current ra current_rate: float, current_profit: float, **kwargs) -> float: dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) candle = dataframe.iloc[-1].squeeze() - return stoploss_from_absolute(current_rate - (candle['atr'] * 2, is_short=trade.is_short), current_rate) + return stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate, is_short=trade.is_short) ``` diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index 90d8d8800..f2ee9c4e4 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -73,7 +73,7 @@ df.tail() ```python # Report results -print(f"Generated {df['buy'].sum()} buy signals") +print(f"Generated {df['enter_long'].sum()} entry signals") data = df.set_index('date', drop=False) data.tail() ``` @@ -244,7 +244,7 @@ import plotly.figure_factory as ff hist_data = [trades.profit_ratio] group_labels = ['profit_ratio'] # name of the dataset -fig = ff.create_distplot(hist_data, group_labels,bin_size=0.01) +fig = ff.create_distplot(hist_data, group_labels, bin_size=0.01) fig.show() ``` diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index 9f0300fe3..71225b84f 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -5,7 +5,7 @@ We have put a great effort into keeping compatibility with existing strategies, To support new markets and trade-types (namely short trades / trades with leverage), some things had to change in the interface. If you intend on using markets other than spot markets, please migrate your strategy to the new format. -## Quick summary / checklist +## Quick summary / migration checklist * Dataframe columns: * `buy` -> `enter_long` @@ -17,11 +17,152 @@ If you intend on using markets other than spot markets, please migrate your stra * `custom_stake_amount` * `confirm_trade_entry` * Renamed `trade.nr_of_successful_buys` to `trade.nr_of_successful_entries`. -* Introduced new `leverage` callback +* Introduced new [`leverage` callback](strategy-callbacks.md#leverage-callback) +* Informative pairs can now pass a 3rd element in the Tuple, defining the candle type. * `@informative` decorator now takes an optional `candle_type` argument * helper methods `stoploss_from_open` and `stoploss_from_absolute` now take `is_short` as additional argument. * `INTERFACE_VERSION` should be set to 3. ## Extensive explanation +### `populate_buy_trend` + +In `populate_buy_trend()` - you will want to change the columns you assign from `'buy`' to `'enter_long` + +```python hl_lines="9" +def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 + (dataframe['tema'] <= dataframe['bb_middleband']) & # Guard + (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + ['buy', 'buy_tag']] = (1, 'rsi_cross') + + return dataframe +``` + +After: + +```python hl_lines="9" +def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 + (dataframe['tema'] <= dataframe['bb_middleband']) & # Guard + (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + ['enter_long', 'enter_tag']] = (1, 'rsi_cross') + + return dataframe +``` + +### `populate_sell_trend` + +``` python hl_lines="9" +def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70 + (dataframe['tema'] > dataframe['bb_middleband']) & # Guard + (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + ['sell', 'exit_tag']] = (1, 'some_exit_tag') + return dataframe +``` + +After + +``` python hl_lines="9" +def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70 + (dataframe['tema'] > dataframe['bb_middleband']) & # Guard + (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + ['exit_long', 'exit_tag']] = (1, 'some_exit_tag') + return dataframe +``` + +### Custom-stake-amount + +New string argument `side` - which can be either `"long"` or `"short"`. + +``` python hl_lines="4" +class AwesomeStrategy(IStrategy): + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + entry_tag: Optional[str], **kwargs) -> float: + # ... + return proposed_stake +``` + +``` python hl_lines="4" +class AwesomeStrategy(IStrategy): + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: + # ... + return proposed_stake +``` + +### `confirm_trade_entry` + +New string argument `side` - which can be either `"long"` or `"short"`. + +``` python hl_lines="5" +class AwesomeStrategy(IStrategy): + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, + time_in_force: str, current_time: datetime, entry_tag: Optional[str], + **kwargs) -> bool: + return True +``` +After: + +``` python hl_lines="5" +class AwesomeStrategy(IStrategy): + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, + time_in_force: str, current_time: datetime, entry_tag: Optional[str], + side: str, **kwargs) -> bool: + return True +``` + +### Adjust trade position changes + +While adjust-trade-position itself did not change, you should no longer use `trade.nr_of_successful_buys` - and instead use `trade.nr_of_successful_entries`, which will also include short entries. + +### Helper methods + +Added argument "is_short" to `stoploss_from_open` and `stoploss_from_absolute`. +This should be given the value of `trade.is_short`. + +``` python hl_lines="5 7" + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + # once the profit has risen above 10%, keep the stoploss at 7% above the open price + if current_profit > 0.10: + return stoploss_from_open(0.07, current_profit) + + return stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate) + + return 1 + +``` + +``` python hl_lines="5 7" + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + # once the profit has risen above 10%, keep the stoploss at 7% above the open price + if current_profit > 0.10: + return stoploss_from_open(0.07, current_profit, is_short=trade.is_short) + + return stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate, is_short=trade.is_short) + + +``` diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 3b937d1c5..dc20d71b8 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -110,7 +110,7 @@ "outputs": [], "source": [ "# Report results\n", - "print(f\"Generated {df['buy'].sum()} buy signals\")\n", + "print(f\"Generated {df['enter_long'].sum()} entry signals\")\n", "data = df.set_index('date', drop=False)\n", "data.tail()" ] @@ -348,7 +348,7 @@ "hist_data = [trades.profit_ratio]\n", "group_labels = ['profit_ratio'] # name of the dataset\n", "\n", - "fig = ff.create_distplot(hist_data, group_labels,bin_size=0.01)\n", + "fig = ff.create_distplot(hist_data, group_labels, bin_size=0.01)\n", "fig.show()\n" ] },