From 69dd56b237a8c964dddd42ec3eed70220830097d Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 18:47:13 +0100 Subject: [PATCH 01/25] wallet sync drafted --- freqtrade/freqtradebot.py | 16 +++++++++++++++- freqtrade/persistence.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index eb92375ec..428e5a726 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -18,7 +18,7 @@ from freqtrade import (DependencyException, OperationalException, TemporaryError, __version__, constants, persistence) from freqtrade.exchange import Exchange from freqtrade.edge import Edge -from freqtrade.persistence import Trade +from freqtrade.persistence import Trade, Wallet from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.state import State from freqtrade.strategy.interface import SellType @@ -800,3 +800,17 @@ class FreqtradeBot(object): # Send the message self.rpc.send_msg(msg) Trade.session.flush() + + def update_wallets(self) -> bool: + wallets = self.exchange.get_balances() + + for currency in wallets: + wallet = Wallet( + exchange=self.exchange._api.id, + currency=currency, + free=wallets[currency]['free'], + used=wallets[currency]['used'], + total=wallets[currency]['total'] + ) + Wallet.session.add(wallet) + Wallet.session.flush() diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 51a8129fb..ac7833d79 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -9,7 +9,7 @@ from typing import Any, Dict, Optional import arrow from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String, - create_engine, inspect) + create_engine, inspect, PrimaryKeyConstraint) from sqlalchemy.exc import NoSuchModuleError from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.scoping import scoped_session @@ -50,8 +50,13 @@ def init(config: Dict) -> None: f'is no valid database URL! (See {_SQL_DOCS_URL})') session = scoped_session(sessionmaker(bind=engine, autoflush=True, autocommit=True)) + Trade.session = session() Trade.query = session.query_property() + + Wallet.session = session() + Wallet.query = session.query_property() + _DECL_BASE.metadata.create_all(engine) check_migrate(engine) @@ -341,3 +346,26 @@ class Trade(_DECL_BASE): ) profit_percent = (close_trade_price / open_trade_price) - 1 return float(f"{profit_percent:.8f}") + + +class Wallet(_DECL_BASE): + """ + Class for wallet structure + It is a mirror of wallets on an exchange + """ + __tablename__ = 'wallets' + + exchange = Column(String, nullable=False, primary_key=True, index=True) + currency = Column(String, nullable=False, primary_key=True, index=True) + + free = Column(Float, index=True) + used = Column(Float) + total = Column(Float) + base = Column(Boolean, index=True, default=False) + quote = Column(Boolean, index=True, default=False) + + __table_args__ = ( + PrimaryKeyConstraint( + exchange, + currency), + {}) From 82cb0e4d95fdd663381977e9720797f96cb6bd31 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:16:32 +0100 Subject: [PATCH 02/25] =?UTF-8?q?putting=20wallets=20into=20a=20class=20(d?= =?UTF-8?q?oesn=E2=80=99t=20need=20to=20be=20in=20persistence)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/finance/wallets.py | 39 ++++++++++++++++++++++++++++++++++++ freqtrade/persistence.py | 23 --------------------- 2 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 freqtrade/finance/wallets.py diff --git a/freqtrade/finance/wallets.py b/freqtrade/finance/wallets.py new file mode 100644 index 000000000..c8d8bab2f --- /dev/null +++ b/freqtrade/finance/wallets.py @@ -0,0 +1,39 @@ +# pragma pylint: disable=W0603 +""" Wallet """ +import logging +from typing import Dict +from collections import namedtuple +from freqtrade.exchange import Exchange + +logger = logging.getLogger(__name__) + + +class Wallets(object): + + # wallet data structure + wallet = namedtuple( + 'wallet', + ['exchange', 'currency', 'free', 'used', 'total'] + ) + + def __init__(self, exchange: Exchange) -> None: + self.exchange = exchange + self.wallets: Dict[str, self.wallet] = {} + + def _update_wallets(self) -> None: + balances = self.exchange.get_balances() + + for currency in balances: + info = { + 'exchange': self.exchange.id, + 'currency': currency, + 'free': balances[currency['free']], + 'used': balances[currency['used']], + 'total': balances[currency['total']] + } + self.wallets[currency] = self.wallet(**info) + + logger.info('Wallets synced ...') + + def update(self) -> None: + self._update_wallets() diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index ac7833d79..82daa0b74 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -346,26 +346,3 @@ class Trade(_DECL_BASE): ) profit_percent = (close_trade_price / open_trade_price) - 1 return float(f"{profit_percent:.8f}") - - -class Wallet(_DECL_BASE): - """ - Class for wallet structure - It is a mirror of wallets on an exchange - """ - __tablename__ = 'wallets' - - exchange = Column(String, nullable=False, primary_key=True, index=True) - currency = Column(String, nullable=False, primary_key=True, index=True) - - free = Column(Float, index=True) - used = Column(Float) - total = Column(Float) - base = Column(Boolean, index=True, default=False) - quote = Column(Boolean, index=True, default=False) - - __table_args__ = ( - PrimaryKeyConstraint( - exchange, - currency), - {}) From afe52efc8ac1f05a0f9210252fa4937bb9b1f5eb Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:17:39 +0100 Subject: [PATCH 03/25] removing wallet from freq --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 428e5a726..570b925cc 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -18,7 +18,7 @@ from freqtrade import (DependencyException, OperationalException, TemporaryError, __version__, constants, persistence) from freqtrade.exchange import Exchange from freqtrade.edge import Edge -from freqtrade.persistence import Trade, Wallet +from freqtrade.persistence import Trade from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.state import State from freqtrade.strategy.interface import SellType From b815c8fe2dd37385708b9313cf689b9179449117 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:22:54 +0100 Subject: [PATCH 04/25] updating wallets whenever a trade happens --- freqtrade/freqtradebot.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 570b925cc..d9f17b999 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -17,6 +17,7 @@ from cachetools import TTLCache, cached from freqtrade import (DependencyException, OperationalException, TemporaryError, __version__, constants, persistence) from freqtrade.exchange import Exchange +from freqtrade.finance.wallets import Wallets from freqtrade.edge import Edge from freqtrade.persistence import Trade from freqtrade.rpc import RPCManager, RPCMessageType @@ -56,6 +57,7 @@ class FreqtradeBot(object): self.rpc: RPCManager = RPCManager(self) self.persistence = None self.exchange = Exchange(self.config) + self.wallets = Wallets(self.exchange) # Initializing Edge only if enabled self.edge = Edge(self.config, self.exchange, self.strategy) if \ @@ -505,6 +507,10 @@ class FreqtradeBot(object): ) Trade.session.add(trade) Trade.session.flush() + + # Updating wallets + self.wallets.update() + return True def process_maybe_execute_buy(self) -> bool: @@ -549,7 +555,11 @@ class FreqtradeBot(object): if trade.is_open and trade.open_order_id is None: # Check if we can sell our current pair - return self.handle_trade(trade) + result = self.handle_trade(trade) + if result: + self.wallets.update() + return result + except DependencyException as exception: logger.warning('Unable to sell trade: %s', exception) return False From 12f07ee126145b105623b0e7d28a711845bf5265 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:26:41 +0100 Subject: [PATCH 05/25] space removed --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d9f17b999..631f4d3b1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -555,7 +555,7 @@ class FreqtradeBot(object): if trade.is_open and trade.open_order_id is None: # Check if we can sell our current pair - result = self.handle_trade(trade) + result = self.handle_trade(trade) if result: self.wallets.update() return result From a0658bb50448b65c5997ea19c96c10a0d7aefe38 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:27:42 +0100 Subject: [PATCH 06/25] comments added --- freqtrade/freqtradebot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 631f4d3b1..568769fff 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -556,8 +556,11 @@ class FreqtradeBot(object): if trade.is_open and trade.open_order_id is None: # Check if we can sell our current pair result = self.handle_trade(trade) + + # Updating wallets if any trade occured if result: self.wallets.update() + return result except DependencyException as exception: From d5b47abe98af09f150176c904b87b51c2e7d1f25 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:31:06 +0100 Subject: [PATCH 07/25] Wallet table removed --- freqtrade/persistence.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 82daa0b74..2936819a6 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -54,9 +54,6 @@ def init(config: Dict) -> None: Trade.session = session() Trade.query = session.query_property() - Wallet.session = session() - Wallet.query = session.query_property() - _DECL_BASE.metadata.create_all(engine) check_migrate(engine) From f4bb203782eb54f8d8557edd2b3d27a020ddc9db Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 21:59:21 +0100 Subject: [PATCH 08/25] removing persistence update --- freqtrade/freqtradebot.py | 14 -------------- freqtrade/persistence.py | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 568769fff..0a75ce3d7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -813,17 +813,3 @@ class FreqtradeBot(object): # Send the message self.rpc.send_msg(msg) Trade.session.flush() - - def update_wallets(self) -> bool: - wallets = self.exchange.get_balances() - - for currency in wallets: - wallet = Wallet( - exchange=self.exchange._api.id, - currency=currency, - free=wallets[currency]['free'], - used=wallets[currency]['used'], - total=wallets[currency]['total'] - ) - Wallet.session.add(wallet) - Wallet.session.flush() diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 2936819a6..aa380d20b 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -9,7 +9,7 @@ from typing import Any, Dict, Optional import arrow from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String, - create_engine, inspect, PrimaryKeyConstraint) + create_engine, inspect) from sqlalchemy.exc import NoSuchModuleError from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.scoping import scoped_session From 606e41d5743594bc69a30e548de1046e3480a1ea Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 22:58:27 +0100 Subject: [PATCH 09/25] wallet tests added --- freqtrade/tests/finance/test_wallets.py | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 freqtrade/tests/finance/test_wallets.py diff --git a/freqtrade/tests/finance/test_wallets.py b/freqtrade/tests/finance/test_wallets.py new file mode 100644 index 000000000..e226d117f --- /dev/null +++ b/freqtrade/tests/finance/test_wallets.py @@ -0,0 +1,32 @@ +# pragma pylint: disable=missing-docstring +from freqtrade.tests.conftest import get_patched_freqtradebot +from unittest.mock import MagicMock + + +def test_sync_wallet_at_boot(mocker, default_conf): + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_balances=MagicMock(return_value={ + "BNT": { + "free": 1.0, + "used": 2.0, + "total": 3.0 + }, + "GAS": { + "free": 0.260739, + "used": 0.0, + "total": 0.260739 + }, + }) + ) + + 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 From 7cb8b28f5885dfeca3ba99723e377668f385bddf Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 17 Nov 2018 23:03:07 +0100 Subject: [PATCH 10/25] wallet sync added --- freqtrade/finance/wallets.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/freqtrade/finance/wallets.py b/freqtrade/finance/wallets.py index c8d8bab2f..7155f90ac 100644 --- a/freqtrade/finance/wallets.py +++ b/freqtrade/finance/wallets.py @@ -19,6 +19,7 @@ class Wallets(object): def __init__(self, exchange: Exchange) -> None: self.exchange = exchange self.wallets: Dict[str, self.wallet] = {} + self._update_wallets() def _update_wallets(self) -> None: balances = self.exchange.get_balances() @@ -27,10 +28,11 @@ class Wallets(object): info = { 'exchange': self.exchange.id, 'currency': currency, - 'free': balances[currency['free']], - 'used': balances[currency['used']], - 'total': balances[currency['total']] + 'free': balances[currency]['free'], + 'used': balances[currency]['used'], + 'total': balances[currency]['total'] } + self.wallets[currency] = self.wallet(**info) logger.info('Wallets synced ...') From a92619f18ca9d56361960d68c213098ada3e23a9 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 18 Nov 2018 14:34:31 +0100 Subject: [PATCH 11/25] Added empty lines related to last commit removed --- freqtrade/persistence.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index aa380d20b..51a8129fb 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -50,10 +50,8 @@ def init(config: Dict) -> None: f'is no valid database URL! (See {_SQL_DOCS_URL})') session = scoped_session(sessionmaker(bind=engine, autoflush=True, autocommit=True)) - Trade.session = session() Trade.query = session.query_property() - _DECL_BASE.metadata.create_all(engine) check_migrate(engine) From 608ce98e1a5c67ce4bd0556cfdccf4d0375c6096 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 18 Nov 2018 14:38:31 +0100 Subject: [PATCH 12/25] moving wallets to root --- freqtrade/freqtradebot.py | 2 +- freqtrade/{finance => }/wallets.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename freqtrade/{finance => }/wallets.py (100%) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0a75ce3d7..83b5b85e5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -17,7 +17,7 @@ from cachetools import TTLCache, cached from freqtrade import (DependencyException, OperationalException, TemporaryError, __version__, constants, persistence) from freqtrade.exchange import Exchange -from freqtrade.finance.wallets import Wallets +from freqtrade.wallets import Wallets from freqtrade.edge import Edge from freqtrade.persistence import Trade from freqtrade.rpc import RPCManager, RPCMessageType diff --git a/freqtrade/finance/wallets.py b/freqtrade/wallets.py similarity index 100% rename from freqtrade/finance/wallets.py rename to freqtrade/wallets.py From 9c549f451390822e22c6b4e141aa239234c9b85d Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 18 Nov 2018 14:39:31 +0100 Subject: [PATCH 13/25] removing unnecessary private function --- freqtrade/wallets.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 7155f90ac..fc2769831 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -19,9 +19,9 @@ class Wallets(object): def __init__(self, exchange: Exchange) -> None: self.exchange = exchange self.wallets: Dict[str, self.wallet] = {} - self._update_wallets() + self.update() - def _update_wallets(self) -> None: + def update(self) -> None: balances = self.exchange.get_balances() for currency in balances: @@ -36,6 +36,3 @@ class Wallets(object): self.wallets[currency] = self.wallet(**info) logger.info('Wallets synced ...') - - def update(self) -> None: - self._update_wallets() From c03337804808914afed09bcaafdd0e50d0cba135 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 18 Nov 2018 14:57:03 +0100 Subject: [PATCH 14/25] change dict type to Any --- freqtrade/wallets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index fc2769831..b4b89bc59 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -1,7 +1,7 @@ # pragma pylint: disable=W0603 """ Wallet """ import logging -from typing import Dict +from typing import Dict, Any from collections import namedtuple from freqtrade.exchange import Exchange @@ -18,7 +18,7 @@ class Wallets(object): def __init__(self, exchange: Exchange) -> None: self.exchange = exchange - self.wallets: Dict[str, self.wallet] = {} + self.wallets: Dict[str, Any] = {} self.update() def update(self) -> None: From b680681b34e25d0641d2c65ca959c395403b9d2f Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 19 Nov 2018 11:16:07 +0100 Subject: [PATCH 15/25] updating wallet at handle timeout functions too --- freqtrade/freqtradebot.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 83b5b85e5..570a806be 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -340,7 +340,9 @@ class FreqtradeBot(object): else: stake_amount = self.config['stake_amount'] + # TODO: should come from the wallet avaliable_amount = self.exchange.get_balance(self.config['stake_currency']) + #avaliable_amount = self.wallets.wallets[self.config['stake_currency']].free if stake_amount == constants.UNLIMITED_STAKE_AMOUNT: open_trades = len(Trade.query.filter(Trade.is_open.is_(True)).all()) @@ -707,8 +709,10 @@ class FreqtradeBot(object): if order['status'] == 'open': if order['side'] == 'buy' and ordertime < buy_timeoutthreashold: self.handle_timedout_limit_buy(trade, order) + self.wallets.update() elif order['side'] == 'sell' and ordertime < sell_timeoutthreashold: self.handle_timedout_limit_sell(trade, order) + self.wallets.update() # FIX: 20180110, why is cancel.order unconditionally here, whereas # it is conditionally called in the From 003480ad9031012f99a56c0d03af6b4a5415549a Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 19 Nov 2018 13:01:17 +0100 Subject: [PATCH 16/25] flake indentation --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 570a806be..2a2a05c84 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -342,7 +342,7 @@ class FreqtradeBot(object): # TODO: should come from the wallet avaliable_amount = self.exchange.get_balance(self.config['stake_currency']) - #avaliable_amount = self.wallets.wallets[self.config['stake_currency']].free + # avaliable_amount = self.wallets.wallets[self.config['stake_currency']].free if stake_amount == constants.UNLIMITED_STAKE_AMOUNT: open_trades = len(Trade.query.filter(Trade.is_open.is_(True)).all()) From 68f81aa2afb61509bca05a80da16d2d9ee1d5387 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 17:27:45 +0100 Subject: [PATCH 17/25] test wallets moved to tests folder --- freqtrade/tests/{finance => }/test_wallets.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename freqtrade/tests/{finance => }/test_wallets.py (100%) diff --git a/freqtrade/tests/finance/test_wallets.py b/freqtrade/tests/test_wallets.py similarity index 100% rename from freqtrade/tests/finance/test_wallets.py rename to freqtrade/tests/test_wallets.py From 5b689402130d2a45ccdc8a65bbac669b5e247bdb Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 17:48:53 +0100 Subject: [PATCH 18/25] update wallet in casse order remaining is zero --- freqtrade/freqtradebot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2a2a05c84..7d6fdd261 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -703,6 +703,7 @@ class FreqtradeBot(object): # Check if trade is still actually open if int(order['remaining']) == 0: + self.wallets.update() continue # Check if trade is still actually open From aeb372c2f04ac992e5d6c82dca34ddb770100424 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 17:54:14 +0100 Subject: [PATCH 19/25] test wallet when api return changes --- freqtrade/tests/test_wallets.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_wallets.py b/freqtrade/tests/test_wallets.py index e226d117f..a5295579b 100644 --- a/freqtrade/tests/test_wallets.py +++ b/freqtrade/tests/test_wallets.py @@ -26,7 +26,32 @@ def test_sync_wallet_at_boot(mocker, default_conf): 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 + + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_balances=MagicMock(return_value={ + "BNT": { + "free": 1.2, + "used": 1.9, + "total": 3.5 + }, + "GAS": { + "free": 0.270739, + "used": 0.1, + "total": 0.260439 + }, + }) + ) + + 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 From cb3cf960d734373618f878bde2632317a366dd25 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 19:47:28 +0100 Subject: [PATCH 20/25] tests added in case of missing data --- freqtrade/tests/test_wallets.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/freqtrade/tests/test_wallets.py b/freqtrade/tests/test_wallets.py index a5295579b..cc10d665c 100644 --- a/freqtrade/tests/test_wallets.py +++ b/freqtrade/tests/test_wallets.py @@ -55,3 +55,30 @@ def test_sync_wallet_at_boot(mocker, default_conf): assert freqtrade.wallets.wallets['GAS'].free == 0.270739 assert freqtrade.wallets.wallets['GAS'].used == 0.1 assert freqtrade.wallets.wallets['GAS'].total == 0.260439 + + +def test_sync_wallet_missing_data(mocker, default_conf): + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_balances=MagicMock(return_value={ + "BNT": { + "free": 1.0, + "used": 2.0, + "total": 3.0 + }, + "GAS": { + "free": 0.260739, + "total": 0.260739 + }, + }) + ) + + 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 From 88f61581d924138b0926a5459a634459c517cf68 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 19:47:51 +0100 Subject: [PATCH 21/25] 1) NamedTuple refactored 2) Missing data handled --- freqtrade/wallets.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index b4b89bc59..5ee33f41e 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -1,13 +1,21 @@ # pragma pylint: disable=W0603 """ Wallet """ import logging -from typing import Dict, Any +from typing import Dict, Any, NamedTuple from collections import namedtuple from freqtrade.exchange import Exchange logger = logging.getLogger(__name__) +class Wallet(NamedTuple): + exchange: str = None + currency: str = None + free: float = 0 + used: float = 0 + total: float = 0 + + class Wallets(object): # wallet data structure @@ -25,14 +33,12 @@ class Wallets(object): balances = self.exchange.get_balances() for currency in balances: - info = { - 'exchange': self.exchange.id, - 'currency': currency, - 'free': balances[currency]['free'], - 'used': balances[currency]['used'], - 'total': balances[currency]['total'] - } - - self.wallets[currency] = self.wallet(**info) + self.wallets[currency] = Wallet( + self.exchange.id, + currency, + balances[currency].get('free', None), + balances[currency].get('used', None), + balances[currency].get('total', None) + ) logger.info('Wallets synced ...') From b129750f4dbff4daca892b6ebefdf1648637caff Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 19:58:28 +0100 Subject: [PATCH 22/25] =?UTF-8?q?adding=20=E2=80=9Coptional=E2=80=9D=20in?= =?UTF-8?q?=20str?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/wallets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 5ee33f41e..531e83a28 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -1,7 +1,7 @@ # pragma pylint: disable=W0603 """ Wallet """ import logging -from typing import Dict, Any, NamedTuple +from typing import Dict, Any, NamedTuple, Optional from collections import namedtuple from freqtrade.exchange import Exchange @@ -9,8 +9,8 @@ logger = logging.getLogger(__name__) class Wallet(NamedTuple): - exchange: str = None - currency: str = None + exchange: Optional[str] = None + currency: Optional[str] = None free: float = 0 used: float = 0 total: float = 0 From 4d75e9059c0f3c10a8c910bea83ff74292ea7367 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 21:05:20 +0100 Subject: [PATCH 23/25] None ripped off for optional as wallet must have exchange and currency --- freqtrade/wallets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 531e83a28..3b4152b8d 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -9,8 +9,8 @@ logger = logging.getLogger(__name__) class Wallet(NamedTuple): - exchange: Optional[str] = None - currency: Optional[str] = None + exchange: Optional[str] + currency: Optional[str] free: float = 0 used: float = 0 total: float = 0 From 3a2134db24d21285cafa8b65c6257cc0e380b928 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 23:35:44 +0100 Subject: [PATCH 24/25] removed Optional --- freqtrade/wallets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 3b4152b8d..65a5e880f 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -9,8 +9,8 @@ logger = logging.getLogger(__name__) class Wallet(NamedTuple): - exchange: Optional[str] - currency: Optional[str] + exchange: str + currency: str free: float = 0 used: float = 0 total: float = 0 From 4b86b2b7e3fa89e16d5a40625f9af12cf488151c Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 21 Nov 2018 23:36:48 +0100 Subject: [PATCH 25/25] Happy flake8 ! --- freqtrade/wallets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 65a5e880f..82f527d2c 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -1,7 +1,7 @@ # pragma pylint: disable=W0603 """ Wallet """ import logging -from typing import Dict, Any, NamedTuple, Optional +from typing import Dict, Any, NamedTuple from collections import namedtuple from freqtrade.exchange import Exchange