From 7b901e180a6c283365ee7de7940b8ad862969772 Mon Sep 17 00:00:00 2001 From: iuvbio Date: Wed, 6 Mar 2019 21:37:52 +0100 Subject: [PATCH 01/19] update sql_cheatsheet --- docs/sql_cheatsheet.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index ff0b92347..80a8e74cb 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -44,6 +44,14 @@ CREATE TABLE trades ( open_date DATETIME NOT NULL, close_date DATETIME, open_order_id VARCHAR, + stop_loss FLOAT, + initial_stop_loss FLOAT, + stoploss_order_id VARCHAR, + stoploss_last_update DATETIME, + max_rate FLOAT, + sell_reason VARCHAR, + strategy VARCHAR, + ticker_interval INTEGER, PRIMARY KEY (id), CHECK (is_open IN (0, 1)) ); @@ -57,36 +65,38 @@ SELECT * FROM trades; ## Fix trade still open after a /forcesell +Note: This should not be necessary, as forcesell orders are closed automatically by the bot on the next iteration. + ```sql UPDATE trades -SET is_open=0, close_date=, close_rate=, close_profit=close_rate/open_rate-1 +SET is_open=0, close_date=, close_rate=, close_profit=close_rate/open_rate-1, sell_reason= WHERE id=; ``` -**Example:** +##### Example + ```sql UPDATE trades -SET is_open=0, close_date='2017-12-20 03:08:45.103418', close_rate=0.19638016, close_profit=0.0496 +SET is_open=0, close_date='2017-12-20 03:08:45.103418', close_rate=0.19638016, close_profit=0.0496, sell_reason='force_sell' WHERE id=31; ``` ## Insert manually a new trade ```sql -INSERT -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, , , , '') +INSERT INTO trades (exchange, pair, is_open, fee_open, fee_close, open_rate, stake_amount, amount, open_date) +VALUES ('bittrex', 'ETH/BTC', 1, 0.0025, 0.0025, , , , '') ``` -**Example:** +##### Example: + ```sql -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') +INSERT INTO trades (exchange, pair, is_open, fee_open, fee_close, open_rate, stake_amount, amount, open_date) +VALUES ('bittrex', 'ETH/BTC', 1, 0.0025, 0.0025, 0.00258580, 0.002, 0.7715262081, '2017-11-28 12:44:24.000000') ``` ## Fix wrong fees in the table -If your DB was created before -[PR#200](https://github.com/freqtrade/freqtrade/pull/200) was merged -(before 12/23/17). +If your DB was created before [PR#200](https://github.com/freqtrade/freqtrade/pull/200) was merged (before 12/23/17). ```sql UPDATE trades SET fee=0.0025 WHERE fee=0.005; From 2da0d479e7e36793513e5943075e47041a938f44 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 8 Mar 2019 13:33:06 +0100 Subject: [PATCH 02/19] Update ccxt from 1.18.345 to 1.18.347 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f7eb4c695..ff407848b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.345 +ccxt==1.18.347 SQLAlchemy==1.3.0 python-telegram-bot==11.1.0 arrow==0.13.1 From 9c1d4183fd9804dca09d13db171f1647d0c0710e Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Fri, 8 Mar 2019 20:18:45 +0300 Subject: [PATCH 03/19] typo in doc --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index a4acffc44..7372e3373 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -36,7 +36,7 @@ Complementary Loss Rate (*L*) is defined as or, which is the same, as - R = 1 – W + L = 1 – W ### Risk Reward Ratio Risk Reward Ratio (*R*) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose: From 702153d08745a477d87abcdb5e5ee9c93d12d29c Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Fri, 8 Mar 2019 22:17:17 +0300 Subject: [PATCH 04/19] exchange.sandbox parameter was missing in the docs --- docs/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/configuration.md b/docs/configuration.md index 5d731bb57..d7e774595 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -39,6 +39,7 @@ Mandatory Parameters are marked as **Required**. | `order_types` | None | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). [More information below](#understand-order_types). [Strategy Override](#parameters-in-strategy). | `order_time_in_force` | None | Configure time in force for buy and sell orders. [More information below](#understand-order_time_in_force). [Strategy Override](#parameters-in-strategy). | `exchange.name` | bittrex | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). +| `exchange.sandbox` | false | Use the 'sandbox' version of the exchange, where the exchange provides a sandbox for risk-free integration. See [here](sandbox-testing.md) in more details. | `exchange.key` | key | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | API secret to use for the exchange. Only required when you are in production mode. | `exchange.pair_whitelist` | [] | List of currency to use by the bot. Can be overrided with `--dynamic-whitelist` param. From 0a2cacbba82b0bbfce3489675d05c89d4d822643 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Mar 2019 21:17:12 +0100 Subject: [PATCH 05/19] Fix #1637 --- freqtrade/exchange/exchange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 874ed93aa..f6fb0a58a 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -298,7 +298,7 @@ class Exchange(object): 'amount': amount, "cost": amount * rate, 'type': ordertype, - 'side': 'buy', + 'side': side, 'remaining': amount, 'datetime': arrow.utcnow().isoformat(), 'status': "open", From 4cd70138b6ace98febc7fa74aeab69c49dbce413 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Mar 2019 21:17:21 +0100 Subject: [PATCH 06/19] Add test to make sure this ain't reintroduced --- freqtrade/tests/exchange/test_exchange.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 3b8d3ad6f..fce9cba14 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -470,6 +470,9 @@ def test_dry_run_order(default_conf, mocker, side, exchange_name): pair='ETH/BTC', ordertype='limit', side=side, amount=1, rate=200) assert 'id' in order assert f'dry_run_{side}_' in order["id"] + assert order["side"] == side + assert order["type"] == "limit" + assert order["pair"] == "ETH/BTC" @pytest.mark.parametrize("side", [ From dba30bbfed9947f2ed5974394bc9ef5371468374 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 7 Mar 2019 21:59:39 +0100 Subject: [PATCH 07/19] Update travis for coveralls --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84f3c78d9..424ac579c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,9 @@ install: - pip install -r requirements-dev.txt - pip install -e . jobs: + allow_failures: + - script: coveralls + include: - stage: tests script: @@ -40,6 +43,8 @@ jobs: name: flake8 - script: mypy freqtrade name: mypy + - script: coveralls + name: "Coveralls" - stage: docker if: branch in (master, develop, feat/improve_travis) AND (type in (push, cron)) @@ -47,9 +52,6 @@ jobs: - build_helpers/publish_docker.sh name: "Build and test and push docker image" -after_success: - - coveralls - notifications: slack: secure: bKLXmOrx8e2aPZl7W8DA5BdPAXWGpI5UzST33oc1G/thegXcDVmHBTJrBs4sZak6bgAclQQrdZIsRd2eFYzHLalJEaw6pk7hoAw8SvLnZO0ZurWboz7qg2+aZZXfK4eKl/VUe4sM9M4e/qxjkK+yWG7Marg69c4v1ypF7ezUi1fPYILYw8u0paaiX0N5UX8XNlXy+PBlga2MxDjUY70MuajSZhPsY2pDUvYnMY1D/7XN3cFW0g+3O8zXjF0IF4q1Z/1ASQe+eYjKwPQacE+O8KDD+ZJYoTOFBAPllrtpO1jnOPFjNGf3JIbVMZw4bFjIL0mSQaiSUaUErbU3sFZ5Or79rF93XZ81V7uEZ55vD8KMfR2CB1cQJcZcj0v50BxLo0InkFqa0Y8Nra3sbpV4fV5Oe8pDmomPJrNFJnX6ULQhQ1gTCe0M5beKgVms5SITEpt4/Y0CmLUr6iHDT0CUiyMIRWAXdIgbGh1jfaWOMksybeRevlgDsIsNBjXmYI1Sw2ZZR2Eo2u4R6zyfyjOMLwYJ3vgq9IrACv2w5nmf0+oguMWHf6iWi2hiOqhlAN1W74+3HsYQcqnuM3LGOmuCnPprV1oGBqkPXjIFGpy21gNx4vHfO1noLUyJnMnlu2L7SSuN1CdLsnjJ1hVjpJjPfqB4nn8g12x87TqM1bOm+3Q= From 25529ad95feee3af68bfd7456ada2bbef15f18cd Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Mar 2019 21:54:40 +0100 Subject: [PATCH 08/19] use || for coveralls --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 424ac579c..d24ffcf1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,13 +23,13 @@ install: - pip install -r requirements-dev.txt - pip install -e . jobs: - allow_failures: - - script: coveralls include: - stage: tests script: - pytest --cov=freqtrade --cov-config=.coveragerc freqtrade/tests/ + # Allow failure for coveralls + - coveralls || true name: pytest - script: - cp config.json.example config.json @@ -43,8 +43,6 @@ jobs: name: flake8 - script: mypy freqtrade name: mypy - - script: coveralls - name: "Coveralls" - stage: docker if: branch in (master, develop, feat/improve_travis) AND (type in (push, cron)) From fa4c8110e781f67193e33a9f3e64d1f71d774ee6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Mar 2019 22:15:03 +0100 Subject: [PATCH 09/19] Rename cheatsheet header --- docs/sql_cheatsheet.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 80a8e74cb..e85aceec8 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -63,9 +63,14 @@ CREATE TABLE trades ( SELECT * FROM trades; ``` -## Fix trade still open after a /forcesell +## Fix trade still open after a manual sell on the exchange -Note: This should not be necessary, as forcesell orders are closed automatically by the bot on the next iteration. +!!! Warning: + Manually selling on the exchange should not be done by default, since the bot does not detect this and will try to sell anyway. + /foresell should accomplish the same thing. + +!!! Note: + This should not be necessary after /forcesell, as forcesell orders are closed automatically by the bot on the next iteration. ```sql UPDATE trades From 3b805813cd49345936ee56219be83d4b92116704 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 9 Mar 2019 13:32:07 +0100 Subject: [PATCH 10/19] Update ccxt from 1.18.347 to 1.18.352 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ff407848b..57ec7ca05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.347 +ccxt==1.18.352 SQLAlchemy==1.3.0 python-telegram-bot==11.1.0 arrow==0.13.1 From 43d30180e8ce3df57f4adbd65b7457cae2f7ad2a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 9 Mar 2019 13:32:08 +0100 Subject: [PATCH 11/19] Update plotly from 3.6.1 to 3.7.0 --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index c01ea6a60..b49aad626 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,5 +1,5 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==3.6.1 +plotly==3.7.0 From 5f726d697bc2a4842ba441c92a47bb8e087bbe1f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 10 Mar 2019 13:32:05 +0100 Subject: [PATCH 12/19] Update ccxt from 1.18.352 to 1.18.353 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 57ec7ca05..2df498452 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.352 +ccxt==1.18.353 SQLAlchemy==1.3.0 python-telegram-bot==11.1.0 arrow==0.13.1 From 0eaac1cd79547233e8dd9d5b3e0c46450e3c9343 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 10 Mar 2019 13:32:06 +0100 Subject: [PATCH 13/19] Update sqlalchemy from 1.3.0 to 1.3.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2df498452..f1ab77b0a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ ccxt==1.18.353 -SQLAlchemy==1.3.0 +SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 cachetools==3.1.0 From 513b96b61c43564053dcfd416feeef8e256fe0fb Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 11 Mar 2019 13:32:04 +0100 Subject: [PATCH 14/19] Update ccxt from 1.18.353 to 1.18.357 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f1ab77b0a..434d597f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.353 +ccxt==1.18.357 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From e666c6850e6a0da1bfe078c13d228bb5ee596a69 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Mar 2019 20:20:30 +0100 Subject: [PATCH 15/19] Fix tests so Market orders should not send timeInForce --- freqtrade/tests/exchange/test_exchange.py | 27 ++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index fce9cba14..26b5297ea 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -594,8 +594,6 @@ def test_buy_prod(default_conf, mocker, exchange_name): def test_buy_considers_time_in_force(default_conf, mocker): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) - order_type = 'market' - time_in_force = 'ioc' api_mock.create_order = MagicMock(return_value={ 'id': order_id, 'info': { @@ -607,6 +605,25 @@ def test_buy_considers_time_in_force(default_conf, mocker): mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) exchange = get_patched_exchange(mocker, default_conf, api_mock) + order_type = 'limit' + time_in_force = 'ioc' + + order = exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'buy' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] == 200 + assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc'} + + order_type = 'market' + time_in_force = 'ioc' + order = exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200, time_in_force=time_in_force) @@ -618,13 +635,13 @@ def test_buy_considers_time_in_force(default_conf, mocker): assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 assert api_mock.create_order.call_args[0][4] is None - assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc'} + assert api_mock.create_order.call_args[0][5] == {} def test_buy_kraken_trading_agreement(default_conf, mocker): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) - order_type = 'market' + order_type = 'limit' time_in_force = 'ioc' api_mock.create_order = MagicMock(return_value={ 'id': order_id, @@ -648,7 +665,7 @@ def test_buy_kraken_trading_agreement(default_conf, mocker): assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None + assert api_mock.create_order.call_args[0][4] == 200 assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc', 'trading_agreement': 'agree'} From c0f276a8920b8cc1919e1b1206d81b577c583dc0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Mar 2019 20:22:51 +0100 Subject: [PATCH 16/19] Move kraken specific tests to their own file --- freqtrade/tests/exchange/test_exchange.py | 68 +---------------------- freqtrade/tests/exchange/test_kraken.py | 67 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 65 deletions(-) create mode 100644 freqtrade/tests/exchange/test_kraken.py diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 26b5297ea..d24dd1757 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -4,7 +4,7 @@ import copy import logging from datetime import datetime from random import randint -from unittest.mock import Mock, MagicMock, PropertyMock +from unittest.mock import MagicMock, Mock, PropertyMock import arrow import ccxt @@ -12,11 +12,10 @@ import pytest from pandas import DataFrame from freqtrade import DependencyException, OperationalException, TemporaryError -from freqtrade.exchange import Exchange, Kraken, Binance +from freqtrade.exchange import Binance, Exchange, Kraken from freqtrade.exchange.exchange import API_RETRY_COUNT -from freqtrade.tests.conftest import get_patched_exchange, log_has, log_has_re from freqtrade.resolvers.exchange_resolver import ExchangeResolver - +from freqtrade.tests.conftest import get_patched_exchange, log_has, log_has_re # Make sure to always keep one exchange here which is NOT subclassed!! EXCHANGES = ['bittrex', 'binance', 'kraken', ] @@ -638,67 +637,6 @@ def test_buy_considers_time_in_force(default_conf, mocker): assert api_mock.create_order.call_args[0][5] == {} -def test_buy_kraken_trading_agreement(default_conf, mocker): - api_mock = MagicMock() - order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) - order_type = 'limit' - time_in_force = 'ioc' - api_mock.create_order = MagicMock(return_value={ - 'id': order_id, - 'info': { - 'foo': 'bar' - } - }) - default_conf['dry_run'] = False - - mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) - mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) - exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken") - - order = exchange.buy(pair='ETH/BTC', ordertype=order_type, - amount=1, rate=200, time_in_force=time_in_force) - - assert 'id' in order - assert 'info' in order - assert order['id'] == order_id - assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' - assert api_mock.create_order.call_args[0][1] == order_type - assert api_mock.create_order.call_args[0][2] == 'buy' - assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] == 200 - assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc', - 'trading_agreement': 'agree'} - - -def test_sell_kraken_trading_agreement(default_conf, mocker): - api_mock = MagicMock() - order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6)) - order_type = 'market' - api_mock.create_order = MagicMock(return_value={ - 'id': order_id, - 'info': { - 'foo': 'bar' - } - }) - default_conf['dry_run'] = False - - mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) - mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) - exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken") - - order = exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) - - assert 'id' in order - assert 'info' in order - assert order['id'] == order_id - assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' - assert api_mock.create_order.call_args[0][1] == order_type - assert api_mock.create_order.call_args[0][2] == 'sell' - assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None - assert api_mock.create_order.call_args[0][5] == {'trading_agreement': 'agree'} - - def test_sell_dry_run(default_conf, mocker): default_conf['dry_run'] = True exchange = get_patched_exchange(mocker, default_conf) diff --git a/freqtrade/tests/exchange/test_kraken.py b/freqtrade/tests/exchange/test_kraken.py new file mode 100644 index 000000000..8b81a08a9 --- /dev/null +++ b/freqtrade/tests/exchange/test_kraken.py @@ -0,0 +1,67 @@ +# pragma pylint: disable=missing-docstring, C0103, bad-continuation, global-statement +# pragma pylint: disable=protected-access +from random import randint +from unittest.mock import MagicMock + +from freqtrade.tests.conftest import get_patched_exchange + + +def test_buy_kraken_trading_agreement(default_conf, mocker): + api_mock = MagicMock() + order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) + order_type = 'limit' + time_in_force = 'ioc' + api_mock.create_order = MagicMock(return_value={ + 'id': order_id, + 'info': { + 'foo': 'bar' + } + }) + default_conf['dry_run'] = False + + mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) + mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken") + + order = exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'buy' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] == 200 + assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc', + 'trading_agreement': 'agree'} + + +def test_sell_kraken_trading_agreement(default_conf, mocker): + api_mock = MagicMock() + order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6)) + order_type = 'market' + api_mock.create_order = MagicMock(return_value={ + 'id': order_id, + 'info': { + 'foo': 'bar' + } + }) + default_conf['dry_run'] = False + + mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) + mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken") + + order = exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'sell' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] is None + assert api_mock.create_order.call_args[0][5] == {'trading_agreement': 'agree'} From 4705b7da0edb6ee405aba89c59dd42a22b6824cb Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Mar 2019 20:30:16 +0100 Subject: [PATCH 17/19] Add time_in_force test for sell --- freqtrade/tests/exchange/test_exchange.py | 60 +++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d24dd1757..ff36ab91c 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -590,7 +590,8 @@ def test_buy_prod(default_conf, mocker, exchange_name): amount=1, rate=200, time_in_force=time_in_force) -def test_buy_considers_time_in_force(default_conf, mocker): +@pytest.mark.parametrize("exchange_name", EXCHANGES) +def test_buy_considers_time_in_force(default_conf, mocker, exchange_name): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) api_mock.create_order = MagicMock(return_value={ @@ -602,7 +603,7 @@ def test_buy_considers_time_in_force(default_conf, mocker): default_conf['dry_run'] = False mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) - exchange = get_patched_exchange(mocker, default_conf, api_mock) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) order_type = 'limit' time_in_force = 'ioc' @@ -618,7 +619,8 @@ def test_buy_considers_time_in_force(default_conf, mocker): assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 assert api_mock.create_order.call_args[0][4] == 200 - assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc'} + assert "timeInForce" in api_mock.create_order.call_args[0][5] + assert api_mock.create_order.call_args[0][5]["timeInForce"] == time_in_force order_type = 'market' time_in_force = 'ioc' @@ -634,7 +636,8 @@ def test_buy_considers_time_in_force(default_conf, mocker): assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 assert api_mock.create_order.call_args[0][4] is None - assert api_mock.create_order.call_args[0][5] == {} + # Market orders should not send timeInForce!! + assert "timeInForce" not in api_mock.create_order.call_args[0][5] def test_sell_dry_run(default_conf, mocker): @@ -705,6 +708,55 @@ def test_sell_prod(default_conf, mocker, exchange_name): exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) +@pytest.mark.parametrize("exchange_name", EXCHANGES) +def test_sell_considers_time_in_force(default_conf, mocker, exchange_name): + api_mock = MagicMock() + order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6)) + api_mock.create_order = MagicMock(return_value={ + 'id': order_id, + 'info': { + 'foo': 'bar' + } + }) + default_conf['dry_run'] = False + mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) + mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) + + order_type = 'limit' + time_in_force = 'ioc' + + order = exchange.sell(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'sell' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] == 200 + assert "timeInForce" in api_mock.create_order.call_args[0][5] + assert api_mock.create_order.call_args[0][5]["timeInForce"] == time_in_force + + order_type = 'market' + time_in_force = 'ioc' + order = exchange.sell(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'sell' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] is None + # Market orders should not send timeInForce!! + assert "timeInForce" not in api_mock.create_order.call_args[0][5] + + def test_get_balance_dry_run(default_conf, mocker): default_conf['dry_run'] = True From 0eb9dd5fe5d8381e2bce26effe66b3309d6ff85a Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Mar 2019 20:30:36 +0100 Subject: [PATCH 18/19] Don't use timeInForce for market orders --- freqtrade/exchange/exchange.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index f6fb0a58a..32d952542 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -352,7 +352,7 @@ class Exchange(object): return dry_order params = self._params.copy() - if time_in_force != 'gtc': + if time_in_force != 'gtc' and ordertype != 'market': params.update({'timeInForce': time_in_force}) return self.create_order(pair, ordertype, 'buy', amount, rate, params) @@ -365,7 +365,7 @@ class Exchange(object): return dry_order params = self._params.copy() - if time_in_force != 'gtc': + if time_in_force != 'gtc' and ordertype != 'market': params.update({'timeInForce': time_in_force}) return self.create_order(pair, ordertype, 'sell', amount, rate, params) From 48d33b070f01a016c46df2ca2f68d26b9122b99f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Mar 2019 07:06:42 +0100 Subject: [PATCH 19/19] Add stoploss to startup messages --- freqtrade/rpc/rpc_manager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index de861677d..bc69c97ad 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -61,6 +61,8 @@ class RPCManager(object): stake_currency = config['stake_currency'] stake_amount = config['stake_amount'] minimal_roi = config['minimal_roi'] + stoploss = config['stoploss'] + trailing_stop = config['trailing_stop'] ticker_interval = config['ticker_interval'] exchange_name = config['exchange']['name'] strategy_name = config.get('strategy', '') @@ -69,6 +71,7 @@ class RPCManager(object): 'status': f'*Exchange:* `{exchange_name}`\n' f'*Stake per trade:* `{stake_amount} {stake_currency}`\n' f'*Minimum ROI:* `{minimal_roi}`\n' + f'*{"Trailing " if trailing_stop else ""}Stoploss:* `{stoploss}`\n' f'*Ticker Interval:* `{ticker_interval}`\n' f'*Strategy:* `{strategy_name}`' })