Merge pull request #1680 from hroff-1902/wallets_and_exchange_cleanup

Minor: Wallet and exchange cleanup
This commit is contained in:
Matthias 2019-03-20 19:31:02 +01:00 committed by GitHub
commit 65f5aa59e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 52 deletions

View File

@ -20,6 +20,7 @@ REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange']
ORDERTYPE_POSSIBILITIES = ['limit', 'market'] ORDERTYPE_POSSIBILITIES = ['limit', 'market']
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList']
DRY_RUN_WALLET = 999.9
TICKER_INTERVAL_MINUTES = { TICKER_INTERVAL_MINUTES = {
'1m': 1, '1m': 1,
@ -60,6 +61,7 @@ CONF_SCHEMA = {
}, },
'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT},
'dry_run': {'type': 'boolean'}, 'dry_run': {'type': 'boolean'},
'dry_run_wallet': {'type': 'number'},
'process_only_new_candles': {'type': 'boolean'}, 'process_only_new_candles': {'type': 'boolean'},
'minimal_roi': { 'minimal_roi': {
'type': 'object', 'type': 'object',

View File

@ -66,7 +66,7 @@ def retrier(f):
class Exchange(object): class Exchange(object):
_conf: Dict = {} _config: Dict = {}
_params: Dict = {} _params: Dict = {}
# Dict to specify which options each exchange implements # 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. it does basic validation whether the specified exchange and pairs are valid.
:return: None :return: None
""" """
self._conf.update(config) self._config.update(config)
self._cached_ticker: Dict[str, Any] = {} self._cached_ticker: Dict[str, Any] = {}
@ -239,7 +239,7 @@ class Exchange(object):
logger.warning('Unable to validate pairs (assuming they are correct).') logger.warning('Unable to validate pairs (assuming they are correct).')
# return # return
stake_cur = self._conf['stake_currency'] stake_cur = self._config['stake_currency']
for pair in pairs: for pair in pairs:
# Note: ccxt has BaseCurrency/QuoteCurrency format for pairs # Note: ccxt has BaseCurrency/QuoteCurrency format for pairs
# TODO: add a support for having coins in BTC/USDT format # TODO: add a support for having coins in BTC/USDT format
@ -374,7 +374,7 @@ class Exchange(object):
def buy(self, pair: str, ordertype: str, amount: float, def buy(self, pair: str, ordertype: str, amount: float,
rate: float, time_in_force) -> Dict: 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) dry_order = self.dry_run_order(pair, ordertype, "buy", amount, rate)
return dry_order return dry_order
@ -387,7 +387,7 @@ class Exchange(object):
def sell(self, pair: str, ordertype: str, amount: float, def sell(self, pair: str, ordertype: str, amount: float,
rate: float, time_in_force='gtc') -> Dict: 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) dry_order = self.dry_run_order(pair, ordertype, "sell", amount, rate)
return dry_order return dry_order
@ -412,7 +412,7 @@ class Exchange(object):
raise OperationalException( raise OperationalException(
'In stoploss limit order, stop price should be more than limit price') '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( dry_order = self.dry_run_order(
pair, ordertype, "sell", amount, stop_price) pair, ordertype, "sell", amount, stop_price)
return dry_order return dry_order
@ -427,8 +427,8 @@ class Exchange(object):
@retrier @retrier
def get_balance(self, currency: str) -> float: def get_balance(self, currency: str) -> float:
if self._conf['dry_run']: if self._config['dry_run']:
return 999.9 return constants.DRY_RUN_WALLET
# ccxt exception is already handled by get_balances # ccxt exception is already handled by get_balances
balances = self.get_balances() balances = self.get_balances()
@ -440,7 +440,7 @@ class Exchange(object):
@retrier @retrier
def get_balances(self) -> dict: def get_balances(self) -> dict:
if self._conf['dry_run']: if self._config['dry_run']:
return {} return {}
try: try:
@ -611,7 +611,7 @@ class Exchange(object):
@retrier @retrier
def cancel_order(self, order_id: str, pair: str) -> None: def cancel_order(self, order_id: str, pair: str) -> None:
if self._conf['dry_run']: if self._config['dry_run']:
return return
try: try:
@ -627,7 +627,7 @@ class Exchange(object):
@retrier @retrier
def get_order(self, order_id: str, pair: str) -> Dict: 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] order = self._dry_run_open_orders[order_id]
return order return order
try: try:
@ -664,7 +664,7 @@ class Exchange(object):
@retrier @retrier
def get_trades_for_order(self, order_id: str, pair: str, since: datetime) -> List: 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 [] return []
if not self.exchange_has('fetchMyTrades'): if not self.exchange_has('fetchMyTrades'):
return [] return []

View File

@ -63,7 +63,7 @@ class FreqtradeBot(object):
exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title() exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title()
self.exchange = ExchangeResolver(exchange_name, self.config).exchange 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) self.dataprovider = DataProvider(self.config, self.exchange)
# Attach Dataprovider to Strategy baseclass # Attach Dataprovider to Strategy baseclass

View File

