Merge branch 'feat/short' into lev-exchange
This commit is contained in:
commit
dc83e04f9b
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -2,14 +2,16 @@ Thank you for sending your pull request. But first, have you included
|
||||
unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||
|
||||
## Summary
|
||||
|
||||
Explain in one sentence the goal of this PR
|
||||
|
||||
Solve the issue: #___
|
||||
|
||||
## Quick changelog
|
||||
|
||||
- <change log #1>
|
||||
- <change log #2>
|
||||
- <change log 1>
|
||||
- <change log 1>
|
||||
|
||||
## What's new?
|
||||
|
||||
*Explain in details what this PR solve or improve. You can include visuals.*
|
||||
|
@ -13,7 +13,7 @@ RUN mkdir /freqtrade \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev \
|
||||
&& apt-get clean \
|
||||
&& useradd -u 1000 -G sudo -U -m ftuser \
|
||||
&& useradd -u 1000 -G sudo -U -m -s /bin/bash ftuser \
|
||||
&& chown ftuser:ftuser /freqtrade \
|
||||
# Allow sudoers
|
||||
&& echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers
|
||||
|
@ -12,9 +12,12 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
|
||||
&& curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \
|
||||
&& ./configure --prefix=${INSTALL_LOC}/ \
|
||||
&& make -j$(nproc) \
|
||||
&& which sudo && sudo make install || make install \
|
||||
&& cd ..
|
||||
&& which sudo && sudo make install || make install
|
||||
if [ -x "$(command -v apt-get)" ]; then
|
||||
echo "Updating library path using ldconfig"
|
||||
sudo ldconfig
|
||||
fi
|
||||
cd .. && rm -rf ./ta-lib/
|
||||
else
|
||||
echo "TA-lib already installed, skipping installation"
|
||||
fi
|
||||
# && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
|
||||
|
@ -80,7 +80,7 @@ To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_sp
|
||||
class MyAwesomeStrategy(IStrategy):
|
||||
class HyperOpt:
|
||||
# Define a custom stoploss space.
|
||||
def stoploss_space(self):
|
||||
def stoploss_space():
|
||||
return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')]
|
||||
```
|
||||
|
||||
|
@ -444,8 +444,8 @@ The possible values are: `gtc` (default), `fok` or `ioc`.
|
||||
```
|
||||
|
||||
!!! Warning
|
||||
This is ongoing work. For now, it is supported only for binance.
|
||||
Please don't change the default value unless you know what you are doing and have researched the impact of using different values.
|
||||
This is ongoing work. For now, it is supported only for binance and kucoin.
|
||||
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
||||
|
||||
### Exchange configuration
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss.
|
||||
|
||||
!!! Warning
|
||||
WHen using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data.
|
||||
When using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data.
|
||||
|
||||
!!! Note
|
||||
`Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file.
|
||||
|
@ -4,6 +4,8 @@ This page combines common gotchas and informations which are exchange-specific a
|
||||
|
||||
## Binance
|
||||
|
||||
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
|
||||
|
||||
!!! Tip "Stoploss on Exchange"
|
||||
Binance supports `stoploss_on_exchange` and uses stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
|
||||
|
||||
@ -113,8 +115,12 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th
|
||||
"key": "your_exchange_key",
|
||||
"secret": "your_exchange_secret",
|
||||
"password": "your_exchange_api_key_password",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force).
|
||||
|
||||
### Kucoin Blacklists
|
||||
|
||||
For Kucoin, please add `"KCS/<STAKE>"` to your blacklist to avoid issues.
|
||||
@ -158,6 +164,8 @@ For example, to test the order type `FOK` with Kraken, and modify candle limit t
|
||||
"order_time_in_force": ["gtc", "fok"],
|
||||
"ohlcv_candle_limit": 200
|
||||
}
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
!!! Warning
|
||||
|
@ -1,4 +1,4 @@
|
||||
mkdocs==1.2.2
|
||||
mkdocs-material==7.2.5
|
||||
mkdocs-material==7.2.6
|
||||
mdx_truly_sane_lists==1.2
|
||||
pymdown-extensions==8.2
|
||||
|
@ -22,7 +22,7 @@ if __version__ == 'develop':
|
||||
# subprocess.check_output(
|
||||
# ['git', 'log', '--format="%h"', '-n 1'],
|
||||
# stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"')
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
# git not available, ignore
|
||||
try:
|
||||
# Try Fallback to freqtrade_commit file (created by CI while building docker image)
|
||||
|
@ -61,13 +61,13 @@ def ask_user_config() -> Dict[str, Any]:
|
||||
"type": "text",
|
||||
"name": "stake_currency",
|
||||
"message": "Please insert your stake currency:",
|
||||
"default": 'BTC',
|
||||
"default": 'USDT',
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "stake_amount",
|
||||
"message": f"Please insert your stake amount (Number or '{UNLIMITED_STAKE_AMOUNT}'):",
|
||||
"default": "0.01",
|
||||
"default": "100",
|
||||
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
|
||||
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
|
||||
if val == UNLIMITED_STAKE_AMOUNT
|
||||
@ -105,6 +105,8 @@ def ask_user_config() -> Dict[str, Any]:
|
||||
"bittrex",
|
||||
"kraken",
|
||||
"ftx",
|
||||
"kucoin",
|
||||
"gateio",
|
||||
Separator(),
|
||||
"other",
|
||||
],
|
||||
@ -128,6 +130,12 @@ def ask_user_config() -> Dict[str, Any]:
|
||||
"message": "Insert Exchange Secret",
|
||||
"when": lambda x: not x['dry_run']
|
||||
},
|
||||
{
|
||||
"type": "password",
|
||||
"name": "exchange_key_password",
|
||||
"message": "Insert Exchange API Key password",
|
||||
"when": lambda x: not x['dry_run'] and x['exchange_name'] == 'kucoin'
|
||||
},
|
||||
{
|
||||
"type": "confirm",
|
||||
"name": "telegram",
|
||||
|
@ -19,6 +19,7 @@ class Binance(Exchange):
|
||||
_ft_has: Dict = {
|
||||
"stoploss_on_exchange": True,
|
||||
"order_time_in_force": ['gtc', 'fok', 'ioc'],
|
||||
"time_in_force_parameter": "timeInForce",
|
||||
"ohlcv_candle_limit": 1000,
|
||||
"trades_pagination": "id",
|
||||
"trades_pagination_arg": "fromId",
|
||||
|
@ -55,12 +55,16 @@ class Exchange:
|
||||
# Parameters to add directly to buy/sell calls (like agreeing to trading agreement)
|
||||
_params: Dict = {}
|
||||
|
||||
# Additional headers - added to the ccxt object
|
||||
_headers: Dict = {}
|
||||
|
||||
# Dict to specify which options each exchange implements
|
||||
# This defines defaults, which can be selectively overridden by subclasses using _ft_has
|
||||
# or by specifying them in the configuration.
|
||||
_ft_has_default: Dict = {
|
||||
"stoploss_on_exchange": False,
|
||||
"order_time_in_force": ["gtc"],
|
||||
"time_in_force_parameter": "timeInForce",
|
||||
"ohlcv_params": {},
|
||||
"ohlcv_candle_limit": 500,
|
||||
"ohlcv_partial_candle": True,
|
||||
@ -190,7 +194,7 @@ class Exchange:
|
||||
asyncio.get_event_loop().run_until_complete(self._api_async.close())
|
||||
|
||||
def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt,
|
||||
ccxt_kwargs: dict = None) -> ccxt.Exchange:
|
||||
ccxt_kwargs: Dict = {}) -> ccxt.Exchange:
|
||||
"""
|
||||
Initialize ccxt with given config and return valid
|
||||
ccxt instance.
|
||||
@ -210,6 +214,10 @@ class Exchange:
|
||||
}
|
||||
if ccxt_kwargs:
|
||||
logger.info('Applying additional ccxt config: %s', ccxt_kwargs)
|
||||
if self._headers:
|
||||
# Inject static headers after the above output to not confuse users.
|
||||
ccxt_kwargs = deep_merge_dicts({'headers': self._headers}, ccxt_kwargs)
|
||||
if ccxt_kwargs:
|
||||
ex_config.update(ccxt_kwargs)
|
||||
try:
|
||||
|
||||
@ -771,7 +779,8 @@ class Exchange:
|
||||
|
||||
params = self._params.copy()
|
||||
if time_in_force != 'gtc' and ordertype != 'market':
|
||||
params.update({'timeInForce': time_in_force})
|
||||
param = self._ft_has.get('time_in_force_parameter', '')
|
||||
params.update({param: time_in_force})
|
||||
|
||||
try:
|
||||
# Set the precision for amount and price(rate) as accepted by the exchange
|
||||
|
@ -21,4 +21,6 @@ class Kucoin(Exchange):
|
||||
_ft_has: Dict = {
|
||||
"l2_limit_range": [20, 100],
|
||||
"l2_limit_range_required": False,
|
||||
"order_time_in_force": ['gtc', 'fok', 'ioc'],
|
||||
"time_in_force_parameter": "timeInForce",
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ def setup_logging(config: Dict[str, Any]) -> None:
|
||||
# syslog config. The messages should be equal for this.
|
||||
handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s'))
|
||||
logging.root.addHandler(handler_sl)
|
||||
elif s[0] == 'journald':
|
||||
elif s[0] == 'journald': # pragma: no cover
|
||||
try:
|
||||
from systemd.journal import JournaldLogHandler
|
||||
except ImportError:
|
||||
|
@ -9,7 +9,7 @@ from typing import Any, List
|
||||
|
||||
|
||||
# check min. python version
|
||||
if sys.version_info < (3, 7):
|
||||
if sys.version_info < (3, 7): # pragma: no cover
|
||||
sys.exit("Freqtrade requires Python version >= 3.7")
|
||||
|
||||
from freqtrade.commands import Arguments
|
||||
@ -46,7 +46,7 @@ def main(sysargv: List[str] = None) -> None:
|
||||
"`freqtrade --help` or `freqtrade <command> --help`."
|
||||
)
|
||||
|
||||
except SystemExit as e:
|
||||
except SystemExit as e: # pragma: no cover
|
||||
return_code = e
|
||||
except KeyboardInterrupt:
|
||||
logger.info('SIGINT received, aborting ...')
|
||||
@ -60,5 +60,5 @@ def main(sysargv: List[str] = None) -> None:
|
||||
sys.exit(return_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
main()
|
||||
|
@ -17,7 +17,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str],
|
||||
if keep_invalid:
|
||||
for pair_wc in wildcardpl:
|
||||
try:
|
||||
comp = re.compile(pair_wc)
|
||||
comp = re.compile(pair_wc, re.IGNORECASE)
|
||||
result_partial = [
|
||||
pair for pair in available_pairs if re.fullmatch(comp, pair)
|
||||
]
|
||||
@ -33,7 +33,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str],
|
||||
else:
|
||||
for pair_wc in wildcardpl:
|
||||
try:
|
||||
comp = re.compile(pair_wc)
|
||||
comp = re.compile(pair_wc, re.IGNORECASE)
|
||||
result += [
|
||||
pair for pair in available_pairs if re.fullmatch(comp, pair)
|
||||
]
|
||||
|
@ -5,6 +5,20 @@ import time
|
||||
import uvicorn
|
||||
|
||||
|
||||
def asyncio_setup() -> None: # pragma: no cover
|
||||
# Set eventloop for win32 setups
|
||||
# Reverts a change done in uvicorn 0.15.0 - which now sets the eventloop
|
||||
# via policy.
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 8) and sys.platform == "win32":
|
||||
import asyncio
|
||||
import selectors
|
||||
selector = selectors.SelectSelector()
|
||||
loop = asyncio.SelectorEventLoop(selector)
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
|
||||
class UvicornServer(uvicorn.Server):
|
||||
"""
|
||||
Multithreaded server - as found in https://github.com/encode/uvicorn/issues/742
|
||||
@ -28,7 +42,7 @@ class UvicornServer(uvicorn.Server):
|
||||
try:
|
||||
import uvloop # noqa
|
||||
except ImportError: # pragma: no cover
|
||||
from uvicorn.loops.asyncio import asyncio_setup
|
||||
|
||||
asyncio_setup()
|
||||
else:
|
||||
asyncio.set_event_loop(uvloop.new_event_loop())
|
||||
|
@ -403,8 +403,11 @@ class RPC:
|
||||
# Doing the sum is not right - overall profit needs to be based on initial capital
|
||||
profit_all_ratio_sum = sum(profit_all_ratio) if profit_all_ratio else 0.0
|
||||
starting_balance = self._freqtrade.wallets.get_starting_balance()
|
||||
profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance
|
||||
profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance
|
||||
profit_closed_ratio_fromstart = 0
|
||||
profit_all_ratio_fromstart = 0
|
||||
if starting_balance:
|
||||
profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance
|
||||
profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance
|
||||
|
||||
profit_all_fiat = self._fiat_converter.convert_amount(
|
||||
profit_all_coin_sum,
|
||||
|
@ -1,3 +1,10 @@
|
||||
{%set volume_pairlist = '{
|
||||
"method": "VolumePairList",
|
||||
"number_assets": 20,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"refresh_period": 1800
|
||||
}' %}
|
||||
{
|
||||
"max_open_trades": {{ max_open_trades }},
|
||||
"stake_currency": "{{ stake_currency }}",
|
||||
@ -29,7 +36,7 @@
|
||||
},
|
||||
{{ exchange | indent(4) }},
|
||||
"pairlists": [
|
||||
{"method": "StaticPairList"}
|
||||
{{ '{"method": "StaticPairList"}' if exchange_name == 'bittrex' else volume_pairlist }}
|
||||
],
|
||||
"edge": {
|
||||
"enabled": false,
|
||||
|
@ -8,34 +8,8 @@
|
||||
"rateLimit": 200
|
||||
},
|
||||
"pair_whitelist": [
|
||||
"ALGO/BTC",
|
||||
"ATOM/BTC",
|
||||
"BAT/BTC",
|
||||
"BCH/BTC",
|
||||
"BRD/BTC",
|
||||
"EOS/BTC",
|
||||
"ETH/BTC",
|
||||
"IOTA/BTC",
|
||||
"LINK/BTC",
|
||||
"LTC/BTC",
|
||||
"NEO/BTC",
|
||||
"NXS/BTC",
|
||||
"XMR/BTC",
|
||||
"XRP/BTC",
|
||||
"XTZ/BTC"
|
||||
],
|
||||
"pair_blacklist": [
|
||||
"BNB/BTC",
|
||||
"BNB/BUSD",
|
||||
"BNB/ETH",
|
||||
"BNB/EUR",
|
||||
"BNB/NGN",
|
||||
"BNB/PAX",
|
||||
"BNB/RUB",
|
||||
"BNB/TRY",
|
||||
"BNB/TUSD",
|
||||
"BNB/USDC",
|
||||
"BNB/USDS",
|
||||
"BNB/USDT"
|
||||
"BNB/.*"
|
||||
]
|
||||
}
|
||||
|
@ -15,16 +15,6 @@
|
||||
"rateLimit": 500
|
||||
},
|
||||
"pair_whitelist": [
|
||||
"ETH/BTC",
|
||||
"LTC/BTC",
|
||||
"ETC/BTC",
|
||||
"DASH/BTC",
|
||||
"ZEC/BTC",
|
||||
"XLM/BTC",
|
||||
"XRP/BTC",
|
||||
"TRX/BTC",
|
||||
"ADA/BTC",
|
||||
"XMR/BTC"
|
||||
],
|
||||
"pair_blacklist": [
|
||||
]
|
||||
|
@ -7,28 +7,10 @@
|
||||
"ccxt_async_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 1000
|
||||
// Enable the below for downoading data.
|
||||
//"rateLimit": 3100
|
||||
},
|
||||
"pair_whitelist": [
|
||||
"ADA/EUR",
|
||||
"ATOM/EUR",
|
||||
"BAT/EUR",
|
||||
"BCH/EUR",
|
||||
"BTC/EUR",
|
||||
"DAI/EUR",
|
||||
"DASH/EUR",
|
||||
"EOS/EUR",
|
||||
"ETC/EUR",
|
||||
"ETH/EUR",
|
||||
"LINK/EUR",
|
||||
"LTC/EUR",
|
||||
"QTUM/EUR",
|
||||
"REP/EUR",
|
||||
"WAVES/EUR",
|
||||
"XLM/EUR",
|
||||
"XMR/EUR",
|
||||
"XRP/EUR",
|
||||
"XTZ/EUR",
|
||||
"ZEC/EUR"
|
||||
],
|
||||
"pair_blacklist": [
|
||||
|
||||
|
18
freqtrade/templates/subtemplates/exchange_kucoin.j2
Normal file
18
freqtrade/templates/subtemplates/exchange_kucoin.j2
Normal file
@ -0,0 +1,18 @@
|
||||
"exchange": {
|
||||
"name": "{{ exchange_name | lower }}",
|
||||
"key": "{{ exchange_key }}",
|
||||
"secret": "{{ exchange_secret }}",
|
||||
"password": "{{ exchange_key_password }}",
|
||||
"ccxt_config": {
|
||||
"enableRateLimit": true
|
||||
"rateLimit": 200
|
||||
},
|
||||
"ccxt_async_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 200
|
||||
},
|
||||
"pair_whitelist": [
|
||||
],
|
||||
"pair_blacklist": [
|
||||
]
|
||||
}
|
@ -8,7 +8,7 @@ flake8==3.9.2
|
||||
flake8-type-annotations==0.1.0
|
||||
flake8-tidy-imports==4.4.1
|
||||
mypy==0.910
|
||||
pytest==6.2.4
|
||||
pytest==6.2.5
|
||||
pytest-asyncio==0.15.1
|
||||
pytest-cov==2.12.1
|
||||
pytest-mock==3.6.1
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Include all requirements to run the bot.
|
||||
-r requirements.txt
|
||||
|
||||
plotly==5.3.0
|
||||
plotly==5.3.1
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
numpy==1.21.2
|
||||
pandas==1.3.2
|
||||
|
||||
ccxt==1.55.56
|
||||
ccxt==1.55.83
|
||||
# Pin cryptography for now due to rust build errors with piwheels
|
||||
cryptography==3.4.8
|
||||
aiohttp==3.7.4.post0
|
||||
|
14
setup.sh
14
setup.sh
@ -95,19 +95,7 @@ function install_talib() {
|
||||
return
|
||||
fi
|
||||
|
||||
cd build_helpers
|
||||
tar zxvf ta-lib-0.4.0-src.tar.gz
|
||||
cd ta-lib
|
||||
sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h
|
||||
./configure --prefix=/usr/local
|
||||
make
|
||||
sudo make install
|
||||
if [ -x "$(command -v apt-get)" ]; then
|
||||
echo "Updating library path using ldconfig"
|
||||
sudo ldconfig
|
||||
fi
|
||||
cd .. && rm -rf ./ta-lib/
|
||||
cd ..
|
||||
cd build_helpers && ./install_ta-lib.sh && cd ..
|
||||
}
|
||||
|
||||
function install_mac_newer_python_dependencies() {
|
||||
|
@ -109,6 +109,13 @@ def test_init_ccxt_kwargs(default_conf, mocker, caplog):
|
||||
assert hasattr(ex._api_async, 'TestKWARG')
|
||||
assert log_has("Applying additional ccxt config: {'TestKWARG': 11, 'TestKWARG44': 11}", caplog)
|
||||
assert log_has(asynclogmsg, caplog)
|
||||
# Test additional headers case
|
||||
Exchange._headers = {'hello': 'world'}
|
||||
ex = Exchange(conf)
|
||||
|
||||
assert log_has("Applying additional ccxt config: {'TestKWARG': 11, 'TestKWARG44': 11}", caplog)
|
||||
assert ex._api.headers == {'hello': 'world'}
|
||||
Exchange._headers = {}
|
||||
|
||||
# TODO-lev: Test with options
|
||||
|
||||
|
@ -739,11 +739,16 @@ def test_auto_hyperopt_interface(default_conf):
|
||||
PairLocks.timeframe = default_conf['timeframe']
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
with pytest.raises(OperationalException):
|
||||
next(strategy.enumerate_parameters('deadBeef'))
|
||||
|
||||
assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi']
|
||||
# PlusDI is NOT in the buy-params, so default should be used
|
||||
assert strategy.buy_plusdi.value == 0.5
|
||||
assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi']
|
||||
|
||||
assert repr(strategy.sell_rsi) == 'IntParameter(74)'
|
||||
|
||||
# Parameter is disabled - so value from sell_param dict will NOT be used.
|
||||
assert strategy.sell_minusdi.value == 0.5
|
||||
all_params = strategy.detect_all_parameters()
|
||||
|
@ -107,6 +107,7 @@ def test_order_dict_dry_run(default_conf, mocker, caplog) -> None:
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
assert not freqtrade.strategy.order_types['stoploss_on_exchange']
|
||||
assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_order_dict_live(default_conf, mocker, caplog) -> None:
|
||||
@ -140,6 +141,7 @@ def test_order_dict_live(default_conf, mocker, caplog) -> None:
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
assert not freqtrade.strategy.order_types['stoploss_on_exchange']
|
||||
assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None:
|
||||
@ -415,6 +417,7 @@ def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_ord
|
||||
|
||||
assert freqtrade.create_trade('ETH/BTC')
|
||||
assert log_has_re(r"Stake amount for pair .* is too small.*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_create_trade_zero_stake_amount(default_conf, ticker, limit_buy_order_open,
|
||||
@ -478,6 +481,7 @@ def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_ope
|
||||
n = freqtrade.enter_positions()
|
||||
assert n == 0
|
||||
assert log_has_re(r"No currency pair in active pair whitelist.*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_enter_positions_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee,
|
||||
@ -518,11 +522,13 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order,
|
||||
# 0 trades, but it's not because of pairlock.
|
||||
assert n == 0
|
||||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
PairLocks.lock_pair('*', arrow.utcnow().shift(minutes=20).datetime, 'Just because')
|
||||
n = freqtrade.enter_positions()
|
||||
assert n == 0
|
||||
assert log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_create_trade_no_signal(default_conf, fee, mocker) -> None:
|
||||
@ -1086,6 +1092,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
|
||||
assert log_has_re(r'STOP_LOSS_LIMIT is hit for Trade\(id=1, .*\)\.', caplog)
|
||||
assert trade.stoploss_order_id is None
|
||||
assert trade.is_open is False
|
||||
caplog.clear()
|
||||
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Binance.stoploss',
|
||||
@ -1115,6 +1122,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
|
||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
|
||||
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
||||
assert stoploss.call_count == 0
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
|
||||
@ -1154,6 +1162,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
|
||||
assert log_has_re(r'Stoploss order was cancelled, but unable to recreate one.*', caplog)
|
||||
assert trade.stoploss_order_id is None
|
||||
assert trade.is_open is True
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
|
||||
@ -1202,6 +1211,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
|
||||
assert rpc_mock.call_count == 2
|
||||
assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == SellType.EMERGENCY_SELL.value
|
||||
assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market'
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, fee,
|
||||
@ -1431,6 +1441,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c
|
||||
freqtrade.handle_trailing_stoploss_on_exchange(trade, stoploss_order_hanging, side="sell")
|
||||
assert cancel_mock.call_count == 1
|
||||
assert log_has_re(r"Could not create trailing stoploss order for pair ETH/BTC\..*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@ -1671,6 +1682,7 @@ def test_enter_positions(mocker, default_conf, caplog) -> None:
|
||||
assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog)
|
||||
# create_trade should be called once for every pair in the whitelist.
|
||||
assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist'])
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_enter_positions_exception(mocker, default_conf, caplog) -> None:
|
||||
@ -1710,6 +1722,7 @@ def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None:
|
||||
# test amount modified by fee-logic
|
||||
n = freqtrade.exit_positions(trades)
|
||||
assert n == 0
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) -> None:
|
||||
@ -1730,6 +1743,7 @@ def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog)
|
||||
n = freqtrade.exit_positions(trades)
|
||||
assert n == 0
|
||||
assert log_has('Unable to sell trade ETH/BTC: ', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> None:
|
||||
@ -1752,10 +1766,12 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
|
||||
)
|
||||
assert not freqtrade.update_trade_state(trade, None)
|
||||
assert log_has_re(r'Orderid for trade .* is empty.', caplog)
|
||||
caplog.clear()
|
||||
# Add datetime explicitly since sqlalchemy defaults apply only once written to database
|
||||
freqtrade.update_trade_state(trade, '123')
|
||||
# Test amount not modified by fee-logic
|
||||
assert not log_has_re(r'Applying fee to .*', caplog)
|
||||
caplog.clear()
|
||||
assert trade.open_order_id is None
|
||||
assert trade.amount == limit_buy_order['amount']
|
||||
|
||||
@ -1773,6 +1789,7 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
|
||||
freqtrade.update_trade_state(trade, '123')
|
||||
|
||||
assert log_has_re('Found open order for.*', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, fee,
|
||||
@ -1823,6 +1840,7 @@ def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_
|
||||
assert trade.amount != amount
|
||||
assert trade.amount == limit_buy_order['amount']
|
||||
assert log_has_re(r'Applying fee on amount for .*', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_update_trade_state_exception(mocker, default_conf,
|
||||
@ -1841,6 +1859,7 @@ def test_update_trade_state_exception(mocker, default_conf,
|
||||
)
|
||||
freqtrade.update_trade_state(trade, trade.open_order_id)
|
||||
assert log_has('Could not update trade amount: ', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None:
|
||||
@ -1857,6 +1876,7 @@ def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None
|
||||
freqtrade.update_trade_state(trade, trade.open_order_id)
|
||||
assert grm_mock.call_count == 0
|
||||
assert log_has(f'Unable to fetch order {trade.open_order_id}: ', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_order_open,
|
||||
@ -2025,6 +2045,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open,
|
||||
assert freqtrade.handle_trade(trade)
|
||||
assert log_has("ETH/BTC - Required profit reached. sell_type=SellType.ROI",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open,
|
||||
@ -2057,6 +2078,7 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open
|
||||
assert freqtrade.handle_trade(trade)
|
||||
assert log_has("ETH/BTC - Sell signal received. sell_type=SellType.SELL_SIGNAL",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open, limit_sell_order,
|
||||
@ -2097,6 +2119,7 @@ def test_bot_loop_start_called_once(mocker, default_conf, caplog):
|
||||
assert log_has_re(r'Strategy caused the following exception.*', caplog)
|
||||
assert ftbot.strategy.bot_loop_start.call_count == 1
|
||||
assert ftbot.strategy.analyze.call_count == 1
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_order_old, open_trade,
|
||||
@ -2211,6 +2234,7 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o
|
||||
nb_trades = len(trades)
|
||||
assert nb_trades == 0
|
||||
assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade,
|
||||
@ -2345,6 +2369,7 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old,
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade.is_open is True
|
||||
assert log_has_re("Sell order cancelled on exchange for Trade.*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old_partial,
|
||||
@ -2413,6 +2438,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap
|
||||
assert trades[0].open_order_id is None
|
||||
assert trades[0].fee_updated('buy')
|
||||
assert pytest.approx(trades[0].fee_open) == 0.001
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, caplog, fee,
|
||||
@ -2453,6 +2479,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade,
|
||||
limit_buy_order_old_partial['remaining'])
|
||||
assert trades[0].open_order_id is None
|
||||
assert trades[0].fee_open == fee()
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocker, caplog) -> None:
|
||||
@ -2482,6 +2509,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocke
|
||||
f"{open_trade.open_date.strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
r"\) due to Traceback \(most recent call last\):\n*",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_handle_cancel_buy(mocker, caplog, default_conf, limit_buy_order) -> None:
|
||||
@ -2525,6 +2553,7 @@ def test_handle_cancel_buy(mocker, caplog, default_conf, limit_buy_order) -> Non
|
||||
mocker.patch('freqtrade.exchange.Exchange.cancel_order_with_result', cancel_order_mock)
|
||||
assert not freqtrade.handle_cancel_buy(trade, limit_buy_order, reason)
|
||||
assert log_has_re(r"Order .* for .* not cancelled.", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("limit_buy_order_canceled_empty", ['binance', 'ftx', 'kraken', 'bittrex'],
|
||||
@ -2546,6 +2575,7 @@ def test_handle_cancel_buy_exchanges(mocker, caplog, default_conf,
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert log_has_re(r'Buy order fully cancelled. Removing .* from database\.', caplog)
|
||||
assert nofiy_mock.call_count == 1
|
||||
caplog.clear()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cancelorder', [
|
||||
@ -2915,6 +2945,7 @@ def test_execute_trade_exit_sloe_cancel_exception(
|
||||
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS))
|
||||
assert create_order_mock.call_count == 2
|
||||
assert log_has('Could not cancel stoploss order abcd', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up,
|
||||
@ -3310,6 +3341,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert log_has_re(r'.*Falling back to wallet-amount.', caplog)
|
||||
assert trade.amount != amnt
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test__safe_sell_amount(default_conf, fee, caplog, mocker):
|
||||
@ -3340,6 +3372,7 @@ def test__safe_sell_amount(default_conf, fee, caplog, mocker):
|
||||
assert freqtrade._safe_sell_amount(trade.pair, amount_wallet) == amount_wallet
|
||||
assert not log_has_re(r'.*Falling back to wallet-amount.', caplog)
|
||||
assert wallet_update.call_count == 1
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test__safe_sell_amount_error(default_conf, fee, caplog, mocker):
|
||||
@ -3396,6 +3429,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo
|
||||
freqtrade.enter_positions()
|
||||
|
||||
assert log_has_re(f"Pair {trade.pair} is still locked.*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open,
|
||||
@ -3487,6 +3521,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order,
|
||||
assert log_has("ETH/BTC - HIT STOP: current price at 0.000012, stoploss is 0.000015, "
|
||||
"initial stoploss was at 0.000010, trade opened at 0.000011", caplog)
|
||||
assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_order_open, fee,
|
||||
@ -3534,6 +3569,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or
|
||||
assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog)
|
||||
assert log_has("ETH/BTC - Adjusting stoploss...", caplog)
|
||||
assert trade.stop_loss == 0.0000138501
|
||||
caplog.clear()
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
MagicMock(return_value={
|
||||
@ -3547,6 +3583,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or
|
||||
f"ETH/BTC - HIT STOP: current price at {buy_price + 0.000002:.6f}, "
|
||||
f"stoploss is {trade.stop_loss:.6f}, "
|
||||
f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_order_open, fee,
|
||||
@ -3594,6 +3631,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde
|
||||
assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog)
|
||||
assert log_has("ETH/BTC - Adjusting stoploss...", caplog)
|
||||
assert trade.stop_loss == 0.0000138501
|
||||
caplog.clear()
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
MagicMock(return_value={
|
||||
@ -3608,6 +3646,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde
|
||||
f"stoploss is {trade.stop_loss:.6f}, "
|
||||
f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog)
|
||||
assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_open, fee,
|
||||
@ -3658,6 +3697,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_
|
||||
|
||||
assert not log_has("ETH/BTC - Adjusting stoploss...", caplog)
|
||||
assert trade.stop_loss == 0.0000098910
|
||||
caplog.clear()
|
||||
|
||||
# price rises above the offset (rises 12% when the offset is 5.5%)
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
@ -3671,6 +3711,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_
|
||||
assert log_has("ETH/BTC - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog)
|
||||
assert log_has("ETH/BTC - Adjusting stoploss...", caplog)
|
||||
assert trade.stop_loss == 0.0000117705
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open,
|
||||
@ -3734,6 +3775,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fe
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).',
|
||||
caplog
|
||||
)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fee, fee,
|
||||
@ -3759,6 +3801,7 @@ def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fe
|
||||
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)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, fee):
|
||||
@ -3784,6 +3827,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f
|
||||
'myTrade-Dict empty found',
|
||||
caplog
|
||||
)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
@ -3879,6 +3923,7 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, caplog, fee,
|
||||
@ -3916,6 +3961,7 @@ def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee,
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee,
|
||||
@ -3946,6 +3992,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996).',
|
||||
caplog
|
||||
)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
@ -4189,6 +4236,7 @@ def test_order_book_bid_strategy_exception(mocker, default_conf, caplog) -> None
|
||||
with pytest.raises(PricingError):
|
||||
freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy")
|
||||
assert log_has_re(r'Buy Price at location 1 from orderbook could not be determined.', caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
|
||||
@ -4259,6 +4307,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o
|
||||
freqtrade.handle_trade(trade)
|
||||
assert log_has_re(r'Sell Price at location 1 from orderbook could not be determined\..*',
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_startup_state(default_conf, mocker):
|
||||
@ -4317,6 +4366,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_
|
||||
assert log_has_re(r"Unable to create trade for XRP/BTC: "
|
||||
r"Available balance \(0.0 BTC\) is lower than stake amount \(0.001 BTC\)",
|
||||
caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@ -4360,6 +4410,7 @@ def test_update_open_orders(mocker, default_conf, fee, caplog):
|
||||
|
||||
freqtrade.update_open_orders()
|
||||
assert not log_has_re(r"Error updating Order .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
freqtrade.config['dry_run'] = False
|
||||
freqtrade.update_open_orders()
|
||||
@ -4475,6 +4526,7 @@ def test_reupdate_buy_order_fees(mocker, default_conf, fee, caplog):
|
||||
assert log_has_re(r"Trying to reupdate buy fees for .*", caplog)
|
||||
assert mock_uts.call_count == 0
|
||||
assert not log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@ -4612,6 +4664,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog):
|
||||
|
||||
freqtrade.refind_lost_order(trades[4])
|
||||
assert log_has(f"Error updating {order['id']}.", caplog)
|
||||
caplog.clear()
|
||||
|
||||
|
||||
def test_get_valid_price(mocker, default_conf) -> None:
|
||||
|
Loading…
Reference in New Issue
Block a user