From 57c835449edc3e79e6be4965f6cc5f9bedddfabb Mon Sep 17 00:00:00 2001 From: gcarq Date: Fri, 13 Oct 2017 23:10:51 +0200 Subject: [PATCH] refactor get_target_bid to use bid as low and ask as high value --- freqtrade/main.py | 19 +++++--- freqtrade/misc.py | 4 +- freqtrade/tests/test_main.py | 80 +++++++++++++++++++++++++------- freqtrade/tests/test_telegram.py | 60 +++++++++++++++++------- 4 files changed, 120 insertions(+), 43 deletions(-) diff --git a/freqtrade/main.py b/freqtrade/main.py index 2e8163b62..e4e0f8335 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -143,13 +143,18 @@ def handle_trade(trade: Trade) -> None: logger.exception('Unable to handle open order') -def get_target_bid(ticker: Dict[str, List[Dict]]) -> float: - """ Calculates bid target between current ask price and last price """ - # TODO: refactor this - ask = ticker['ask'][0]['Rate'] - bid = ticker['bid'][0]['Rate'] - balance = _CONF['bid_strategy']['ask_last_balance'] - return ask + balance * (bid - ask) +def get_target_bid(orderbook: Dict[str, List[Dict]]) -> float: + """ + Calculates bid target between + bid and ask prices from the given orderbook + :param orderbook: + :return: target bit as float + """ + default_target = 1.0 # Use ask price as default + ask = orderbook['ask'][0]['Rate'] # Get lowest ask + bid = orderbook['bid'][0]['Rate'] # Get highest bid + balance = _CONF['bid_strategy'].get('bid_ask_balance', default_target) + return bid + balance * (ask - bid) def create_trade(stake_amount: float) -> Optional[Trade]: diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 585aee3de..74251a344 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -51,14 +51,14 @@ CONF_SCHEMA = { 'bid_strategy': { 'type': 'object', 'properties': { - 'ask_last_balance': { + 'bid_ask_balance': { 'type': 'number', 'minimum': 0, 'maximum': 1, 'exclusiveMaximum': False }, }, - 'required': ['ask_last_balance'] + 'required': ['bid_ask_balance'] }, 'exchange': {'$ref': '#/definitions/exchange'}, 'telegram': { diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index 050d21ad4..3479ba898 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -25,7 +25,7 @@ def conf(): "0": 0.02 }, "bid_strategy": { - "ask_last_balance": 0.0 + "bid_ask_balance": 1.0 }, "exchange": { "name": "bittrex", @@ -48,16 +48,22 @@ def conf(): validate(configuration, CONF_SCHEMA) return configuration + def test_create_trade(conf, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) buy_signal = mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.07256061, - 'ask': 0.072661, - 'last': 0.07256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.07256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.072661 + }] }), buy=MagicMock(return_value='mocked_order_id')) # Save state of current whitelist @@ -82,15 +88,21 @@ def test_create_trade(conf, mocker): [call('BTC_ETH'), call('BTC_TKN'), call('BTC_TRST'), call('BTC_SWT')] ) + def test_handle_trade(conf, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock()) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.17256061, - 'ask': 0.172661, - 'last': 0.17256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.17256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.172661 + }] }), buy=MagicMock(return_value='mocked_order_id')) trade = Trade.query.filter(Trade.is_open.is_(True)).first() @@ -101,6 +113,7 @@ def test_handle_trade(conf, mocker): assert trade.close_date is not None assert trade.open_order_id == 'dry_run' + def test_close_trade(conf, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) trade = Trade.query.filter(Trade.is_open.is_(True)).first() @@ -113,14 +126,47 @@ def test_close_trade(conf, mocker): assert closed assert not trade.is_open + +def test_balance_fully_bid_side(mocker): + mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'bid_ask_balance': 0.0}}) + orderbook = { + 'bid': [{ + 'Quantity': 10, + 'Rate': 10 + }], + 'ask': [{ + 'Quantity': 20, + 'Rate': 20 + }] + } + assert get_target_bid(orderbook) == 10 + + def test_balance_fully_ask_side(mocker): - mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 0.0}}) - assert get_target_bid({'ask': 20, 'last': 10}) == 20 + mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'bid_ask_balance': 1.0}}) + orderbook = { + 'bid': [{ + 'Quantity': 10, + 'Rate': 10 + }], + 'ask': [{ + 'Quantity': 20, + 'Rate': 20 + }] + } + assert get_target_bid(orderbook) == 20 -def test_balance_fully_last_side(mocker): - mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}}) - assert get_target_bid({'ask': 20, 'last': 10}) == 10 -def test_balance_when_last_bigger_than_ask(mocker): - mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}}) - assert get_target_bid({'ask': 5, 'last': 10}) == 5 +def test_balance_half(mocker): + mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'bid_ask_balance': 0.5}}) + orderbook = { + 'bid': [{ + 'Quantity': 10, + 'Rate': 10 + }], + 'ask': [{ + 'Quantity': 20, + 'Rate': 20 + }] + } + assert get_target_bid(orderbook) == 15 diff --git a/freqtrade/tests/test_telegram.py b/freqtrade/tests/test_telegram.py index fb9a618a0..d3d54197d 100644 --- a/freqtrade/tests/test_telegram.py +++ b/freqtrade/tests/test_telegram.py @@ -25,7 +25,7 @@ def conf(): "0": 0.02 }, "bid_strategy": { - "ask_last_balance": 0.0 + "bid_ask_balance": 1.0, }, "exchange": { "name": "bittrex", @@ -46,6 +46,7 @@ def conf(): validate(configuration, CONF_SCHEMA) return configuration + @pytest.fixture def update(): _update = Update(0) @@ -64,10 +65,15 @@ def test_status_handle(conf, update, mocker): mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.07256061, - 'ask': 0.072661, - 'last': 0.07256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.07256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.072661 + }] }), buy=MagicMock(return_value='mocked_order_id')) init(conf, 'sqlite://') @@ -82,6 +88,7 @@ def test_status_handle(conf, update, mocker): assert msg_mock.call_count == 2 assert '[BTC_ETH]' in msg_mock.call_args_list[-1][0][0] + def test_profit_handle(conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) @@ -89,10 +96,15 @@ def test_profit_handle(conf, update, mocker): mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.07256061, - 'ask': 0.072661, - 'last': 0.07256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.07256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.072661 + }] }), buy=MagicMock(return_value='mocked_order_id')) init(conf, 'sqlite://') @@ -112,6 +124,7 @@ def test_profit_handle(conf, update, mocker): assert msg_mock.call_count == 2 assert '(100.00%)' in msg_mock.call_args_list[-1][0][0] + def test_forcesell_handle(conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) @@ -119,10 +132,15 @@ def test_forcesell_handle(conf, update, mocker): mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.07256061, - 'ask': 0.072661, - 'last': 0.07256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.07256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.072661 + }] }), buy=MagicMock(return_value='mocked_order_id')) init(conf, 'sqlite://') @@ -140,6 +158,7 @@ def test_forcesell_handle(conf, update, mocker): assert 'Selling [BTC/ETH]' in msg_mock.call_args_list[-1][0][0] assert '0.072561' in msg_mock.call_args_list[-1][0][0] + def test_performance_handle(conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) @@ -147,10 +166,15 @@ def test_performance_handle(conf, update, mocker): mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock) mocker.patch.multiple('freqtrade.main.exchange', validate_pairs=MagicMock(), - get_ticker=MagicMock(return_value={ - 'bid': 0.07256061, - 'ask': 0.072661, - 'last': 0.07256061 + get_orderbook=MagicMock(return_value={ + 'bid': [{ + 'Quantity': 1, + 'Rate': 0.07256061 + }], + 'ask': [{ + 'Quantity': 1, + 'Rate': 0.072661 + }] }), buy=MagicMock(return_value='mocked_order_id')) init(conf, 'sqlite://') @@ -171,6 +195,7 @@ def test_performance_handle(conf, update, mocker): assert 'Performance' in msg_mock.call_args_list[-1][0][0] assert 'BTC_ETH 100.00%' in msg_mock.call_args_list[-1][0][0] + def test_start_handle(conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) msg_mock = MagicMock() @@ -184,6 +209,7 @@ def test_start_handle(conf, update, mocker): assert get_state() == State.RUNNING assert msg_mock.call_count == 0 + def test_stop_handle(conf, update, mocker): mocker.patch.dict('freqtrade.main._CONF', conf) msg_mock = MagicMock()