diff --git a/docs/backtesting.md b/docs/backtesting.md
index e7846b1f8..11608aad9 100644
--- a/docs/backtesting.md
+++ b/docs/backtesting.md
@@ -26,7 +26,7 @@ usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH]
optional arguments:
-h, --help show this help message and exit
- -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME
+ -i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--timerange TIMERANGE
Specify what timerange of data to use.
@@ -63,7 +63,7 @@ optional arguments:
`30m`, `1h`, `1d`).
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
Provide a space-separated list of strategies to
- backtest. Please note that ticker-interval needs to be
+ backtest. Please note that timeframe needs to be
set either in config or via command line. When using
this together with `--export trades`, the strategy-
name is injected into the filename (so `backtest-
diff --git a/docs/bot-basics.md b/docs/bot-basics.md
index 8c6303063..4b5ba3a5b 100644
--- a/docs/bot-basics.md
+++ b/docs/bot-basics.md
@@ -24,7 +24,7 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and
* Fetch open trades from persistence.
* Calculate current list of tradable pairs.
-* Download ohlcv data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs)
+* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs)
This step is only executed once per Candle to avoid unnecessary network traffic.
* Call `bot_loop_start()` strategy callback.
* Analyze strategy per pair.
diff --git a/docs/configuration.md b/docs/configuration.md
index d702fe8f9..2cb5dfa93 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -86,7 +86,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
| `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade).
*Defaults to `false`.*
**Datatype:** Boolean
| `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade).
*Defaults to `0.5`.*
**Datatype:** Float (as ratio)
| `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals.
*Defaults to `0.05` (5%).*
**Datatype:** Positive Float as ratio.
-| `timeframe` | The timeframe (former ticker interval) to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** String
+| `timeframe` | The timeframe to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** String
| `fiat_display_currency` | Fiat currency used to show your profits. [More information below](#what-values-can-be-used-for-fiat_display_currency).
**Datatype:** String
| `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode.
*Defaults to `true`.*
**Datatype:** Boolean
| `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode.
*Defaults to `1000`.*
**Datatype:** Float
diff --git a/docs/deprecated.md b/docs/deprecated.md
index eaf85bfbf..87c8a2b38 100644
--- a/docs/deprecated.md
+++ b/docs/deprecated.md
@@ -24,6 +24,10 @@ Please refer to [pairlists](plugins.md#pairlists-and-pairlist-handlers) instead.
Did only download the latest 500 candles, so was ineffective in getting good backtest data.
Removed in 2019-7-dev (develop branch) and in freqtrade 2019.8.
+### `ticker_interval` (now `timeframe`)
+
+Support for `ticker_interval` terminology was deprecated in 2020.6 in favor of `timeframe` - and compatibility code was removed in 2022.3.
+
### Allow running multiple pairlists in sequence
The former `"pairlist"` section in the configuration has been removed, and is replaced by `"pairlists"` - being a list to specify a sequence of pairlists.
diff --git a/docs/edge.md b/docs/edge.md
index 4402d767f..e92abf40f 100644
--- a/docs/edge.md
+++ b/docs/edge.md
@@ -222,7 +222,7 @@ usage: freqtrade edge [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
optional arguments:
-h, --help show this help message and exit
- -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME
+ -i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--timerange TIMERANGE
Specify what timerange of data to use.
diff --git a/docs/exchanges.md b/docs/exchanges.md
index 8adf19081..c2368170d 100644
--- a/docs/exchanges.md
+++ b/docs/exchanges.md
@@ -210,6 +210,9 @@ OKX requires a passphrase for each api key, you will therefore need to add this
## Gate.io
+!!! Tip "Stoploss on Exchange"
+ Gate.io supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange..
+
Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0).
The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value.
diff --git a/docs/hyperopt.md b/docs/hyperopt.md
index 19d8cd692..c8cb118f7 100644
--- a/docs/hyperopt.md
+++ b/docs/hyperopt.md
@@ -55,7 +55,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
optional arguments:
-h, --help show this help message and exit
- -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME
+ -i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--timerange TIMERANGE
Specify what timerange of data to use.
diff --git a/docs/plotting.md b/docs/plotting.md
index ccfbb12cb..004dd7821 100644
--- a/docs/plotting.md
+++ b/docs/plotting.md
@@ -65,7 +65,7 @@ optional arguments:
_today.json`
--timerange TIMERANGE
Specify what timerange of data to use.
- -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME
+ -i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--no-trades Skip using trades from backtesting file and DB.
@@ -330,7 +330,7 @@ optional arguments:
--trade-source {DB,file}
Specify the source for trades (Can be DB or file
(backtest file)) Default: file
- -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME
+ -i TIMEFRAME, --timeframe TIMEFRAME
Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).
--auto-open Automatically open generated plot.
diff --git a/docs/stoploss.md b/docs/stoploss.md
index d0e106d8f..62081b540 100644
--- a/docs/stoploss.md
+++ b/docs/stoploss.md
@@ -24,7 +24,7 @@ These modes can be configured with these values:
```
!!! Note
- Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), FTX (stop limit and stop-market) and kucoin (stop-limit and stop-market) as of now.
+ Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), FTX (stop limit and stop-market) Gateio (stop-limit), and Kucoin (stop-limit and stop-market) as of now.
Do not set too low/tight stoploss value if using stop loss on exchange!
If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work.
diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md
index e6eff2416..045a55c5b 100644
--- a/docs/strategy-customization.md
+++ b/docs/strategy-customization.md
@@ -325,7 +325,7 @@ stoploss = -0.10
For the full documentation on stoploss features, look at the dedicated [stoploss page](stoploss.md).
-### Timeframe (formerly ticker interval)
+### Timeframe
This is the set of candles the bot should download and use for the analysis.
Common values are `"1m"`, `"5m"`, `"15m"`, `"1h"`, however all values supported by your exchange should work.
diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md
index c7f9c58f6..232885ed2 100644
--- a/docs/telegram-usage.md
+++ b/docs/telegram-usage.md
@@ -277,6 +277,7 @@ Starting capital is either taken from the `available_capital` setting, or calcul
> **BITTREX:** Buying ETH/BTC with limit `0.03400000` (`1.000000 ETH`, `225.290 USD`)
Omitting the pair will open a query asking for the pair to buy (based on the current whitelist).
+Trades crated through `/forcebuy` will have the buy-tag of `forceentry`.
![Telegram force-buy screenshot](assets/telegram_forcebuy.png)
diff --git a/docs/utils.md b/docs/utils.md
index c6e795e60..a28a0f456 100644
--- a/docs/utils.md
+++ b/docs/utils.md
@@ -517,20 +517,25 @@ Requires a configuration with specified `pairlists` attribute.
Can be used to generate static pairlists to be used during backtesting / hyperopt.
```
-usage: freqtrade test-pairlist [-h] [-c PATH]
+usage: freqtrade test-pairlist [-h] [-v] [-c PATH]
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]]
- [-1] [--print-json]
+ [-1] [--print-json] [--exchange EXCHANGE]
optional arguments:
-h, --help show this help message and exit
+ -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
-c PATH, --config PATH
- Specify configuration file (default: `config.json`).
- Multiple --config options may be used. Can be set to
- `-` to read config from stdin.
+ Specify configuration file (default:
+ `userdir/config.json` or `config.json` whichever
+ exists). Multiple --config options may be used. Can be
+ set to `-` to read config from stdin.
--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]
Specify quote currency(-ies). Space-separated list.
-1, --one-column Print output in one column.
--print-json Print list of pairs or market symbols in JSON format.
+ --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no
+ config is provided.
+
```
### Examples
diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py
index 201ec09bf..28f7d7148 100644
--- a/freqtrade/commands/arguments.py
+++ b/freqtrade/commands/arguments.py
@@ -51,7 +51,7 @@ ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all"]
ARGS_TEST_PAIRLIST = ["verbosity", "config", "quote_currencies", "print_one_column",
- "list_pairs_print_json"]
+ "list_pairs_print_json", "exchange"]
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py
index 11fcc6b81..f30c25ba1 100644
--- a/freqtrade/commands/cli_options.py
+++ b/freqtrade/commands/cli_options.py
@@ -117,7 +117,7 @@ AVAILABLE_CLI_OPTIONS = {
),
# Optimize common
"timeframe": Arg(
- '-i', '--timeframe', '--ticker-interval',
+ '-i', '--timeframe',
help='Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`).',
),
"timerange": Arg(
@@ -169,7 +169,7 @@ AVAILABLE_CLI_OPTIONS = {
"strategy_list": Arg(
'--strategy-list',
help='Provide a space-separated list of strategies to backtest. '
- 'Please note that ticker-interval needs to be set either in config '
+ 'Please note that timeframe needs to be set either in config '
'or via command line. When using this together with `--export trades`, '
'the strategy-name is injected into the filename '
'(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`',
diff --git a/freqtrade/configuration/deprecated_settings.py b/freqtrade/configuration/deprecated_settings.py
index 5efe26bd2..cafa8957b 100644
--- a/freqtrade/configuration/deprecated_settings.py
+++ b/freqtrade/configuration/deprecated_settings.py
@@ -100,16 +100,11 @@ def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None:
"from the edge configuration."
)
if 'ticker_interval' in config:
- logger.warning(
- "DEPRECATED: "
+
+ raise OperationalException(
+ "DEPRECATED: 'ticker_interval' detected. "
"Please use 'timeframe' instead of 'ticker_interval."
)
- if 'timeframe' in config:
- raise OperationalException(
- "Both 'timeframe' and 'ticker_interval' detected."
- "Please remove 'ticker_interval' from your configuration to continue operating."
- )
- config['timeframe'] = config['ticker_interval']
if 'protections' in config:
logger.warning("DEPRECATED: Setting 'protections' in the configuration is deprecated.")
diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py
index 1950f0d08..08f43598d 100644
--- a/freqtrade/edge/edge_positioning.py
+++ b/freqtrade/edge/edge_positioning.py
@@ -219,9 +219,11 @@ class Edge:
"""
final = []
for pair, info in self._cached_pairs.items():
- if info.expectancy > float(self.edge_config.get('minimum_expectancy', 0.2)) and \
- info.winrate > float(self.edge_config.get('minimum_winrate', 0.60)) and \
- pair in pairs:
+ if (
+ info.expectancy > float(self.edge_config.get('minimum_expectancy', 0.2))
+ and info.winrate > float(self.edge_config.get('minimum_winrate', 0.60))
+ and pair in pairs
+ ):
final.append(pair)
if self._final_pairs != final:
@@ -246,8 +248,8 @@ class Edge:
"""
final = []
for pair, info in self._cached_pairs.items():
- if info.expectancy > float(self.edge_config.get('minimum_expectancy', 0.2)) and \
- info.winrate > float(self.edge_config.get('minimum_winrate', 0.60)):
+ if (info.expectancy > float(self.edge_config.get('minimum_expectancy', 0.2)) and
+ info.winrate > float(self.edge_config.get('minimum_winrate', 0.60))):
final.append({
'Pair': pair,
'Winrate': info.winrate,
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
index cfd12622b..a502ad034 100644
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -376,7 +376,7 @@ class Exchange:
raise OperationalException(
'Could not load markets, therefore cannot start. '
'Please investigate the above error for more details.'
- )
+ )
quote_currencies = self.get_quote_currencies()
if stake_currency not in quote_currencies:
raise OperationalException(
@@ -882,11 +882,11 @@ class Exchange:
raise OperationalException(e) from e
@retrier(retries=API_FETCH_ORDER_RETRY_COUNT)
- def fetch_order(self, order_id: str, pair: str) -> Dict:
+ def fetch_order(self, order_id: str, pair: str, params={}) -> Dict:
if self._config['dry_run']:
return self.fetch_dry_run_order(order_id)
try:
- order = self._api.fetch_order(order_id, pair)
+ order = self._api.fetch_order(order_id, pair, params=params)
self._log_exchange_response('fetch_order', order)
return order
except ccxt.OrderNotFound as e:
@@ -929,7 +929,7 @@ class Exchange:
and order.get('filled') == 0.0)
@retrier
- def cancel_order(self, order_id: str, pair: str) -> Dict:
+ def cancel_order(self, order_id: str, pair: str, params={}) -> Dict:
if self._config['dry_run']:
try:
order = self.fetch_dry_run_order(order_id)
@@ -940,7 +940,7 @@ class Exchange:
return {}
try:
- order = self._api.cancel_order(order_id, pair)
+ order = self._api.cancel_order(order_id, pair, params=params)
self._log_exchange_response('cancel_order', order)
return order
except ccxt.InvalidOrder as e:
diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py
index 7e1f21921..d0fd787b7 100644
--- a/freqtrade/exchange/gateio.py
+++ b/freqtrade/exchange/gateio.py
@@ -22,13 +22,34 @@ class Gateio(Exchange):
_ft_has: Dict = {
"ohlcv_candle_limit": 1000,
"ohlcv_volume_currency": "quote",
+ "stoploss_order_types": {"limit": "limit"},
+ "stoploss_on_exchange": True,
}
- _headers = {'X-Gate-Channel-Id': 'freqtrade'}
-
def validate_ordertypes(self, order_types: Dict) -> None:
super().validate_ordertypes(order_types)
if any(v == 'market' for k, v in order_types.items()):
raise OperationalException(
- f'Exchange {self.name} does not support market orders.')
+ f'Exchange {self.name} does not support market orders.')
+
+ def fetch_stoploss_order(self, order_id: str, pair: str, params={}) -> Dict:
+ return self.fetch_order(
+ order_id=order_id,
+ pair=pair,
+ params={'stop': True}
+ )
+
+ def cancel_stoploss_order(self, order_id: str, pair: str, params={}) -> Dict:
+ return self.cancel_order(
+ order_id=order_id,
+ pair=pair,
+ params={'stop': True}
+ )
+
+ def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool:
+ """
+ Verify stop_loss against stoploss-order value (limit or price)
+ Returns True if adjustment is necessary.
+ """
+ return stop_loss > float(order['stopPrice'])
diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py
index 16864f814..1c2b7208f 100644
--- a/freqtrade/freqtradebot.py
+++ b/freqtrade/freqtradebot.py
@@ -1428,14 +1428,14 @@ class FreqtradeBot(LoggingMixin):
def handle_order_fee(self, trade: Trade, order_obj: Order, order: Dict[str, Any]) -> None:
# Try update amount (binance-fix)
try:
- new_amount = self.get_real_amount(trade, order)
+ new_amount = self.get_real_amount(trade, order, order_obj)
if not isclose(safe_value_fallback(order, 'filled', 'amount'), new_amount,
abs_tol=constants.MATH_CLOSE_PREC):
order_obj.ft_fee_base = trade.amount - new_amount
except DependencyException as exception:
logger.warning("Could not update trade amount: %s", exception)
- def get_real_amount(self, trade: Trade, order: Dict) -> float:
+ def get_real_amount(self, trade: Trade, order: Dict, order_obj: Order) -> float:
"""
Detect and update trade fee.
Calls trade.update_fee() upon correct detection.
@@ -1453,7 +1453,7 @@ class FreqtradeBot(LoggingMixin):
# use fee from order-dict if possible
if self.exchange.order_has_fee(order):
fee_cost, fee_currency, fee_rate = self.exchange.extract_cost_curr_rate(order)
- logger.info(f"Fee for Trade {trade} [{order.get('side')}]: "
+ logger.info(f"Fee for Trade {trade} [{order_obj.ft_order_side}]: "
f"{fee_cost:.8g} {fee_currency} - rate: {fee_rate}")
if fee_rate is None or fee_rate < 0.02:
# Reject all fees that report as > 2%.
@@ -1465,17 +1465,18 @@ class FreqtradeBot(LoggingMixin):
return self.apply_fee_conditional(trade, trade_base_currency,
amount=order_amount, fee_abs=fee_cost)
return order_amount
- return self.fee_detection_from_trades(trade, order, order_amount, order.get('trades', []))
+ return self.fee_detection_from_trades(
+ trade, order, order_obj, order_amount, order.get('trades', []))
- def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float,
- trades: List) -> float:
+ def fee_detection_from_trades(self, trade: Trade, order: Dict, order_obj: Order,
+ order_amount: float, trades: List) -> float:
"""
fee-detection fallback to Trades.
Either uses provided trades list or the result of fetch_my_trades to get correct fee.
"""
if not trades:
trades = self.exchange.get_trades_for_order(
- self.exchange.get_order_id_conditional(order), trade.pair, trade.open_date)
+ self.exchange.get_order_id_conditional(order), trade.pair, order_obj.order_date)
if len(trades) == 0:
logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade)
diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py
index eca643732..76f0e68f4 100644
--- a/freqtrade/optimize/backtesting.py
+++ b/freqtrade/optimize/backtesting.py
@@ -87,7 +87,7 @@ class Backtesting:
validate_config_consistency(self.config)
if "timeframe" not in self.config:
- raise OperationalException("Timeframe (ticker interval) needs to be set in either "
+ raise OperationalException("Timeframe needs to be set in either "
"configuration or as cli argument `--timeframe 5m`")
self.timeframe = str(self.config.get('timeframe'))
self.timeframe_min = timeframe_to_minutes(self.timeframe)
diff --git a/freqtrade/optimize/hyperopt_interface.py b/freqtrade/optimize/hyperopt_interface.py
index 01ffd7844..b1c68caca 100644
--- a/freqtrade/optimize/hyperopt_interface.py
+++ b/freqtrade/optimize/hyperopt_interface.py
@@ -29,15 +29,13 @@ class IHyperOpt(ABC):
Class attributes you can use:
timeframe -> int: value of the timeframe to use for the strategy
"""
- ticker_interval: str # DEPRECATED
timeframe: str
strategy: IStrategy
def __init__(self, config: dict) -> None:
self.config = config
- # Assign ticker_interval to be used in hyperopt
- IHyperOpt.ticker_interval = str(config['timeframe']) # DEPRECATED
+ # Assign timeframe to be used in hyperopt
IHyperOpt.timeframe = str(config['timeframe'])
def generate_estimator(self, dimensions: List[Dimension], **kwargs) -> EstimatorType:
@@ -192,7 +190,7 @@ class IHyperOpt(ABC):
Categorical([True, False], name='trailing_only_offset_is_reached'),
]
- # This is needed for proper unpickling the class attribute ticker_interval
+ # This is needed for proper unpickling the class attribute timeframe
# which is set to the actual value by the resolver.
# Why do I still need such shamanic mantras in modern python?
def __getstate__(self):
@@ -202,5 +200,4 @@ class IHyperOpt(ABC):
def __setstate__(self, state):
self.__dict__.update(state)
- IHyperOpt.ticker_interval = state['timeframe']
IHyperOpt.timeframe = state['timeframe']
diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py
index ef64a2b27..2da24b748 100644
--- a/freqtrade/persistence/migrations.py
+++ b/freqtrade/persistence/migrations.py
@@ -174,16 +174,17 @@ def drop_orders_table(engine, table_back_name: str):
def migrate_orders_table(engine, table_back_name: str, cols_order: List):
ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null')
+ average = get_column_def(cols_order, 'average', 'null')
# let SQLAlchemy create the schema as required
with engine.begin() as connection:
connection.execute(text(f"""
insert into orders ( id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
- status, symbol, order_type, side, price, amount, filled, average, remaining, cost,
- order_date, order_filled_date, order_update_date, ft_fee_base)
+ status, symbol, order_type, side, price, amount, filled, average, remaining,
+ cost, order_date, order_filled_date, order_update_date, ft_fee_base)
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
- status, symbol, order_type, side, price, amount, filled, null average, remaining, cost,
- order_date, order_filled_date, order_update_date, {ft_fee_base}
+ status, symbol, order_type, side, price, amount, filled, {average} average, remaining,
+ cost, order_date, order_filled_date, order_update_date, {ft_fee_base} ft_fee_base
from {table_back_name}
"""))
diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py
index 5627d82ce..a6d5ec79b 100644
--- a/freqtrade/plugins/pairlist/AgeFilter.py
+++ b/freqtrade/plugins/pairlist/AgeFilter.py
@@ -98,7 +98,7 @@ class AgeFilter(IPairList):
"""
Validate age for the ticker
:param pair: Pair that's currently validated
- :param ticker: ticker dict as returned from ccxt.fetch_tickers()
+ :param daily_candles: Downloaded daily candles
:return: True if the pair can stay, false if it should be removed
"""
# Check symbol in cache
diff --git a/freqtrade/plugins/pairlist/PrecisionFilter.py b/freqtrade/plugins/pairlist/PrecisionFilter.py
index a3c262e8c..521f38635 100644
--- a/freqtrade/plugins/pairlist/PrecisionFilter.py
+++ b/freqtrade/plugins/pairlist/PrecisionFilter.py
@@ -51,7 +51,7 @@ class PrecisionFilter(IPairList):
:param ticker: ticker dict as returned from ccxt.fetch_tickers()
:return: True if the pair can stay, false if it should be removed
"""
- stop_price = ticker['ask'] * self._stoploss
+ stop_price = ticker['last'] * self._stoploss
# Adjust stop-prices to precision
sp = self._exchange.price_to_precision(pair, stop_price)
diff --git a/freqtrade/plugins/pairlist/SpreadFilter.py b/freqtrade/plugins/pairlist/SpreadFilter.py
index ad0c0f0be..d1f88d2a5 100644
--- a/freqtrade/plugins/pairlist/SpreadFilter.py
+++ b/freqtrade/plugins/pairlist/SpreadFilter.py
@@ -4,6 +4,7 @@ Spread pair list filter
import logging
from typing import Any, Dict
+from freqtrade.exceptions import OperationalException
from freqtrade.plugins.pairlist.IPairList import IPairList
@@ -20,6 +21,12 @@ class SpreadFilter(IPairList):
self._max_spread_ratio = pairlistconfig.get('max_spread_ratio', 0.005)
self._enabled = self._max_spread_ratio != 0
+ if not self._exchange.exchange_has('fetchTickers'):
+ raise OperationalException(
+ 'Exchange does not support fetchTickers, therefore SpreadFilter cannot be used.'
+ 'Please edit your config and restart the bot.'
+ )
+
@property
def needstickers(self) -> bool:
"""
diff --git a/freqtrade/plugins/pairlist/VolatilityFilter.py b/freqtrade/plugins/pairlist/VolatilityFilter.py
index 20b899c5f..8a7eeeca8 100644
--- a/freqtrade/plugins/pairlist/VolatilityFilter.py
+++ b/freqtrade/plugins/pairlist/VolatilityFilter.py
@@ -90,7 +90,7 @@ class VolatilityFilter(IPairList):
"""
Validate trading range
:param pair: Pair that's currently validated
- :param ticker: ticker dict as returned from ccxt.fetch_tickers()
+ :param daily_candles: Downloaded daily candles
:return: True if the pair can stay, false if it should be removed
"""
# Check symbol in cache
diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py
index 314056fbb..e17ec2dab 100644
--- a/freqtrade/plugins/pairlist/rangestabilityfilter.py
+++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py
@@ -88,7 +88,7 @@ class RangeStabilityFilter(IPairList):
"""
Validate trading range
:param pair: Pair that's currently validated
- :param ticker: ticker dict as returned from ccxt.fetch_tickers()
+ :param daily_candles: Downloaded daily candles
:return: True if the pair can stay, false if it should be removed
"""
# Check symbol in cache
diff --git a/freqtrade/resolvers/hyperopt_resolver.py b/freqtrade/resolvers/hyperopt_resolver.py
index 6f0263e93..e3c234f60 100644
--- a/freqtrade/resolvers/hyperopt_resolver.py
+++ b/freqtrade/resolvers/hyperopt_resolver.py
@@ -44,7 +44,6 @@ class HyperOptLossResolver(IResolver):
extra_dir=config.get('hyperopt_path'))
# Assign timeframe to be used in hyperopt
- hyperoptloss.__class__.ticker_interval = str(config['timeframe'])
hyperoptloss.__class__.timeframe = str(config['timeframe'])
return hyperoptloss
diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py
index e9fcc3496..8ad7cdb59 100644
--- a/freqtrade/resolvers/strategy_resolver.py
+++ b/freqtrade/resolvers/strategy_resolver.py
@@ -45,14 +45,6 @@ class StrategyResolver(IResolver):
strategy_name, config=config,
extra_dir=config.get('strategy_path'))
- if hasattr(strategy, 'ticker_interval') and not hasattr(strategy, 'timeframe'):
- # Assign ticker_interval to timeframe to keep compatibility
- if 'timeframe' not in config:
- logger.warning(
- "DEPRECATED: Please migrate to using 'timeframe' instead of 'ticker_interval'."
- )
- strategy.timeframe = strategy.ticker_interval
-
if strategy._ft_params_from_file:
# Set parameters from Hyperopt results file
params = strategy._ft_params_from_file
@@ -145,10 +137,6 @@ class StrategyResolver(IResolver):
"""
Normalize attributes to have the correct type.
"""
- # Assign deprecated variable - to not break users code relying on this.
- if hasattr(strategy, 'timeframe'):
- strategy.ticker_interval = strategy.timeframe
-
# Sort and apply type conversions
if hasattr(strategy, 'minimal_roi'):
strategy.minimal_roi = dict(sorted(
diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py
index 6379150ee..5a34385da 100644
--- a/freqtrade/rpc/api_server/api_v1.py
+++ b/freqtrade/rpc/api_server/api_v1.py
@@ -137,7 +137,7 @@ def show_config(rpc: Optional[RPC] = Depends(get_rpc_optional), config=Depends(g
def forcebuy(payload: ForceBuyPayload, rpc: RPC = Depends(get_rpc)):
ordertype = payload.ordertype.value if payload.ordertype else None
stake_amount = payload.stakeamount if payload.stakeamount else None
- entry_tag = payload.entry_tag if payload.entry_tag else None
+ entry_tag = payload.entry_tag if payload.entry_tag else 'forceentry'
trade = rpc._rpc_forcebuy(payload.pair, payload.price, ordertype, stake_amount, entry_tag)
diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py
index 7a602978e..7fd419a5b 100644
--- a/freqtrade/rpc/rpc.py
+++ b/freqtrade/rpc/rpc.py
@@ -582,7 +582,7 @@ class RPC:
else:
try:
pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency)
- rate = tickers.get(pair, {}).get('bid', None)
+ rate = tickers.get(pair, {}).get('last', None)
if rate:
if pair.startswith(stake_currency) and not pair.endswith(stake_currency):
rate = 1.0 / rate
@@ -713,7 +713,7 @@ class RPC:
def _rpc_forcebuy(self, pair: str, price: Optional[float], order_type: Optional[str] = None,
stake_amount: Optional[float] = None,
- buy_tag: Optional[str] = None) -> Optional[Trade]:
+ buy_tag: Optional[str] = 'forceentry') -> Optional[Trade]:
"""
Handler for forcebuy
Buys a pair trade at the given or current price
diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py
index 2f3657059..1eea84676 100644
--- a/freqtrade/strategy/interface.py
+++ b/freqtrade/strategy/interface.py
@@ -55,7 +55,7 @@ class IStrategy(ABC, HyperStrategyMixin):
Attributes you can use:
minimal_roi -> Dict: Minimal ROI designed for the strategy
stoploss -> float: optimal stoploss designed for the strategy
- timeframe -> str: value of the timeframe (ticker interval) to use with the strategy
+ timeframe -> str: value of the timeframe to use with the strategy
"""
# Strategy interface version
# Default to version 2
@@ -81,7 +81,6 @@ class IStrategy(ABC, HyperStrategyMixin):
use_custom_stoploss: bool = False
# associated timeframe
- ticker_interval: str # DEPRECATED
timeframe: str
# Optional order types
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 5c94ac7c8..c2f3eae8a 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -6,8 +6,8 @@
coveralls==3.3.1
flake8==4.0.1
flake8-tidy-imports==4.6.0
-mypy==0.931
-pytest==7.0.1
+mypy==0.940
+pytest==7.1.0
pytest-asyncio==0.18.2
pytest-cov==3.0.0
pytest-mock==3.7.0
@@ -17,12 +17,12 @@ isort==5.10.1
time-machine==2.6.0
# Convert jupyter notebooks to markdown documents
-nbconvert==6.4.2
+nbconvert==6.4.4
# mypy types
-types-cachetools==4.2.10
+types-cachetools==5.0.0
types-filelock==3.2.5
-types-requests==2.27.11
+types-requests==2.27.12
types-tabulate==0.8.5
# Extensions to datetime library
diff --git a/requirements.txt b/requirements.txt
index f8b6049f1..f0f030e78 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,8 @@
-numpy==1.22.2
+numpy==1.22.3
pandas==1.4.1
pandas-ta==0.3.14b
-ccxt==1.75.12
+ccxt==1.76.5
# Pin cryptography for now due to rust build errors with piwheels
cryptography==36.0.1
aiohttp==3.8.1
@@ -32,7 +32,7 @@ sdnotify==0.3.2
# API Server
fastapi==0.75.0
-uvicorn==0.17.5
+uvicorn==0.17.6
pyjwt==2.3.0
aiofiles==0.8.0
psutil==5.9.0
diff --git a/setup.py b/setup.py
index ec41228c1..a89e717a1 100644
--- a/setup.py
+++ b/setup.py
@@ -42,7 +42,7 @@ setup(
],
install_requires=[
# from requirements.txt
- 'ccxt>=1.74.17',
+ 'ccxt>=1.76.5',
'SQLAlchemy',
'python-telegram-bot>=13.4',
'arrow>=0.17.0',
diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py
index 2bd84942d..ff8383997 100644
--- a/tests/exchange/test_exchange.py
+++ b/tests/exchange/test_exchange.py
@@ -1695,7 +1695,7 @@ def test_refresh_latest_ohlcv(mocker, default_conf, caplog) -> None:
exchange._api_async.fetch_ohlcv.reset_mock()
caplog.clear()
# Call with invalid timeframe
- res = exchange.refresh_latest_ohlcv([('IOTA/ETH', '3m')],cache=False)
+ res = exchange.refresh_latest_ohlcv([('IOTA/ETH', '3m')], cache=False)
assert not res
assert len(res) == 0
assert log_has_re(r'Cannot download \(IOTA\/ETH, 3m\).*', caplog)
diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py
index 6f7862909..ce356be8c 100644
--- a/tests/exchange/test_gateio.py
+++ b/tests/exchange/test_gateio.py
@@ -1,8 +1,11 @@
+from unittest.mock import MagicMock
+
import pytest
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Gateio
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
+from tests.conftest import get_patched_exchange
def test_validate_order_types_gateio(default_conf, mocker):
@@ -26,3 +29,39 @@ def test_validate_order_types_gateio(default_conf, mocker):
with pytest.raises(OperationalException,
match=r'Exchange .* does not support market orders.'):
ExchangeResolver.load_exchange('gateio', default_conf, True)
+
+
+def test_fetch_stoploss_order_gateio(default_conf, mocker):
+ exchange = get_patched_exchange(mocker, default_conf, id='gateio')
+
+ fetch_order_mock = MagicMock()
+ exchange.fetch_order = fetch_order_mock
+
+ exchange.fetch_stoploss_order('1234', 'ETH/BTC')
+ assert fetch_order_mock.call_count == 1
+ assert fetch_order_mock.call_args_list[0][1]['order_id'] == '1234'
+ assert fetch_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC'
+ assert fetch_order_mock.call_args_list[0][1]['params'] == {'stop': True}
+
+
+def test_cancel_stoploss_order_gateio(default_conf, mocker):
+ exchange = get_patched_exchange(mocker, default_conf, id='gateio')
+
+ cancel_order_mock = MagicMock()
+ exchange.cancel_order = cancel_order_mock
+
+ exchange.cancel_stoploss_order('1234', 'ETH/BTC')
+ assert cancel_order_mock.call_count == 1
+ assert cancel_order_mock.call_args_list[0][1]['order_id'] == '1234'
+ assert cancel_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC'
+ assert cancel_order_mock.call_args_list[0][1]['params'] == {'stop': True}
+
+
+def test_stoploss_adjust_gateio(mocker, default_conf):
+ exchange = get_patched_exchange(mocker, default_conf, id='gateio')
+ order = {
+ 'price': 1500,
+ 'stopPrice': 1500,
+ }
+ assert exchange.stoploss_adjust(1501, order)
+ assert not exchange.stoploss_adjust(1499, order)
diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py
index a8998eb63..7a72747c0 100644
--- a/tests/optimize/test_backtesting.py
+++ b/tests/optimize/test_backtesting.py
@@ -314,16 +314,15 @@ def test_backtesting_init_no_timeframe(mocker, default_conf, caplog) -> None:
patch_exchange(mocker)
del default_conf['timeframe']
default_conf['strategy_list'] = ['StrategyTestV2',
- 'SampleStrategy']
+ 'HyperoptableStrategy']
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5))
- with pytest.raises(OperationalException):
+ with pytest.raises(OperationalException,
+ match=r"Timeframe needs to be set in either configuration"):
Backtesting(default_conf)
- log_has("Ticker-interval needs to be set in either configuration "
- "or as cli argument `--ticker-interval 5m`", caplog)
-def test_data_with_fee(default_conf, mocker, testdatadir) -> None:
+def test_data_with_fee(default_conf, mocker) -> None:
patch_exchange(mocker)
default_conf['fee'] = 0.1234
diff --git a/tests/optimize/test_edge_cli.py b/tests/optimize/test_edge_cli.py
index 18d5f1c76..466a5f1cd 100644
--- a/tests/optimize/test_edge_cli.py
+++ b/tests/optimize/test_edge_cli.py
@@ -6,8 +6,7 @@ from unittest.mock import MagicMock
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_edge
from freqtrade.enums import RunMode
from freqtrade.optimize.edge_cli import EdgeCli
-from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
- patched_configuration_load_config_file)
+from tests.conftest import get_args, log_has, patch_exchange, patched_configuration_load_config_file
def test_setup_optimize_configuration_without_arguments(mocker, default_conf, caplog) -> None:
@@ -30,7 +29,6 @@ def test_setup_optimize_configuration_without_arguments(mocker, default_conf, ca
assert 'datadir' in config
assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog)
assert 'timeframe' in config
- assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog)
assert 'timerange' not in config
assert 'stoploss_range' not in config
diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py
index 2328585dd..cc551277a 100644
--- a/tests/optimize/test_hyperopt.py
+++ b/tests/optimize/test_hyperopt.py
@@ -63,7 +63,6 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
assert 'datadir' in config
assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog)
assert 'timeframe' in config
- assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog)
assert 'position_stacking' not in config
assert not log_has('Parameter --enable-position-stacking detected ...', caplog)
diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py
index 52158a889..08ba892fe 100644
--- a/tests/plugins/test_pairlist.py
+++ b/tests/plugins/test_pairlist.py
@@ -782,6 +782,19 @@ def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None
get_patched_freqtradebot(mocker, default_conf)
+def test_pair_whitelist_not_supported_Spread(mocker, default_conf, tickers) -> None:
+ default_conf['pairlists'] = [{'method': 'StaticPairList'}, {'method': 'SpreadFilter'}]
+
+ mocker.patch.multiple('freqtrade.exchange.Exchange',
+ get_tickers=tickers,
+ exchange_has=MagicMock(return_value=False),
+ )
+
+ with pytest.raises(OperationalException,
+ match=r'Exchange does not support fetchTickers, .*'):
+ get_patched_freqtradebot(mocker, default_conf)
+
+
@pytest.mark.parametrize("pairlist", AVAILABLE_PAIRLISTS)
def test_pairlist_class(mocker, whitelist_conf, markets, pairlist):
whitelist_conf['pairlists'][0]['method'] = pairlist
diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py
index 6bfee8e86..003b43ad2 100644
--- a/tests/rpc/test_rpc.py
+++ b/tests/rpc/test_rpc.py
@@ -605,8 +605,8 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
rpc._fiat_converter = CryptoToFiatConverter()
result = rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency'])
- assert prec_satoshi(result['total'], 12.309096315)
- assert prec_satoshi(result['value'], 184636.44472997)
+ assert prec_satoshi(result['total'], 12.30909624)
+ assert prec_satoshi(result['value'], 184636.443606915)
assert tickers.call_count == 1
assert tickers.call_args_list[0][1]['cached'] is True
assert 'USD' == result['symbol']
@@ -624,17 +624,16 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
'est_stake': 0.30794,
'used': 4.0,
'stake': 'BTC',
-
},
{'free': 5.0,
'balance': 10.0,
'currency': 'USDT',
- 'est_stake': 0.0011563153318162476,
+ 'est_stake': 0.0011562404610161968,
'used': 5.0,
'stake': 'BTC',
}
]
- assert result['total'] == 12.309096315331816
+ assert result['total'] == 12.309096240461017
def test_rpc_start(mocker, default_conf) -> None:
@@ -1148,6 +1147,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order_open) ->
pair = 'LTC/BTC'
trade = rpc._rpc_forcebuy(pair, 0.0001, order_type='limit', stake_amount=0.05)
assert trade.stake_amount == 0.05
+ assert trade.buy_tag == 'forceentry'
# Test not buying
pair = 'XRP/BTC'
diff --git a/tests/strategy/strats/legacy_strategy_v1.py b/tests/strategy/strats/legacy_strategy_v1.py
index ebfce632b..d7ed2014b 100644
--- a/tests/strategy/strats/legacy_strategy_v1.py
+++ b/tests/strategy/strats/legacy_strategy_v1.py
@@ -31,9 +31,7 @@ class TestStrategyLegacyV1(IStrategy):
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.10
- # Optimal timeframe for the strategy
- # Keep the legacy value here to test compatibility
- ticker_interval = '5m'
+ timeframe = '5m'
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
"""
diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py
index 3590c3e01..cc924d1c2 100644
--- a/tests/strategy/test_strategy_loading.py
+++ b/tests/strategy/test_strategy_loading.py
@@ -111,7 +111,6 @@ def test_strategy(result, default_conf):
assert default_conf['stoploss'] == -0.10
assert strategy.timeframe == '5m'
- assert strategy.ticker_interval == '5m'
assert default_conf['timeframe'] == '5m'
df_indicators = strategy.advise_indicators(result, metadata=metadata)
@@ -376,7 +375,6 @@ def test_call_deprecated_function(result, monkeypatch, default_conf, caplog):
assert strategy._sell_fun_len == 2
assert strategy.INTERFACE_VERSION == 1
assert strategy.timeframe == '5m'
- assert strategy.ticker_interval == '5m'
indicator_df = strategy.advise_indicators(result, metadata=metadata)
assert isinstance(indicator_df, DataFrame)
@@ -390,9 +388,6 @@ def test_call_deprecated_function(result, monkeypatch, default_conf, caplog):
assert isinstance(selldf, DataFrame)
assert 'sell' in selldf
- assert log_has("DEPRECATED: Please migrate to using 'timeframe' instead of 'ticker_interval'.",
- caplog)
-
def test_strategy_interface_versioning(result, monkeypatch, default_conf):
default_conf.update({'strategy': 'StrategyTestV2'})
diff --git a/tests/test_arguments.py b/tests/test_arguments.py
index fca5c6ab9..ba9d154e5 100644
--- a/tests/test_arguments.py
+++ b/tests/test_arguments.py
@@ -111,17 +111,17 @@ def test_parse_args_strategy_path_invalid() -> None:
def test_parse_args_backtesting_invalid() -> None:
with pytest.raises(SystemExit, match=r'2'):
- Arguments(['backtesting --ticker-interval']).get_parsed_arg()
+ Arguments(['backtesting --timeframe']).get_parsed_arg()
with pytest.raises(SystemExit, match=r'2'):
- Arguments(['backtesting --ticker-interval', 'abc']).get_parsed_arg()
+ Arguments(['backtesting --timeframe', 'abc']).get_parsed_arg()
def test_parse_args_backtesting_custom() -> None:
args = [
'backtesting',
'-c', 'test_conf.json',
- '--ticker-interval', '1m',
+ '--timeframe', '1m',
'--strategy-list',
'StrategyTestV2',
'SampleStrategy'
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index 0a6935649..1cd9b0ff7 100644
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -443,7 +443,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'--strategy', 'StrategyTestV2',
'--datadir', '/foo/bar',
'--userdir', "/tmp/freqtrade",
- '--ticker-interval', '1m',
+ '--timeframe', '1m',
'--enable-position-stacking',
'--disable-max-market-positions',
'--timerange', ':100',
@@ -494,7 +494,7 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
arglist = [
'backtesting',
'--config', 'config.json',
- '--ticker-interval', '1m',
+ '--timeframe', '1m',
'--export', 'trades',
'--strategy-list',
'StrategyTestV2',
@@ -1320,22 +1320,14 @@ def test_process_removed_setting(mocker, default_conf, caplog):
def test_process_deprecated_ticker_interval(default_conf, caplog):
message = "DEPRECATED: Please use 'timeframe' instead of 'ticker_interval."
config = deepcopy(default_conf)
+
process_temporary_deprecated_settings(config)
assert not log_has(message, caplog)
del config['timeframe']
config['ticker_interval'] = '15m'
- process_temporary_deprecated_settings(config)
- assert log_has(message, caplog)
- assert config['ticker_interval'] == '15m'
-
- config = deepcopy(default_conf)
- # Have both timeframe and ticker interval in config
- # Can also happen when using ticker_interval in configuration, and --timeframe as cli argument
- config['timeframe'] = '5m'
- config['ticker_interval'] = '4h'
with pytest.raises(OperationalException,
- match=r"Both 'timeframe' and 'ticker_interval' detected."):
+ match=r"DEPRECATED: 'ticker_interval' detected. Please use.*"):
process_temporary_deprecated_settings(config)
diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py
index 1aeb56cdd..bafed8488 100644
--- a/tests/test_freqtradebot.py
+++ b/tests/test_freqtradebot.py
@@ -3568,9 +3568,9 @@ def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fe
open_order_id="123456"
)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
-
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount is reduced by "fee"
- assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
+ assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount - (amount * 0.001)
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).',
caplog)
@@ -3594,8 +3594,9 @@ def test_get_real_amount_quote_dust(default_conf_usdt, trades_for_order, buy_ord
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
walletmock.reset_mock()
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount is kept as is
- assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
+ assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount
assert walletmock.call_count == 1
assert log_has_re(r'Fee amount for Trade.* was in base currency '
'- Eating Fee 0.008 into dust', caplog)
@@ -3616,8 +3617,9 @@ def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mock
)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount is reduced by "fee"
- assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
+ assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
'open_rate=0.24544100, open_since=closed) failed: myTrade-Dict empty found',
caplog)
@@ -3668,7 +3670,8 @@ def test_get_real_amount(
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError)
caplog.clear()
- assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
+ assert freqtrade.get_real_amount(trade, buy_order, order_obj) == amount - fee_reduction_amount
if expected_log:
assert log_has(expected_log, caplog)
@@ -3715,7 +3718,8 @@ def test_get_real_amount_multi(
# Amount is reduced by "fee"
expected_amount = amount - (amount * fee_reduction_amount)
- assert freqtrade.get_real_amount(trade, buy_order_fee) == expected_amount
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
+ assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == expected_amount
assert log_has(
(
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
@@ -3750,8 +3754,9 @@ def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_
)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount does not change
- assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount
+ assert freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj) == amount
def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_doublefee,
@@ -3773,7 +3778,8 @@ def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_dou
# Amount does not change
assert trade.fee_open == 0.0025
- assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee) == 30.0
+ order_obj = Order.parse_from_ccxt_object(market_buy_order_usdt_doublefee, 'LTC/ETH', 'buy')
+ assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee, order_obj) == 30.0
assert tfo_mock.call_count == 0
# Fetch fees from trades dict if available to get "proper" values
assert round(trade.fee_open, 4) == 0.001
@@ -3797,9 +3803,10 @@ def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_o
)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount does not change
with pytest.raises(DependencyException, match=r"Half bought\? Amounts don't match"):
- freqtrade.get_real_amount(trade, limit_buy_order_usdt)
+ freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj)
def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_order, buy_order_fee,
@@ -3821,9 +3828,10 @@ def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_ord
)
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+ order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
# Amount changes by fee amount.
assert isclose(
- freqtrade.get_real_amount(trade, limit_buy_order_usdt),
+ freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj),
amount - (amount * 0.001),
abs_tol=MATH_CLOSE_PREC,
)
@@ -3847,7 +3855,8 @@ def test_get_real_amount_open_trade(default_conf_usdt, fee, mocker):
'side': 'buy',
}
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
- assert freqtrade.get_real_amount(trade, order) == amount
+ order_obj = Order.parse_from_ccxt_object(order, 'LTC/ETH', 'buy')
+ assert freqtrade.get_real_amount(trade, order, order_obj) == amount
@pytest.mark.parametrize('amount,fee_abs,wallet,amount_exp', [
diff --git a/tests/test_periodiccache.py b/tests/test_periodiccache.py
index f874f9041..b2bd8ba2b 100644
--- a/tests/test_periodiccache.py
+++ b/tests/test_periodiccache.py
@@ -26,7 +26,9 @@ def test_ttl_cache():
assert 'a' in cache1h
t.move_to("2021-09-01 05:59:59 +00:00")
+ assert 'a' not in cache
assert 'a' in cache1h
t.move_to("2021-09-01 06:00:00 +00:00")
+ assert 'a' not in cache
assert 'a' not in cache1h