Merge pull request #6512 from freqtrade/short_order_types

Short order types renamal
This commit is contained in:
Matthias
2022-03-12 09:32:16 +01:00
committed by GitHub
33 changed files with 198 additions and 131 deletions

View File

@@ -6,6 +6,7 @@ from jsonschema import Draft4Validator, validators
from jsonschema.exceptions import ValidationError, best_match
from freqtrade import constants
from freqtrade.configuration.deprecated_settings import process_deprecated_setting
from freqtrade.enums import RunMode, TradingMode
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
"""
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'):
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'):
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:
_validate_time_in_force(conf)
_validate_order_types(conf)
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."
"Please migrate your time_in_force settings to use 'entry' and 'exit'."
)
time_in_force['entry'] = time_in_force.pop('buy')
time_in_force['exit'] = time_in_force.pop('sell')
process_deprecated_setting(
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)

View File

@@ -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[name_new] = section_old_config[name_old]
del section_old_config[name_old]
def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None:

View File

@@ -20,7 +20,7 @@ DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite'
UNLIMITED_STAKE_AMOUNT = 'unlimited'
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
REQUIRED_ORDERTIF = ['entry', 'exit']
REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
ORDERBOOK_SIDES = ['ask', 'bid']
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
@@ -214,11 +214,11 @@ CONF_SCHEMA = {
'order_types': {
'type': 'object',
'properties': {
'buy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'sell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forcesell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forcebuy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'emergencysell': {
'entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forceexit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forceentry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'emergencyexit': {
'type': 'string',
'enum': ORDERTYPE_POSSIBILITIES,
'default': 'market'},
@@ -228,7 +228,7 @@ CONF_SCHEMA = {
'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0,
'maximum': 1.0}
},
'required': ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
'required': ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
},
'order_time_in_force': {
'type': 'object',

View File

@@ -629,7 +629,7 @@ class FreqtradeBot(LoggingMixin):
f"{stake_amount} ...")
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(
self.strategy.confirm_trade_entry, default_retval=True)(
@@ -1155,7 +1155,7 @@ class FreqtradeBot(LoggingMixin):
max_timeouts = self.config.get(
'unfilledtimeout', {}).get('exit_timeout_count', 0)
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.')
try:
self.execute_trade_exit(
@@ -1248,11 +1248,11 @@ class FreqtradeBot(LoggingMixin):
self.update_trade_state(trade, trade.open_order_id, corder)
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']}"
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)
return was_trade_fully_canceled
@@ -1297,7 +1297,7 @@ class FreqtradeBot(LoggingMixin):
self.wallets.update()
self._notify_exit_cancel(
trade,
order_type=self.strategy.order_types[trade.exit_side],
order_type=self.strategy.order_types['exit'],
reason=reason
)
return cancelled
@@ -1353,7 +1353,7 @@ class FreqtradeBot(LoggingMixin):
is_short=trade.is_short,
open_date=trade.open_date,
)
exit_type = 'sell'
exit_type = 'exit'
if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
exit_type = 'stoploss'
@@ -1380,7 +1380,7 @@ class FreqtradeBot(LoggingMixin):
order_type = ordertype or self.strategy.order_types[exit_type]
if sell_reason.sell_type == SellType.EMERGENCY_SELL:
# 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)
time_in_force = self.strategy.order_time_in_force['exit']

View File

@@ -490,7 +490,7 @@ class Backtesting:
return None
# call the custom exit price,with default value as previous 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):
# Custom exit pricing only for sell-signals
if order_type == 'limit':
@@ -598,7 +598,7 @@ class Backtesting:
current_time = row[DATE_IDX].to_pydatetime()
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
order_type = self.strategy.order_types['buy']
order_type = self.strategy.order_types['entry']
propose_rate = row[OPEN_IDX]
if order_type == 'limit':
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
# If not pos adjust, trade is None
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']
if not pos_adjust:

View File

@@ -138,11 +138,11 @@ class UnfilledTimeout(BaseModel):
class OrderTypes(BaseModel):
buy: OrderTypeValues
sell: OrderTypeValues
emergencysell: Optional[OrderTypeValues]
forcesell: Optional[OrderTypeValues]
forcebuy: Optional[OrderTypeValues]
entry: OrderTypeValues
exit: OrderTypeValues
emergencyexit: Optional[OrderTypeValues]
forceexit: Optional[OrderTypeValues]
forceentry: Optional[OrderTypeValues]
stoploss: OrderTypeValues
stoploss_on_exchange: bool
stoploss_on_exchange_interval: Optional[int]

View File

@@ -712,7 +712,7 @@ class RPC:
trade.pair, refresh=False, side=trade.exit_side)
sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
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(
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), ]
).first()
if not trade:
logger.warning('forcesell: Invalid argument received')
logger.warning('forceexit: Invalid argument received')
raise RPCException('invalid argument')
_exec_forcesell(trade)
@@ -784,7 +784,7 @@ class RPC:
# execute buy
if not order_type:
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,
ordertype=order_type, trade=trade,
is_short=is_short,

View File

@@ -944,7 +944,7 @@ class Telegram(RPCHandler):
return
try:
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:
self._send_msg(str(e))

View File

@@ -90,8 +90,8 @@ class IStrategy(ABC, HyperStrategyMixin):
# Optional order types
order_types: Dict = {
'buy': 'limit',
'sell': 'limit',
'entry': 'limit',
'exit': 'limit',
'stoploss': 'limit',
'stoploss_on_exchange': False,
'stoploss_on_exchange_interval': 60,

View File

@@ -78,8 +78,8 @@ class {{ strategy }}(IStrategy):
# Optional order type mapping.
order_types = {
'buy': 'limit',
'sell': 'limit',
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}

View File

@@ -79,8 +79,8 @@ class SampleShortStrategy(IStrategy):
# Optional order type mapping.
order_types = {
'buy': 'limit',
'sell': 'limit',
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}

View File

@@ -80,8 +80,8 @@ class SampleStrategy(IStrategy):
# Optional order type mapping.
order_types = {
'buy': 'limit',
'sell': 'limit',
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}

View File

@@ -1,7 +1,7 @@
"order_types": {
"buy": "limit",
"sell": "limit",
"emergencysell": "limit",
"entry": "limit",
"exit": "limit",
"emergencyexit": "limit",
"stoploss": "limit",
"stoploss_on_exchange": false
},