From 6d2afdb1466eb097968280928b0e05dccf8784d1 Mon Sep 17 00:00:00 2001 From: Gert Wohlgemuth Date: Thu, 3 May 2018 02:18:35 -0700 Subject: [PATCH 01/48] added support for showing the exposed real value on the count table (#634) --- freqtrade/rpc/telegram.py | 5 +++-- freqtrade/tests/rpc/test_rpc_telegram.py | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 81749d778..086c408ac 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -357,8 +357,9 @@ class Telegram(RPC): message = tabulate({ 'current': [len(trades)], - 'max': [self._config['max_open_trades']] - }, headers=['current', 'max'], tablefmt='simple') + 'max': [self._config['max_open_trades']], + 'total stake': [sum((trade.open_rate * trade.amount) for trade in trades)] + }, headers=['current', 'max', 'total stake'], tablefmt='simple') message = "
{}
".format(message) logger.debug(message) self.send_msg(message, parse_mode=ParseMode.HTML) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 86dfd6f41..72408c908 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1001,9 +1001,12 @@ def test_count_handle(default_conf, update, ticker, mocker) -> None: msg_mock.reset_mock() telegram._count(bot=MagicMock(), update=update) - msg = '
  current    max\n---------  -----\n        1      {}
'.format( - default_conf['max_open_trades'] - ) + msg = '
  current    max    total stake\n---------  -----  -------------\n' \
+          '        1      {}          {}
'\ + .format( + default_conf['max_open_trades'], + default_conf['stake_amount'] + ) assert msg in msg_mock.call_args_list[0][0][0] From 3d4019d8b7c963d9da30e7327918794b21a6396a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 5 May 2018 00:14:03 +0200 Subject: [PATCH 02/48] Update python-telegram-bot from 10.0.2 to 10.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7093d783e..492be0362 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ python-bittrex==0.3.0 SQLAlchemy==1.2.7 -python-telegram-bot==10.0.2 +python-telegram-bot==10.1.0 arrow==0.12.1 cachetools==2.0.1 requests==2.18.4 From d3fb2e4516e245ac8feff0b959470449e58f0eaa Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Wed, 25 Apr 2018 20:16:36 +0200 Subject: [PATCH 03/48] Add open_rate_requested and close_rate_requested for slippage detection --- freqtrade/freqtradebot.py | 2 ++ freqtrade/persistence.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0a332b952..56ace2ae2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -330,6 +330,7 @@ class FreqtradeBot(object): fee_open=fee, fee_close=fee, open_rate=buy_limit, + open_rate_requested=buy_limit, open_date=datetime.utcnow(), exchange=exchange.get_id(), open_order_id=order_id @@ -538,6 +539,7 @@ class FreqtradeBot(object): # Execute sell and update trade record order_id = exchange.sell(str(trade.pair), limit, trade.amount)['id'] trade.open_order_id = order_id + trade.close_rate_requested = limit fmt_exp_profit = round(trade.calc_profit_percent(rate=limit) * 100, 2) profit_trade = trade.calc_profit(rate=limit) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index ed81ad2ec..1da551c7d 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -88,7 +88,9 @@ class Trade(_DECL_BASE): fee_open = Column(Float, nullable=False, default=0.0) fee_close = Column(Float, nullable=False, default=0.0) open_rate = Column(Float) + open_rate_requested = Column(Float) close_rate = Column(Float) + close_rate_requested = Column(Float) close_profit = Column(Float) stake_amount = Column(Float, nullable=False) amount = Column(Float) From 490cbde6520e32d3c8a9d5747a061040570e077a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 5 May 2018 21:31:05 +0200 Subject: [PATCH 04/48] Update scipy from 1.0.1 to 1.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 492be0362..8d9ba34fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ urllib3==1.22 wrapt==1.10.11 pandas==0.22.0 scikit-learn==0.19.1 -scipy==1.0.1 +scipy==1.1.0 jsonschema==2.6.0 numpy==1.14.3 TA-Lib==0.4.17 From ccf1c894b459b03a9b7a6272b9c0079afd57df0c Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 6 May 2018 09:09:53 +0200 Subject: [PATCH 05/48] Inital try mirate --- freqtrade/persistence.py | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 1da551c7d..68ec923ea 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -15,6 +15,8 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.scoping import scoped_session from sqlalchemy.orm.session import sessionmaker from sqlalchemy.pool import StaticPool +from sqlalchemy import inspect + logger = logging.getLogger(__name__) @@ -50,12 +52,58 @@ def init(config: dict, engine: Optional[Engine] = None) -> None: Trade.session = session() Trade.query = session.query_property() _DECL_BASE.metadata.create_all(engine) + check_migrate(engine) # Clean dry_run DB if _CONF.get('dry_run', False) and _CONF.get('dry_run_db', False): clean_dry_run_db() +def has_column(columns, searchname: str) -> bool: + return len(list(filter(lambda x: x["name"] == searchname, columns))) == 1 + + +def check_migrate(engine) -> None: + """ + Checks if migration is necessary and migrates if necessary + """ + inspector = inspect(engine) + + cols = inspector.get_columns('trades') + + if not has_column(cols, 'fee_open'): + # Schema migration necessary + engine.execute("create table trades_bak as select * from trades;") + + # let SQLAlchemy create the schema as required + _DECL_BASE.metadata.create_all(engine) + + # Copy data back - following the correct schema + engine.execute("""insert into trades + (id, exchange, pair, is_open, fee_open, fee_close, open_rate, + open_rate_requested, close_rate, close_rate_requested, close_profit, + stake_amount, amount, open_date, close_date, open_order_id) + select id, exchange, pair, is_open, fee fee_open, fee fee_close, + open_rate, null open_rate_requested, close_rate, + null close_rate_requested, close_profit, + stake_amount, amount, open_date, close_date, open_order_id + from trades_bak + """) + + # engine.execute("alter table trades add fee_open float not null") + # engine.execute("alter table trades add fee_close float not null") + # # Update fee_open and fee_close with "fee" column values + # engine.execute("update trades set fee_open = fee, fee_close = fee where fee_open is null") + # engine.execute("alter table trades drop fee_close float not null") + + if not has_column(cols, 'open_rate_requested'): + engine.execute("alter table trades add open_rate_requested float") + if not has_column(cols, 'close_rate_requested'): + engine.execute("alter table trades add close_rate_requested float") + + + + def cleanup() -> None: """ Flushes all pending operations to disk. From 394ef35a45f80df82bdafb6146a80520a00dcbdb Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 6 May 2018 20:23:20 +0200 Subject: [PATCH 06/48] Add unnecessary files to .dockerignore these files are not needed to run the bot - therefore should not be added to the docker container --- .dockerignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.dockerignore b/.dockerignore index 9f4726bfb..223b3b110 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,12 @@ Dockerfile .dockerignore config.json* *.sqlite +.coveragerc +.eggs +.github +.pylintrc +.travis.yml +CONTRIBUTING.md +MANIFEST.in +README.md +freqtrade.service From 6b008d223752a4bfcc77b529c7b45433facc0424 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 8 May 2018 15:41:10 +0200 Subject: [PATCH 07/48] Update coinmarketcap from 4.2.1 to 5.0.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8d9ba34fc..fbd179558 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ hyperopt==0.1 # do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325 networkx==1.11 tabulate==0.8.2 -coinmarketcap==4.2.1 +coinmarketcap==5.0.1 # Required for plotting data #plotly==2.3.0 From 7552c912a2206ba557f121f841e20c94455e4f8e Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Wed, 9 May 2018 09:15:09 +0300 Subject: [PATCH 08/48] config.json.example: add ticker_interval --- config.json.example | 1 + 1 file changed, 1 insertion(+) diff --git a/config.json.example b/config.json.example index 6a4f20cd6..d3dbeb52e 100644 --- a/config.json.example +++ b/config.json.example @@ -3,6 +3,7 @@ "stake_currency": "BTC", "stake_amount": 0.05, "fiat_display_currency": "USD", + "ticker_interval" : "5m", "dry_run": false, "unfilledtimeout": 600, "bid_strategy": { From b55822ad30b2384fe039fec3b197fd0b932fcc9c Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Wed, 9 May 2018 09:22:01 +0300 Subject: [PATCH 09/48] telegram: document proxy usage without code changes per gcarq's comment in #609 --- docs/telegram-usage.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index e041fa2ff..20e80269b 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -129,12 +129,8 @@ Day Profit BTC Profit USD > **Version:** `0.14.3` ### using proxy with telegram -in [freqtrade/freqtrade/rpc/telegram.py](https://github.com/gcarq/freqtrade/blob/develop/freqtrade/rpc/telegram.py) replace ``` -self._updater = Updater(token=self._config['telegram']['token'], workers=0) -``` - -with -``` -self._updater = Updater(token=self._config['telegram']['token'], request_kwargs={'proxy_url': 'socks5://127.0.0.1:1080/'}, workers=0) +$ export HTTP_PROXY="http://addr:port" +$ export HTTPS_PROXY="http://addr:port" +$ freqtrade ``` From 01b6a0eb53dc83b90c338fcac670e36f9776e499 Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Sat, 12 May 2018 09:57:10 +0300 Subject: [PATCH 10/48] Freqtrade: ccxt release shall be called 0.17.0 --- freqtrade/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index c630d06b2..37187a404 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,5 +1,5 @@ """ FreqTrade bot """ -__version__ = '0.16.0' +__version__ = '0.17.0' class DependencyException(BaseException): From ab4e2bd5a9b4dd2c377b154b502d6ddb54033024 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:04:41 +0200 Subject: [PATCH 11/48] Fix migrate script --- freqtrade/persistence.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 68ec923ea..7170ab4ff 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -73,8 +73,9 @@ def check_migrate(engine) -> None: if not has_column(cols, 'fee_open'): # Schema migration necessary - engine.execute("create table trades_bak as select * from trades;") - + engine.execute("drop table if exists trades_bak") + engine.execute("create table trades_bak as select * from trades") + engine.execute("drop table if exists trades") # let SQLAlchemy create the schema as required _DECL_BASE.metadata.create_all(engine) @@ -90,11 +91,9 @@ def check_migrate(engine) -> None: from trades_bak """) - # engine.execute("alter table trades add fee_open float not null") - # engine.execute("alter table trades add fee_close float not null") - # # Update fee_open and fee_close with "fee" column values - # engine.execute("update trades set fee_open = fee, fee_close = fee where fee_open is null") - # engine.execute("alter table trades drop fee_close float not null") + # Reread columns - the above recreated the table! + inspector = inspect(engine) + cols = inspector.get_columns('trades') if not has_column(cols, 'open_rate_requested'): engine.execute("alter table trades add open_rate_requested float") @@ -102,8 +101,6 @@ def check_migrate(engine) -> None: engine.execute("alter table trades add close_rate_requested float") - - def cleanup() -> None: """ Flushes all pending operations to disk. From 81ee6f82658ac5116ce4488174f5e283dbc89bd5 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:19:52 +0200 Subject: [PATCH 12/48] Update sql docs to new schema --- docs/sql_cheatsheet.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 065f264f1..141eaeafe 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -32,9 +32,12 @@ CREATE TABLE trades ( exchange VARCHAR NOT NULL, pair VARCHAR NOT NULL, is_open BOOLEAN NOT NULL, - fee FLOAT NOT NULL, + fee_open FLOAT NOT NULL, + fee_close FLOAT NOT NULL, open_rate FLOAT, + open_rate_requested FLOAT, close_rate FLOAT, + close_rate_requested FLOAT, close_profit FLOAT, stake_amount FLOAT NOT NULL, amount FLOAT, @@ -71,13 +74,13 @@ WHERE id=31; ```sql INSERT -INTO trades (exchange, pair, is_open, fee, open_rate, stake_amount, amount, open_date) -VALUES ('BITTREX', 'BTC_', 1, 0.0025, , , , '') +INTO trades (exchange, pair, is_open, fee_open, fee_close, open_rate, stake_amount, amount, open_date) +VALUES ('BITTREX', 'BTC_', 1, 0.0025, 0.0025, , , , '') ``` **Example:** ```sql -INSERT INTO trades (exchange, pair, is_open, fee, open_rate, stake_amount, amount, open_date) VALUES ('BITTREX', 'BTC_ETC', 1, 0.0025, 0.00258580, 0.002, 0.7715262081, '2017-11-28 12:44:24.000000') +INSERT INTO trades (exchange, pair, is_open, fee_open, fee_close, open_rate, stake_amount, amount, open_date) VALUES ('BITTREX', 'BTC_ETC', 1, 0.0025, 0.0025, 0.00258580, 0.002, 0.7715262081, '2017-11-28 12:44:24.000000') ``` ## Fix wrong fees in the table @@ -87,4 +90,4 @@ If your DB was created before ```sql UPDATE trades SET fee=0.0025 WHERE fee=0.005; -``` \ No newline at end of file +``` From f5ff6ceead76c07779e27126caf76621c12e1a11 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:29:10 +0200 Subject: [PATCH 13/48] Rename instead of drop/create --- freqtrade/persistence.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 7170ab4ff..c6a185188 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -73,9 +73,7 @@ def check_migrate(engine) -> None: if not has_column(cols, 'fee_open'): # Schema migration necessary - engine.execute("drop table if exists trades_bak") - engine.execute("create table trades_bak as select * from trades") - engine.execute("drop table if exists trades") + engine.execute("alter table trades rename to trades_bak") # let SQLAlchemy create the schema as required _DECL_BASE.metadata.create_all(engine) From 49266fc4b8a9478700ec7040d7fb153035951fdc Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:29:26 +0200 Subject: [PATCH 14/48] Add migration test --- freqtrade/tests/test_persistence.py | 39 ++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index db8a5e9bd..8c3ffeb6a 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -4,7 +4,7 @@ import os import pytest from sqlalchemy import create_engine -from freqtrade.persistence import Trade, init, clean_dry_run_db +from freqtrade.persistence import Trade, init, clean_dry_run_db, check_migrate @pytest.fixture(scope='function') @@ -375,3 +375,40 @@ def test_clean_dry_run_db(default_conf, fee): # We have now only the prod assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1 + + +def test_migrate(default_conf, fee): + create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( + id INTEGER NOT NULL, + exchange VARCHAR NOT NULL, + pair VARCHAR NOT NULL, + is_open BOOLEAN NOT NULL, + fee FLOAT NOT NULL, + open_rate FLOAT, + close_rate FLOAT, + close_profit FLOAT, + stake_amount FLOAT NOT NULL, + amount FLOAT, + open_date DATETIME NOT NULL, + close_date DATETIME, + open_order_id VARCHAR, + PRIMARY KEY (id), + CHECK (is_open IN (0, 1)) + );""" + insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee, + open_rate, stake_amount, amount, open_date) + VALUES ('BITTREX', 'BTC_ETC', 1, {}, + 0.00258580, 0.002, 0.7715262081, + '2017-11-28 12:44:24.000000')""".format(fee.return_value) + engine = create_engine('sqlite://') + engine.execute(create_table_old) + engine.execute(insert_table_old) + init(default_conf, engine) + assert len(Trade.query.filter(Trade.id == 1).all()) == 1 + trade = Trade.query.filter(Trade.id == 1).first() + assert trade.fee_open == fee.return_value + assert trade.fee_close == fee.return_value + assert trade.open_rate_requested is None + assert trade.close_rate_requested is None + + From ada98abfee3f674a21d62344b25d077886f6fa26 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:30:30 +0200 Subject: [PATCH 15/48] fix flake --- freqtrade/tests/test_persistence.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 8c3ffeb6a..26c2e385a 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -4,7 +4,7 @@ import os import pytest from sqlalchemy import create_engine -from freqtrade.persistence import Trade, init, clean_dry_run_db, check_migrate +from freqtrade.persistence import Trade, init, clean_dry_run_db @pytest.fixture(scope='function') @@ -410,5 +410,3 @@ def test_migrate(default_conf, fee): assert trade.fee_close == fee.return_value assert trade.open_rate_requested is None assert trade.close_rate_requested is None - - From 8e3ff8235fb673171dc20061648146de0ecb08ac Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:31:24 +0200 Subject: [PATCH 16/48] add explaining comments --- freqtrade/tests/test_persistence.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 26c2e385a..90cf7dad5 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -401,9 +401,12 @@ def test_migrate(default_conf, fee): 0.00258580, 0.002, 0.7715262081, '2017-11-28 12:44:24.000000')""".format(fee.return_value) engine = create_engine('sqlite://') + # Create table using the old format engine.execute(create_table_old) engine.execute(insert_table_old) + # Run init to test migration init(default_conf, engine) + assert len(Trade.query.filter(Trade.id == 1).all()) == 1 trade = Trade.query.filter(Trade.id == 1).first() assert trade.fee_open == fee.return_value From 631081a2b2b7e2234bd6e0bb90ab4ced78ace31e Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 10:37:17 +0200 Subject: [PATCH 17/48] Add additional tests --- freqtrade/tests/test_persistence.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 90cf7dad5..27a09fa5a 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -378,6 +378,7 @@ def test_clean_dry_run_db(default_conf, fee): def test_migrate(default_conf, fee): + amount = 103.223 create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( id INTEGER NOT NULL, exchange VARCHAR NOT NULL, @@ -397,9 +398,13 @@ def test_migrate(default_conf, fee): );""" insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee, open_rate, stake_amount, amount, open_date) - VALUES ('BITTREX', 'BTC_ETC', 1, {}, - 0.00258580, 0.002, 0.7715262081, - '2017-11-28 12:44:24.000000')""".format(fee.return_value) + VALUES ('BITTREX', 'BTC_ETC', 1, {fee}, + 0.00258580, {stake}, {amount}, + '2017-11-28 12:44:24.000000') + """.format(fee=fee.return_value, + stake=default_conf.get("stake_amount"), + amount=amount + ) engine = create_engine('sqlite://') # Create table using the old format engine.execute(create_table_old) @@ -413,3 +418,6 @@ def test_migrate(default_conf, fee): assert trade.fee_close == fee.return_value assert trade.open_rate_requested is None assert trade.close_rate_requested is None + assert trade.is_open == 1 + assert trade.amount == amount + assert trade.stake_amount == default_conf.get("stake_amount") From 40c581e5a8426aeba04c7a91bfdff8f6f7841e6c Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 13:37:42 +0200 Subject: [PATCH 18/48] Convert pair-format to new format --- freqtrade/persistence.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index c6a185188..6c89fd737 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -82,7 +82,15 @@ def check_migrate(engine) -> None: (id, exchange, pair, is_open, fee_open, fee_close, open_rate, open_rate_requested, close_rate, close_rate_requested, close_profit, stake_amount, amount, open_date, close_date, open_order_id) - select id, exchange, pair, is_open, fee fee_open, fee fee_close, + select id, exchange, + case + when instr(pair, '_') != 0 then + substr(pair, instr(pair, '_') + 1) || '/' || + substr(pair, 1, instr(pair, '_') - 1) + else pair + end + pair, + is_open, fee fee_open, fee fee_close, open_rate, null open_rate_requested, close_rate, null close_rate_requested, close_profit, stake_amount, amount, open_date, close_date, open_order_id From e3ae1c6c2f974fc90793fc961b729a8a395d4ff7 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 13:39:16 +0200 Subject: [PATCH 19/48] Convert exchange-name to new format --- freqtrade/persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 6c89fd737..2d497662e 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -82,7 +82,7 @@ def check_migrate(engine) -> None: (id, exchange, pair, is_open, fee_open, fee_close, open_rate, open_rate_requested, close_rate, close_rate_requested, close_profit, stake_amount, amount, open_date, close_date, open_order_id) - select id, exchange, + select id, lower(exchange), case when instr(pair, '_') != 0 then substr(pair, instr(pair, '_') + 1) || '/' || From 58425993daa73558bc13abccf76a6d9458d6e79a Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 13:39:29 +0200 Subject: [PATCH 20/48] Adapt tests to verify pair-conversion and exchange conversion --- freqtrade/tests/test_persistence.py | 58 ++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 27a09fa5a..3e0f50fbb 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -377,7 +377,10 @@ def test_clean_dry_run_db(default_conf, fee): assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1 -def test_migrate(default_conf, fee): +def test_migrate_old(default_conf, fee): + """ + Test Database migration(starting with old pairformat) + """ amount = 103.223 create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( id INTEGER NOT NULL, @@ -421,3 +424,56 @@ def test_migrate(default_conf, fee): assert trade.is_open == 1 assert trade.amount == amount assert trade.stake_amount == default_conf.get("stake_amount") + assert trade.pair == "ETC/BTC" + assert trade.exchange == "bittrex" + + +def test_migrate_new(default_conf, fee): + """ + Test Database migration (starting with new pairformat) + """ + amount = 103.223 + create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( + id INTEGER NOT NULL, + exchange VARCHAR NOT NULL, + pair VARCHAR NOT NULL, + is_open BOOLEAN NOT NULL, + fee FLOAT NOT NULL, + open_rate FLOAT, + close_rate FLOAT, + close_profit FLOAT, + stake_amount FLOAT NOT NULL, + amount FLOAT, + open_date DATETIME NOT NULL, + close_date DATETIME, + open_order_id VARCHAR, + PRIMARY KEY (id), + CHECK (is_open IN (0, 1)) + );""" + insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee, + open_rate, stake_amount, amount, open_date) + VALUES ('binance', 'ETC/BTC', 1, {fee}, + 0.00258580, {stake}, {amount}, + '2019-11-28 12:44:24.000000') + """.format(fee=fee.return_value, + stake=default_conf.get("stake_amount"), + amount=amount + ) + engine = create_engine('sqlite://') + # Create table using the old format + engine.execute(create_table_old) + engine.execute(insert_table_old) + # Run init to test migration + init(default_conf, engine) + + assert len(Trade.query.filter(Trade.id == 1).all()) == 1 + trade = Trade.query.filter(Trade.id == 1).first() + assert trade.fee_open == fee.return_value + assert trade.fee_close == fee.return_value + assert trade.open_rate_requested is None + assert trade.close_rate_requested is None + assert trade.is_open == 1 + assert trade.amount == amount + assert trade.stake_amount == default_conf.get("stake_amount") + assert trade.pair == "ETC/BTC" + assert trade.exchange == "binance" From 189873f9d4d14017b1cd771d1a8a5b44828aea8d Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 12 May 2018 14:04:16 +0200 Subject: [PATCH 21/48] Update ccxt from 1.11.149 to 1.13.133 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c37a81b47..4a06a96ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.11.149 +ccxt==1.13.133 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From bc25007fef41b6d017e6b7c4df08361bb86246a3 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 12 May 2018 18:45:18 +0200 Subject: [PATCH 22/48] Update cachetools from 2.0.1 to 2.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4a06a96ef..deb0c9c5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ ccxt==1.13.133 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 -cachetools==2.0.1 +cachetools==2.1.0 requests==2.18.4 urllib3==1.22 wrapt==1.10.11 From 8b098859f4f5b2a0b528cf63b1cbff118cc5323e Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sat, 12 May 2018 20:15:59 +0200 Subject: [PATCH 23/48] Reduce verbosity of get_ticker_history --- freqtrade/exchange/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 54b88c79c..109e3f7b2 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -297,9 +297,10 @@ def get_ticker_history(pair: str, tick_interval: str, since_ms: Optional[int] = if not data_part: break - logger.info('Downloaded data for time range [%s, %s]', - arrow.get(data_part[0][0] / 1000).format(), - arrow.get(data_part[-1][0] / 1000).format()) + logger.debug('Downloaded data for %s time range [%s, %s]', + pair, + arrow.get(data_part[0][0] / 1000).format(), + arrow.get(data_part[-1][0] / 1000).format()) data.extend(data_part) since_ms = data[-1][0] + 1 From d51ac94662394456cc992c2b53a1e4291c6437c9 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 13 May 2018 05:41:24 +0200 Subject: [PATCH 24/48] Update ccxt from 1.13.133 to 1.13.136 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index deb0c9c5f..90426ffd1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.133 +ccxt==1.13.136 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From 8f17b11610467287a22c24430eee67becf390430 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 13:38:29 +0200 Subject: [PATCH 25/48] Fix testfluke in hyperopt --- freqtrade/tests/optimize/test_hyperopt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/tests/optimize/test_hyperopt.py b/freqtrade/tests/optimize/test_hyperopt.py index 68fc99955..f8fa66b2e 100644 --- a/freqtrade/tests/optimize/test_hyperopt.py +++ b/freqtrade/tests/optimize/test_hyperopt.py @@ -123,7 +123,7 @@ def test_loss_calculation_has_limited_profit(init_hyperopt) -> None: assert under > correct -def test_log_results_if_loss_improves(capsys) -> None: +def test_log_results_if_loss_improves(init_hyperopt, capsys) -> None: hyperopt = _HYPEROPT hyperopt.current_best_loss = 2 hyperopt.log_results( From 14c140d2424d989bd34be36a2e47b1781bd906bb Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 13 May 2018 16:26:25 +0200 Subject: [PATCH 26/48] Update ccxt from 1.13.136 to 1.13.138 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 90426ffd1..dc822e710 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.136 +ccxt==1.13.138 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From d07491ceb290ecdb7a8c130dcba51dfd6ad182c8 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 19:46:08 +0200 Subject: [PATCH 27/48] Dynamically load cryptomap --- freqtrade/fiat_convert.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index 1258ee149..d24e5187c 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -5,6 +5,7 @@ e.g BTC to USD import logging import time +from typing import Dict from coinmarketcap import Market @@ -73,12 +74,7 @@ class CryptoToFiatConverter(object): "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD" ] - CRYPTOMAP = { - 'BTC': 'bitcoin', - 'ETH': 'ethereum', - 'USDT': 'thether', - 'BNB': 'binance-coin' - } + _cryptomap: Dict = {} def __new__(cls): if CryptoToFiatConverter.__instance is None: @@ -91,6 +87,15 @@ class CryptoToFiatConverter(object): def __init__(self) -> None: self._pairs = [] + self._load_cryptomap() + + def _load_cryptomap(self) -> None: + try: + coinlistings = self._coinmarketcap.listings() + self._cryptomap = dict(map(lambda coin: (coin["symbol"], coin["id"]), + coinlistings["data"])) + except ValueError: + logger.error("Could not load FIAT Cryptocurrency map") def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float: """ @@ -182,14 +187,14 @@ class CryptoToFiatConverter(object): if not self._is_supported_fiat(fiat=fiat_symbol): raise ValueError('The fiat {} is not supported.'.format(fiat_symbol)) - if crypto_symbol not in self.CRYPTOMAP: + if crypto_symbol not in self._cryptomap: # return 0 for unsupported stake currencies (fiat-convert should not break the bot) logger.warning("unsupported crypto-symbol %s - returning 0.0", crypto_symbol) return 0.0 try: return float( self._coinmarketcap.ticker( - currency=self.CRYPTOMAP[crypto_symbol], + currency=self._cryptomap[crypto_symbol], convert=fiat_symbol )[0]['price_' + fiat_symbol.lower()] ) From 9b8f90dc9fe9586da8140177a6b6a802725e8c58 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 19:50:04 +0200 Subject: [PATCH 28/48] log error in find_price --- freqtrade/fiat_convert.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index d24e5187c..6a80b5641 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -198,5 +198,6 @@ class CryptoToFiatConverter(object): convert=fiat_symbol )[0]['price_' + fiat_symbol.lower()] ) - except BaseException: + except BaseException as ex: + logger.error("Error in _find_price: %s", ex) return 0.0 From 144be37a9aec0edd9f88d020085016138cbba09a Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 19:53:23 +0200 Subject: [PATCH 29/48] Convert ID to string --- freqtrade/fiat_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index 6a80b5641..28f00acdf 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -92,7 +92,7 @@ class CryptoToFiatConverter(object): def _load_cryptomap(self) -> None: try: coinlistings = self._coinmarketcap.listings() - self._cryptomap = dict(map(lambda coin: (coin["symbol"], coin["id"]), + self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"]), coinlistings["data"])) except ValueError: logger.error("Could not load FIAT Cryptocurrency map") From 57fc9df5f355fd21ff2fdcecc6802dbd7b980913 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 19:54:19 +0200 Subject: [PATCH 30/48] Fix typo --- freqtrade/fiat_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index 28f00acdf..5509b9f3a 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -92,7 +92,7 @@ class CryptoToFiatConverter(object): def _load_cryptomap(self) -> None: try: coinlistings = self._coinmarketcap.listings() - self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"]), + self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"])), coinlistings["data"])) except ValueError: logger.error("Could not load FIAT Cryptocurrency map") From 3246c604723b5d7d07619604f8d3cc881b9ff291 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 19:58:48 +0200 Subject: [PATCH 31/48] Fix coinmarketcap ticker --- freqtrade/fiat_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index 5509b9f3a..7e74adcd2 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -196,7 +196,7 @@ class CryptoToFiatConverter(object): self._coinmarketcap.ticker( currency=self._cryptomap[crypto_symbol], convert=fiat_symbol - )[0]['price_' + fiat_symbol.lower()] + )['data']['quotes'][fiat_symbol.upper()]['price'] ) except BaseException as ex: logger.error("Error in _find_price: %s", ex) From 790f35a5c86004b9efb0f1e19e9d671c151d6c69 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 20:03:54 +0200 Subject: [PATCH 32/48] fix test which resets singleton without reinstating it --- freqtrade/tests/test_fiat_convert.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/tests/test_fiat_convert.py b/freqtrade/tests/test_fiat_convert.py index 2305b27b1..0e288bdf9 100644 --- a/freqtrade/tests/test_fiat_convert.py +++ b/freqtrade/tests/test_fiat_convert.py @@ -128,7 +128,9 @@ def test_fiat_convert_without_network(): fiat_convert = CryptoToFiatConverter() + cmc_temp = CryptoToFiatConverter._coinmarketcap CryptoToFiatConverter._coinmarketcap = None assert fiat_convert._coinmarketcap is None assert fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='USD') == 0.0 + CryptoToFiatConverter._coinmarketcap = cmc_temp From b1c53ec6567697c2ee8af18e13881b2405454764 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 20:04:40 +0200 Subject: [PATCH 33/48] refactor "patch_coinmarketcap" to conftest" add patch_coinmarketcap to get_patched_freqtradebot --- freqtrade/tests/conftest.py | 23 ++++++++++++++++++++++- freqtrade/tests/test_freqtradebot.py | 17 +---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index bb42bcff9..1ce7b0af0 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -2,6 +2,7 @@ import json import logging from datetime import datetime +from typing import Dict, Optional from functools import reduce from unittest.mock import MagicMock @@ -34,7 +35,8 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot: :param config: Config to pass to the bot :return: None """ - mocker.patch('freqtrade.fiat_convert.Market', {'price_usd': 12345.0}) + # mocker.patch('freqtrade.fiat_convert.Market', {'price_usd': 12345.0}) + patch_coinmarketcap(mocker, {'price_usd': 12345.0}) mocker.patch('freqtrade.freqtradebot.Analyze', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) @@ -46,6 +48,25 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot: return FreqtradeBot(config, create_engine('sqlite://')) +def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> None: + """ + Mocker to coinmarketcap to speed up tests + :param mocker: mocker to patch coinmarketcap class + :return: None + """ + mock = MagicMock() + + if value: + mock.ticker = {'price_usd': 12345.0} + mock.listings = {'data': [{'id': 1, 'name': 'Bitcoin', 'symbol': 'BTC', + 'website_slug': 'bitcoin'}, + {'id': 1027, 'name': 'Ethereum', 'symbol': 'ETH', + 'website_slug': 'ethereum'} + ]} + + mocker.patch('freqtrade.fiat_convert.Market', mock) + + @pytest.fixture(scope="function") def default_conf(): """ Returns validated configuration suitable for most tests """ diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index ead796aca..d9de2c3dc 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -8,7 +8,6 @@ import logging import re import time from copy import deepcopy -from typing import Dict, Optional from unittest.mock import MagicMock import arrow @@ -20,7 +19,7 @@ from freqtrade import DependencyException, OperationalException, TemporaryError from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.state import State -from freqtrade.tests.conftest import log_has +from freqtrade.tests.conftest import log_has, patch_coinmarketcap # Functions for recurrent object patching @@ -64,20 +63,6 @@ def patch_RPCManager(mocker) -> MagicMock: return rpc_mock -def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> None: - """ - Mocker to coinmarketcap to speed up tests - :param mocker: mocker to patch coinmarketcap class - :return: None - """ - mock = MagicMock() - - if value: - mock.ticker = {'price_usd': 12345.0} - - mocker.patch('freqtrade.fiat_convert.Market', mock) - - # Unit tests def test_freqtradebot_object() -> None: """ From 8549201502847e656931c333956ee46383bf067b Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Sun, 13 May 2018 20:46:02 +0200 Subject: [PATCH 34/48] add test for new fiat_convert logic --- freqtrade/tests/conftest.py | 20 +++++++++++--------- freqtrade/tests/test_fiat_convert.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 1ce7b0af0..5d6195a2f 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -54,17 +54,19 @@ def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> Non :param mocker: mocker to patch coinmarketcap class :return: None """ - mock = MagicMock() - if value: - mock.ticker = {'price_usd': 12345.0} - mock.listings = {'data': [{'id': 1, 'name': 'Bitcoin', 'symbol': 'BTC', - 'website_slug': 'bitcoin'}, - {'id': 1027, 'name': 'Ethereum', 'symbol': 'ETH', - 'website_slug': 'ethereum'} - ]} + tickermock = MagicMock(return_value={'price_usd': 12345.0}) + listmock = MagicMock(return_value={'data': [{'id': 1, 'name': 'Bitcoin', 'symbol': 'BTC', + 'website_slug': 'bitcoin'}, + {'id': 1027, 'name': 'Ethereum', 'symbol': 'ETH', + 'website_slug': 'ethereum'} + ]}) + mocker.patch.multiple( + 'freqtrade.fiat_convert.Market', + ticker=tickermock, + listings=listmock, - mocker.patch('freqtrade.fiat_convert.Market', mock) + ) @pytest.fixture(scope="function") diff --git a/freqtrade/tests/test_fiat_convert.py b/freqtrade/tests/test_fiat_convert.py index 0e288bdf9..f5be9daf0 100644 --- a/freqtrade/tests/test_fiat_convert.py +++ b/freqtrade/tests/test_fiat_convert.py @@ -7,6 +7,7 @@ from unittest.mock import MagicMock import pytest from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter +from freqtrade.tests.conftest import patch_coinmarketcap def test_pair_convertion_object(): @@ -123,6 +124,15 @@ def test_fiat_convert_get_price(mocker): assert fiat_convert._pairs[0]._expiration is not expiration +def test_loadcryptomap(mocker): + patch_coinmarketcap(mocker) + + fiat_convert = CryptoToFiatConverter() + assert len(fiat_convert._cryptomap) == 2 + + assert fiat_convert._cryptomap["BTC"] == "1" + + def test_fiat_convert_without_network(): # Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap From 9a09e6b81583e4f52db3e03d3874f3a0b4c41bc1 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 14 May 2018 03:26:26 +0200 Subject: [PATCH 35/48] Update ccxt from 1.13.138 to 1.13.142 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dc822e710..8392e7f8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.138 +ccxt==1.13.142 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From e0bd45efab376a649c9ebcd1ab189e78fc091598 Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Mon, 14 May 2018 08:08:40 +0300 Subject: [PATCH 36/48] Scripts: fix syntax errors and flake8ify --- scripts/plot_dataframe.py | 5 ----- scripts/plot_profit.py | 10 +++++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index 5e533a030..6d14fb596 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -26,12 +26,7 @@ from freqtrade.analyze import Analyze from freqtrade import exchange import freqtrade.optimize as optimize - -<<<<<<< HEAD -logger = logging.getLogger('freqtrade') -======= logger = logging.getLogger(__name__) ->>>>>>> bddf009a2b6d0e1a19cca558887ce972e99a6238 def plot_analyzed_dataframe(args: Namespace) -> None: diff --git a/scripts/plot_profit.py b/scripts/plot_profit.py index c1e1d068f..daa16ddc9 100755 --- a/scripts/plot_profit.py +++ b/scripts/plot_profit.py @@ -24,8 +24,7 @@ import plotly.graph_objs as go from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration from freqtrade.analyze import Analyze -from freqtradeimport constants - +from freqtrade import constants import freqtrade.optimize as optimize import freqtrade.misc as misc @@ -33,11 +32,12 @@ import freqtrade.misc as misc logger = logging.getLogger(__name__) + # data:: [ pair, profit-%, enter, exit, time, duration] # data:: ["ETH/BTC", 0.0023975, "1515598200", "1515602100", "2018-01-10 07:30:00+00:00", 65] -def make_profit_array( - data: List, px: int, min_date: int, - interval: int, filter_pairs: Optional[List] = None) -> np.ndarray: +def make_profit_array(data: List, px: int, min_date: int, + interval: int, + filter_pairs: Optional[List] = None) -> np.ndarray: pg = np.zeros(px) filter_pairs = filter_pairs or [] # Go through the trades From f175f4841847b7705f54382858fe6a923dae47fa Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 15 May 2018 00:31:56 +0300 Subject: [PATCH 37/48] Fix get balance functionality --- freqtrade/rpc/rpc.py | 37 +++++++++--------- freqtrade/tests/rpc/test_rpc.py | 36 ++++++++--------- freqtrade/tests/rpc/test_rpc_telegram.py | 49 ++++++++++-------------- 3 files changed, 55 insertions(+), 67 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 05bdafd08..dd3eed001 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -245,35 +245,34 @@ class RPC(object): """ :return: current account balance per crypto """ - balances = [ - c for c in exchange.get_balances() - if c['Balance'] or c['Available'] or c['Pending'] - ] - if not balances: - return True, '`All balances are zero.`' - output = [] total = 0.0 - for currency in balances: - coin = currency['Currency'] + for coin, balance in exchange.get_balances().items(): + if not balance['total']: + continue + + rate = None if coin == 'BTC': - currency["Rate"] = 1.0 + rate = 1.0 else: if coin == 'USDT': - currency["Rate"] = 1.0 / exchange.get_ticker('BTC/USDT', False)['bid'] + rate = 1.0 / exchange.get_ticker('BTC/USDT', False)['bid'] else: - currency["Rate"] = exchange.get_ticker(coin + '/BTC', False)['bid'] - currency['BTC'] = currency["Rate"] * currency["Balance"] - total = total + currency['BTC'] + rate = exchange.get_ticker(coin + '/BTC', False)['bid'] + est_btc: float = rate * balance['total'] + total = total + est_btc output.append( { - 'currency': currency['Currency'], - 'available': currency['Available'], - 'balance': currency['Balance'], - 'pending': currency['Pending'], - 'est_btc': currency['BTC'] + 'currency': coin, + 'available': balance['free'], + 'balance': balance['total'], + 'pending': balance['used'], + 'est_btc': est_btc } ) + if total == 0.0: + return True, '`All balances are zero.`' + fiat = self.freqtrade.fiat_converter symbol = fiat_display_currency value = fiat.convert_amount(total, 'BTC', symbol) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index f600af5dc..1d1b3b39c 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -288,22 +288,18 @@ def test_rpc_balance_handle(default_conf, mocker): """ Test rpc_balance() method """ - mock_balance = [ - { - 'Currency': 'BTC', - 'Balance': 10.0, - 'Available': 12.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + mock_balance = { + 'BTC': { + 'free': 10.0, + 'total': 12.0, + 'used': 2.0, }, - { - 'Currency': 'ETH', - 'Balance': 0.0, - 'Available': 0.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + 'ETH': { + 'free': 0.0, + 'total': 0.0, + 'used': 0.0, } - ] + } patch_get_signal(mocker, (True, False)) mocker.patch.multiple( @@ -324,15 +320,15 @@ def test_rpc_balance_handle(default_conf, mocker): (error, res) = rpc.rpc_balance(default_conf['fiat_display_currency']) assert not error (trade, x, y, z) = res - assert prec_satoshi(x, 10) - assert prec_satoshi(z, 150000) + assert prec_satoshi(x, 12) + assert prec_satoshi(z, 180000) assert 'USD' in y assert len(trade) == 1 assert 'BTC' in trade[0]['currency'] - assert prec_satoshi(trade[0]['available'], 12) - assert prec_satoshi(trade[0]['balance'], 10) - assert prec_satoshi(trade[0]['pending'], 0) - assert prec_satoshi(trade[0]['est_btc'], 10) + assert prec_satoshi(trade[0]['available'], 10) + assert prec_satoshi(trade[0]['balance'], 12) + assert prec_satoshi(trade[0]['pending'], 2) + assert prec_satoshi(trade[0]['est_btc'], 12) def test_rpc_start(mocker, default_conf) -> None: diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 38e9c8b8a..27637c013 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -554,36 +554,29 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: """ Test _balance() method """ - mock_balance = [ - { - 'Currency': 'BTC', - 'Balance': 10.0, - 'Available': 12.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + + mock_balance = { + 'BTC': { + 'total': 12.0, + 'free': 12.0, + 'used': 0.0 }, - { - 'Currency': 'ETH', - 'Balance': 0.0, - 'Available': 0.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + 'ETH': { + 'total': 0.0, + 'free': 0.0, + 'used': 0.0 }, - { - 'Currency': 'USDT', - 'Balance': 10000.0, - 'Available': 0.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + 'USDT': { + 'total': 10000.0, + 'free': 10000.0, + 'used': 0.0 }, - { - 'Currency': 'LTC', - 'Balance': 10.0, - 'Available': 10.0, - 'Pending': 0.0, - 'CryptoAddress': 'XXXX', + 'LTC': { + 'total': 10.0, + 'free': 10.0, + 'used': 0.0 } - ] + } def mock_ticker(symbol, refresh): """ @@ -626,7 +619,7 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: assert '*Currency*: USDT' in result assert 'Balance' in result assert 'Est. BTC' in result - assert '*BTC*: 12.00000000' in result + assert '*BTC*: 14.00000000' in result def test_zero_balance_handle(default_conf, update, mocker) -> None: @@ -636,7 +629,7 @@ def test_zero_balance_handle(default_conf, update, mocker) -> None: patch_get_signal(mocker, (True, False)) patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) mocker.patch('freqtrade.freqtradebot.exchange.init', MagicMock()) - mocker.patch('freqtrade.freqtradebot.exchange.get_balances', return_value=[]) + mocker.patch('freqtrade.freqtradebot.exchange.get_balances', return_value={}) msg_mock = MagicMock() mocker.patch.multiple( From c96f91204316f896aced69dfa79342d8e03d35a6 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 15 May 2018 01:11:29 +0200 Subject: [PATCH 38/48] Update ccxt from 1.13.142 to 1.13.147 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8392e7f8b..93573f8bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.142 +ccxt==1.13.147 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From c2245362dac907d0509a64aabe0965c87d1beea0 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 15 May 2018 08:41:22 +0200 Subject: [PATCH 39/48] Update coinmarketcap from 5.0.1 to 5.0.3 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8392e7f8b..637ef2434 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ hyperopt==0.1 # do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325 networkx==1.11 tabulate==0.8.2 -coinmarketcap==5.0.1 +coinmarketcap==5.0.3 # Required for plotting data #plotly==2.3.0 From d112d90e8ef9235219711d1d84b28ac1c405735d Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 15 May 2018 13:37:34 +0300 Subject: [PATCH 40/48] Make telegram message beautiful --- freqtrade/rpc/telegram.py | 18 ++++++++---------- freqtrade/tests/rpc/test_rpc_telegram.py | 12 ++++++------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 086c408ac..c640fc77b 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -264,17 +264,15 @@ class Telegram(RPC): (currencys, total, symbol, value) = result output = '' for currency in currencys: - output += """*Currency*: {currency} - *Available*: {available} - *Balance*: {balance} - *Pending*: {pending} - *Est. BTC*: {est_btc: .8f} - """.format(**currency) + output += "*{currency}:*\n" \ + "\t`Available: {available: .8f}`\n" \ + "\t`Balance: {balance: .8f}`\n" \ + "\t`Pending: {pending: .8f}`\n" \ + "\t`Est. BTC: {est_btc: .8f}`\n".format(**currency) - output += """*Estimated Value*: - *BTC*: {0: .8f} - *{1}*: {2: .2f} - """.format(total, symbol, value) + output += "\n*Estimated Value*:\n" \ + "\t`BTC: {0: .8f}`\n" \ + "\t`{1}: {2: .2f}`\n".format(total, symbol, value) self.send_msg(output) @authorized_only diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 27637c013..28fdc7902 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -614,12 +614,12 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: telegram._balance(bot=MagicMock(), update=update) result = msg_mock.call_args_list[0][0][0] assert msg_mock.call_count == 1 - assert '*Currency*: BTC' in result - assert '*Currency*: ETH' not in result - assert '*Currency*: USDT' in result - assert 'Balance' in result - assert 'Est. BTC' in result - assert '*BTC*: 14.00000000' in result + assert '*BTC:*' in result + assert '*ETH:*' not in result + assert '*USDT:*' in result + assert 'Balance:' in result + assert 'Est. BTC:' in result + assert 'BTC: 14.00000000' in result def test_zero_balance_handle(default_conf, update, mocker) -> None: From cc3e4e9aa73527f8dd05cf80f4158e0d88d890e3 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 15 May 2018 16:41:31 +0200 Subject: [PATCH 41/48] Update ccxt from 1.13.147 to 1.13.148 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2f7d5cf99..638bf7167 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.147 +ccxt==1.13.148 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From 263bf918b13e19a69a3b8c7b64bfbd8f0773df1b Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Tue, 15 May 2018 19:49:28 +0200 Subject: [PATCH 42/48] Fix bug pointed out in #679 --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 56ace2ae2..7c955d423 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -397,7 +397,7 @@ class FreqtradeBot(object): return order_amount # use fee from order-dict if possible - if 'fee' in order and order['fee']: + if 'fee' in order and order['fee'] and (order['fee'].keys() >= {'currency', 'cost'}): if trade.pair.startswith(order['fee']['currency']): new_amount = order_amount - order['fee']['cost'] logger.info("Applying fee on amount for %s (from %s to %s) from Order", @@ -414,7 +414,7 @@ class FreqtradeBot(object): fee_abs = 0 for exectrade in trades: amount += exectrade['amount'] - if "fee" in exectrade: + if "fee" in exectrade and (exectrade['fee'].keys() >= {'currency', 'cost'}): # only applies if fee is in quote currency! if trade.pair.startswith(exectrade['fee']['currency']): fee_abs += exectrade['fee']['cost'] From a1fa688da007bf20f91562e2a1d4fad515c10022 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Tue, 15 May 2018 19:49:47 +0200 Subject: [PATCH 43/48] Add tests for the new scenario --- freqtrade/tests/test_freqtradebot.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index d9de2c3dc..a5bd435b0 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1458,3 +1458,28 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996) from Order', caplog.record_tuples) + + +def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, caplog, mocker): + """ + Test get_real_amount - fees in Stake currency + """ + # Remove "Currency" from fee dict + trades_for_order[0]['fee'] = {'cost': 0.008} + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=trades_for_order) + amount = sum(x['amount'] for x in trades_for_order) + trade = Trade( + pair='LTC/ETH', + amount=amount, + exchange='binance', + open_rate=0.245441, + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount does not change + assert freqtrade.get_real_amount(trade, buy_order_fee) == amount From ef78f2f03a6f74992d00d45bd3b725a2953ef6f0 Mon Sep 17 00:00:00 2001 From: Matthias Voppichler Date: Tue, 15 May 2018 20:13:43 +0200 Subject: [PATCH 44/48] Add test for invalid order_fee dict --- freqtrade/tests/test_freqtradebot.py | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index a5bd435b0..ebabc0187 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1443,7 +1443,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee patch_RPCManager(mocker) patch_coinmarketcap(mocker) mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) - mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=trades_for_order) + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=[trades_for_order]) amount = float(sum(x['amount'] for x in trades_for_order)) trade = Trade( pair='LTC/ETH', @@ -1460,7 +1460,32 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee caplog.record_tuples) -def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, caplog, mocker): +def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, mocker): + """ + Test get_real_amount with split trades (multiple trades for this order) + """ + limit_buy_order = deepcopy(buy_order_fee) + limit_buy_order['fee'] = {'cost': 0.004} + + patch_get_signal(mocker) + patch_RPCManager(mocker) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) + mocker.patch('freqtrade.exchange.get_trades_for_order', return_value=[]) + amount = float(sum(x['amount'] for x in trades_for_order)) + trade = Trade( + pair='LTC/ETH', + amount=amount, + exchange='binance', + open_rate=0.245441, + open_order_id="123456" + ) + freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://')) + # Amount does not change + assert freqtrade.get_real_amount(trade, limit_buy_order) == amount + + +def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, mocker): """ Test get_real_amount - fees in Stake currency """ From 8094f84efe536bd34fee2bf0534912bf8224a6c9 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 16 May 2018 05:16:24 +0200 Subject: [PATCH 45/48] Update pandas from 0.22.0 to 0.23.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 638bf7167..32d60d7c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ cachetools==2.1.0 requests==2.18.4 urllib3==1.22 wrapt==1.10.11 -pandas==0.22.0 +pandas==0.23.0 scikit-learn==0.19.1 scipy==1.1.0 jsonschema==2.6.0 From e88fabe1d623bb8519bda31f06a9552cf0bb7ead Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 17 May 2018 00:26:32 +0200 Subject: [PATCH 46/48] Update ccxt from 1.13.148 to 1.14.10 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 32d60d7c9..22c27851a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.13.148 +ccxt==1.14.10 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From 16eb793081f2186c50e9e6f6eb06f9ee0747bbc9 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 19 May 2018 06:56:37 +0200 Subject: [PATCH 47/48] Update ccxt from 1.14.10 to 1.14.24 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 22c27851a..3fe8d7a7e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.14.10 +ccxt==1.14.24 SQLAlchemy==1.2.7 python-telegram-bot==10.1.0 arrow==0.12.1 From 0c051b1b7a449315b44324d394dca1f428cd3674 Mon Sep 17 00:00:00 2001 From: peterkorodi Date: Sat, 19 May 2018 08:14:42 +0200 Subject: [PATCH 48/48] Make plot_dataframe able to show trades stored in database. (#692) * Show trades stored in db on the graph --- docs/plotting.md | 4 ++++ freqtrade/arguments.py | 7 +++++++ scripts/plot_dataframe.py | 41 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/plotting.md b/docs/plotting.md index 80ab6866e..ae964fb16 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -43,6 +43,10 @@ python scripts/plot_dataframe.py -p BTC_ETH --timerange=100-200 ``` Timerange doesn't work with live data. +To plot trades stored in a database use `--db-url` argument: +``` +python scripts/plot_dataframe.py --db-url tradesv3.dry_run.sqlite -p BTC_ETH +``` ## Plot profit diff --git a/freqtrade/arguments.py b/freqtrade/arguments.py index 357bcb937..afcb05511 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/arguments.py @@ -260,6 +260,13 @@ class Arguments(object): default=None ) + self.parser.add_argument( + '-db', '--db-url', + help='Show trades stored in database.', + dest='db_url', + default=None + ) + def testdata_dl_options(self) -> None: """ Parses given arguments for testdata download diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index 6d14fb596..108c0b609 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -10,6 +10,7 @@ Optional Cli parameters -d / --datadir: path to pair backtest data --timerange: specify what timerange of data to use. -l / --live: Live, to download the latest ticker for the pair +-db / --db-url: Show trades stored in database """ import logging import sys @@ -21,13 +22,18 @@ from plotly import tools from plotly.offline import plot import plotly.graph_objs as go +from typing import Dict, List, Any +from sqlalchemy import create_engine + from freqtrade.arguments import Arguments from freqtrade.analyze import Analyze from freqtrade import exchange import freqtrade.optimize as optimize +from freqtrade import persistence +from freqtrade.persistence import Trade logger = logging.getLogger(__name__) - +_CONF: Dict[str, Any] = {} def plot_analyzed_dataframe(args: Namespace) -> None: """ @@ -68,6 +74,12 @@ def plot_analyzed_dataframe(args: Namespace) -> None: dataframe = analyze.populate_buy_trend(dataframe) dataframe = analyze.populate_sell_trend(dataframe) + trades = [] + if args.db_url: + engine = create_engine('sqlite:///' + args.db_url) + persistence.init(_CONF, engine) + trades = Trade.query.filter(Trade.pair.is_(pair)).all() + if len(dataframe.index) > 750: logger.warning('Ticker contained more than 750 candles, clipping.') data = dataframe.tail(750) @@ -108,6 +120,31 @@ def plot_analyzed_dataframe(args: Namespace) -> None: ) ) + trade_buys = go.Scattergl( + x=[t.open_date.isoformat() for t in trades], + y=[t.open_rate for t in trades], + mode='markers', + name='trade_buy', + marker=dict( + symbol='square-open', + size=11, + line=dict(width=2), + color='green' + ) + ) + trade_sells = go.Scattergl( + x=[t.close_date.isoformat() for t in trades], + y=[t.close_rate for t in trades], + mode='markers', + name='trade_sell', + marker=dict( + symbol='square-open', + size=11, + line=dict(width=2), + color='red' + ) + ) + bb_lower = go.Scatter( x=data.date, y=data.bb_lowerband, @@ -142,6 +179,8 @@ def plot_analyzed_dataframe(args: Namespace) -> None: fig.append_trace(volume, 2, 1) fig.append_trace(macd, 3, 1) fig.append_trace(macdsignal, 3, 1) + fig.append_trace(trade_buys, 1, 1) + fig.append_trace(trade_sells, 1, 1) fig['layout'].update(title=args.pair) fig['layout']['yaxis1'].update(title='Price')