Merge branch 'develop' into main_refactoring
This commit is contained in:
@@ -11,6 +11,7 @@ class Binance(Exchange):
|
||||
|
||||
_ft_has: Dict = {
|
||||
"stoploss_on_exchange": True,
|
||||
"order_time_in_force": ['gtc', 'fok', 'ioc'],
|
||||
}
|
||||
|
||||
def get_order_book(self, pair: str, limit: int = 100) -> dict:
|
||||
|
@@ -13,7 +13,7 @@ import ccxt
|
||||
import ccxt.async_support as ccxt_async
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade import constants, OperationalException, DependencyException, TemporaryError
|
||||
from freqtrade import constants, DependencyException, OperationalException, TemporaryError
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,13 +21,6 @@ logger = logging.getLogger(__name__)
|
||||
API_RETRY_COUNT = 4
|
||||
|
||||
|
||||
# Urls to exchange markets, insert quote and base with .format()
|
||||
_EXCHANGE_URLS = {
|
||||
ccxt.bittrex.__name__: '/Market/Index?MarketName={quote}-{base}',
|
||||
ccxt.binance.__name__: '/tradeDetail.html?symbol={base}_{quote}',
|
||||
}
|
||||
|
||||
|
||||
def retrier_async(f):
|
||||
async def wrapper(*args, **kwargs):
|
||||
count = kwargs.pop('count', API_RETRY_COUNT)
|
||||
@@ -72,8 +65,9 @@ class Exchange(object):
|
||||
# Dict to specify which options each exchange implements
|
||||
# TODO: this should be merged with attributes from subclasses
|
||||
# To avoid having to copy/paste this to all subclasses.
|
||||
_ft_has = {
|
||||
_ft_has: Dict = {
|
||||
"stoploss_on_exchange": False,
|
||||
"order_time_in_force": ["gtc"],
|
||||
}
|
||||
|
||||
def __init__(self, config: dict) -> None:
|
||||
@@ -275,10 +269,10 @@ class Exchange(object):
|
||||
"""
|
||||
Checks if order time in force configured in strategy/config are supported
|
||||
"""
|
||||
if any(v != 'gtc' for k, v in order_time_in_force.items()):
|
||||
if self.name != 'Binance':
|
||||
raise OperationalException(
|
||||
f'Time in force policies are not supporetd for {self.name} yet.')
|
||||
if any(v not in self._ft_has["order_time_in_force"]
|
||||
for k, v in order_time_in_force.items()):
|
||||
raise OperationalException(
|
||||
f'Time in force policies are not supported for {self.name} yet.')
|
||||
|
||||
def exchange_has(self, endpoint: str) -> bool:
|
||||
"""
|
||||
|
@@ -18,6 +18,7 @@ from freqtrade import DependencyException, constants
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.data import history
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
||||
@@ -64,6 +65,15 @@ class Backtesting(object):
|
||||
self.config['exchange']['uid'] = ''
|
||||
self.config['dry_run'] = True
|
||||
self.strategylist: List[IStrategy] = []
|
||||
|
||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||
self.fee = self.exchange.get_fee()
|
||||
|
||||
if self.config.get('runmode') != RunMode.HYPEROPT:
|
||||
self.dataprovider = DataProvider(self.config, self.exchange)
|
||||
IStrategy.dp = self.dataprovider
|
||||
|
||||
if self.config.get('strategy_list', None):
|
||||
# Force one interval
|
||||
self.ticker_interval = str(self.config.get('ticker_interval'))
|
||||
@@ -78,15 +88,13 @@ class Backtesting(object):
|
||||
self.strategylist.append(StrategyResolver(self.config).strategy)
|
||||
# Load one strategy
|
||||
self._set_strategy(self.strategylist[0])
|
||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||
self.fee = self.exchange.get_fee()
|
||||
|
||||
def _set_strategy(self, strategy):
|
||||
"""
|
||||
Load strategy into backtesting
|
||||
"""
|
||||
self.strategy = strategy
|
||||
|
||||
self.ticker_interval = self.config.get('ticker_interval')
|
||||
self.ticker_interval_mins = constants.TICKER_INTERVAL_MINUTES[self.ticker_interval]
|
||||
self.tickerdata_to_dataframe = strategy.tickerdata_to_dataframe
|
||||
|
@@ -56,6 +56,8 @@ class StrategyResolver(IResolver):
|
||||
("process_only_new_candles", None, False),
|
||||
("order_types", None, False),
|
||||
("order_time_in_force", None, False),
|
||||
("stake_currency", None, False),
|
||||
("stake_amount", None, False),
|
||||
("use_sell_signal", False, True),
|
||||
("sell_profit_only", False, True),
|
||||
("ignore_roi_if_buy_signal", False, True),
|
||||
|
@@ -456,7 +456,37 @@ class RPC(object):
|
||||
def _rpc_whitelist(self) -> Dict:
|
||||
""" Returns the currently active whitelist"""
|
||||
res = {'method': self._freqtrade.pairlists.name,
|
||||
'length': len(self._freqtrade.pairlists.whitelist),
|
||||
'length': len(self._freqtrade.active_pair_whitelist),
|
||||
'whitelist': self._freqtrade.active_pair_whitelist
|
||||
}
|
||||
return res
|
||||
|
||||
def _rpc_blacklist(self, add: List[str]) -> Dict:
|
||||
""" Returns the currently active blacklist"""
|
||||
if add:
|
||||
stake_currency = self._freqtrade.config.get('stake_currency')
|
||||
for pair in add:
|
||||
if (pair.endswith(stake_currency)
|
||||
and pair not in self._freqtrade.pairlists.blacklist):
|
||||
self._freqtrade.pairlists.blacklist.append(pair)
|
||||
|
||||
res = {'method': self._freqtrade.pairlists.name,
|
||||
'length': len(self._freqtrade.pairlists.blacklist),
|
||||
'blacklist': self._freqtrade.pairlists.blacklist,
|
||||
}
|
||||
return res
|
||||
|
||||
def _rpc_edge(self) -> List[Dict[str, Any]]:
|
||||
""" Returns information related to Edge """
|
||||
if not self._freqtrade.edge:
|
||||
raise RPCException(f'Edge is not enabled.')
|
||||
|
||||
return [
|
||||
{
|
||||
'Pair': k,
|
||||
'Winrate': v.winrate,
|
||||
'Expectancy': v.expectancy,
|
||||
'Stoploss': v.stoploss,
|
||||
}
|
||||
for k, v in self._freqtrade.edge._cached_pairs.items()
|
||||
]
|
||||
|
@@ -4,7 +4,7 @@
|
||||
This module manage Telegram communication
|
||||
"""
|
||||
import logging
|
||||
from typing import Any, Callable, Dict
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
from tabulate import tabulate
|
||||
from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update
|
||||
@@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
|
||||
logger.debug('Included module rpc.telegram ...')
|
||||
|
||||
|
||||
def authorized_only(command_handler: Callable[[Any, Bot, Update], None]) -> Callable[..., Any]:
|
||||
def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]:
|
||||
"""
|
||||
Decorator to check if the message comes from the correct chat_id
|
||||
:param command_handler: Telegram CommandHandler
|
||||
@@ -93,6 +93,8 @@ class Telegram(RPC):
|
||||
CommandHandler('reload_conf', self._reload_conf),
|
||||
CommandHandler('stopbuy', self._stopbuy),
|
||||
CommandHandler('whitelist', self._whitelist),
|
||||
CommandHandler('blacklist', self._blacklist, pass_args=True),
|
||||
CommandHandler('edge', self._edge),
|
||||
CommandHandler('help', self._help),
|
||||
CommandHandler('version', self._version),
|
||||
]
|
||||
@@ -470,6 +472,39 @@ class Telegram(RPC):
|
||||
except RPCException as e:
|
||||
self._send_msg(str(e), bot=bot)
|
||||
|
||||
@authorized_only
|
||||
def _blacklist(self, bot: Bot, update: Update, args: List[str]) -> None:
|
||||
"""
|
||||
Handler for /blacklist
|
||||
Shows the currently active blacklist
|
||||
"""
|
||||
try:
|
||||
|
||||
blacklist = self._rpc_blacklist(args)
|
||||
|
||||
message = f"Blacklist contains {blacklist['length']} pairs\n"
|
||||
message += f"`{', '.join(blacklist['blacklist'])}`"
|
||||
|
||||
logger.debug(message)
|
||||
self._send_msg(message)
|
||||
except RPCException as e:
|
||||
self._send_msg(str(e), bot=bot)
|
||||
|
||||
@authorized_only
|
||||
def _edge(self, bot: Bot, update: Update) -> None:
|
||||
"""
|
||||
Handler for /edge
|
||||
Shows information related to Edge
|
||||
"""
|
||||
try:
|
||||
edge_pairs = self._rpc_edge()
|
||||
print(edge_pairs)
|
||||
edge_pairs_tab = tabulate(edge_pairs, headers='keys', tablefmt='simple')
|
||||
message = f'<b>Edge only validated following pairs:</b>\n<pre>{edge_pairs_tab}</pre>'
|
||||
self._send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
|
||||
except RPCException as e:
|
||||
self._send_msg(str(e), bot=bot)
|
||||
|
||||
@authorized_only
|
||||
def _help(self, bot: Bot, update: Update) -> None:
|
||||
"""
|
||||
@@ -497,6 +532,9 @@ class Telegram(RPC):
|
||||
"*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \
|
||||
"*/reload_conf:* `Reload configuration file` \n" \
|
||||
"*/whitelist:* `Show current whitelist` \n" \
|
||||
"*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " \
|
||||
"to the blacklist.` \n" \
|
||||
"*/edge:* `Shows validated pairs by Edge if it is enabeld` \n" \
|
||||
"*/help:* `This help message`\n" \
|
||||
"*/version:* `Show version`"
|
||||
|
||||
|
@@ -180,6 +180,10 @@ def default_conf():
|
||||
"LTC/BTC",
|
||||
"XRP/BTC",
|
||||
"NEO/BTC"
|
||||
],
|
||||
"pair_blacklist": [
|
||||
"DOGE/BTC",
|
||||
"HOT/BTC",
|
||||
]
|
||||
},
|
||||
"telegram": {
|
||||
|
@@ -139,6 +139,28 @@ def test_exchange_resolver(default_conf, mocker, caplog):
|
||||
caplog.record_tuples)
|
||||
|
||||
|
||||
def test_validate_order_time_in_force(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
# explicitly test bittrex, exchanges implementing other policies need seperate tests
|
||||
ex = get_patched_exchange(mocker, default_conf, id="bittrex")
|
||||
tif = {
|
||||
"buy": "gtc",
|
||||
"sell": "gtc",
|
||||
}
|
||||
|
||||
ex.validate_order_time_in_force(tif)
|
||||
tif2 = {
|
||||
"buy": "fok",
|
||||
"sell": "ioc",
|
||||
}
|
||||
with pytest.raises(OperationalException, match=r"Time in force.*not supported for .*"):
|
||||
ex.validate_order_time_in_force(tif2)
|
||||
|
||||
# Patch to see if this will pass if the values are in the ft dict
|
||||
ex._ft_has.update({"order_time_in_force": ["gtc", "fok", "ioc"]})
|
||||
ex.validate_order_time_in_force(tif2)
|
||||
|
||||
|
||||
def test_symbol_amount_prec(default_conf, mocker):
|
||||
'''
|
||||
Test rounds down to 4 Decimal places
|
||||
|
@@ -16,6 +16,7 @@ from freqtrade.arguments import Arguments, TimeRange
|
||||
from freqtrade.data import history
|
||||
from freqtrade.data.btanalysis import evaluate_result_multi
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.optimize import get_timeframe
|
||||
from freqtrade.optimize.backtesting import (Backtesting, setup_configuration,
|
||||
start)
|
||||
@@ -346,6 +347,7 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None:
|
||||
assert callable(backtesting.strategy.tickerdata_to_dataframe)
|
||||
assert callable(backtesting.advise_buy)
|
||||
assert callable(backtesting.advise_sell)
|
||||
assert isinstance(backtesting.strategy.dp, DataProvider)
|
||||
get_fee.assert_called()
|
||||
assert backtesting.fee == 0.5
|
||||
assert not backtesting.strategy.order_types["stoploss_on_exchange"]
|
||||
|
@@ -2,20 +2,21 @@
|
||||
# pragma pylint: disable=invalid-sequence-index, invalid-name, too-many-arguments
|
||||
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock, ANY, PropertyMock
|
||||
from unittest.mock import ANY, MagicMock, PropertyMock
|
||||
|
||||
import pytest
|
||||
from numpy import isnan
|
||||
|
||||
from freqtrade import TemporaryError, DependencyException
|
||||
from freqtrade.worker import Worker
|
||||
from freqtrade import DependencyException, TemporaryError
|
||||
from freqtrade.edge import PairInfo
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import RPC, RPCException
|
||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal
|
||||
from freqtrade.tests.conftest import patch_coinmarketcap, patch_exchange
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal
|
||||
from freqtrade.worker import Worker
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
@@ -731,3 +732,54 @@ def test_rpc_whitelist_dynamic(mocker, default_conf) -> None:
|
||||
assert ret['method'] == 'VolumePairList'
|
||||
assert ret['length'] == 4
|
||||
assert ret['whitelist'] == default_conf['exchange']['pair_whitelist']
|
||||
|
||||
|
||||
def test_rpc_blacklist(mocker, default_conf) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
ret = rpc._rpc_blacklist(None)
|
||||
assert ret['method'] == 'StaticPairList'
|
||||
assert len(ret['blacklist']) == 2
|
||||
assert ret['blacklist'] == default_conf['exchange']['pair_blacklist']
|
||||
assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC']
|
||||
|
||||
ret = rpc._rpc_blacklist(["ETH/BTC"])
|
||||
assert ret['method'] == 'StaticPairList'
|
||||
assert len(ret['blacklist']) == 3
|
||||
assert ret['blacklist'] == default_conf['exchange']['pair_blacklist']
|
||||
assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC']
|
||||
|
||||
|
||||
def test_rpc_edge_disabled(mocker, default_conf) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
with pytest.raises(RPCException, match=r'Edge is not enabled.'):
|
||||
rpc._rpc_edge()
|
||||
|
||||
|
||||
def test_rpc_edge_enabled(mocker, edge_conf) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock(
|
||||
return_value={
|
||||
'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60),
|
||||
}
|
||||
))
|
||||
freqtradebot = FreqtradeBot(edge_conf)
|
||||
|
||||
rpc = RPC(freqtradebot)
|
||||
ret = rpc._rpc_edge()
|
||||
|
||||
assert len(ret) == 1
|
||||
assert ret[0]['Pair'] == 'E/F'
|
||||
assert ret[0]['Winrate'] == 0.66
|
||||
assert ret[0]['Expectancy'] == 1.71
|
||||
assert ret[0]['Stoploss'] == -0.02
|
||||
|
@@ -13,17 +13,17 @@ from telegram import Chat, Message, Update
|
||||
from telegram.error import NetworkError
|
||||
|
||||
from freqtrade import __version__
|
||||
from freqtrade.worker import Worker
|
||||
from freqtrade.edge import PairInfo
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import RPCMessageType
|
||||
from freqtrade.rpc.telegram import Telegram, authorized_only
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.conftest import (get_patched_freqtradebot, get_patched_worker, log_has,
|
||||
patch_exchange)
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from freqtrade.tests.conftest import (get_patched_freqtradebot, get_patched_worker,
|
||||
log_has, patch_coinmarketcap, patch_exchange)
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal
|
||||
from freqtrade.tests.conftest import patch_coinmarketcap
|
||||
from freqtrade.worker import Worker
|
||||
|
||||
|
||||
class DummyCls(Telegram):
|
||||
@@ -75,7 +75,7 @@ def test_init(default_conf, mocker, caplog) -> None:
|
||||
message_str = "rpc.telegram is listening for following commands: [['status'], ['profit'], " \
|
||||
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], " \
|
||||
"['performance'], ['daily'], ['count'], ['reload_conf'], " \
|
||||
"['stopbuy'], ['whitelist'], ['help'], ['version']]"
|
||||
"['stopbuy'], ['whitelist'], ['blacklist'], ['edge'], ['help'], ['version']]"
|
||||
|
||||
assert log_has(message_str, caplog.record_tuples)
|
||||
|
||||
@@ -1122,6 +1122,73 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None:
|
||||
in msg_mock.call_args_list[0][0][0])
|
||||
|
||||
|
||||
def test_blacklist_static(default_conf, update, mocker) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._blacklist(bot=MagicMock(), update=update, args=[])
|
||||
assert msg_mock.call_count == 1
|
||||
assert ("Blacklist contains 2 pairs\n`DOGE/BTC, HOT/BTC`"
|
||||
in msg_mock.call_args_list[0][0][0])
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram._blacklist(bot=MagicMock(), update=update, args=["ETH/BTC"])
|
||||
assert msg_mock.call_count == 1
|
||||
assert ("Blacklist contains 3 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC`"
|
||||
in msg_mock.call_args_list[0][0][0])
|
||||
assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"]
|
||||
|
||||
|
||||
def test_edge_disabled(default_conf, update, mocker) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._edge(bot=MagicMock(), update=update)
|
||||
assert msg_mock.call_count == 1
|
||||
assert "Edge is not enabled." in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_edge_enabled(edge_conf, update, mocker) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock(
|
||||
return_value={
|
||||
'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60),
|
||||
}
|
||||
))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, edge_conf)
|
||||
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._edge(bot=MagicMock(), update=update)
|
||||
assert msg_mock.call_count == 1
|
||||
assert '<b>Edge only validated following pairs:</b>\n<pre>' in msg_mock.call_args_list[0][0][0]
|
||||
assert 'Pair Winrate Expectancy Stoploss' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_help_handle(default_conf, update, mocker) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
msg_mock = MagicMock()
|
||||
|
@@ -194,11 +194,13 @@ def test_strategy_override_ticker_interval(caplog):
|
||||
|
||||
config = {
|
||||
'strategy': 'DefaultStrategy',
|
||||
'ticker_interval': 60
|
||||
'ticker_interval': 60,
|
||||
'stake_currency': 'ETH'
|
||||
}
|
||||
resolver = StrategyResolver(config)
|
||||
|
||||
assert resolver.strategy.ticker_interval == 60
|
||||
assert resolver.strategy.stake_currency == 'ETH'
|
||||
assert ('freqtrade.resolvers.strategy_resolver',
|
||||
logging.INFO,
|
||||
"Override strategy 'ticker_interval' with value in config file: 60."
|
||||
|
@@ -13,13 +13,15 @@ import requests
|
||||
|
||||
from freqtrade import (DependencyException, OperationalException,
|
||||
TemporaryError, constants)
|
||||
from freqtrade.worker import Worker
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import RPCMessageType
|
||||
from freqtrade.state import State
|
||||
from freqtrade.strategy.interface import SellType, SellCheckTuple
|
||||
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange, patch_edge, patch_wallet
|
||||
from freqtrade.strategy.interface import SellCheckTuple, SellType
|
||||
from freqtrade.tests.conftest import (log_has, log_has_re, patch_edge,
|
||||
patch_exchange, patch_wallet)
|
||||
from freqtrade.worker import Worker
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
@@ -109,6 +111,10 @@ def test_worker_running(mocker, default_conf, caplog) -> None:
|
||||
assert state is State.RUNNING
|
||||
assert log_has('Changing state to: RUNNING', caplog.record_tuples)
|
||||
assert mock_throttle.call_count == 1
|
||||
# Check strategy is loaded, and received a dataprovider object
|
||||
assert freqtrade.strategy
|
||||
assert freqtrade.strategy.dp
|
||||
assert isinstance(freqtrade.strategy.dp, DataProvider)
|
||||
|
||||
|
||||
def test_worker_stopped(mocker, default_conf, caplog) -> None:
|
||||
|
Reference in New Issue
Block a user