Merge branch 'develop' into 'validate_whitelist'
This commit is contained in:
@@ -20,6 +20,7 @@ REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
|
||||
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
||||
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
||||
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList']
|
||||
DRY_RUN_WALLET = 999.9
|
||||
|
||||
TICKER_INTERVAL_MINUTES = {
|
||||
'1m': 1,
|
||||
@@ -60,6 +61,7 @@ CONF_SCHEMA = {
|
||||
},
|
||||
'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT},
|
||||
'dry_run': {'type': 'boolean'},
|
||||
'dry_run_wallet': {'type': 'number'},
|
||||
'process_only_new_candles': {'type': 'boolean'},
|
||||
'minimal_roi': {
|
||||
'type': 'object',
|
||||
|
@@ -66,7 +66,7 @@ def retrier(f):
|
||||
|
||||
class Exchange(object):
|
||||
|
||||
_conf: Dict = {}
|
||||
_config: Dict = {}
|
||||
_params: Dict = {}
|
||||
|
||||
# Dict to specify which options each exchange implements
|
||||
@@ -82,7 +82,7 @@ class Exchange(object):
|
||||
it does basic validation whether the specified exchange and pairs are valid.
|
||||
:return: None
|
||||
"""
|
||||
self._conf.update(config)
|
||||
self._config.update(config)
|
||||
|
||||
self._cached_ticker: Dict[str, Any] = {}
|
||||
|
||||
@@ -370,7 +370,7 @@ class Exchange(object):
|
||||
def buy(self, pair: str, ordertype: str, amount: float,
|
||||
rate: float, time_in_force) -> Dict:
|
||||
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
dry_order = self.dry_run_order(pair, ordertype, "buy", amount, rate)
|
||||
return dry_order
|
||||
|
||||
@@ -383,7 +383,7 @@ class Exchange(object):
|
||||
def sell(self, pair: str, ordertype: str, amount: float,
|
||||
rate: float, time_in_force='gtc') -> Dict:
|
||||
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
dry_order = self.dry_run_order(pair, ordertype, "sell", amount, rate)
|
||||
return dry_order
|
||||
|
||||
@@ -408,7 +408,7 @@ class Exchange(object):
|
||||
raise OperationalException(
|
||||
'In stoploss limit order, stop price should be more than limit price')
|
||||
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
dry_order = self.dry_run_order(
|
||||
pair, ordertype, "sell", amount, stop_price)
|
||||
return dry_order
|
||||
@@ -423,8 +423,8 @@ class Exchange(object):
|
||||
|
||||
@retrier
|
||||
def get_balance(self, currency: str) -> float:
|
||||
if self._conf['dry_run']:
|
||||
return 999.9
|
||||
if self._config['dry_run']:
|
||||
return constants.DRY_RUN_WALLET
|
||||
|
||||
# ccxt exception is already handled by get_balances
|
||||
balances = self.get_balances()
|
||||
@@ -436,7 +436,7 @@ class Exchange(object):
|
||||
|
||||
@retrier
|
||||
def get_balances(self) -> dict:
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
return {}
|
||||
|
||||
try:
|
||||
@@ -607,7 +607,7 @@ class Exchange(object):
|
||||
|
||||
@retrier
|
||||
def cancel_order(self, order_id: str, pair: str) -> None:
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -623,7 +623,7 @@ class Exchange(object):
|
||||
|
||||
@retrier
|
||||
def get_order(self, order_id: str, pair: str) -> Dict:
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
order = self._dry_run_open_orders[order_id]
|
||||
return order
|
||||
try:
|
||||
@@ -660,7 +660,7 @@ class Exchange(object):
|
||||
|
||||
@retrier
|
||||
def get_trades_for_order(self, order_id: str, pair: str, since: datetime) -> List:
|
||||
if self._conf['dry_run']:
|
||||
if self._config['dry_run']:
|
||||
return []
|
||||
if not self.exchange_has('fetchMyTrades'):
|
||||
return []
|
||||
|
@@ -63,7 +63,7 @@ class FreqtradeBot(object):
|
||||
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
|
||||
self.exchange = ExchangeResolver(exchange_name, self.config).exchange
|
||||
|
||||
self.wallets = Wallets(self.exchange)
|
||||
self.wallets = Wallets(self.config, self.exchange)
|
||||
self.dataprovider = DataProvider(self.config, self.exchange)
|
||||
|
||||
# Attach Dataprovider to Strategy baseclass
|
||||
@@ -613,6 +613,25 @@ class FreqtradeBot(object):
|
||||
f"(from {order_amount} to {real_amount}) from Trades")
|
||||
return real_amount
|
||||
|
||||
def get_sell_rate(self, pair: str, refresh: bool) -> float:
|
||||
"""
|
||||
Get sell rate - either using get-ticker bid or first bid based on orderbook
|
||||
The orderbook portion is only used for rpc messaging, which would otherwise fail
|
||||
for BitMex (has no bid/ask in get_ticker)
|
||||
or remain static in any other case since it's not updating.
|
||||
:return: Bid rate
|
||||
"""
|
||||
config_ask_strategy = self.config.get('ask_strategy', {})
|
||||
if config_ask_strategy.get('use_order_book', False):
|
||||
logger.debug('Using order book to get sell rate')
|
||||
|
||||
order_book = self.exchange.get_order_book(pair, 1)
|
||||
rate = order_book['bids'][0][0]
|
||||
|
||||
else:
|
||||
rate = self.exchange.get_ticker(pair, refresh)['bid']
|
||||
return rate
|
||||
|
||||
def handle_trade(self, trade: Trade) -> bool:
|
||||
"""
|
||||
Sells the current pair if the threshold is reached and updates the trade record.
|
||||
@@ -649,7 +668,7 @@ class FreqtradeBot(object):
|
||||
|
||||
else:
|
||||
logger.debug('checking sell')
|
||||
sell_rate = self.exchange.get_ticker(trade.pair)['bid']
|
||||
sell_rate = self.get_sell_rate(trade.pair, True)
|
||||
if self.check_sell(trade, sell_rate, buy, sell):
|
||||
return True
|
||||
|
||||
@@ -892,7 +911,8 @@ class FreqtradeBot(object):
|
||||
"""
|
||||
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
|
||||
profit_trade = trade.calc_profit(rate=profit_rate)
|
||||
current_rate = self.exchange.get_ticker(trade.pair)['bid']
|
||||
# Use cached ticker here - it was updated seconds ago.
|
||||
current_rate = self.get_sell_rate(trade.pair, False)
|
||||
profit_percent = trade.calc_profit_percent(profit_rate)
|
||||
gain = "profit" if profit_percent > 0 else "loss"
|
||||
|
||||
|
@@ -94,7 +94,7 @@ class RPC(object):
|
||||
order = self._freqtrade.exchange.get_order(trade.open_order_id, trade.pair)
|
||||
# calculate profit and send message to user
|
||||
try:
|
||||
current_rate = self._freqtrade.exchange.get_ticker(trade.pair, False)['bid']
|
||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||
except DependencyException:
|
||||
current_rate = NAN
|
||||
current_profit = trade.calc_profit_percent(current_rate)
|
||||
@@ -125,7 +125,7 @@ class RPC(object):
|
||||
for trade in trades:
|
||||
# calculate profit and send message to user
|
||||
try:
|
||||
current_rate = self._freqtrade.exchange.get_ticker(trade.pair, False)['bid']
|
||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||
except DependencyException:
|
||||
current_rate = NAN
|
||||
trade_perc = (100 * trade.calc_profit_percent(current_rate))
|
||||
@@ -213,7 +213,7 @@ class RPC(object):
|
||||
else:
|
||||
# Get current rate
|
||||
try:
|
||||
current_rate = self._freqtrade.exchange.get_ticker(trade.pair, False)['bid']
|
||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||
except DependencyException:
|
||||
current_rate = NAN
|
||||
profit_percent = trade.calc_profit_percent(rate=current_rate)
|
||||
@@ -280,9 +280,9 @@ class RPC(object):
|
||||
else:
|
||||
try:
|
||||
if coin == 'USDT':
|
||||
rate = 1.0 / self._freqtrade.exchange.get_ticker('BTC/USDT', False)['bid']
|
||||
rate = 1.0 / self._freqtrade.get_sell_rate('BTC/USDT', False)
|
||||
else:
|
||||
rate = self._freqtrade.exchange.get_ticker(coin + '/BTC', False)['bid']
|
||||
rate = self._freqtrade.get_sell_rate(coin + '/BTC', False)
|
||||
except (TemporaryError, DependencyException):
|
||||
continue
|
||||
est_btc: float = rate * balance['total']
|
||||
@@ -328,6 +328,16 @@ class RPC(object):
|
||||
self._freqtrade.state = State.RELOAD_CONF
|
||||
return {'status': 'reloading config ...'}
|
||||
|
||||
def _rpc_stopbuy(self) -> Dict[str, str]:
|
||||
"""
|
||||
Handler to stop buying, but handle open trades gracefully.
|
||||
"""
|
||||
if self._freqtrade.state == State.RUNNING:
|
||||
# Set 'max_open_trades' to 0
|
||||
self._freqtrade.config['max_open_trades'] = 0
|
||||
|
||||
return {'status': 'No more buy will occur from now. Run /reload_conf to reset.'}
|
||||
|
||||
def _rpc_forcesell(self, trade_id) -> None:
|
||||
"""
|
||||
Handler for forcesell <id>.
|
||||
@@ -356,7 +366,7 @@ class RPC(object):
|
||||
return
|
||||
|
||||
# Get current rate and execute sell
|
||||
current_rate = self._freqtrade.exchange.get_ticker(trade.pair, False)['bid']
|
||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||
self._freqtrade.execute_sell(trade, current_rate, SellType.FORCE_SELL)
|
||||
# ---- EOF def _exec_forcesell ----
|
||||
|
||||
|
@@ -91,6 +91,7 @@ class Telegram(RPC):
|
||||
CommandHandler('daily', self._daily),
|
||||
CommandHandler('count', self._count),
|
||||
CommandHandler('reload_conf', self._reload_conf),
|
||||
CommandHandler('stopbuy', self._stopbuy),
|
||||
CommandHandler('whitelist', self._whitelist),
|
||||
CommandHandler('help', self._help),
|
||||
CommandHandler('version', self._version),
|
||||
@@ -362,6 +363,18 @@ class Telegram(RPC):
|
||||
msg = self._rpc_reload_conf()
|
||||
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
|
||||
|
||||
@authorized_only
|
||||
def _stopbuy(self, bot: Bot, update: Update) -> None:
|
||||
"""
|
||||
Handler for /stop_buy.
|
||||
Sets max_open_trades to 0 and gracefully sells all open trades
|
||||
:param bot: telegram bot
|
||||
:param update: message update
|
||||
:return: None
|
||||
"""
|
||||
msg = self._rpc_stopbuy()
|
||||
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
|
||||
|
||||
@authorized_only
|
||||
def _forcesell(self, bot: Bot, update: Update) -> None:
|
||||
"""
|
||||
@@ -481,6 +494,7 @@ class Telegram(RPC):
|
||||
"*/count:* `Show number of trades running compared to allowed number of trades`" \
|
||||
"\n" \
|
||||
"*/balance:* `Show account balance per currency`\n" \
|
||||
"*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \
|
||||
"*/reload_conf:* `Reload configuration file` \n" \
|
||||
"*/whitelist:* `Show current whitelist` \n" \
|
||||
"*/help:* `This help message`\n" \
|
||||
|
@@ -406,6 +406,26 @@ def test_rpc_stop(mocker, default_conf) -> None:
|
||||
assert freqtradebot.state == State.STOPPED
|
||||
|
||||
|
||||
def test_rpc_stopbuy(mocker, default_conf) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_ticker=MagicMock()
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.RUNNING
|
||||
|
||||
assert freqtradebot.config['max_open_trades'] != 0
|
||||
result = rpc._rpc_stopbuy()
|
||||
assert {'status': 'No more buy will occur from now. Run /reload_conf to reset.'} == result
|
||||
assert freqtradebot.config['max_open_trades'] == 0
|
||||
|
||||
|
||||
def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
patch_exchange(mocker)
|
||||
|
@@ -74,7 +74,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'], " \
|
||||
"['whitelist'], ['help'], ['version']]"
|
||||
"['stopbuy'], ['whitelist'], ['help'], ['version']]"
|
||||
|
||||
assert log_has(message_str, caplog.record_tuples)
|
||||
|
||||
@@ -662,6 +662,26 @@ def test_stop_handle_already_stopped(default_conf, update, mocker) -> None:
|
||||
assert 'already stopped' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_stopbuy_handle(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)
|
||||
|
||||
assert freqtradebot.config['max_open_trades'] != 0
|
||||
telegram._stopbuy(bot=MagicMock(), update=update)
|
||||
assert freqtradebot.config['max_open_trades'] == 0
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'No more buy will occur from now. Run /reload_conf to reset.' \
|
||||
in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_reload_conf_handle(default_conf, update, mocker) -> None:
|
||||
patch_coinmarketcap(mocker)
|
||||
msg_mock = MagicMock()
|
||||
|
@@ -2962,6 +2962,31 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
|
||||
|
||||
def test_get_sell_rate(default_conf, mocker, ticker, order_book_l2) -> None:
|
||||
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_order_book=order_book_l2,
|
||||
get_ticker=ticker,
|
||||
)
|
||||
pair = "ETH/BTC"
|
||||
|
||||
# Test regular mode
|
||||
ft = get_patched_freqtradebot(mocker, default_conf)
|
||||
rate = ft.get_sell_rate(pair, True)
|
||||
assert isinstance(rate, float)
|
||||
assert rate == 0.00001098
|
||||
|
||||
# Test orderbook mode
|
||||
default_conf['ask_strategy']['use_order_book'] = True
|
||||
default_conf['ask_strategy']['order_book_min'] = 1
|
||||
default_conf['ask_strategy']['order_book_max'] = 2
|
||||
ft = get_patched_freqtradebot(mocker, default_conf)
|
||||
rate = ft.get_sell_rate(pair, True)
|
||||
assert isinstance(rate, float)
|
||||
assert rate == 0.043936
|
||||
|
||||
|
||||
def test_startup_messages(default_conf, mocker):
|
||||
default_conf['pairlist'] = {'method': 'VolumePairList',
|
||||
'config': {'number_assets': 20}
|
||||
|
@@ -23,13 +23,13 @@ def test_sync_wallet_at_boot(mocker, default_conf):
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
assert len(freqtrade.wallets.wallets) == 2
|
||||
assert freqtrade.wallets.wallets['BNT'].free == 1.0
|
||||
assert freqtrade.wallets.wallets['BNT'].used == 2.0
|
||||
assert freqtrade.wallets.wallets['BNT'].total == 3.0
|
||||
assert freqtrade.wallets.wallets['GAS'].free == 0.260739
|
||||
assert freqtrade.wallets.wallets['GAS'].used == 0.0
|
||||
assert freqtrade.wallets.wallets['GAS'].total == 0.260739
|
||||
assert len(freqtrade.wallets._wallets) == 2
|
||||
assert freqtrade.wallets._wallets['BNT'].free == 1.0
|
||||
assert freqtrade.wallets._wallets['BNT'].used == 2.0
|
||||
assert freqtrade.wallets._wallets['BNT'].total == 3.0
|
||||
assert freqtrade.wallets._wallets['GAS'].free == 0.260739
|
||||
assert freqtrade.wallets._wallets['GAS'].used == 0.0
|
||||
assert freqtrade.wallets._wallets['GAS'].total == 0.260739
|
||||
assert freqtrade.wallets.get_free('BNT') == 1.0
|
||||
|
||||
mocker.patch.multiple(
|
||||
@@ -50,13 +50,13 @@ def test_sync_wallet_at_boot(mocker, default_conf):
|
||||
|
||||
freqtrade.wallets.update()
|
||||
|
||||
assert len(freqtrade.wallets.wallets) == 2
|
||||
assert freqtrade.wallets.wallets['BNT'].free == 1.2
|
||||
assert freqtrade.wallets.wallets['BNT'].used == 1.9
|
||||
assert freqtrade.wallets.wallets['BNT'].total == 3.5
|
||||
assert freqtrade.wallets.wallets['GAS'].free == 0.270739
|
||||
assert freqtrade.wallets.wallets['GAS'].used == 0.1
|
||||
assert freqtrade.wallets.wallets['GAS'].total == 0.260439
|
||||
assert len(freqtrade.wallets._wallets) == 2
|
||||
assert freqtrade.wallets._wallets['BNT'].free == 1.2
|
||||
assert freqtrade.wallets._wallets['BNT'].used == 1.9
|
||||
assert freqtrade.wallets._wallets['BNT'].total == 3.5
|
||||
assert freqtrade.wallets._wallets['GAS'].free == 0.270739
|
||||
assert freqtrade.wallets._wallets['GAS'].used == 0.1
|
||||
assert freqtrade.wallets._wallets['GAS'].total == 0.260439
|
||||
assert freqtrade.wallets.get_free('GAS') == 0.270739
|
||||
assert freqtrade.wallets.get_used('GAS') == 0.1
|
||||
assert freqtrade.wallets.get_total('GAS') == 0.260439
|
||||
@@ -81,11 +81,11 @@ def test_sync_wallet_missing_data(mocker, default_conf):
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
assert len(freqtrade.wallets.wallets) == 2
|
||||
assert freqtrade.wallets.wallets['BNT'].free == 1.0
|
||||
assert freqtrade.wallets.wallets['BNT'].used == 2.0
|
||||
assert freqtrade.wallets.wallets['BNT'].total == 3.0
|
||||
assert freqtrade.wallets.wallets['GAS'].free == 0.260739
|
||||
assert freqtrade.wallets.wallets['GAS'].used is None
|
||||
assert freqtrade.wallets.wallets['GAS'].total == 0.260739
|
||||
assert len(freqtrade.wallets._wallets) == 2
|
||||
assert freqtrade.wallets._wallets['BNT'].free == 1.0
|
||||
assert freqtrade.wallets._wallets['BNT'].used == 2.0
|
||||
assert freqtrade.wallets._wallets['BNT'].total == 3.0
|
||||
assert freqtrade.wallets._wallets['GAS'].free == 0.260739
|
||||
assert freqtrade.wallets._wallets['GAS'].used is None
|
||||
assert freqtrade.wallets._wallets['GAS'].total == 0.260739
|
||||
assert freqtrade.wallets.get_free('GAS') == 0.260739
|
||||
|
@@ -1,15 +1,16 @@
|
||||
# pragma pylint: disable=W0603
|
||||
""" Wallet """
|
||||
|
||||
import logging
|
||||
from typing import Dict, Any, NamedTuple
|
||||
from typing import Dict, NamedTuple
|
||||
from freqtrade.exchange import Exchange
|
||||
from freqtrade import constants
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# wallet data structure
|
||||
class Wallet(NamedTuple):
|
||||
exchange: str
|
||||
currency: str
|
||||
free: float = 0
|
||||
used: float = 0
|
||||
@@ -18,17 +19,19 @@ class Wallet(NamedTuple):
|
||||
|
||||
class Wallets(object):
|
||||
|
||||
def __init__(self, exchange: Exchange) -> None:
|
||||
self.exchange = exchange
|
||||
self.wallets: Dict[str, Any] = {}
|
||||
def __init__(self, config: dict, exchange: Exchange) -> None:
|
||||
self._config = config
|
||||
self._exchange = exchange
|
||||
self._wallets: Dict[str, Wallet] = {}
|
||||
|
||||
self.update()
|
||||
|
||||
def get_free(self, currency) -> float:
|
||||
|
||||
if self.exchange._conf['dry_run']:
|
||||
return 999.9
|
||||
if self._config['dry_run']:
|
||||
return self._config.get('dry_run_wallet', constants.DRY_RUN_WALLET)
|
||||
|
||||
balance = self.wallets.get(currency)
|
||||
balance = self._wallets.get(currency)
|
||||
if balance and balance.free:
|
||||
return balance.free
|
||||
else:
|
||||
@@ -36,10 +39,10 @@ class Wallets(object):
|
||||
|
||||
def get_used(self, currency) -> float:
|
||||
|
||||
if self.exchange._conf['dry_run']:
|
||||
return 999.9
|
||||
if self._config['dry_run']:
|
||||
return self._config.get('dry_run_wallet', constants.DRY_RUN_WALLET)
|
||||
|
||||
balance = self.wallets.get(currency)
|
||||
balance = self._wallets.get(currency)
|
||||
if balance and balance.used:
|
||||
return balance.used
|
||||
else:
|
||||
@@ -47,25 +50,25 @@ class Wallets(object):
|
||||
|
||||
def get_total(self, currency) -> float:
|
||||
|
||||
if self.exchange._conf['dry_run']:
|
||||
return 999.9
|
||||
if self._config['dry_run']:
|
||||
return self._config.get('dry_run_wallet', constants.DRY_RUN_WALLET)
|
||||
|
||||
balance = self.wallets.get(currency)
|
||||
balance = self._wallets.get(currency)
|
||||
if balance and balance.total:
|
||||
return balance.total
|
||||
else:
|
||||
return 0
|
||||
|
||||
def update(self) -> None:
|
||||
balances = self.exchange.get_balances()
|
||||
|
||||
balances = self._exchange.get_balances()
|
||||
|
||||
for currency in balances:
|
||||
self.wallets[currency] = Wallet(
|
||||
self.exchange.id,
|
||||
self._wallets[currency] = Wallet(
|
||||
currency,
|
||||
balances[currency].get('free', None),
|
||||
balances[currency].get('used', None),
|
||||
balances[currency].get('total', None)
|
||||
)
|
||||
|
||||
logger.info('Wallets synced ...')
|
||||
logger.info('Wallets synced.')
|
||||
|
Reference in New Issue
Block a user