Merge pull request #6507 from freqtrade/short_order_tif
Update order time in force to use entry/exit wording
This commit is contained in:
commit
b4ec2b3a5a
@ -61,8 +61,8 @@
|
|||||||
"stoploss_on_exchange_interval": 60
|
"stoploss_on_exchange_interval": 60
|
||||||
},
|
},
|
||||||
"order_time_in_force": {
|
"order_time_in_force": {
|
||||||
"buy": "gtc",
|
"entry": "gtc",
|
||||||
"sell": "gtc"
|
"exit": "gtc"
|
||||||
},
|
},
|
||||||
"pairlists": [
|
"pairlists": [
|
||||||
{"method": "StaticPairList"},
|
{"method": "StaticPairList"},
|
||||||
|
@ -122,7 +122,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `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 (`"buy"`, `"sell"`, `"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 buy and sell 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
|
||||||
| `exchange.sandbox` | Use the 'sandbox' version of the exchange, where the exchange provides a sandbox for risk-free integration. See [here](sandbox-testing.md) in more details.<br> **Datatype:** Boolean
|
| `exchange.sandbox` | Use the 'sandbox' version of the exchange, where the exchange provides a sandbox for risk-free integration. See [here](sandbox-testing.md) in more details.<br> **Datatype:** Boolean
|
||||||
@ -465,8 +465,8 @@ The possible values are: `gtc` (default), `fok` or `ioc`.
|
|||||||
|
|
||||||
``` python
|
``` python
|
||||||
"order_time_in_force": {
|
"order_time_in_force": {
|
||||||
"buy": "gtc",
|
"entry": "gtc",
|
||||||
"sell": "gtc"
|
"exit": "gtc"
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -6,7 +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.enums import RunMode
|
from freqtrade.enums import RunMode, TradingMode
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
|
|
||||||
|
|
||||||
@ -80,6 +80,7 @@ def validate_config_consistency(conf: Dict[str, Any]) -> None:
|
|||||||
_validate_protections(conf)
|
_validate_protections(conf)
|
||||||
_validate_unlimited_amount(conf)
|
_validate_unlimited_amount(conf)
|
||||||
_validate_ask_orderbook(conf)
|
_validate_ask_orderbook(conf)
|
||||||
|
validate_migrated_strategy_settings(conf)
|
||||||
|
|
||||||
# validate configuration before returning
|
# validate configuration before returning
|
||||||
logger.info('Validating configuration ...')
|
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` "
|
"Please use `order_book_top` instead of `order_book_min` and `order_book_max` "
|
||||||
"for your `ask_strategy` configuration."
|
"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')
|
||||||
|
@ -19,7 +19,7 @@ DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
|
|||||||
DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite'
|
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 = ['buy', 'sell']
|
REQUIRED_ORDERTIF = ['entry', 'exit']
|
||||||
REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
|
REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
|
||||||
ORDERBOOK_SIDES = ['ask', 'bid']
|
ORDERBOOK_SIDES = ['ask', 'bid']
|
||||||
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
||||||
@ -233,10 +233,10 @@ CONF_SCHEMA = {
|
|||||||
'order_time_in_force': {
|
'order_time_in_force': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'buy': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES},
|
'entry': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES},
|
||||||
'sell': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}
|
'exit': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}
|
||||||
},
|
},
|
||||||
'required': ['buy', 'sell']
|
'required': REQUIRED_ORDERTIF
|
||||||
},
|
},
|
||||||
'exchange': {'$ref': '#/definitions/exchange'},
|
'exchange': {'$ref': '#/definitions/exchange'},
|
||||||
'edge': {'$ref': '#/definitions/edge'},
|
'edge': {'$ref': '#/definitions/edge'},
|
||||||
|
@ -595,7 +595,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
:param leverage: amount of leverage applied to this trade
|
:param leverage: amount of leverage applied to this trade
|
||||||
:return: True if a buy order is created, false if it fails.
|
: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']
|
[side, name] = ['sell', 'Short'] if is_short else ['buy', 'Long']
|
||||||
trade_side = 'short' if is_short else 'long'
|
trade_side = 'short' if is_short else 'long'
|
||||||
@ -659,13 +659,12 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
amount_requested = amount
|
amount_requested = amount
|
||||||
|
|
||||||
if order_status == 'expired' or order_status == 'rejected':
|
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
|
# return false if the order is not filled
|
||||||
if float(order['filled']) == 0:
|
if float(order['filled']) == 0:
|
||||||
logger.warning('%s %s order with time in force %s for %s is %s by %s.'
|
logger.warning(f'{name} {time_in_force} order with time in force {order_type} '
|
||||||
' zero amount is fulfilled.',
|
f'for {pair} is {order_status} by {self.exchange.name}.'
|
||||||
name, order_tif, order_type, pair, order_status, self.exchange.name)
|
' zero amount is fulfilled.')
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# the order is partially fulfilled
|
# the order is partially fulfilled
|
||||||
@ -673,8 +672,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# if the order is fulfilled fully or partially
|
# if the order is fulfilled fully or partially
|
||||||
logger.warning('%s %s order with time in force %s for %s is %s by %s.'
|
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).',
|
' %s amount fulfilled out of %s (%s remaining which is canceled).',
|
||||||
name, order_tif, order_type, pair, order_status, self.exchange.name,
|
name, time_in_force, order_type, pair, order_status,
|
||||||
order['filled'], order['amount'], order['remaining']
|
self.exchange.name, order['filled'], order['amount'],
|
||||||
|
order['remaining']
|
||||||
)
|
)
|
||||||
stake_amount = order['cost']
|
stake_amount = order['cost']
|
||||||
amount = safe_value_fallback(order, 'filled', 'amount')
|
amount = safe_value_fallback(order, 'filled', 'amount')
|
||||||
@ -1382,7 +1382,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
order_type = self.strategy.order_types.get("emergencysell", "market")
|
order_type = self.strategy.order_types.get("emergencysell", "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['sell']
|
time_in_force = self.strategy.order_time_in_force['exit']
|
||||||
|
|
||||||
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
|
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,
|
pair=trade.pair, trade=trade, order_type=order_type, amount=amount, rate=limit,
|
||||||
|
@ -504,7 +504,7 @@ class Backtesting:
|
|||||||
# freqtrade does not support this in live, and the order would fill immediately
|
# freqtrade does not support this in live, and the order would fill immediately
|
||||||
closerate = max(closerate, sell_row[LOW_IDX])
|
closerate = max(closerate, sell_row[LOW_IDX])
|
||||||
# Confirm trade exit:
|
# 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)(
|
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
|
||||||
pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount,
|
pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount,
|
||||||
@ -640,7 +640,7 @@ class Backtesting:
|
|||||||
# 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['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:
|
if not pos_adjust:
|
||||||
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
|
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
|
||||||
|
@ -10,6 +10,7 @@ from inspect import getfullargspec
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Optional
|
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.constants import REQUIRED_ORDERTIF, REQUIRED_ORDERTYPES, USERPATH_STRATEGIES
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.resolvers import IResolver
|
from freqtrade.resolvers import IResolver
|
||||||
@ -160,10 +161,12 @@ class StrategyResolver(IResolver):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _strategy_sanity_validations(strategy):
|
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):
|
if not all(k in strategy.order_types for k in REQUIRED_ORDERTYPES):
|
||||||
raise ImportError(f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
|
raise ImportError(f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
|
||||||
f"Order-types mapping is incomplete.")
|
f"Order-types mapping is incomplete.")
|
||||||
|
|
||||||
if not all(k in strategy.order_time_in_force for k in REQUIRED_ORDERTIF):
|
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__}'. "
|
raise ImportError(f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
|
||||||
f"Order-time-in-force mapping is incomplete.")
|
f"Order-time-in-force mapping is incomplete.")
|
||||||
|
@ -96,8 +96,8 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
|
|
||||||
# Optional time in force
|
# Optional time in force
|
||||||
order_time_in_force: Dict = {
|
order_time_in_force: Dict = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc',
|
'exit': 'gtc',
|
||||||
}
|
}
|
||||||
|
|
||||||
# run "populate_indicators" only for new candle
|
# run "populate_indicators" only for new candle
|
||||||
|
@ -83,8 +83,8 @@ class {{ strategy }}(IStrategy):
|
|||||||
|
|
||||||
# Optional order time in force.
|
# Optional order time in force.
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc'
|
'exit': 'gtc'
|
||||||
}
|
}
|
||||||
{{ plot_config | indent(4) }}
|
{{ plot_config | indent(4) }}
|
||||||
|
|
||||||
|
@ -84,8 +84,8 @@ class SampleShortStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional order time in force.
|
# Optional order time in force.
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc'
|
'exit': 'gtc'
|
||||||
}
|
}
|
||||||
|
|
||||||
plot_config = {
|
plot_config = {
|
||||||
|
@ -85,8 +85,8 @@ class SampleStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional order time in force.
|
# Optional order time in force.
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc'
|
'exit': 'gtc'
|
||||||
}
|
}
|
||||||
|
|
||||||
plot_config = {
|
plot_config = {
|
||||||
|
@ -319,6 +319,7 @@ def test_backtesting_init_no_timeframe(mocker, default_conf, caplog) -> None:
|
|||||||
del default_conf['timeframe']
|
del default_conf['timeframe']
|
||||||
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY,
|
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY,
|
||||||
'SampleStrategy']
|
'SampleStrategy']
|
||||||
|
# TODO: This refers to the sampleStrategy in user_data if it exists...
|
||||||
|
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5))
|
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5))
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
|
@ -45,8 +45,8 @@ class HyperoptableStrategy(IStrategy):
|
|||||||
|
|
||||||
# Optional time in force for orders
|
# Optional time in force for orders
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc',
|
'exit': 'gtc',
|
||||||
}
|
}
|
||||||
|
|
||||||
buy_params = {
|
buy_params = {
|
||||||
|
@ -47,8 +47,8 @@ class StrategyTestV2(IStrategy):
|
|||||||
|
|
||||||
# Optional time in force for orders
|
# Optional time in force for orders
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc',
|
'exit': 'gtc',
|
||||||
}
|
}
|
||||||
|
|
||||||
# By default this strategy does not use Position Adjustments
|
# By default this strategy does not use Position Adjustments
|
||||||
|
@ -48,8 +48,8 @@ class StrategyTestV3(IStrategy):
|
|||||||
|
|
||||||
# Optional time in force for orders
|
# Optional time in force for orders
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'gtc',
|
'entry': 'gtc',
|
||||||
'sell': 'gtc',
|
'exit': 'gtc',
|
||||||
}
|
}
|
||||||
|
|
||||||
buy_params = {
|
buy_params = {
|
||||||
|
@ -257,8 +257,8 @@ def test_strategy_override_order_tif(caplog, default_conf):
|
|||||||
caplog.set_level(logging.INFO)
|
caplog.set_level(logging.INFO)
|
||||||
|
|
||||||
order_time_in_force = {
|
order_time_in_force = {
|
||||||
'buy': 'fok',
|
'entry': 'fok',
|
||||||
'sell': 'gtc',
|
'exit': 'gtc',
|
||||||
}
|
}
|
||||||
|
|
||||||
default_conf.update({
|
default_conf.update({
|
||||||
@ -268,15 +268,15 @@ def test_strategy_override_order_tif(caplog, default_conf):
|
|||||||
strategy = StrategyResolver.load_strategy(default_conf)
|
strategy = StrategyResolver.load_strategy(default_conf)
|
||||||
|
|
||||||
assert strategy.order_time_in_force
|
assert strategy.order_time_in_force
|
||||||
for method in ['buy', 'sell']:
|
for method in ['entry', 'exit']:
|
||||||
assert strategy.order_time_in_force[method] == order_time_in_force[method]
|
assert strategy.order_time_in_force[method] == order_time_in_force[method]
|
||||||
|
|
||||||
assert log_has("Override strategy 'order_time_in_force' with value in config file:"
|
assert log_has("Override strategy 'order_time_in_force' with value in config file:"
|
||||||
" {'buy': 'fok', 'sell': 'gtc'}.", caplog)
|
" {'entry': 'fok', 'exit': 'gtc'}.", caplog)
|
||||||
|
|
||||||
default_conf.update({
|
default_conf.update({
|
||||||
'strategy': CURRENT_TEST_STRATEGY,
|
'strategy': CURRENT_TEST_STRATEGY,
|
||||||
'order_time_in_force': {'buy': 'fok'}
|
'order_time_in_force': {'entry': 'fok'}
|
||||||
})
|
})
|
||||||
# Raise error for invalid configuration
|
# Raise error for invalid configuration
|
||||||
with pytest.raises(ImportError,
|
with pytest.raises(ImportError,
|
||||||
|
@ -941,6 +941,28 @@ def test_validate_ask_orderbook(default_conf, caplog) -> None:
|
|||||||
validate_config_consistency(conf)
|
validate_config_consistency(conf)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_time_in_force(default_conf, caplog) -> None:
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['order_time_in_force'] = {
|
||||||
|
'buy': 'gtc',
|
||||||
|
'sell': 'gtc',
|
||||||
|
}
|
||||||
|
validate_config_consistency(conf)
|
||||||
|
assert log_has_re(r"DEPRECATED: Using 'buy' and 'sell' for time_in_force is.*", caplog)
|
||||||
|
assert conf['order_time_in_force']['entry'] == 'gtc'
|
||||||
|
assert conf['order_time_in_force']['exit'] == 'gtc'
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['order_time_in_force'] = {
|
||||||
|
'buy': 'gtc',
|
||||||
|
'sell': 'gtc',
|
||||||
|
}
|
||||||
|
conf['trading_mode'] = 'futures'
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match=r"Please migrate your time_in_force settings .* 'entry' and 'exit'\."):
|
||||||
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user