Implement caching in the correct place

This commit is contained in:
Matthias 2020-02-22 11:12:33 +01:00
parent f5b4a6d3d7
commit 97e6e5e976
2 changed files with 29 additions and 9 deletions

View File

@ -11,6 +11,7 @@ from threading import Lock
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
import arrow import arrow
from cachetools import TTLCache
from requests.exceptions import RequestException from requests.exceptions import RequestException
from freqtrade import __version__, constants, persistence from freqtrade import __version__, constants, persistence
@ -54,6 +55,9 @@ class FreqtradeBot:
self._heartbeat_msg = 0 self._heartbeat_msg = 0
self._sell_rate_cache = TTLCache(maxsize=100, ttl=5)
self._buy_rate_cache = TTLCache(maxsize=100, ttl=5)
self.heartbeat_interval = self.config.get('internals', {}).get('heartbeat_interval', 60) self.heartbeat_interval = self.config.get('internals', {}).get('heartbeat_interval', 60)
self.strategy: IStrategy = StrategyResolver.load_strategy(self.config) self.strategy: IStrategy = StrategyResolver.load_strategy(self.config)
@ -234,11 +238,19 @@ class FreqtradeBot:
return trades_created return trades_created
def get_buy_rate(self, pair: str, refresh: bool, tick: Dict = None) -> float: def get_buy_rate(self, pair: str, refresh: bool) -> float:
""" """
Calculates bid target between current ask price and last price Calculates bid target between current ask price and last price
:param pair: Pair to get rate for
:param refresh: allow cached data
:return: float: Price :return: float: Price
""" """
if not refresh:
rate = self._sell_rate_cache.get(pair)
# Check if cache has been invalidated
if rate:
return rate
config_bid_strategy = self.config.get('bid_strategy', {}) config_bid_strategy = self.config.get('bid_strategy', {})
if 'use_order_book' in config_bid_strategy and\ if 'use_order_book' in config_bid_strategy and\
config_bid_strategy.get('use_order_book', False): config_bid_strategy.get('use_order_book', False):
@ -251,11 +263,8 @@ class FreqtradeBot:
logger.info('...top %s order book buy rate %0.8f', order_book_top, order_book_rate) logger.info('...top %s order book buy rate %0.8f', order_book_top, order_book_rate)
used_rate = order_book_rate used_rate = order_book_rate
else: else:
if not tick: logger.info('Using Last Ask / Last Price')
logger.info('Using Last Ask / Last Price') ticker = self.exchange.fetch_ticker(pair)
ticker = self.exchange.fetch_ticker(pair)
else:
ticker = tick
if ticker['ask'] < ticker['last']: if ticker['ask'] < ticker['last']:
ticker_rate = ticker['ask'] ticker_rate = ticker['ask']
else: else:
@ -263,6 +272,8 @@ class FreqtradeBot:
ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask']) ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask'])
used_rate = ticker_rate used_rate = ticker_rate
self._buy_rate_cache[pair] = used_rate
return used_rate return used_rate
def get_trade_stake_amount(self, pair: str) -> float: def get_trade_stake_amount(self, pair: str) -> float:
@ -621,8 +632,16 @@ class FreqtradeBot:
The orderbook portion is only used for rpc messaging, which would otherwise fail The orderbook portion is only used for rpc messaging, which would otherwise fail
for BitMex (has no bid/ask in fetch_ticker) for BitMex (has no bid/ask in fetch_ticker)
or remain static in any other case since it's not updating. or remain static in any other case since it's not updating.
:param pair: Pair to get rate for
:param refresh: allow cached data
:return: Bid rate :return: Bid rate
""" """
if not refresh:
rate = self._sell_rate_cache.get(pair)
# Check if cache has been invalidated
if rate:
return rate
config_ask_strategy = self.config.get('ask_strategy', {}) config_ask_strategy = self.config.get('ask_strategy', {})
if config_ask_strategy.get('use_order_book', False): if config_ask_strategy.get('use_order_book', False):
logger.debug('Using order book to get sell rate') logger.debug('Using order book to get sell rate')
@ -632,6 +651,7 @@ class FreqtradeBot:
else: else:
rate = self.exchange.fetch_ticker(pair)['bid'] rate = self.exchange.fetch_ticker(pair)['bid']
self._sell_rate_cache[pair] = rate
return rate return rate
def handle_trade(self, trade: Trade) -> bool: def handle_trade(self, trade: Trade) -> bool:

View File

@ -65,7 +65,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'open_order': '(limit buy rem=0.00000000)' 'open_order': '(limit buy rem=0.00000000)'
} == results[0] } == results[0]
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
results = rpc._rpc_trade_status() results = rpc._rpc_trade_status()
assert isnan(results[0]['current_profit']) assert isnan(results[0]['current_profit'])
@ -132,7 +132,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
assert 'ETH/BTC' in result[0][1] assert 'ETH/BTC' in result[0][1]
assert '-0.59% (-0.09)' == result[0][3] assert '-0.59% (-0.09)' == result[0][3]
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
assert 'instantly' == result[0][2] assert 'instantly' == result[0][2]
@ -256,7 +256,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
assert prec_satoshi(stats['best_rate'], 6.2) assert prec_satoshi(stats['best_rate'], 6.2)
# Test non-available pair # Test non-available pair
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert stats['trade_count'] == 2 assert stats['trade_count'] == 2