diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 0582e7d08..02062acc4 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -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', diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 33f62f2f7..ab9e29722 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -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] = {} @@ -239,7 +239,7 @@ class Exchange(object): logger.warning('Unable to validate pairs (assuming they are correct).') # return - stake_cur = self._conf['stake_currency'] + stake_cur = self._config['stake_currency'] for pair in pairs: # Note: ccxt has BaseCurrency/QuoteCurrency format for pairs # 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, 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 @@ -387,7 +387,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 @@ -412,7 +412,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 @@ -427,8 +427,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() @@ -440,7 +440,7 @@ class Exchange(object): @retrier def get_balances(self) -> dict: - if self._conf['dry_run']: + if self._config['dry_run']: return {} try: @@ -611,7 +611,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: @@ -627,7 +627,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: @@ -664,7 +664,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 [] diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 5c0d69e91..6f1fb2c99 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -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 diff --git a/freqtrade/tests/test_wallets.py b/freqtrade/tests/test_wallets.py index 8d9adc74c..2c493cfc3 100644 --- a/freqtrade/tests/test_wallets.py +++ b/freqtrade/tests/test_wallets.py @@ -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 diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 1f1d2c511..c8ab90276 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -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.')