Merge branch 'develop' into order_creation
This commit is contained in:
commit
bf5d2a68f5
@ -67,6 +67,7 @@ CONF_SCHEMA = {
|
|||||||
},
|
},
|
||||||
'minProperties': 1
|
'minProperties': 1
|
||||||
},
|
},
|
||||||
|
'amount_reserve_percent': {'type': 'number', 'minimum': 0.0, 'maximum': 0.5},
|
||||||
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True},
|
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True},
|
||||||
'trailing_stop': {'type': 'boolean'},
|
'trailing_stop': {'type': 'boolean'},
|
||||||
'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1},
|
'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1},
|
||||||
|
@ -160,7 +160,6 @@ class Exchange(object):
|
|||||||
return self._api.id
|
return self._api.id
|
||||||
|
|
||||||
def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame:
|
def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame:
|
||||||
# create key tuple
|
|
||||||
if pair_interval in self._klines:
|
if pair_interval in self._klines:
|
||||||
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]
|
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]
|
||||||
else:
|
else:
|
||||||
@ -502,14 +501,10 @@ class Exchange(object):
|
|||||||
|
|
||||||
input_coroutines = []
|
input_coroutines = []
|
||||||
|
|
||||||
# Gather corotines to run
|
# Gather coroutines to run
|
||||||
for pair, ticker_interval in set(pair_list):
|
for pair, ticker_interval in set(pair_list):
|
||||||
# Calculating ticker interval in second
|
if (not ((pair, ticker_interval) in self._klines)
|
||||||
interval_in_sec = constants.TICKER_INTERVAL_MINUTES[ticker_interval] * 60
|
or self._now_is_time_to_refresh(pair, ticker_interval)):
|
||||||
|
|
||||||
if not ((self._pairs_last_refresh_time.get((pair, ticker_interval), 0)
|
|
||||||
+ interval_in_sec) >= arrow.utcnow().timestamp
|
|
||||||
and (pair, ticker_interval) in self._klines):
|
|
||||||
input_coroutines.append(self._async_get_candle_history(pair, ticker_interval))
|
input_coroutines.append(self._async_get_candle_history(pair, ticker_interval))
|
||||||
else:
|
else:
|
||||||
logger.debug("Using cached ohlcv data for %s, %s ...", pair, ticker_interval)
|
logger.debug("Using cached ohlcv data for %s, %s ...", pair, ticker_interval)
|
||||||
@ -533,6 +528,13 @@ class Exchange(object):
|
|||||||
ticks, tick_interval, fill_missing=True)
|
ticks, tick_interval, fill_missing=True)
|
||||||
return tickers
|
return tickers
|
||||||
|
|
||||||
|
def _now_is_time_to_refresh(self, pair: str, ticker_interval: str) -> bool:
|
||||||
|
# Calculating ticker interval in seconds
|
||||||
|
interval_in_sec = constants.TICKER_INTERVAL_MINUTES[ticker_interval] * 60
|
||||||
|
|
||||||
|
return not ((self._pairs_last_refresh_time.get((pair, ticker_interval), 0)
|
||||||
|
+ interval_in_sec) >= arrow.utcnow().timestamp)
|
||||||
|
|
||||||
@retrier_async
|
@retrier_async
|
||||||
async def _async_get_candle_history(self, pair: str, tick_interval: str,
|
async def _async_get_candle_history(self, pair: str, tick_interval: str,
|
||||||
since_ms: Optional[int] = None) -> Tuple[str, str, List]:
|
since_ms: Optional[int] = None) -> Tuple[str, str, List]:
|
||||||
|
@ -17,7 +17,6 @@ from freqtrade import (DependencyException, OperationalException,
|
|||||||
from freqtrade.data.converter import order_book_to_dataframe
|
from freqtrade.data.converter import order_book_to_dataframe
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.edge import Edge
|
from freqtrade.edge import Edge
|
||||||
from freqtrade.exchange import Exchange
|
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc import RPCManager, RPCMessageType
|
from freqtrade.rpc import RPCManager, RPCMessageType
|
||||||
from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver
|
from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver
|
||||||
@ -57,12 +56,7 @@ class FreqtradeBot(object):
|
|||||||
self.rpc: RPCManager = RPCManager(self)
|
self.rpc: RPCManager = RPCManager(self)
|
||||||
|
|
||||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||||
try:
|
|
||||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||||
except ImportError:
|
|
||||||
logger.info(
|
|
||||||
f"No {exchange_name} specific subclass found. Using the generic class instead.")
|
|
||||||
self.exchange = Exchange(self.config)
|
|
||||||
|
|
||||||
self.wallets = Wallets(self.exchange)
|
self.wallets = Wallets(self.exchange)
|
||||||
self.dataprovider = DataProvider(self.config, self.exchange)
|
self.dataprovider = DataProvider(self.config, self.exchange)
|
||||||
|
@ -22,7 +22,12 @@ class ExchangeResolver(IResolver):
|
|||||||
Load the custom class from config parameter
|
Load the custom class from config parameter
|
||||||
:param config: configuration dictionary or None
|
:param config: configuration dictionary or None
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
self.exchange = self._load_exchange(exchange_name, kwargs={'config': config})
|
self.exchange = self._load_exchange(exchange_name, kwargs={'config': config})
|
||||||
|
except ImportError:
|
||||||
|
logger.info(
|
||||||
|
f"No {exchange_name} specific subclass found. Using the generic class instead.")
|
||||||
|
self.exchange = Exchange(config)
|
||||||
|
|
||||||
def _load_exchange(
|
def _load_exchange(
|
||||||
self, exchange_name: str, kwargs: dict) -> Exchange:
|
self, exchange_name: str, kwargs: dict) -> Exchange:
|
||||||
|
@ -13,7 +13,8 @@ from pandas import DataFrame
|
|||||||
|
|
||||||
from freqtrade import DependencyException, OperationalException, TemporaryError
|
from freqtrade import DependencyException, OperationalException, TemporaryError
|
||||||
from freqtrade.exchange import API_RETRY_COUNT, Exchange
|
from freqtrade.exchange import API_RETRY_COUNT, Exchange
|
||||||
from freqtrade.tests.conftest import get_patched_exchange, log_has
|
from freqtrade.tests.conftest import get_patched_exchange, log_has, log_has_re
|
||||||
|
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
||||||
|
|
||||||
|
|
||||||
# Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines
|
# Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines
|
||||||
@ -106,6 +107,23 @@ def test_init_exception(default_conf, mocker):
|
|||||||
Exchange(default_conf)
|
Exchange(default_conf)
|
||||||
|
|
||||||
|
|
||||||
|
def test_exchange_resolver(default_conf, mocker, caplog):
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=MagicMock()))
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
|
||||||
|
exchange = ExchangeResolver('Binance', default_conf).exchange
|
||||||
|
assert isinstance(exchange, Exchange)
|
||||||
|
assert log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
exchange = ExchangeResolver('Kraken', default_conf).exchange
|
||||||
|
assert isinstance(exchange, Exchange)
|
||||||
|
assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_symbol_amount_prec(default_conf, mocker):
|
def test_symbol_amount_prec(default_conf, mocker):
|
||||||
'''
|
'''
|
||||||
Test rounds down to 4 Decimal places
|
Test rounds down to 4 Decimal places
|
||||||
|
Loading…
Reference in New Issue
Block a user