Merge pull request #2718 from hroff-1902/minor-freqtrade-2
Minor: code cleanup in freqtradebot
This commit is contained in:
commit
09b77d9f14
@ -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,
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user