Merge pull request #6512 from freqtrade/short_order_types
Short order types renamal
This commit is contained in:
commit
efc313b28b
@ -128,7 +128,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor
|
|||||||
- `/stopbuy`: Stop entering new trades.
|
- `/stopbuy`: Stop entering new trades.
|
||||||
- `/status <trade_id>|[table]`: Lists all or specific open trades.
|
- `/status <trade_id>|[table]`: Lists all or specific open trades.
|
||||||
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
|
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
|
||||||
- `/forcesell <trade_id>|all`: Instantly sells the given trade (Ignoring `minimum_roi`).
|
- `/forceexit <trade_id>|all`: Instantly exits the given trade (Ignoring `minimum_roi`).
|
||||||
- `/performance`: Show performance of each finished trade grouped by pair
|
- `/performance`: Show performance of each finished trade grouped by pair
|
||||||
- `/balance`: Show account balance per currency.
|
- `/balance`: Show account balance per currency.
|
||||||
- `/daily <n>`: Shows profit or loss per day, over the last n days.
|
- `/daily <n>`: Shows profit or loss per day, over the last n days.
|
||||||
|
@ -51,11 +51,11 @@
|
|||||||
"order_book_top": 1
|
"order_book_top": 1
|
||||||
},
|
},
|
||||||
"order_types": {
|
"order_types": {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit",
|
"exit": "limit",
|
||||||
"emergencysell": "market",
|
"emergencyexit": "market",
|
||||||
"forcesell": "market",
|
"forceexit": "market",
|
||||||
"forcebuy": "market",
|
"forceentry": "market",
|
||||||
"stoploss": "market",
|
"stoploss": "market",
|
||||||
"stoploss_on_exchange": false,
|
"stoploss_on_exchange": false,
|
||||||
"stoploss_on_exchange_interval": 60,
|
"stoploss_on_exchange_interval": 60,
|
||||||
|
@ -121,7 +121,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `sell_profit_offset` | Sell-signal is only active above this value. Only active in combination with `sell_profit_only=True`. [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `0.0`.* <br> **Datatype:** Float (as ratio)
|
| `sell_profit_offset` | Sell-signal is only active above this value. Only active in combination with `sell_profit_only=True`. [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `0.0`.* <br> **Datatype:** Float (as ratio)
|
||||||
| `ignore_roi_if_buy_signal` | Do not sell if the buy signal is still active. This setting takes preference over `minimal_roi` and `use_sell_signal`. [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
| `ignore_roi_if_buy_signal` | Do not sell if the buy signal is still active. This setting takes preference over `minimal_roi` and `use_sell_signal`. [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
||||||
| `ignore_buying_expired_candle_after` | Specifies the number of seconds until a buy signal is no longer used. <br> **Datatype:** Integer
|
| `ignore_buying_expired_candle_after` | Specifies the number of seconds until a buy signal is no longer used. <br> **Datatype:** Integer
|
||||||
| `order_types` | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). [More information below](#understand-order_types). [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Dict
|
| `order_types` | Configure order-types depending on the action (`"entry"`, `"exit"`, `"stoploss"`, `"stoploss_on_exchange"`). [More information below](#understand-order_types). [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Dict
|
||||||
| `order_time_in_force` | Configure time in force for entry and exit orders. [More information below](#understand-order_time_in_force). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Dict
|
| `order_time_in_force` | Configure time in force for entry and exit orders. [More information below](#understand-order_time_in_force). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Dict
|
||||||
| `custom_price_max_distance_ratio` | Configure maximum distance ratio between current and custom entry or exit price. <br>*Defaults to `0.02` 2%).*<br> **Datatype:** Positive float
|
| `custom_price_max_distance_ratio` | Configure maximum distance ratio between current and custom entry or exit price. <br>*Defaults to `0.02` 2%).*<br> **Datatype:** Positive float
|
||||||
| `exchange.name` | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). <br> **Datatype:** String
|
| `exchange.name` | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). <br> **Datatype:** String
|
||||||
@ -374,29 +374,28 @@ For example, if your strategy is using a 1h timeframe, and you only want to buy
|
|||||||
|
|
||||||
### Understand order_types
|
### Understand order_types
|
||||||
|
|
||||||
The `order_types` configuration parameter maps actions (`buy`, `sell`, `stoploss`, `emergencysell`, `forcesell`, `forcebuy`) to order-types (`market`, `limit`, ...) as well as configures stoploss to be on the exchange and defines stoploss on exchange update interval in seconds.
|
The `order_types` configuration parameter maps actions (`entry`, `exit`, `stoploss`, `emergencyexit`, `forceexit`, `forceentry`) to order-types (`market`, `limit`, ...) as well as configures stoploss to be on the exchange and defines stoploss on exchange update interval in seconds.
|
||||||
|
|
||||||
This allows to buy using limit orders, sell using
|
This allows to buy using limit orders, sell using
|
||||||
limit-orders, and create stoplosses using market orders. It also allows to set the
|
limit-orders, and create stoplosses using market orders. It also allows to set the
|
||||||
stoploss "on exchange" which means stoploss order would be placed immediately once
|
stoploss "on exchange" which means stoploss order would be placed immediately once
|
||||||
the buy order is fulfilled.
|
the buy order is fulfilled.
|
||||||
|
|
||||||
`order_types` set in the configuration file overwrites values set in the strategy as a whole, so you need to configure the whole `order_types` dictionary in one place.
|
`order_types` set in the configuration file overwrites values set in the strategy as a whole, so you need to configure the whole `order_types` dictionary in one place.
|
||||||
|
|
||||||
If this is configured, the following 4 values (`buy`, `sell`, `stoploss` and
|
If this is configured, the following 4 values (`entry`, `exit`, `stoploss` and `stoploss_on_exchange`) need to be present, otherwise, the bot will fail to start.
|
||||||
`stoploss_on_exchange`) need to be present, otherwise, the bot will fail to start.
|
|
||||||
|
|
||||||
For information on (`emergencysell`,`forcesell`, `forcebuy`, `stoploss_on_exchange`,`stoploss_on_exchange_interval`,`stoploss_on_exchange_limit_ratio`) please see stop loss documentation [stop loss on exchange](stoploss.md)
|
For information on (`emergencyexit`,`forceexit`, `forceentry`, `stoploss_on_exchange`,`stoploss_on_exchange_interval`,`stoploss_on_exchange_limit_ratio`) please see stop loss documentation [stop loss on exchange](stoploss.md)
|
||||||
|
|
||||||
Syntax for Strategy:
|
Syntax for Strategy:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
order_types = {
|
order_types = {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit",
|
"exit": "limit",
|
||||||
"emergencysell": "market",
|
"emergencyexit": "market",
|
||||||
"forcebuy": "market",
|
"forceentry": "market",
|
||||||
"forcesell": "market",
|
"forceexit": "market",
|
||||||
"stoploss": "market",
|
"stoploss": "market",
|
||||||
"stoploss_on_exchange": False,
|
"stoploss_on_exchange": False,
|
||||||
"stoploss_on_exchange_interval": 60,
|
"stoploss_on_exchange_interval": 60,
|
||||||
@ -408,11 +407,11 @@ Configuration:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
"order_types": {
|
"order_types": {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit",
|
"exit": "limit",
|
||||||
"emergencysell": "market",
|
"emergencyexit": "market",
|
||||||
"forcebuy": "market",
|
"forceentry": "market",
|
||||||
"forcesell": "market",
|
"forceexit": "market",
|
||||||
"stoploss": "market",
|
"stoploss": "market",
|
||||||
"stoploss_on_exchange": false,
|
"stoploss_on_exchange": false,
|
||||||
"stoploss_on_exchange_interval": 60
|
"stoploss_on_exchange_interval": 60
|
||||||
@ -435,7 +434,7 @@ Configuration:
|
|||||||
If `stoploss_on_exchange` is enabled and the stoploss is cancelled manually on the exchange, then the bot will create a new stoploss order.
|
If `stoploss_on_exchange` is enabled and the stoploss is cancelled manually on the exchange, then the bot will create a new stoploss order.
|
||||||
|
|
||||||
!!! Warning "Warning: stoploss_on_exchange failures"
|
!!! Warning "Warning: stoploss_on_exchange failures"
|
||||||
If stoploss on exchange creation fails for some reason, then an "emergency sell" is initiated. By default, this will sell the asset using a market order. The order-type for the emergency-sell can be changed by setting the `emergencysell` value in the `order_types` dictionary - however, this is not advised.
|
If stoploss on exchange creation fails for some reason, then an "emergency exit" is initiated. By default, this will sell the asset using a market order. The order-type for the emergency-sell can be changed by setting the `emergencyexit` value in the `order_types` dictionary - however, this is not advised.
|
||||||
|
|
||||||
### Understand order_time_in_force
|
### Understand order_time_in_force
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ You can use "current" market data by using the [dataprovider](strategy-customiza
|
|||||||
|
|
||||||
### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
|
### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
|
||||||
|
|
||||||
You can use the `/stopbuy` command in Telegram to prevent future buys, followed by `/forcesell all` (sell all open trades).
|
You can use the `/stopbuy` command in Telegram to prevent future buys, followed by `/forceexit all` (sell all open trades).
|
||||||
|
|
||||||
### I want to run multiple bots on the same machine
|
### I want to run multiple bots on the same machine
|
||||||
|
|
||||||
@ -117,10 +117,10 @@ As the message says, your exchange does not support market orders and you have o
|
|||||||
|
|
||||||
To fix this, redefine order types in the strategy to use "limit" instead of "market":
|
To fix this, redefine order types in the strategy to use "limit" instead of "market":
|
||||||
|
|
||||||
```
|
``` python
|
||||||
order_types = {
|
order_types = {
|
||||||
...
|
...
|
||||||
'stoploss': 'limit',
|
"stoploss": "limit",
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -101,8 +101,8 @@ Assuming both buy and sell are using market orders, a configuration similar to t
|
|||||||
|
|
||||||
``` jsonc
|
``` jsonc
|
||||||
"order_types": {
|
"order_types": {
|
||||||
"buy": "market",
|
"entry": "market",
|
||||||
"sell": "market"
|
"exit": "market"
|
||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
"bid_strategy": {
|
"bid_strategy": {
|
||||||
|
@ -145,9 +145,9 @@ python3 scripts/rest_client.py --config rest_config.json <command> [optional par
|
|||||||
| `locks` | Displays currently locked pairs.
|
| `locks` | Displays currently locked pairs.
|
||||||
| `delete_lock <lock_id>` | Deletes (disables) the lock by id.
|
| `delete_lock <lock_id>` | Deletes (disables) the lock by id.
|
||||||
| `profit` | Display a summary of your profit/loss from close trades and some stats about your performance.
|
| `profit` | Display a summary of your profit/loss from close trades and some stats about your performance.
|
||||||
| `forcesell <trade_id>` | Instantly sells the given trade (Ignoring `minimum_roi`).
|
| `forceexit <trade_id>` | Instantly exits the given trade (Ignoring `minimum_roi`).
|
||||||
| `forcesell all` | Instantly sells all open trades (Ignoring `minimum_roi`).
|
| `forceexit all` | Instantly exits all open trades (Ignoring `minimum_roi`).
|
||||||
| `forcebuy <pair> [rate]` | Instantly buys the given pair. Rate is optional. (`forcebuy_enable` must be set to True)
|
| `forceenter <pair> [rate]` | Instantly enters the given pair. Rate is optional. (`forcebuy_enable` must be set to True)
|
||||||
| `forceenter <pair> <side> [rate]` | Instantly longs or shorts the given pair. Rate is optional. (`forcebuy_enable` must be set to True)
|
| `forceenter <pair> <side> [rate]` | Instantly longs or shorts the given pair. Rate is optional. (`forcebuy_enable` must be set to True)
|
||||||
| `performance` | Show performance of each finished trade grouped by pair.
|
| `performance` | Show performance of each finished trade grouped by pair.
|
||||||
| `balance` | Show account balance per currency.
|
| `balance` | Show account balance per currency.
|
||||||
|
@ -104,8 +104,8 @@ To mitigate this, you can try to match the first order on the opposite orderbook
|
|||||||
|
|
||||||
``` jsonc
|
``` jsonc
|
||||||
"order_types": {
|
"order_types": {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit"
|
"exit": "limit"
|
||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
"bid_strategy": {
|
"bid_strategy": {
|
||||||
|
@ -49,14 +49,14 @@ sqlite3
|
|||||||
SELECT * FROM trades;
|
SELECT * FROM trades;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fix trade still open after a manual sell on the exchange
|
## Fix trade still open after a manual exit on the exchange
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
Manually selling a pair on the exchange will not be detected by the bot and it will try to sell anyway. Whenever possible, forcesell <tradeid> should be used to accomplish the same thing.
|
Manually selling a pair on the exchange will not be detected by the bot and it will try to sell anyway. Whenever possible, forceexit <tradeid> should be used to accomplish the same thing.
|
||||||
It is strongly advised to backup your database file before making any manual changes.
|
It is strongly advised to backup your database file before making any manual changes.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
This should not be necessary after /forcesell, as forcesell orders are closed automatically by the bot on the next iteration.
|
This should not be necessary after /forceexit, as forceexit orders are closed automatically by the bot on the next iteration.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
UPDATE trades
|
UPDATE trades
|
||||||
|
@ -17,7 +17,7 @@ Those stoploss modes can be *on exchange* or *off exchange*.
|
|||||||
These modes can be configured with these values:
|
These modes can be configured with these values:
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
'emergencysell': 'market',
|
'emergencyexit': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
'stoploss_on_exchange_interval': 60,
|
'stoploss_on_exchange_interval': 60,
|
||||||
'stoploss_on_exchange_limit_ratio': 0.99
|
'stoploss_on_exchange_limit_ratio': 0.99
|
||||||
@ -52,30 +52,30 @@ The bot cannot do these every 5 seconds (at each iteration), otherwise it would
|
|||||||
So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute).
|
So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute).
|
||||||
This same logic will reapply a stoploss order on the exchange should you cancel it accidentally.
|
This same logic will reapply a stoploss order on the exchange should you cancel it accidentally.
|
||||||
|
|
||||||
### forcesell
|
### forceexit
|
||||||
|
|
||||||
`forcesell` is an optional value, which defaults to the same value as `sell` and is used when sending a `/forcesell` command from Telegram or from the Rest API.
|
`forceexit` is an optional value, which defaults to the same value as `exit` and is used when sending a `/forceexit` command from Telegram or from the Rest API.
|
||||||
|
|
||||||
### forcebuy
|
### forceentry
|
||||||
|
|
||||||
`forcebuy` is an optional value, which defaults to the same value as `buy` and is used when sending a `/forcebuy` command from Telegram or from the Rest API.
|
`forceentry` is an optional value, which defaults to the same value as `entry` and is used when sending a `/forceentry` command from Telegram or from the Rest API.
|
||||||
|
|
||||||
### emergencysell
|
### emergencyexit
|
||||||
|
|
||||||
`emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails.
|
`emergencyexit` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails.
|
||||||
The below is the default which is used if not changed in strategy or configuration file.
|
The below is the default which is used if not changed in strategy or configuration file.
|
||||||
|
|
||||||
Example from strategy file:
|
Example from strategy file:
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
"entry": "limit",
|
||||||
'sell': 'limit',
|
"exit": "limit",
|
||||||
'emergencysell': 'market',
|
"emergencyexit": "market",
|
||||||
'stoploss': 'market',
|
"stoploss": "market",
|
||||||
'stoploss_on_exchange': True,
|
"stoploss_on_exchange": True,
|
||||||
'stoploss_on_exchange_interval': 60,
|
"stoploss_on_exchange_interval": 60,
|
||||||
'stoploss_on_exchange_limit_ratio': 0.99
|
"stoploss_on_exchange_limit_ratio": 0.99
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -171,8 +171,8 @@ official commands. You can ask at any moment for help with `/help`.
|
|||||||
| `/locks` | Show currently locked pairs.
|
| `/locks` | Show currently locked pairs.
|
||||||
| `/unlock <pair or lock_id>` | Remove the lock for this pair (or for this lock id).
|
| `/unlock <pair or lock_id>` | Remove the lock for this pair (or for this lock id).
|
||||||
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
|
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
|
||||||
| `/forcesell <trade_id>` | Instantly sells the given trade (Ignoring `minimum_roi`).
|
| `/forceexit <trade_id>` | Instantly exits the given trade (Ignoring `minimum_roi`).
|
||||||
| `/forcesell all` | Instantly sells all open trades (Ignoring `minimum_roi`).
|
| `/forceexit all` | Instantly exits all open trades (Ignoring `minimum_roi`).
|
||||||
| `/forcelong <pair> [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`forcebuy_enable` must be set to True)
|
| `/forcelong <pair> [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`forcebuy_enable` must be set to True)
|
||||||
| `/forceshort <pair> [rate]` | Instantly shorts the given pair. Rate is optional and only applies to limit orders. This will only work on non-spot markets. (`forcebuy_enable` must be set to True)
|
| `/forceshort <pair> [rate]` | Instantly shorts the given pair. Rate is optional and only applies to limit orders. This will only work on non-spot markets. (`forcebuy_enable` must be set to True)
|
||||||
| `/performance` | Show performance of each finished trade grouped by pair
|
| `/performance` | Show performance of each finished trade grouped by pair
|
||||||
|
@ -6,6 +6,7 @@ from jsonschema import Draft4Validator, validators
|
|||||||
from jsonschema.exceptions import ValidationError, best_match
|
from jsonschema.exceptions import ValidationError, best_match
|
||||||
|
|
||||||
from freqtrade import constants
|
from freqtrade import constants
|
||||||
|
from freqtrade.configuration.deprecated_settings import process_deprecated_setting
|
||||||
from freqtrade.enums import RunMode, TradingMode
|
from freqtrade.enums import RunMode, TradingMode
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
|
|
||||||
@ -102,11 +103,12 @@ def _validate_price_config(conf: Dict[str, Any]) -> None:
|
|||||||
"""
|
"""
|
||||||
When using market orders, price sides must be using the "other" side of the price
|
When using market orders, price sides must be using the "other" side of the price
|
||||||
"""
|
"""
|
||||||
if (conf.get('order_types', {}).get('buy') == 'market'
|
# TODO-lev: check this again when determining how to migrate pricing strategies!
|
||||||
|
if (conf.get('order_types', {}).get('entry') == 'market'
|
||||||
and conf.get('bid_strategy', {}).get('price_side') != 'ask'):
|
and conf.get('bid_strategy', {}).get('price_side') != 'ask'):
|
||||||
raise OperationalException('Market buy orders require bid_strategy.price_side = "ask".')
|
raise OperationalException('Market buy orders require bid_strategy.price_side = "ask".')
|
||||||
|
|
||||||
if (conf.get('order_types', {}).get('sell') == 'market'
|
if (conf.get('order_types', {}).get('exit') == 'market'
|
||||||
and conf.get('ask_strategy', {}).get('price_side') != 'bid'):
|
and conf.get('ask_strategy', {}).get('price_side') != 'bid'):
|
||||||
raise OperationalException('Market sell orders require ask_strategy.price_side = "bid".')
|
raise OperationalException('Market sell orders require ask_strategy.price_side = "bid".')
|
||||||
|
|
||||||
@ -213,6 +215,7 @@ def _validate_ask_orderbook(conf: Dict[str, Any]) -> None:
|
|||||||
def validate_migrated_strategy_settings(conf: Dict[str, Any]) -> None:
|
def validate_migrated_strategy_settings(conf: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
_validate_time_in_force(conf)
|
_validate_time_in_force(conf)
|
||||||
|
_validate_order_types(conf)
|
||||||
|
|
||||||
|
|
||||||
def _validate_time_in_force(conf: Dict[str, Any]) -> None:
|
def _validate_time_in_force(conf: Dict[str, Any]) -> None:
|
||||||
@ -227,5 +230,31 @@ def _validate_time_in_force(conf: Dict[str, Any]) -> None:
|
|||||||
"DEPRECATED: Using 'buy' and 'sell' for time_in_force is deprecated."
|
"DEPRECATED: Using 'buy' and 'sell' for time_in_force is deprecated."
|
||||||
"Please migrate your time_in_force settings to use 'entry' and 'exit'."
|
"Please migrate your time_in_force settings to use 'entry' and 'exit'."
|
||||||
)
|
)
|
||||||
time_in_force['entry'] = time_in_force.pop('buy')
|
process_deprecated_setting(
|
||||||
time_in_force['exit'] = time_in_force.pop('sell')
|
conf, 'order_time_in_force', 'buy', 'order_time_in_force', 'entry')
|
||||||
|
|
||||||
|
process_deprecated_setting(
|
||||||
|
conf, 'order_time_in_force', 'sell', 'order_time_in_force', 'exit')
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_order_types(conf: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
|
order_types = conf.get('order_types', {})
|
||||||
|
if any(x in order_types for x in ['buy', 'sell', 'emergencysell', 'forcebuy', 'forcesell']):
|
||||||
|
if conf.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT:
|
||||||
|
raise OperationalException(
|
||||||
|
"Please migrate your order_types settings to use the new wording.")
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
"DEPRECATED: Using 'buy' and 'sell' for order_types is deprecated."
|
||||||
|
"Please migrate your order_types settings to use 'entry' and 'exit' wording."
|
||||||
|
)
|
||||||
|
for o, n in [
|
||||||
|
('buy', 'entry'),
|
||||||
|
('sell', 'exit'),
|
||||||
|
('emergencysell', 'emergencyexit'),
|
||||||
|
('forcesell', 'forceexit'),
|
||||||
|
('forcebuy', 'forceentry'),
|
||||||
|
]:
|
||||||
|
|
||||||
|
process_deprecated_setting(conf, 'order_types', o, 'order_types', n)
|
||||||
|
@ -64,6 +64,7 @@ def process_deprecated_setting(config: Dict[str, Any],
|
|||||||
|
|
||||||
section_new_config = config.get(section_new, {}) if section_new else config
|
section_new_config = config.get(section_new, {}) if section_new else config
|
||||||
section_new_config[name_new] = section_old_config[name_old]
|
section_new_config[name_new] = section_old_config[name_old]
|
||||||
|
del section_old_config[name_old]
|
||||||
|
|
||||||
|
|
||||||
def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None:
|
def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None:
|
||||||
|
@ -20,7 +20,7 @@ DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite'
|
|||||||
UNLIMITED_STAKE_AMOUNT = 'unlimited'
|
UNLIMITED_STAKE_AMOUNT = 'unlimited'
|
||||||
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
|
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
|
||||||
REQUIRED_ORDERTIF = ['entry', 'exit']
|
REQUIRED_ORDERTIF = ['entry', 'exit']
|
||||||
REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
|
REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
|
||||||
ORDERBOOK_SIDES = ['ask', 'bid']
|
ORDERBOOK_SIDES = ['ask', 'bid']
|
||||||
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
||||||
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
||||||
@ -214,11 +214,11 @@ CONF_SCHEMA = {
|
|||||||
'order_types': {
|
'order_types': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'buy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
'entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
'sell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
'exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
'forcesell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
'forceexit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
'forcebuy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
'forceentry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
'emergencysell': {
|
'emergencyexit': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'enum': ORDERTYPE_POSSIBILITIES,
|
'enum': ORDERTYPE_POSSIBILITIES,
|
||||||
'default': 'market'},
|
'default': 'market'},
|
||||||
@ -228,7 +228,7 @@ CONF_SCHEMA = {
|
|||||||
'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0,
|
'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0,
|
||||||
'maximum': 1.0}
|
'maximum': 1.0}
|
||||||
},
|
},
|
||||||
'required': ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
|
'required': ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
|
||||||
},
|
},
|
||||||
'order_time_in_force': {
|
'order_time_in_force': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
|
@ -629,7 +629,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
f"{stake_amount} ...")
|
f"{stake_amount} ...")
|
||||||
|
|
||||||
amount = (stake_amount / enter_limit_requested) * leverage
|
amount = (stake_amount / enter_limit_requested) * leverage
|
||||||
order_type = ordertype or self.strategy.order_types['buy']
|
order_type = ordertype or self.strategy.order_types['entry']
|
||||||
|
|
||||||
if not pos_adjust and not strategy_safe_wrapper(
|
if not pos_adjust and not strategy_safe_wrapper(
|
||||||
self.strategy.confirm_trade_entry, default_retval=True)(
|
self.strategy.confirm_trade_entry, default_retval=True)(
|
||||||
@ -1155,7 +1155,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
max_timeouts = self.config.get(
|
max_timeouts = self.config.get(
|
||||||
'unfilledtimeout', {}).get('exit_timeout_count', 0)
|
'unfilledtimeout', {}).get('exit_timeout_count', 0)
|
||||||
if canceled and max_timeouts > 0 and canceled_count >= max_timeouts:
|
if canceled and max_timeouts > 0 and canceled_count >= max_timeouts:
|
||||||
logger.warning(f'Emergencyselling trade {trade}, as the sell order '
|
logger.warning(f'Emergency exiting trade {trade}, as the exit order '
|
||||||
f'timed out {max_timeouts} times.')
|
f'timed out {max_timeouts} times.')
|
||||||
try:
|
try:
|
||||||
self.execute_trade_exit(
|
self.execute_trade_exit(
|
||||||
@ -1248,11 +1248,11 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
self.update_trade_state(trade, trade.open_order_id, corder)
|
self.update_trade_state(trade, trade.open_order_id, corder)
|
||||||
|
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
logger.info('Partial %s order timeout for %s.', trade.enter_side, trade)
|
logger.info(f'Partial {trade.enter_side} order timeout for {trade}.')
|
||||||
reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}"
|
reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}"
|
||||||
|
|
||||||
self.wallets.update()
|
self.wallets.update()
|
||||||
self._notify_enter_cancel(trade, order_type=self.strategy.order_types[trade.enter_side],
|
self._notify_enter_cancel(trade, order_type=self.strategy.order_types['entry'],
|
||||||
reason=reason)
|
reason=reason)
|
||||||
return was_trade_fully_canceled
|
return was_trade_fully_canceled
|
||||||
|
|
||||||
@ -1297,7 +1297,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
self.wallets.update()
|
self.wallets.update()
|
||||||
self._notify_exit_cancel(
|
self._notify_exit_cancel(
|
||||||
trade,
|
trade,
|
||||||
order_type=self.strategy.order_types[trade.exit_side],
|
order_type=self.strategy.order_types['exit'],
|
||||||
reason=reason
|
reason=reason
|
||||||
)
|
)
|
||||||
return cancelled
|
return cancelled
|
||||||
@ -1353,7 +1353,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
is_short=trade.is_short,
|
is_short=trade.is_short,
|
||||||
open_date=trade.open_date,
|
open_date=trade.open_date,
|
||||||
)
|
)
|
||||||
exit_type = 'sell'
|
exit_type = 'exit'
|
||||||
if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
||||||
exit_type = 'stoploss'
|
exit_type = 'stoploss'
|
||||||
|
|
||||||
@ -1380,7 +1380,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
order_type = ordertype or self.strategy.order_types[exit_type]
|
order_type = ordertype or self.strategy.order_types[exit_type]
|
||||||
if sell_reason.sell_type == SellType.EMERGENCY_SELL:
|
if sell_reason.sell_type == SellType.EMERGENCY_SELL:
|
||||||
# Emergency sells (default to market!)
|
# Emergency sells (default to market!)
|
||||||
order_type = self.strategy.order_types.get("emergencysell", "market")
|
order_type = self.strategy.order_types.get("emergencyexit", "market")
|
||||||
|
|
||||||
amount = self._safe_exit_amount(trade.pair, trade.amount)
|
amount = self._safe_exit_amount(trade.pair, trade.amount)
|
||||||
time_in_force = self.strategy.order_time_in_force['exit']
|
time_in_force = self.strategy.order_time_in_force['exit']
|
||||||
|
@ -490,7 +490,7 @@ class Backtesting:
|
|||||||
return None
|
return None
|
||||||
# call the custom exit price,with default value as previous closerate
|
# call the custom exit price,with default value as previous closerate
|
||||||
current_profit = trade.calc_profit_ratio(closerate)
|
current_profit = trade.calc_profit_ratio(closerate)
|
||||||
order_type = self.strategy.order_types['sell']
|
order_type = self.strategy.order_types['exit']
|
||||||
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
||||||
# Custom exit pricing only for sell-signals
|
# Custom exit pricing only for sell-signals
|
||||||
if order_type == 'limit':
|
if order_type == 'limit':
|
||||||
@ -598,7 +598,7 @@ class Backtesting:
|
|||||||
current_time = row[DATE_IDX].to_pydatetime()
|
current_time = row[DATE_IDX].to_pydatetime()
|
||||||
entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None
|
entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None
|
||||||
# let's call the custom entry price, using the open price as default price
|
# let's call the custom entry price, using the open price as default price
|
||||||
order_type = self.strategy.order_types['buy']
|
order_type = self.strategy.order_types['entry']
|
||||||
propose_rate = row[OPEN_IDX]
|
propose_rate = row[OPEN_IDX]
|
||||||
if order_type == 'limit':
|
if order_type == 'limit':
|
||||||
propose_rate = strategy_safe_wrapper(self.strategy.custom_entry_price,
|
propose_rate = strategy_safe_wrapper(self.strategy.custom_entry_price,
|
||||||
@ -638,7 +638,7 @@ class Backtesting:
|
|||||||
# In case of pos adjust, still return the original trade
|
# In case of pos adjust, still return the original trade
|
||||||
# If not pos adjust, trade is None
|
# If not pos adjust, trade is None
|
||||||
return trade
|
return trade
|
||||||
order_type = self.strategy.order_types['buy']
|
order_type = self.strategy.order_types['entry']
|
||||||
time_in_force = self.strategy.order_time_in_force['entry']
|
time_in_force = self.strategy.order_time_in_force['entry']
|
||||||
|
|
||||||
if not pos_adjust:
|
if not pos_adjust:
|
||||||
|
@ -138,11 +138,11 @@ class UnfilledTimeout(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class OrderTypes(BaseModel):
|
class OrderTypes(BaseModel):
|
||||||
buy: OrderTypeValues
|
entry: OrderTypeValues
|
||||||
sell: OrderTypeValues
|
exit: OrderTypeValues
|
||||||
emergencysell: Optional[OrderTypeValues]
|
emergencyexit: Optional[OrderTypeValues]
|
||||||
forcesell: Optional[OrderTypeValues]
|
forceexit: Optional[OrderTypeValues]
|
||||||
forcebuy: Optional[OrderTypeValues]
|
forceentry: Optional[OrderTypeValues]
|
||||||
stoploss: OrderTypeValues
|
stoploss: OrderTypeValues
|
||||||
stoploss_on_exchange: bool
|
stoploss_on_exchange: bool
|
||||||
stoploss_on_exchange_interval: Optional[int]
|
stoploss_on_exchange_interval: Optional[int]
|
||||||
|
@ -712,7 +712,7 @@ class RPC:
|
|||||||
trade.pair, refresh=False, side=trade.exit_side)
|
trade.pair, refresh=False, side=trade.exit_side)
|
||||||
sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
|
sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
|
||||||
order_type = ordertype or self._freqtrade.strategy.order_types.get(
|
order_type = ordertype or self._freqtrade.strategy.order_types.get(
|
||||||
"forcesell", self._freqtrade.strategy.order_types["sell"])
|
"forceexit", self._freqtrade.strategy.order_types["exit"])
|
||||||
|
|
||||||
self._freqtrade.execute_trade_exit(
|
self._freqtrade.execute_trade_exit(
|
||||||
trade, current_rate, sell_reason, ordertype=order_type)
|
trade, current_rate, sell_reason, ordertype=order_type)
|
||||||
@ -735,7 +735,7 @@ class RPC:
|
|||||||
trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True), ]
|
trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True), ]
|
||||||
).first()
|
).first()
|
||||||
if not trade:
|
if not trade:
|
||||||
logger.warning('forcesell: Invalid argument received')
|
logger.warning('forceexit: Invalid argument received')
|
||||||
raise RPCException('invalid argument')
|
raise RPCException('invalid argument')
|
||||||
|
|
||||||
_exec_forcesell(trade)
|
_exec_forcesell(trade)
|
||||||
@ -784,7 +784,7 @@ class RPC:
|
|||||||
# execute buy
|
# execute buy
|
||||||
if not order_type:
|
if not order_type:
|
||||||
order_type = self._freqtrade.strategy.order_types.get(
|
order_type = self._freqtrade.strategy.order_types.get(
|
||||||
'forcebuy', self._freqtrade.strategy.order_types['buy'])
|
'forceentry', self._freqtrade.strategy.order_types['entry'])
|
||||||
if self._freqtrade.execute_entry(pair, stake_amount, price,
|
if self._freqtrade.execute_entry(pair, stake_amount, price,
|
||||||
ordertype=order_type, trade=trade,
|
ordertype=order_type, trade=trade,
|
||||||
is_short=is_short,
|
is_short=is_short,
|
||||||
|
@ -944,7 +944,7 @@ class Telegram(RPCHandler):
|
|||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
msg = self._rpc._rpc_forceexit(trade_id)
|
msg = self._rpc._rpc_forceexit(trade_id)
|
||||||
self._send_msg('Forcesell Result: `{result}`'.format(**msg))
|
self._send_msg('Forceexit Result: `{result}`'.format(**msg))
|
||||||
|
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
@ -90,8 +90,8 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
|
|
||||||
# Optional order types
|
# Optional order types
|
||||||
order_types: Dict = {
|
order_types: Dict = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False,
|
'stoploss_on_exchange': False,
|
||||||
'stoploss_on_exchange_interval': 60,
|
'stoploss_on_exchange_interval': 60,
|
||||||
|
@ -78,8 +78,8 @@ class {{ strategy }}(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping.
|
# Optional order type mapping.
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ class SampleShortStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping.
|
# Optional order type mapping.
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,8 @@ class SampleStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping.
|
# Optional order type mapping.
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"order_types": {
|
"order_types": {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit",
|
"exit": "limit",
|
||||||
"emergencysell": "limit",
|
"emergencyexit": "limit",
|
||||||
"stoploss": "limit",
|
"stoploss": "limit",
|
||||||
"stoploss_on_exchange": false
|
"stoploss_on_exchange": false
|
||||||
},
|
},
|
||||||
|
@ -951,8 +951,8 @@ def test_validate_order_types(default_conf, mocker):
|
|||||||
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
|
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
|
||||||
|
|
||||||
default_conf['order_types'] = {
|
default_conf['order_types'] = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
@ -962,8 +962,8 @@ def test_validate_order_types(default_conf, mocker):
|
|||||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
|
|
||||||
default_conf['order_types'] = {
|
default_conf['order_types'] = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
@ -972,8 +972,8 @@ def test_validate_order_types(default_conf, mocker):
|
|||||||
Exchange(default_conf)
|
Exchange(default_conf)
|
||||||
|
|
||||||
default_conf['order_types'] = {
|
default_conf['order_types'] = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': True
|
'stoploss_on_exchange': True
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ def test_validate_order_types_gateio(default_conf, mocker):
|
|||||||
assert isinstance(exch, Gateio)
|
assert isinstance(exch, Gateio)
|
||||||
|
|
||||||
default_conf['order_types'] = {
|
default_conf['order_types'] = {
|
||||||
'buy': 'market',
|
'entry': 'market',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'market',
|
'stoploss': 'market',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -32,14 +32,14 @@ from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has, log_has_re
|
|||||||
|
|
||||||
ORDER_TYPES = [
|
ORDER_TYPES = [
|
||||||
{
|
{
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': True
|
'stoploss_on_exchange': True
|
||||||
}]
|
}]
|
||||||
|
@ -34,8 +34,8 @@ class HyperoptableStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping
|
# Optional order type mapping
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ class StrategyTestV2(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping
|
# Optional order type mapping
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ class StrategyTestV3(IStrategy):
|
|||||||
|
|
||||||
# Optional order type mapping
|
# Optional order type mapping
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'limit',
|
'entry': 'limit',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False
|
'stoploss_on_exchange': False
|
||||||
}
|
}
|
||||||
|
@ -239,8 +239,8 @@ def test_strategy_override_order_types(caplog, default_conf):
|
|||||||
caplog.set_level(logging.INFO)
|
caplog.set_level(logging.INFO)
|
||||||
|
|
||||||
order_types = {
|
order_types = {
|
||||||
'buy': 'market',
|
'entry': 'market',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': True,
|
'stoploss_on_exchange': True,
|
||||||
}
|
}
|
||||||
@ -251,16 +251,16 @@ def test_strategy_override_order_types(caplog, default_conf):
|
|||||||
strategy = StrategyResolver.load_strategy(default_conf)
|
strategy = StrategyResolver.load_strategy(default_conf)
|
||||||
|
|
||||||
assert strategy.order_types
|
assert strategy.order_types
|
||||||
for method in ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']:
|
for method in ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']:
|
||||||
assert strategy.order_types[method] == order_types[method]
|
assert strategy.order_types[method] == order_types[method]
|
||||||
|
|
||||||
assert log_has("Override strategy 'order_types' with value in config file:"
|
assert log_has("Override strategy 'order_types' with value in config file:"
|
||||||
" {'buy': 'market', 'sell': 'limit', 'stoploss': 'limit',"
|
" {'entry': 'market', 'exit': 'limit', 'stoploss': 'limit',"
|
||||||
" 'stoploss_on_exchange': True}.", caplog)
|
" 'stoploss_on_exchange': True}.", caplog)
|
||||||
|
|
||||||
default_conf.update({
|
default_conf.update({
|
||||||
'strategy': CURRENT_TEST_STRATEGY,
|
'strategy': CURRENT_TEST_STRATEGY,
|
||||||
'order_types': {'buy': 'market'}
|
'order_types': {'exit': 'market'}
|
||||||
})
|
})
|
||||||
# Raise error for invalid configuration
|
# Raise error for invalid configuration
|
||||||
with pytest.raises(ImportError,
|
with pytest.raises(ImportError,
|
||||||
|
@ -798,8 +798,8 @@ def test_validate_max_open_trades(default_conf):
|
|||||||
|
|
||||||
def test_validate_price_side(default_conf):
|
def test_validate_price_side(default_conf):
|
||||||
default_conf['order_types'] = {
|
default_conf['order_types'] = {
|
||||||
"buy": "limit",
|
"entry": "limit",
|
||||||
"sell": "limit",
|
"exit": "limit",
|
||||||
"stoploss": "limit",
|
"stoploss": "limit",
|
||||||
"stoploss_on_exchange": False,
|
"stoploss_on_exchange": False,
|
||||||
}
|
}
|
||||||
@ -807,21 +807,21 @@ def test_validate_price_side(default_conf):
|
|||||||
validate_config_consistency(default_conf)
|
validate_config_consistency(default_conf)
|
||||||
|
|
||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['order_types']['buy'] = 'market'
|
conf['order_types']['entry'] = 'market'
|
||||||
with pytest.raises(OperationalException,
|
with pytest.raises(OperationalException,
|
||||||
match='Market buy orders require bid_strategy.price_side = "ask".'):
|
match='Market buy orders require bid_strategy.price_side = "ask".'):
|
||||||
validate_config_consistency(conf)
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['order_types']['sell'] = 'market'
|
conf['order_types']['exit'] = 'market'
|
||||||
with pytest.raises(OperationalException,
|
with pytest.raises(OperationalException,
|
||||||
match='Market sell orders require ask_strategy.price_side = "bid".'):
|
match='Market sell orders require ask_strategy.price_side = "bid".'):
|
||||||
validate_config_consistency(conf)
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
# Validate inversed case
|
# Validate inversed case
|
||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['order_types']['sell'] = 'market'
|
conf['order_types']['exit'] = 'market'
|
||||||
conf['order_types']['buy'] = 'market'
|
conf['order_types']['entry'] = 'market'
|
||||||
conf['ask_strategy']['price_side'] = 'bid'
|
conf['ask_strategy']['price_side'] = 'bid'
|
||||||
conf['bid_strategy']['price_side'] = 'ask'
|
conf['bid_strategy']['price_side'] = 'ask'
|
||||||
|
|
||||||
@ -963,6 +963,41 @@ def test_validate_time_in_force(default_conf, caplog) -> None:
|
|||||||
validate_config_consistency(conf)
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_order_types(default_conf, caplog) -> None:
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['order_types'] = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'market',
|
||||||
|
'forcesell': 'market',
|
||||||
|
'forcebuy': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False,
|
||||||
|
}
|
||||||
|
validate_config_consistency(conf)
|
||||||
|
assert log_has_re(r"DEPRECATED: Using 'buy' and 'sell' for order_types is.*", caplog)
|
||||||
|
assert conf['order_types']['entry'] == 'limit'
|
||||||
|
assert conf['order_types']['exit'] == 'market'
|
||||||
|
assert conf['order_types']['forceentry'] == 'limit'
|
||||||
|
assert 'buy' not in conf['order_types']
|
||||||
|
assert 'sell' not in conf['order_types']
|
||||||
|
assert 'forcebuy' not in conf['order_types']
|
||||||
|
assert 'forcesell' not in conf['order_types']
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['order_types'] = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'market',
|
||||||
|
'forcesell': 'market',
|
||||||
|
'forcebuy': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False,
|
||||||
|
}
|
||||||
|
conf['trading_mode'] = 'futures'
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match=r"Please migrate your order_types settings to use the new wording\."):
|
||||||
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
|
|
||||||
def test_load_config_test_comments() -> None:
|
def test_load_config_test_comments() -> None:
|
||||||
"""
|
"""
|
||||||
Load config with comments
|
Load config with comments
|
||||||
@ -1280,11 +1315,14 @@ def test_process_deprecated_setting(mocker, default_conf, caplog):
|
|||||||
# The value of the new setting shall have been set to the
|
# The value of the new setting shall have been set to the
|
||||||
# value of the deprecated one
|
# value of the deprecated one
|
||||||
assert default_conf['sectionA']['new_setting'] == 'valB'
|
assert default_conf['sectionA']['new_setting'] == 'valB'
|
||||||
|
# Old setting is removed
|
||||||
|
assert 'deprecated_setting' not in default_conf['sectionB']
|
||||||
|
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
# Delete new setting (deprecated exists)
|
# Delete new setting (deprecated exists)
|
||||||
del default_conf['sectionA']['new_setting']
|
del default_conf['sectionA']['new_setting']
|
||||||
|
default_conf['sectionB']['deprecated_setting'] = 'valB'
|
||||||
process_deprecated_setting(default_conf,
|
process_deprecated_setting(default_conf,
|
||||||
'sectionB', 'deprecated_setting',
|
'sectionB', 'deprecated_setting',
|
||||||
'sectionA', 'new_setting')
|
'sectionA', 'new_setting')
|
||||||
@ -1298,7 +1336,7 @@ def test_process_deprecated_setting(mocker, default_conf, caplog):
|
|||||||
# Assign new setting
|
# Assign new setting
|
||||||
default_conf['sectionA']['new_setting'] = 'valA'
|
default_conf['sectionA']['new_setting'] = 'valA'
|
||||||
# Delete deprecated setting
|
# Delete deprecated setting
|
||||||
del default_conf['sectionB']['deprecated_setting']
|
default_conf['sectionB'].pop('deprecated_setting', None)
|
||||||
process_deprecated_setting(default_conf,
|
process_deprecated_setting(default_conf,
|
||||||
'sectionB', 'deprecated_setting',
|
'sectionB', 'deprecated_setting',
|
||||||
'sectionA', 'new_setting')
|
'sectionA', 'new_setting')
|
||||||
|
@ -91,8 +91,8 @@ def test_order_dict(default_conf_usdt, mocker, runmode, caplog) -> None:
|
|||||||
conf = default_conf_usdt.copy()
|
conf = default_conf_usdt.copy()
|
||||||
conf['runmode'] = runmode
|
conf['runmode'] = runmode
|
||||||
conf['order_types'] = {
|
conf['order_types'] = {
|
||||||
'buy': 'market',
|
'entry': 'market',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': True,
|
'stoploss_on_exchange': True,
|
||||||
}
|
}
|
||||||
@ -108,8 +108,8 @@ def test_order_dict(default_conf_usdt, mocker, runmode, caplog) -> None:
|
|||||||
conf = default_conf_usdt.copy()
|
conf = default_conf_usdt.copy()
|
||||||
conf['runmode'] = runmode
|
conf['runmode'] = runmode
|
||||||
conf['order_types'] = {
|
conf['order_types'] = {
|
||||||
'buy': 'market',
|
'entry': 'market',
|
||||||
'sell': 'limit',
|
'exit': 'limit',
|
||||||
'stoploss': 'limit',
|
'stoploss': 'limit',
|
||||||
'stoploss_on_exchange': False,
|
'stoploss_on_exchange': False,
|
||||||
}
|
}
|
||||||
@ -2578,7 +2578,7 @@ def test_check_handle_timedout_sell_usercustom(
|
|||||||
assert et_mock.call_count == 0
|
assert et_mock.call_count == 0
|
||||||
|
|
||||||
freqtrade.check_handle_timedout()
|
freqtrade.check_handle_timedout()
|
||||||
assert log_has_re('Emergencyselling trade.*', caplog)
|
assert log_has_re('Emergency exiting trade.*', caplog)
|
||||||
assert et_mock.call_count == 1
|
assert et_mock.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@ -3517,7 +3517,7 @@ def test_execute_trade_exit_market_order(
|
|||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
fetch_ticker=ticker_usdt_sell_up
|
fetch_ticker=ticker_usdt_sell_up
|
||||||
)
|
)
|
||||||
freqtrade.config['order_types']['sell'] = 'market'
|
freqtrade.config['order_types']['exit'] = 'market'
|
||||||
|
|
||||||
freqtrade.execute_trade_exit(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
|
@ -80,7 +80,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
|
|||||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||||
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
|
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
|
||||||
# Switch ordertype to market to close trade immediately
|
# Switch ordertype to market to close trade immediately
|
||||||
freqtrade.strategy.order_types['sell'] = 'market'
|
freqtrade.strategy.order_types['exit'] = 'market'
|
||||||
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
|
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
|
||||||
freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True)
|
freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True)
|
||||||
patch_get_signal(freqtrade)
|
patch_get_signal(freqtrade)
|
||||||
@ -173,7 +173,7 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati
|
|||||||
rpc = RPC(freqtrade)
|
rpc = RPC(freqtrade)
|
||||||
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
|
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
|
||||||
# Switch ordertype to market to close trade immediately
|
# Switch ordertype to market to close trade immediately
|
||||||
freqtrade.strategy.order_types['sell'] = 'market'
|
freqtrade.strategy.order_types['exit'] = 'market'
|
||||||
patch_get_signal(freqtrade)
|
patch_get_signal(freqtrade)
|
||||||
|
|
||||||
# Create 4 trades
|
# Create 4 trades
|
||||||
|
Loading…
Reference in New Issue
Block a user