示例#1
0
        def _exec_forcesell(trade: Trade) -> None:
            # Check if there is there is an open order
            fully_canceled = False
            if trade.open_order_id:
                order = self._freqtrade.exchange.fetch_order(
                    trade.open_order_id, trade.pair)

                if order['side'] == 'buy':
                    fully_canceled = self._freqtrade.handle_cancel_enter(
                        trade, order, CANCEL_REASON['FORCE_SELL'])

                if order['side'] == 'sell':
                    # Cancel order - so it is placed anew with a fresh price.
                    self._freqtrade.handle_cancel_exit(
                        trade, order, CANCEL_REASON['FORCE_SELL'])

            if not fully_canceled:
                # Get current rate and execute sell
                current_rate = self._freqtrade.exchange.get_rate(trade.pair,
                                                                 refresh=False,
                                                                 side="sell")
                sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
                order_type = ordertype or self._freqtrade.strategy.order_types.get(
                    "forcesell", self._freqtrade.strategy.order_types["sell"])

                self._freqtrade.execute_trade_exit(trade,
                                                   current_rate,
                                                   sell_reason,
                                                   ordertype=order_type)
示例#2
0
def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order,
                                 mocker, balance_ratio, result1) -> None:
    """
    Tests workflow unlimited stake-amount
    Buy 4 trades, forcebuy a 5th trade
    Sell one trade, calculated stake amount should now be lower than before since
    one trade was sold at a loss.
    """
    default_conf['max_open_trades'] = 5
    default_conf['forcebuy_enable'] = True
    default_conf['stake_amount'] = 'unlimited'
    default_conf['tradable_balance_ratio'] = balance_ratio
    default_conf['dry_run_wallet'] = 1000
    default_conf['exchange']['name'] = 'binance'
    default_conf['telegram']['enabled'] = True
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
        amount_to_precision=lambda s, x, y: y,
        price_to_precision=lambda s, x, y: y,
    )

    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        create_stoploss_order=MagicMock(return_value=True),
        update_trade_state=MagicMock(),
        _notify_sell=MagicMock(),
    )
    should_sell_mock = MagicMock(side_effect=[
        SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
        SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL),
        SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
        SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
        SellCheckTuple(sell_flag=None, sell_type=SellType.NONE)
    ])
    mocker.patch("freqtrade.strategy.interface.IStrategy.should_sell",
                 should_sell_mock)

    freqtrade = get_patched_freqtradebot(mocker, default_conf)
    rpc = RPC(freqtrade)
    freqtrade.strategy.order_types['stoploss_on_exchange'] = True
    # Switch ordertype to market to close trade immediately
    freqtrade.strategy.order_types['sell'] = 'market'
    patch_get_signal(freqtrade)

    # Create 4 trades
    n = freqtrade.enter_positions()
    assert n == 4

    trades = Trade.query.all()
    assert len(trades) == 4
    assert freqtrade.get_trade_stake_amount('XRP/BTC') == result1

    rpc._rpc_forcebuy('TKN/BTC', None)

    trades = Trade.query.all()
    assert len(trades) == 5

    for trade in trades:
        assert trade.stake_amount == result1
        # Reset trade open order id's
        trade.open_order_id = None
    trades = Trade.get_open_trades()
    assert len(trades) == 5
    bals = freqtrade.wallets.get_all_balances()

    n = freqtrade.exit_positions(trades)
    assert n == 1
    trades = Trade.get_open_trades()
    # One trade sold
    assert len(trades) == 4
    # stake-amount should now be reduced, since one trade was sold at a loss.
    assert freqtrade.get_trade_stake_amount('XRP/BTC') < result1
    # Validate that balance of sold trade is not in dry-run balances anymore.
    bals2 = freqtrade.wallets.get_all_balances()
    assert bals != bals2
    assert len(bals) == 6
    assert len(bals2) == 5
    assert 'LTC' in bals
    assert 'LTC' not in bals2
示例#3
0
def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
                                                     limit_buy_order,
                                                     mocker) -> None:
    """
    Tests workflow of selling stoploss_on_exchange.
    Sells
    * first trade as stoploss
    * 2nd trade is kept
    * 3rd trade is sold via sell-signal
    """
    default_conf['max_open_trades'] = 3
    default_conf['exchange']['name'] = 'binance'

    stoploss = {'id': 123, 'info': {}}
    stoploss_order_open = {
        "id": "123",
        "timestamp": 1542707426845,
        "datetime": "2018-11-20T09:50:26.845Z",
        "lastTradeTimestamp": None,
        "symbol": "BTC/USDT",
        "type": "stop_loss_limit",
        "side": "sell",
        "price": 1.08801,
        "amount": 90.99181074,
        "cost": 0.0,
        "average": 0.0,
        "filled": 0.0,
        "remaining": 0.0,
        "status": "open",
        "fee": None,
        "trades": None
    }
    stoploss_order_closed = stoploss_order_open.copy()
    stoploss_order_closed['status'] = 'closed'
    # Sell first trade based on stoploss, keep 2nd and 3rd trade open
    stoploss_order_mock = MagicMock(side_effect=[
        stoploss_order_closed, stoploss_order_open, stoploss_order_open
    ])
    # Sell 3rd trade (not called for the first trade)
    should_sell_mock = MagicMock(side_effect=[
        SellCheckTuple(sell_flag=False, sell_type=SellType.NONE),
        SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL)
    ])
    cancel_order_mock = MagicMock()
    mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
        amount_to_precision=lambda s, x, y: y,
        price_to_precision=lambda s, x, y: y,
        get_order=stoploss_order_mock,
        cancel_order=cancel_order_mock,
    )

    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        create_stoploss_order=MagicMock(return_value=True),
        update_trade_state=MagicMock(),
        _notify_sell=MagicMock(),
    )
    mocker.patch("freqtrade.strategy.interface.IStrategy.should_sell",
                 should_sell_mock)
    wallets_mock = mocker.patch("freqtrade.wallets.Wallets.update",
                                MagicMock())
    mocker.patch("freqtrade.wallets.Wallets.get_free",
                 MagicMock(return_value=1000))

    freqtrade = get_patched_freqtradebot(mocker, default_conf)
    freqtrade.strategy.order_types['stoploss_on_exchange'] = True
    # Switch ordertype to market to close trade immediately
    freqtrade.strategy.order_types['sell'] = 'market'
    patch_get_signal(freqtrade)

    # Create some test data
    freqtrade.enter_positions()
    wallets_mock.reset_mock()
    Trade.session = MagicMock()

    trades = Trade.query.all()
    # Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
    for trade in trades:
        trade.stoploss_order_id = 3
        trade.open_order_id = None

    n = freqtrade.exit_positions(trades)
    assert n == 2
    assert should_sell_mock.call_count == 2

    # Only order for 3rd trade needs to be cancelled
    assert cancel_order_mock.call_count == 1
    # Wallets must be updated between stoploss cancellation and selling.
    assert wallets_mock.call_count == 2

    trade = trades[0]
    assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value
    assert not trade.is_open

    trade = trades[1]
    assert not trade.sell_reason
    assert trade.is_open

    trade = trades[2]
    assert trade.sell_reason == SellType.SELL_SIGNAL.value
    assert not trade.is_open