mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Update some documentation for short trading
This commit is contained in:
parent
72fd937a74
commit
23b98fbb73
|
@ -86,7 +86,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
||||||
| `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
| `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
||||||
| `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade). <br>*Defaults to `0.5`.* <br> **Datatype:** Float (as ratio)
|
| `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade). <br>*Defaults to `0.5`.* <br> **Datatype:** Float (as ratio)
|
||||||
| `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals. <br>*Defaults to `0.05` (5%).* <br> **Datatype:** Positive Float as ratio.
|
| `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals. <br>*Defaults to `0.05` (5%).* <br> **Datatype:** Positive Float as ratio.
|
||||||
| `timeframe` | The timeframe (former ticker interval) to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** String
|
| `timeframe` | The timeframe to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** String
|
||||||
| `fiat_display_currency` | Fiat currency used to show your profits. [More information below](#what-values-can-be-used-for-fiat_display_currency). <br> **Datatype:** String
|
| `fiat_display_currency` | Fiat currency used to show your profits. [More information below](#what-values-can-be-used-for-fiat_display_currency). <br> **Datatype:** String
|
||||||
| `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
|
| `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
|
||||||
| `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode.<br>*Defaults to `1000`.* <br> **Datatype:** Float
|
| `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode.<br>*Defaults to `1000`.* <br> **Datatype:** Float
|
||||||
|
|
|
@ -153,8 +153,8 @@ Checklist on all tasks / possibilities in hyperopt
|
||||||
|
|
||||||
Depending on the space you want to optimize, only some of the below are required:
|
Depending on the space you want to optimize, only some of the below are required:
|
||||||
|
|
||||||
* define parameters with `space='buy'` - for buy signal optimization
|
* define parameters with `space='buy'` - for entry signal optimization
|
||||||
* define parameters with `space='sell'` - for sell signal optimization
|
* define parameters with `space='sell'` - for exit signal optimization
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
`populate_indicators` needs to create all indicators any of the spaces may use, otherwise hyperopt will not work.
|
`populate_indicators` needs to create all indicators any of the spaces may use, otherwise hyperopt will not work.
|
||||||
|
@ -204,7 +204,7 @@ There you have two different types of indicators: 1. `guards` and 2. `triggers`.
|
||||||
|
|
||||||
Hyper-optimization will, for each epoch round, pick one trigger and possibly multiple guards.
|
Hyper-optimization will, for each epoch round, pick one trigger and possibly multiple guards.
|
||||||
|
|
||||||
#### Sell optimization
|
#### Exit signal optimization
|
||||||
|
|
||||||
Similar to the entry-signal above, exit-signals can also be optimized.
|
Similar to the entry-signal above, exit-signals can also be optimized.
|
||||||
Place the corresponding settings into the following methods
|
Place the corresponding settings into the following methods
|
||||||
|
@ -296,7 +296,7 @@ So let's write the buy strategy using these values:
|
||||||
if conditions:
|
if conditions:
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
reduce(lambda x, y: x & y, conditions),
|
reduce(lambda x, y: x & y, conditions),
|
||||||
'buy'] = 1
|
'enter_long'] = 1
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
@ -376,7 +376,7 @@ class MyAwesomeStrategy(IStrategy):
|
||||||
if conditions:
|
if conditions:
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
reduce(lambda x, y: x & y, conditions),
|
reduce(lambda x, y: x & y, conditions),
|
||||||
'buy'] = 1
|
'enter_long'] = 1
|
||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
@ -391,7 +391,7 @@ class MyAwesomeStrategy(IStrategy):
|
||||||
if conditions:
|
if conditions:
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
reduce(lambda x, y: x & y, conditions),
|
reduce(lambda x, y: x & y, conditions),
|
||||||
'sell'] = 1
|
'exit_long'] = 1
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
(dataframe['rsi'] < 35) &
|
(dataframe['rsi'] < 35) &
|
||||||
(dataframe['volume'] > 0)
|
(dataframe['volume'] > 0)
|
||||||
),
|
),
|
||||||
['buy', 'enter_tag']] = (1, 'buy_signal_rsi')
|
['enter_long', 'enter_tag']] = (1, 'buy_signal_rsi')
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame
|
||||||
(dataframe['rsi'] > 70) &
|
(dataframe['rsi'] > 70) &
|
||||||
(dataframe['volume'] > 0)
|
(dataframe['volume'] > 0)
|
||||||
),
|
),
|
||||||
['sell', 'exit_tag']] = (1, 'exit_rsi')
|
['exit_long', 'exit_tag']] = (1, 'exit_rsi')
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
|
|
@ -664,7 +664,7 @@ class DigDeeperStrategy(IStrategy):
|
||||||
if last_candle['close'] < previous_candle['close']:
|
if last_candle['close'] < previous_candle['close']:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
filled_buys = trade.select_filled_orders('buy')
|
filled_entries = trade.select_filled_orders(trade.enter_side)
|
||||||
count_of_entries = trade.nr_of_successful_entries
|
count_of_entries = trade.nr_of_successful_entries
|
||||||
# Allow up to 3 additional increasingly larger buys (4 in total)
|
# Allow up to 3 additional increasingly larger buys (4 in total)
|
||||||
# Initial buy is 1x
|
# Initial buy is 1x
|
||||||
|
@ -676,7 +676,7 @@ class DigDeeperStrategy(IStrategy):
|
||||||
# Hope you have a deep wallet!
|
# Hope you have a deep wallet!
|
||||||
try:
|
try:
|
||||||
# This returns first order stake size
|
# This returns first order stake size
|
||||||
stake_amount = filled_buys[0].cost
|
stake_amount = filled_entries[0].cost
|
||||||
# This then calculates current safety order size
|
# This then calculates current safety order size
|
||||||
stake_amount = stake_amount * (1 + (count_of_entries * 0.25))
|
stake_amount = stake_amount * (1 + (count_of_entries * 0.25))
|
||||||
return stake_amount
|
return stake_amount
|
||||||
|
|
|
@ -26,8 +26,8 @@ This will create a new strategy file from a template, which will be located unde
|
||||||
A strategy file contains all the information needed to build a good strategy:
|
A strategy file contains all the information needed to build a good strategy:
|
||||||
|
|
||||||
- Indicators
|
- Indicators
|
||||||
- Buy strategy rules
|
- Entry strategy rules
|
||||||
- Sell strategy rules
|
- Exit strategy rules
|
||||||
- Minimal ROI recommended
|
- Minimal ROI recommended
|
||||||
- Stoploss strongly recommended
|
- Stoploss strongly recommended
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ As a dataframe is a table, simple python comparisons like the following will not
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
if dataframe['rsi'] > 30:
|
if dataframe['rsi'] > 30:
|
||||||
dataframe['buy'] = 1
|
dataframe['enter_long'] = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
The above section will fail with `The truth value of a Series is ambiguous. [...]`.
|
The above section will fail with `The truth value of a Series is ambiguous. [...]`.
|
||||||
|
@ -92,7 +92,7 @@ This must instead be written in a pandas-compatible way, so the operation is per
|
||||||
``` python
|
``` python
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
(dataframe['rsi'] > 30)
|
(dataframe['rsi'] > 30)
|
||||||
, 'buy'] = 1
|
, 'enter_long'] = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
With this section, you have a new column in your dataframe, which has `1` assigned whenever RSI is above 30.
|
With this section, you have a new column in your dataframe, which has `1` assigned whenever RSI is above 30.
|
||||||
|
@ -199,13 +199,13 @@ If this data is available, indicators will be calculated with this extended time
|
||||||
!!! Note
|
!!! Note
|
||||||
If data for the startup period is not available, then the timerange will be adjusted to account for this startup period - so Backtesting would start at 2019-01-01 08:30:00.
|
If data for the startup period is not available, then the timerange will be adjusted to account for this startup period - so Backtesting would start at 2019-01-01 08:30:00.
|
||||||
|
|
||||||
### Buy signal rules
|
### Entry signal rules
|
||||||
|
|
||||||
Edit the method `populate_buy_trend()` in your strategy file to update your buy strategy.
|
Edit the method `populate_buy_trend()` in your strategy file to update your entry strategy.
|
||||||
|
|
||||||
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
||||||
|
|
||||||
This method will also define a new column, `"buy"`, which needs to contain 1 for buys, and 0 for "no action".
|
This method will also define a new column, `"enter_long"`, which needs to contain 1 for entries, and 0 for "no action".
|
||||||
|
|
||||||
Sample from `user_data/strategies/sample_strategy.py`:
|
Sample from `user_data/strategies/sample_strategy.py`:
|
||||||
|
|
||||||
|
@ -224,22 +224,50 @@ def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard
|
||||||
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
),
|
),
|
||||||
'buy'] = 1
|
['enter_long', 'enter_tag']] = (1, 'rsi_cross')
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? Note "Enter short trades"
|
||||||
|
Short-entries can be created by setting `enter_short` (corresponds to `enter_long` for long trades).
|
||||||
|
The `enter_tag` column remains identical.
|
||||||
|
Short-trades need to be supported by your exchange and market configuration!
|
||||||
|
|
||||||
|
```python
|
||||||
|
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')
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_below(dataframe['rsi'], 70)) & # Signal: RSI crosses below 70
|
||||||
|
(dataframe['tema'] > dataframe['bb_middleband']) & # Guard
|
||||||
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
['enter_short', 'enter_tag']] = (1, 'rsi_cross')
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
```
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
Buying requires sellers to buy from - therefore volume needs to be > 0 (`dataframe['volume'] > 0`) to make sure that the bot does not buy/sell in no-activity periods.
|
Buying requires sellers to buy from - therefore volume needs to be > 0 (`dataframe['volume'] > 0`) to make sure that the bot does not buy/sell in no-activity periods.
|
||||||
|
|
||||||
### Sell signal rules
|
### Exit signal rules
|
||||||
|
|
||||||
Edit the method `populate_sell_trend()` into your strategy file to update your sell strategy.
|
Edit the method `populate_sell_trend()` into your strategy file to update your sell strategy.
|
||||||
Please note that the sell-signal is only used if `use_sell_signal` is set to true in the configuration.
|
Please note that the sell-signal is only used if `use_sell_signal` is set to true in the configuration.
|
||||||
|
|
||||||
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
||||||
|
|
||||||
This method will also define a new column, `"sell"`, which needs to contain 1 for sells, and 0 for "no action".
|
This method will also define a new column, `"exit_long"`, which needs to contain 1 for sells, and 0 for "no action".
|
||||||
|
|
||||||
Sample from `user_data/strategies/sample_strategy.py`:
|
Sample from `user_data/strategies/sample_strategy.py`:
|
||||||
|
|
||||||
|
@ -258,10 +286,36 @@ def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame
|
||||||
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard
|
||||||
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
),
|
),
|
||||||
'sell'] = 1
|
['exit_long', 'exit_tag']] = (1, 'rsi_too_high')
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? Note "Exit short trades"
|
||||||
|
Short-exits can be created by setting `exit_short` (corresponds to `exit_long`).
|
||||||
|
The `exit_tag` column remains identical.
|
||||||
|
Short-trades need to be supported by your exchange and market configuration!
|
||||||
|
|
||||||
|
```python
|
||||||
|
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, 'rsi_too_high')
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_below(dataframe['rsi'], 30)) & # Signal: RSI crosses below 30
|
||||||
|
(dataframe['tema'] < dataframe['bb_middleband']) & # Guard
|
||||||
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
['exit_short', 'exit_tag']] = (1, 'rsi_too_low')
|
||||||
|
return dataframe
|
||||||
|
```
|
||||||
|
|
||||||
### Minimal ROI
|
### Minimal ROI
|
||||||
|
|
||||||
This dict defines the minimal Return On Investment (ROI) a trade should reach before selling, independent from the sell signal.
|
This dict defines the minimal Return On Investment (ROI) a trade should reach before selling, independent from the sell signal.
|
||||||
|
@ -325,7 +379,7 @@ stoploss = -0.10
|
||||||
|
|
||||||
For the full documentation on stoploss features, look at the dedicated [stoploss page](stoploss.md).
|
For the full documentation on stoploss features, look at the dedicated [stoploss page](stoploss.md).
|
||||||
|
|
||||||
### Timeframe (formerly ticker interval)
|
### Timeframe
|
||||||
|
|
||||||
This is the set of candles the bot should download and use for the analysis.
|
This is the set of candles the bot should download and use for the analysis.
|
||||||
Common values are `"1m"`, `"5m"`, `"15m"`, `"1h"`, however all values supported by your exchange should work.
|
Common values are `"1m"`, `"5m"`, `"15m"`, `"1h"`, however all values supported by your exchange should work.
|
||||||
|
@ -454,7 +508,7 @@ for more information.
|
||||||
|
|
||||||
# Define BTC/STAKE informative pair. Available in populate_indicators and other methods as
|
# Define BTC/STAKE informative pair. Available in populate_indicators and other methods as
|
||||||
# 'btc_rsi_1h'. Current stake currency should be specified as {stake} format variable
|
# 'btc_rsi_1h'. Current stake currency should be specified as {stake} format variable
|
||||||
# instead of hardcoding actual stake currency. Available in populate_indicators and other
|
# instead of hard-coding actual stake currency. Available in populate_indicators and other
|
||||||
# methods as 'btc_usdt_rsi_1h' (when stake currency is USDT).
|
# methods as 'btc_usdt_rsi_1h' (when stake currency is USDT).
|
||||||
@informative('1h', 'BTC/{stake}')
|
@informative('1h', 'BTC/{stake}')
|
||||||
def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
@ -501,7 +555,7 @@ for more information.
|
||||||
&
|
&
|
||||||
(dataframe['volume'] > 0)
|
(dataframe['volume'] > 0)
|
||||||
),
|
),
|
||||||
['buy', 'enter_tag']] = (1, 'buy_signal_rsi')
|
['enter_long', 'enter_tag']] = (1, 'buy_signal_rsi')
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
@ -716,7 +770,7 @@ class SampleStrategy(IStrategy):
|
||||||
(dataframe['rsi_1d'] < 30) & # Ensure daily RSI is < 30
|
(dataframe['rsi_1d'] < 30) & # Ensure daily RSI is < 30
|
||||||
(dataframe['volume'] > 0) # Ensure this candle had volume (important for backtesting)
|
(dataframe['volume'] > 0) # Ensure this candle had volume (important for backtesting)
|
||||||
),
|
),
|
||||||
'buy'] = 1
|
['enter_long', 'enter_tag']] = (1, 'rsi_cross')
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -922,7 +976,7 @@ if self.config['runmode'].value in ('live', 'dry_run'):
|
||||||
Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of 0.015).
|
Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of 0.015).
|
||||||
|
|
||||||
``` json
|
``` json
|
||||||
{'pair': "ETH/BTC", 'profit': 0.015, 'count': 5}
|
{"pair": "ETH/BTC", "profit": 0.015, "count": 5}
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
|
@ -985,7 +1039,7 @@ def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
(
|
(
|
||||||
#>> whatever condition<<<
|
#>> whatever condition<<<
|
||||||
),
|
),
|
||||||
'buy'] = 1
|
['enter_long', 'enter_tag']] = (1, 'somestring')
|
||||||
|
|
||||||
# Print the Analyzed pair
|
# Print the Analyzed pair
|
||||||
print(f"result for {metadata['pair']}")
|
print(f"result for {metadata['pair']}")
|
||||||
|
@ -1014,7 +1068,12 @@ The following lists some common patterns which should be avoided to prevent frus
|
||||||
|
|
||||||
### Colliding signals
|
### Colliding signals
|
||||||
|
|
||||||
When buy and sell signals collide (both `'buy'` and `'sell'` are 1), freqtrade will do nothing and ignore the entry (buy) signal. This will avoid trades that buy, and sell immediately. Obviously, this can potentially lead to missed entries.
|
When conflicting signals collide (e.g. both `'enter_long'` and `'exit_long'` are 1), freqtrade will do nothing and ignore the entry signal. This will avoid trades that buy, and sell immediately. Obviously, this can potentially lead to missed entries.
|
||||||
|
|
||||||
|
The following rules apply, and entry signals will be ignored if more than one of the 3 signals is set:
|
||||||
|
|
||||||
|
- `enter_long` -> `exit_long`, `exit_short`
|
||||||
|
- `enter_short` -> `exit_short`, `enter_long`
|
||||||
|
|
||||||
## Further strategy ideas
|
## Further strategy ideas
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user