Update order time in force to use entry/exit wording

This commit is contained in:
Matthias
2022-03-07 07:09:01 +01:00
parent da733a458d
commit 3ff261e22c
17 changed files with 88 additions and 40 deletions

View File

@@ -6,7 +6,7 @@ from jsonschema import Draft4Validator, validators
from jsonschema.exceptions import ValidationError, best_match
from freqtrade import constants
from freqtrade.enums import RunMode
from freqtrade.enums import RunMode, TradingMode
from freqtrade.exceptions import OperationalException
@@ -80,6 +80,7 @@ def validate_config_consistency(conf: Dict[str, Any]) -> None:
_validate_protections(conf)
_validate_unlimited_amount(conf)
_validate_ask_orderbook(conf)
validate_migrated_strategy_settings(conf)
# validate configuration before returning
logger.info('Validating configuration ...')
@@ -207,3 +208,24 @@ def _validate_ask_orderbook(conf: Dict[str, Any]) -> None:
"Please use `order_book_top` instead of `order_book_min` and `order_book_max` "
"for your `ask_strategy` configuration."
)
def validate_migrated_strategy_settings(conf: Dict[str, Any]) -> None:
_validate_time_in_force(conf)
def _validate_time_in_force(conf: Dict[str, Any]) -> None:
time_in_force = conf.get('order_time_in_force', {})
if 'buy' in time_in_force or 'sell' in time_in_force:
if conf.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT:
raise OperationalException(
"Please migrate your time_in_force settings to use 'entry' and 'exit'.")
else:
logger.warning(
"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')

View File

@@ -19,7 +19,7 @@ DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite'
UNLIMITED_STAKE_AMOUNT = 'unlimited'
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
REQUIRED_ORDERTIF = ['buy', 'sell']
REQUIRED_ORDERTIF = ['entry', 'exit']
REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
ORDERBOOK_SIDES = ['ask', 'bid']
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
@@ -233,10 +233,10 @@ CONF_SCHEMA = {
'order_time_in_force': {
'type': 'object',
'properties': {
'buy': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES},
'sell': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}
'entry': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES},
'exit': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}
},
'required': ['buy', 'sell']
'required': REQUIRED_ORDERTIF
},
'exchange': {'$ref': '#/definitions/exchange'},
'edge': {'$ref': '#/definitions/edge'},

View File

@@ -595,7 +595,7 @@ class FreqtradeBot(LoggingMixin):
:param leverage: amount of leverage applied to this trade
:return: True if a buy order is created, false if it fails.
"""
time_in_force = self.strategy.order_time_in_force['buy']
time_in_force = self.strategy.order_time_in_force['entry']
[side, name] = ['sell', 'Short'] if is_short else ['buy', 'Long']
trade_side = 'short' if is_short else 'long'
@@ -659,13 +659,12 @@ class FreqtradeBot(LoggingMixin):
amount_requested = amount
if order_status == 'expired' or order_status == 'rejected':
order_tif = self.strategy.order_time_in_force['buy']
# return false if the order is not filled
if float(order['filled']) == 0:
logger.warning('%s %s order with time in force %s for %s is %s by %s.'
' zero amount is fulfilled.',
name, order_tif, order_type, pair, order_status, self.exchange.name)
logger.warning(f'{name} {time_in_force} order with time in force {order_type} '
f'for {pair} is {order_status} by {self.exchange.name}.'
' zero amount is fulfilled.')
return False
else:
# the order is partially fulfilled
@@ -673,8 +672,9 @@ class FreqtradeBot(LoggingMixin):
# if the order is fulfilled fully or partially
logger.warning('%s %s order with time in force %s for %s is %s by %s.'
' %s amount fulfilled out of %s (%s remaining which is canceled).',
name, order_tif, order_type, pair, order_status, self.exchange.name,
order['filled'], order['amount'], order['remaining']
name, time_in_force, order_type, pair, order_status,
self.exchange.name, order['filled'], order['amount'],
order['remaining']
)
stake_amount = order['cost']
amount = safe_value_fallback(order, 'filled', 'amount')
@@ -1382,7 +1382,7 @@ class FreqtradeBot(LoggingMixin):
order_type = self.strategy.order_types.get("emergencysell", "market")
amount = self._safe_exit_amount(trade.pair, trade.amount)
time_in_force = self.strategy.order_time_in_force['sell']
time_in_force = self.strategy.order_time_in_force['exit']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
pair=trade.pair, trade=trade, order_type=order_type, amount=amount, rate=limit,

View File

@@ -504,7 +504,7 @@ class Backtesting:
# freqtrade does not support this in live, and the order would fill immediately
closerate = max(closerate, sell_row[LOW_IDX])
# Confirm trade exit:
time_in_force = self.strategy.order_time_in_force['sell']
time_in_force = self.strategy.order_time_in_force['exit']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount,
@@ -640,7 +640,7 @@ class Backtesting:
# If not pos adjust, trade is None
return trade
order_type = self.strategy.order_types['buy']
time_in_force = self.strategy.order_time_in_force['buy']
time_in_force = self.strategy.order_time_in_force['entry']
if not pos_adjust:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)

View File

@@ -10,6 +10,7 @@ from inspect import getfullargspec
from pathlib import Path
from typing import Any, Dict, Optional
from freqtrade.configuration.config_validation import validate_migrated_strategy_settings
from freqtrade.constants import REQUIRED_ORDERTIF, REQUIRED_ORDERTYPES, USERPATH_STRATEGIES
from freqtrade.exceptions import OperationalException
from freqtrade.resolvers import IResolver
@@ -160,10 +161,12 @@ class StrategyResolver(IResolver):
@staticmethod
def _strategy_sanity_validations(strategy):
# Ensure necessary migrations are performed first.
validate_migrated_strategy_settings(strategy.config)
if not all(k in strategy.order_types for k in REQUIRED_ORDERTYPES):
raise ImportError(f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
f"Order-types mapping is incomplete.")
if not all(k in strategy.order_time_in_force for k in REQUIRED_ORDERTIF):
raise ImportError(f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
f"Order-time-in-force mapping is incomplete.")

View File

@@ -96,8 +96,8 @@ class IStrategy(ABC, HyperStrategyMixin):
# Optional time in force
order_time_in_force: Dict = {
'buy': 'gtc',
'sell': 'gtc',
'entry': 'gtc',
'exit': 'gtc',
}
# run "populate_indicators" only for new candle

View File

@@ -83,8 +83,8 @@ class {{ strategy }}(IStrategy):
# Optional order time in force.
order_time_in_force = {
'buy': 'gtc',
'sell': 'gtc'
'entry': 'gtc',
'exit': 'gtc'
}
{{ plot_config | indent(4) }}

View File

@@ -84,8 +84,8 @@ class SampleShortStrategy(IStrategy):
# Optional order time in force.
order_time_in_force = {
'buy': 'gtc',
'sell': 'gtc'
'entry': 'gtc',
'exit': 'gtc'
}
plot_config = {

View File

@@ -85,8 +85,8 @@ class SampleStrategy(IStrategy):
# Optional order time in force.
order_time_in_force = {
'buy': 'gtc',
'sell': 'gtc'
'entry': 'gtc',
'exit': 'gtc'
}
plot_config = {