Merge pull request #2718 from hroff-1902/minor-freqtrade-2

Minor: code cleanup in freqtradebot
This commit is contained in:
hroff-1902 2019-12-28 14:55:42 +03:00 committed by GitHub
commit 09b77d9f14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 41 deletions

View File

@ -136,7 +136,7 @@ class FreqtradeBot:
self.process_maybe_execute_sells(trades)
# Then looking for buy opportunities
if len(trades) < self.config['max_open_trades']:
if self.get_free_open_trades():
self.process_maybe_execute_buys()
# Check and handle any timed out open orders
@ -173,6 +173,14 @@ class FreqtradeBot:
"""
return [(pair, self.config['ticker_interval']) for pair in pairs]
def get_free_open_trades(self):
"""
Return the number of free open trades slots or 0 if
max number of open trades reached
"""
open_trades = len(Trade.get_open_trades())
return max(0, self.config['max_open_trades'] - open_trades)
def get_target_bid(self, pair: str, tick: Dict = None) -> float:
"""
Calculates bid target between current ask price and last price
@ -204,14 +212,14 @@ class FreqtradeBot:
return used_rate
def _get_trade_stake_amount(self, pair) -> Optional[float]:
def get_trade_stake_amount(self, pair) -> Optional[float]:
"""
Check if stake amount can be fulfilled with the available balance
for the stake currency
:return: float: Stake Amount
Calculate stake amount for the trade
:return: float: Stake amount
"""
stake_amount: Optional[float]
if self.edge:
return self.edge.stake_amount(
stake_amount = self.edge.stake_amount(
pair,
self.wallets.get_free(self.config['stake_currency']),
self.wallets.get_total(self.config['stake_currency']),
@ -219,18 +227,31 @@ class FreqtradeBot:
)
else:
stake_amount = self.config['stake_amount']
if stake_amount == constants.UNLIMITED_STAKE_AMOUNT:
stake_amount = self._calculate_unlimited_stake_amount()
return self._check_available_stake_amount(stake_amount)
def _calculate_unlimited_stake_amount(self) -> Optional[float]:
"""
Calculate stake amount for "unlimited" stake amount
:return: None if max number of trades reached
"""
free_open_trades = self.get_free_open_trades()
if not free_open_trades:
return None
available_amount = self.wallets.get_free(self.config['stake_currency'])
return available_amount / free_open_trades
def _check_available_stake_amount(self, stake_amount: Optional[float]) -> Optional[float]:
"""
Check if stake amount can be fulfilled with the available balance
for the stake currency
:return: float: Stake amount
"""
available_amount = self.wallets.get_free(self.config['stake_currency'])
if stake_amount == constants.UNLIMITED_STAKE_AMOUNT:
open_trades = len(Trade.get_open_trades())
if open_trades >= self.config['max_open_trades']:
logger.warning("Can't open a new trade: max number of trades is reached")
return None
return available_amount / (self.config['max_open_trades'] - open_trades)
# Check if stake_amount is fulfilled
if available_amount < stake_amount:
if stake_amount is not None and available_amount < stake_amount:
raise DependencyException(
f"Available balance ({available_amount} {self.config['stake_currency']}) is "
f"lower than stake amount ({stake_amount} {self.config['stake_currency']})"
@ -299,18 +320,23 @@ class FreqtradeBot:
buycount = 0
# running get_signal on historical data fetched
for _pair in whitelist:
if self.strategy.is_pair_locked(_pair):
logger.info(f"Pair {_pair} is currently locked.")
for pair in whitelist:
if self.strategy.is_pair_locked(pair):
logger.info(f"Pair {pair} is currently locked.")
continue
(buy, sell) = self.strategy.get_signal(
_pair, self.strategy.ticker_interval,
self.dataprovider.ohlcv(_pair, self.strategy.ticker_interval))
pair, self.strategy.ticker_interval,
self.dataprovider.ohlcv(pair, self.strategy.ticker_interval))
if buy and not sell and len(Trade.get_open_trades()) < self.config['max_open_trades']:
stake_amount = self._get_trade_stake_amount(_pair)
if buy and not sell:
if not self.get_free_open_trades():
logger.debug("Can't open a new trade: max number of trades is reached")
continue
stake_amount = self.get_trade_stake_amount(pair)
if not stake_amount:
logger.debug("Stake amount is 0, ignoring possible trade for {pair}.")
continue
logger.info(f"Buy signal found: about create a new trade with stake_amount: "
@ -320,11 +346,11 @@ class FreqtradeBot:
get('check_depth_of_market', {})
if (bidstrat_check_depth_of_market.get('enabled', False)) and\
(bidstrat_check_depth_of_market.get('bids_to_ask_delta', 0) > 0):
if self._check_depth_of_market_buy(_pair, bidstrat_check_depth_of_market):
buycount += self.execute_buy(_pair, stake_amount)
if self._check_depth_of_market_buy(pair, bidstrat_check_depth_of_market):
buycount += self.execute_buy(pair, stake_amount)
continue
buycount += self.execute_buy(_pair, stake_amount)
buycount += self.execute_buy(pair, stake_amount)
return buycount > 0
@ -351,7 +377,6 @@ class FreqtradeBot:
:param pair: pair for which we want to create a LIMIT_BUY
:return: None
"""
pair_s = pair.replace('_', '/')
stake_currency = self.config['stake_currency']
fiat_currency = self.config.get('fiat_display_currency', None)
time_in_force = self.strategy.order_time_in_force['buy']
@ -362,10 +387,10 @@ class FreqtradeBot:
# Calculate amount
buy_limit_requested = self.get_target_bid(pair)
min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit_requested)
min_stake_amount = self._get_min_pair_stake_amount(pair, buy_limit_requested)
if min_stake_amount is not None and min_stake_amount > stake_amount:
logger.warning(
f"Can't open a new trade for {pair_s}: stake amount "
f"Can't open a new trade for {pair}: stake amount "
f"is too small ({stake_amount} < {min_stake_amount})"
)
return False
@ -388,7 +413,7 @@ class FreqtradeBot:
if float(order['filled']) == 0:
logger.warning('Buy %s order with time in force %s for %s is %s by %s.'
' zero amount is fulfilled.',
order_tif, order_type, pair_s, order_status, self.exchange.name)
order_tif, order_type, pair, order_status, self.exchange.name)
return False
else:
# the order is partially fulfilled
@ -396,7 +421,7 @@ class FreqtradeBot:
# if the order is fulfilled fully or partially
logger.warning('Buy %s order with time in force %s for %s is %s by %s.'
' %s amount fulfilled out of %s (%s remaining which is canceled).',
order_tif, order_type, pair_s, order_status, self.exchange.name,
order_tif, order_type, pair, order_status, self.exchange.name,
order['filled'], order['amount'], order['remaining']
)
stake_amount = order['cost']
@ -413,7 +438,7 @@ class FreqtradeBot:
self.rpc.send_msg({
'type': RPCMessageType.BUY_NOTIFICATION,
'exchange': self.exchange.name.capitalize(),
'pair': pair_s,
'pair': pair,
'limit': buy_limit_filled_price,
'order_type': order_type,
'stake_amount': stake_amount,

View File

@ -462,7 +462,7 @@ class RPC:
raise RPCException(f'position for {pair} already open - id: {trade.id}')
# gen stake amount
stakeamount = self._freqtrade._get_trade_stake_amount(pair)
stakeamount = self._freqtrade.get_trade_stake_amount(pair)
# execute buy
if self._freqtrade.execute_buy(pair, stakeamount, price):

View File

@ -136,7 +136,7 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None:
freqtrade = FreqtradeBot(default_conf)
result = freqtrade._get_trade_stake_amount('ETH/BTC')
result = freqtrade.get_trade_stake_amount('ETH/BTC')
assert result == default_conf['stake_amount']
@ -147,7 +147,7 @@ def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None:
freqtrade = FreqtradeBot(default_conf)
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
freqtrade._get_trade_stake_amount('ETH/BTC')
freqtrade.get_trade_stake_amount('ETH/BTC')
def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker,
@ -170,25 +170,25 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker,
patch_get_signal(freqtrade)
# no open trades, order amount should be 'balance / max_open_trades'
result = freqtrade._get_trade_stake_amount('ETH/BTC')
result = freqtrade.get_trade_stake_amount('ETH/BTC')
assert result == default_conf['stake_amount'] / conf['max_open_trades']
# create one trade, order amount should be 'balance / (max_open_trades - num_open_trades)'
freqtrade.execute_buy('ETH/BTC', result)
result = freqtrade._get_trade_stake_amount('LTC/BTC')
result = freqtrade.get_trade_stake_amount('LTC/BTC')
assert result == default_conf['stake_amount'] / (conf['max_open_trades'] - 1)
# create 2 trades, order amount should be None
freqtrade.execute_buy('LTC/BTC', result)
result = freqtrade._get_trade_stake_amount('XRP/BTC')
result = freqtrade.get_trade_stake_amount('XRP/BTC')
assert result is None
# set max_open_trades = None, so do not trade
conf['max_open_trades'] = 0
freqtrade = FreqtradeBot(conf)
result = freqtrade._get_trade_stake_amount('NEO/BTC')
result = freqtrade.get_trade_stake_amount('NEO/BTC')
assert result is None
@ -214,8 +214,8 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None:
edge_conf['dry_run_wallet'] = 999.9
freqtrade = FreqtradeBot(edge_conf)
assert freqtrade._get_trade_stake_amount('NEO/BTC') == (999.9 * 0.5 * 0.01) / 0.20
assert freqtrade._get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21
assert freqtrade.get_trade_stake_amount('NEO/BTC') == (999.9 * 0.5 * 0.01) / 0.20
assert freqtrade.get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21
def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf) -> None:
@ -570,7 +570,7 @@ def test_create_trades_limit_reached(default_conf, ticker, limit_buy_order,
patch_get_signal(freqtrade)
assert not freqtrade.create_trades()
assert freqtrade._get_trade_stake_amount('ETH/BTC') is None
assert freqtrade.get_trade_stake_amount('ETH/BTC') is None
def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee,