diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 4807ff295..080e06df5 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -1,5 +1,6 @@ import enum import logging +from random import randint from typing import List, Dict import arrow @@ -13,6 +14,9 @@ logger = logging.getLogger(__name__) _API: Exchange = None _CONF: dict = {} +# Holds all open sell orders for dry_run +_DRY_RUN_OPEN_ORDERS: Dict[str, Dict] = {} + class Exchanges(enum.Enum): """ @@ -66,14 +70,36 @@ def validate_pairs(pairs: List[str]) -> None: def buy(pair: str, rate: float, amount: float) -> str: if _CONF['dry_run']: - return 'dry_run_buy' + global _DRY_RUN_OPEN_ORDERS + order_id = 'dry_run_buy_{}'.format(randint(0, 1e6)) + _DRY_RUN_OPEN_ORDERS[order_id] = { + 'pair': pair, + 'rate': rate, + 'amount': amount, + 'type': 'LIMIT_BUY', + 'remaining': 0.0, + 'opened': arrow.utcnow().datetime, + 'closed': arrow.utcnow().datetime, + } + return order_id return _API.buy(pair, rate, amount) def sell(pair: str, rate: float, amount: float) -> str: if _CONF['dry_run']: - return 'dry_run_sell' + global _DRY_RUN_OPEN_ORDERS + order_id = 'dry_run_sell_{}'.format(randint(0, 1e6)) + _DRY_RUN_OPEN_ORDERS[order_id] = { + 'pair': pair, + 'rate': rate, + 'amount': amount, + 'type': 'LIMIT_SELL', + 'remaining': 0.0, + 'opened': arrow.utcnow().datetime, + 'closed': arrow.utcnow().datetime, + } + return order_id return _API.sell(pair, rate, amount) @@ -109,16 +135,11 @@ def cancel_order(order_id: str) -> None: def get_order(order_id: str) -> Dict: if _CONF['dry_run']: - return { - 'id': 'dry_run_sell', - 'type': 'LIMIT_SELL', - 'pair': 'mocked', - 'opened': arrow.utcnow().datetime, - 'rate': 0.07256060, - 'amount': 206.43811673387373, - 'remaining': 0.0, - 'closed': arrow.utcnow().datetime, - } + order = _DRY_RUN_OPEN_ORDERS.pop(order_id) + order.update({ + 'id': order_id + }) + return order return _API.get_order(order_id) diff --git a/freqtrade/main.py b/freqtrade/main.py index 7c89da55f..34d4cdbc7 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -201,12 +201,11 @@ def create_trade(stake_amount: float) -> Optional[Trade]: return Trade(pair=pair, stake_amount=stake_amount, amount=amount, - fee=fee * 2, + fee=fee*2, open_rate=buy_limit, open_date=datetime.utcnow(), exchange=exchange.get_name().upper(), - open_order_id=order_id, - is_open=True) + open_order_id=order_id) def init(config: dict, db_url: Optional[str] = None) -> None: diff --git a/freqtrade/tests/test_telegram.py b/freqtrade/tests/test_telegram.py index 8ee830d92..8c45e2a83 100644 --- a/freqtrade/tests/test_telegram.py +++ b/freqtrade/tests/test_telegram.py @@ -6,6 +6,7 @@ import pytest from jsonschema import validate from telegram import Bot, Update, Message, Chat +from freqtrade import exchange from freqtrade.main import init, create_trade from freqtrade.misc import update_state, State, get_state, CONF_SCHEMA from freqtrade.persistence import Trade @@ -74,8 +75,7 @@ def test_status_handle(conf, update, mocker): 'bid': 0.07256061, 'ask': 0.072661, 'last': 0.07256061 - }), - buy=MagicMock(return_value='mocked_order_id')) + })) init(conf, 'sqlite://') # Create some test data @@ -84,26 +84,10 @@ def test_status_handle(conf, update, mocker): Trade.session.add(trade) Trade.session.flush() - # Trigger status while we don't know the open_rate yet - _status(bot=MagicBot(), update=update) - - # Simulate fulfilled LIMIT_BUY order for trade - trade.update({ - 'id': 'mocked_limit_buy', - 'type': 'LIMIT_BUY', - 'pair': 'mocked', - 'opened': datetime.utcnow(), - 'rate': 0.07256060, - 'amount': 206.43811673387373, - 'remaining': 0.0, - 'closed': datetime.utcnow(), - }) - Trade.session.flush() - # Trigger status while we have a fulfilled order for the open trade _status(bot=MagicBot(), update=update) - assert msg_mock.call_count == 3 + assert msg_mock.call_count == 2 assert '[BTC_ETH]' in msg_mock.call_args_list[-1][0][0] @@ -121,8 +105,7 @@ def test_profit_handle(conf, update, mocker): 'bid': 0.07256061, 'ask': 0.072661, 'last': 0.07256061 - }), - buy=MagicMock(return_value='mocked_limit_buy')) + })) init(conf, 'sqlite://') # Create some test data @@ -153,7 +136,6 @@ def test_profit_handle(conf, update, mocker): }) trade.close_date = datetime.utcnow() - trade.open_order_id = None trade.is_open = False Trade.session.add(trade) Trade.session.flush() @@ -178,26 +160,13 @@ def test_forcesell_handle(conf, update, mocker): 'bid': 0.07256061, 'ask': 0.072661, 'last': 0.07256061 - }), - buy=MagicMock(return_value='mocked_order_id')) + })) init(conf, 'sqlite://') # Create some test data trade = create_trade(15.0) assert trade - # Simulate fulfilled LIMIT_BUY order for trade - trade.update({ - 'id': 'mocked_limit_buy', - 'type': 'LIMIT_BUY', - 'pair': 'mocked', - 'opened': datetime.utcnow(), - 'rate': 0.07256060, - 'amount': 206.43811673387373, - 'remaining': 0.0, - 'closed': datetime.utcnow(), - }) - Trade.session.add(trade) Trade.session.flush() @@ -206,7 +175,7 @@ def test_forcesell_handle(conf, update, mocker): assert msg_mock.call_count == 2 assert 'Selling [BTC/ETH]' in msg_mock.call_args_list[-1][0][0] - assert '0.072561 (profit: ~-0.5%)' in msg_mock.call_args_list[-1][0][0] + assert '0.072561 (profit: ~-0.64%)' in msg_mock.call_args_list[-1][0][0] def test_performance_handle(conf, update, mocker): @@ -223,8 +192,7 @@ def test_performance_handle(conf, update, mocker): 'bid': 0.07256061, 'ask': 0.072661, 'last': 0.07256061 - }), - buy=MagicMock(return_value='mocked_order_id')) + })) init(conf, 'sqlite://') # Create some test data