@ -23,13 +23,13 @@ def test_sync_wallet_at_boot(mocker, default_conf):
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
assert len(freqtrade.wallets.wallets) == 2 assert len(freqtrade.wallets._wallets) == 2
assert freqtrade.wallets.wallets['BNT'].free == 1.0 assert freqtrade.wallets._wallets['BNT'].free == 1.0
assert freqtrade.wallets.wallets['BNT'].used == 2.0 assert freqtrade.wallets._wallets['BNT'].used == 2.0
assert freqtrade.wallets.wallets['BNT'].total == 3.0 assert freqtrade.wallets._wallets['BNT'].total == 3.0
assert freqtrade.wallets.wallets['GAS'].free == 0.260739 assert freqtrade.wallets._wallets['GAS'].free == 0.260739
assert freqtrade.wallets.wallets['GAS'].used == 0.0 assert freqtrade.wallets._wallets['GAS'].used == 0.0
assert freqtrade.wallets.wallets['GAS'].total == 0.260739 assert freqtrade.wallets._wallets['GAS'].total == 0.260739
assert freqtrade.wallets.get_free('BNT') == 1.0 assert freqtrade.wallets.get_free('BNT') == 1.0
mocker.patch.multiple( mocker.patch.multiple(
@ -50,13 +50,13 @@ def test_sync_wallet_at_boot(mocker, default_conf):
freqtrade.wallets.update() freqtrade.wallets.update()
assert len(freqtrade.wallets.wallets) == 2 assert len(freqtrade.wallets._wallets) == 2
assert freqtrade.wallets.wallets['BNT'].free == 1.2 assert freqtrade.wallets._wallets['BNT'].free == 1.2
assert freqtrade.wallets.wallets['BNT'].used == 1.9 assert freqtrade.wallets._wallets['BNT'].used == 1.9
assert freqtrade.wallets.wallets['BNT'].total == 3.5 assert freqtrade.wallets._wallets['BNT'].total == 3.5
assert freqtrade.wallets.wallets['GAS'].free == 0.270739 assert freqtrade.wallets._wallets['GAS'].free == 0.270739
assert freqtrade.wallets.wallets['GAS'].used == 0.1 assert freqtrade.wallets._wallets['GAS'].used == 0.1
assert freqtrade.wallets.wallets['GAS'].total == 0.260439 assert freqtrade.wallets._wallets['GAS'].total == 0.260439
assert freqtrade.wallets.get_free('GAS') == 0.270739 assert freqtrade.wallets.get_free('GAS') == 0.270739
assert freqtrade.wallets.get_used('GAS') == 0.1 assert freqtrade.wallets.get_used('GAS') == 0.1
assert freqtrade.wallets.get_total('GAS') == 0.260439 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) freqtrade = get_patched_freqtradebot(mocker, default_conf)
assert len(freqtrade.wallets.wallets) == 2 assert len(freqtrade.wallets._wallets) == 2
assert freqtrade.wallets.wallets['BNT'].free == 1.0 assert freqtrade.wallets._wallets['BNT'].free == 1.0
assert freqtrade.wallets.wallets['BNT'].used == 2.0 assert freqtrade.wallets._wallets['BNT'].used == 2.0
assert freqtrade.wallets.wallets['BNT'].total == 3.0 assert freqtrade.wallets._wallets['BNT'].total == 3.0
assert freqtrade.wallets.wallets['GAS'].free == 0.260739 assert freqtrade.wallets._wallets['GAS'].free == 0.260739
assert freqtrade.wallets.wallets['GAS'].used is None assert freqtrade.wallets._wallets['GAS'].used is None
assert freqtrade.wallets.wallets['GAS'].total == 0.260739 assert freqtrade.wallets._wallets['GAS'].total == 0.260739
assert freqtrade.wallets.get_free('GAS') == 0.260739 assert freqtrade.wallets.get_free('GAS') == 0.260739

View File

@ -1,15 +1,16 @@
# pragma pylint: disable=W0603 # pragma pylint: disable=W0603
""" Wallet """ """ Wallet """
import logging import logging
from typing import Dict, Any, NamedTuple from typing import Dict, NamedTuple
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
from freqtrade import constants
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# wallet data structure # wallet data structure
class Wallet(NamedTuple): class Wallet(NamedTuple):
exchange: str
currency: str currency: str
free: float = 0 free: float = 0
used: float = 0 used: float = 0
@ -18,17 +19,19 @@ class Wallet(NamedTuple):
class Wallets(object): class Wallets(object):
def __init__(self, exchange: Exchange) -> None: def __init__(self, config: dict, exchange: Exchange) -> None:
self.exchange = exchange self._config = config
self.wallets: Dict[str, Any] = {} self._exchange = exchange
self._wallets: Dict[str, Wallet] = {}
self.update() self.update()
def get_free(self, currency) -> float: def get_free(self, currency) -> float:
if self.exchange._conf['dry_run']: if self._config['dry_run']:
return 999.9 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: if balance and balance.free:
return balance.free return balance.free
else: else:
@ -36,10 +39,10 @@ class Wallets(object):
def get_used(self, currency) -> float: def get_used(self, currency) -> float:
if self.exchange._conf['dry_run']: if self._config['dry_run']:
return 999.9 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: if balance and balance.used:
return balance.used return balance.used
else: else:
@ -47,25 +50,25 @@ class Wallets(object):
def get_total(self, currency) -> float: def get_total(self, currency) -> float:
if self.exchange._conf['dry_run']: if self._config['dry_run']:
return 999.9 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: if balance and balance.total:
return balance.total return balance.total
else: else:
return 0 return 0
def update(self) -> None: def update(self) -> None:
balances = self.exchange.get_balances()
balances = self._exchange.get_balances()
for currency in balances: for currency in balances:
self.wallets[currency] = Wallet( self._wallets[currency] = Wallet(
self.exchange.id,
currency, currency,
balances[currency].get('free', None), balances[currency].get('free', None),
balances[currency].get('used', None), balances[currency].get('used', None),
balances[currency].get('total', None) balances[currency].get('total', None)
) )
logger.info('Wallets synced ...') logger.info('Wallets synced.')