예제 #1
0
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
                              limit_buy_order, limit_sell_order,
                              mocker) -> None:
    mocker.patch.multiple(
        'freqtrade.rpc.fiat_convert.CoinGeckoAPI',
        get_price=MagicMock(return_value={'bitcoin': {
            'usd': 15000.0
        }}),
    )
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
    )

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    stake_currency = default_conf['stake_currency']
    fiat_display_currency = default_conf['fiat_display_currency']

    rpc = RPC(freqtradebot)
    rpc._fiat_converter = CryptoToFiatConverter()

    res = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
    assert res['trade_count'] == 0
    assert res['first_trade_date'] == ''
    assert res['first_trade_timestamp'] == 0
    assert res['latest_trade_date'] == ''
    assert res['latest_trade_timestamp'] == 0

    # Create some test data
    freqtradebot.enter_positions()
    trade = Trade.query.first()
    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Update the ticker with a market going up
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          fetch_ticker=ticker_sell_up)
    trade.update(limit_sell_order)
    trade.close_date = datetime.utcnow()
    trade.is_open = False

    freqtradebot.enter_positions()
    trade = Trade.query.first()
    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Update the ticker with a market going up
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          fetch_ticker=ticker_sell_up)
    trade.update(limit_sell_order)
    trade.close_date = datetime.utcnow()
    trade.is_open = False

    stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
    assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05)
    assert prec_satoshi(stats['profit_closed_percent_mean'], 6.2)
    assert prec_satoshi(stats['profit_closed_fiat'], 0.93255)
    assert prec_satoshi(stats['profit_all_coin'], 5.802e-05)
    assert prec_satoshi(stats['profit_all_percent_mean'], 2.89)
    assert prec_satoshi(stats['profit_all_fiat'], 0.8703)
    assert stats['trade_count'] == 2
    assert stats['first_trade_date'] == 'just now'
    assert stats['latest_trade_date'] == 'just now'
    assert stats['avg_duration'] == '0:00:00'
    assert stats['best_pair'] == 'ETH/BTC'
    assert prec_satoshi(stats['best_rate'], 6.2)

    # Test non-available pair
    mocker.patch(
        'freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
        MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
    stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
    assert stats['trade_count'] == 2
    assert stats['first_trade_date'] == 'just now'
    assert stats['latest_trade_date'] == 'just now'
    assert stats['avg_duration'] == '0:00:00'
    assert stats['best_pair'] == 'ETH/BTC'
    assert prec_satoshi(stats['best_rate'], 6.2)
    assert isnan(stats['profit_all_coin'])
예제 #2
0
def test_api_status(botclient, mocker, ticker, fee, markets):
    ftbot, client = botclient
    patch_get_signal(ftbot)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_balances=MagicMock(return_value=ticker),
        fetch_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(return_value=markets),
        fetch_order=MagicMock(return_value={}),
    )

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc, 200)
    assert rc.json() == []
    create_mock_trades(fee)

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc)
    assert len(rc.json()) == 4
    assert rc.json()[0] == {
        'amount': 123.0,
        'amount_requested': 123.0,
        'close_date': None,
        'close_timestamp': None,
        'close_profit': None,
        'close_profit_pct': None,
        'close_profit_abs': None,
        'close_rate': None,
        'current_profit': ANY,
        'current_profit_pct': ANY,
        'current_profit_abs': ANY,
        'profit_ratio': ANY,
        'profit_pct': ANY,
        'profit_abs': ANY,
        'profit_fiat': ANY,
        'current_rate': 1.099e-05,
        'open_date': ANY,
        'open_timestamp': ANY,
        'open_order': None,
        'open_rate': 0.123,
        'pair': 'ETH/BTC',
        'stake_amount': 0.001,
        'stop_loss_abs': ANY,
        'stop_loss_pct': ANY,
        'stop_loss_ratio': ANY,
        'stoploss_order_id': None,
        'stoploss_last_update': ANY,
        'stoploss_last_update_timestamp': ANY,
        'initial_stop_loss_abs': 0.0,
        'initial_stop_loss_pct': ANY,
        'initial_stop_loss_ratio': ANY,
        'stoploss_current_dist': ANY,
        'stoploss_current_dist_ratio': ANY,
        'stoploss_current_dist_pct': ANY,
        'stoploss_entry_dist': ANY,
        'stoploss_entry_dist_ratio': ANY,
        'trade_id': 1,
        'close_rate_requested': ANY,
        'fee_close': 0.0025,
        'fee_close_cost': None,
        'fee_close_currency': None,
        'fee_open': 0.0025,
        'fee_open_cost': None,
        'fee_open_currency': None,
        'is_open': True,
        'max_rate': ANY,
        'min_rate': ANY,
        'open_order_id': 'dry_run_buy_12345',
        'open_rate_requested': ANY,
        'open_trade_value': 15.1668225,
        'sell_reason': None,
        'sell_order_status': None,
        'strategy': 'StrategyTestV2',
        'buy_tag': None,
        'timeframe': 5,
        'exchange': 'binance',
    }

    mocker.patch('freqtrade.exchange.Exchange.get_rate',
                 MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc)
    resp_values = rc.json()
    assert len(resp_values) == 4
    assert isnan(resp_values[0]['profit_abs'])
예제 #3
0
def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
    )

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*no active trade*'):
        rpc._rpc_trade_status()

    freqtradebot.enter_positions()
    trades = Trade.get_open_trades()
    trades[0].open_order_id = None
    freqtradebot.exit_positions(trades)

    results = rpc._rpc_trade_status()
    assert results[0] == {
        'trade_id': 1,
        'pair': 'ETH/BTC',
        'base_currency': 'BTC',
        'open_date': ANY,
        'open_timestamp': ANY,
        'is_open': ANY,
        'fee_open': ANY,
        'fee_open_cost': ANY,
        'fee_open_currency': ANY,
        'fee_close': fee.return_value,
        'fee_close_cost': ANY,
        'fee_close_currency': ANY,
        'open_rate_requested': ANY,
        'open_trade_value': 0.0010025,
        'close_rate_requested': ANY,
        'sell_reason': ANY,
        'sell_order_status': ANY,
        'min_rate': ANY,
        'max_rate': ANY,
        'strategy': ANY,
        'timeframe': 5,
        'open_order_id': ANY,
        'close_date': None,
        'close_timestamp': None,
        'open_rate': 1.098e-05,
        'close_rate': None,
        'current_rate': 1.099e-05,
        'amount': 91.07468123,
        'amount_requested': 91.07468123,
        'stake_amount': 0.001,
        'trade_duration': None,
        'trade_duration_s': None,
        'close_profit': None,
        'close_profit_pct': None,
        'close_profit_abs': None,
        'current_profit': -0.00408133,
        'current_profit_pct': -0.41,
        'current_profit_abs': -4.09e-06,
        'profit_ratio': -0.00408133,
        'profit_pct': -0.41,
        'profit_abs': -4.09e-06,
        'profit_fiat': ANY,
        'stop_loss_abs': 9.882e-06,
        'stop_loss_pct': -10.0,
        'stop_loss_ratio': -0.1,
        'stoploss_order_id': None,
        'stoploss_last_update': ANY,
        'stoploss_last_update_timestamp': ANY,
        'initial_stop_loss_abs': 9.882e-06,
        'initial_stop_loss_pct': -10.0,
        'initial_stop_loss_ratio': -0.1,
        'stoploss_current_dist': -1.1080000000000002e-06,
        'stoploss_current_dist_ratio': -0.10081893,
        'stoploss_current_dist_pct': -10.08,
        'stoploss_entry_dist': -0.00010475,
        'stoploss_entry_dist_ratio': -0.10448878,
        'open_order': None,
        'exchange': 'bittrex',
    }

    mocker.patch(
        'freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
        MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
    results = rpc._rpc_trade_status()
    assert isnan(results[0]['current_profit'])
    assert isnan(results[0]['current_rate'])
    assert results[0] == {
        'trade_id': 1,
        'pair': 'ETH/BTC',
        'base_currency': 'BTC',
        'open_date': ANY,
        'open_timestamp': ANY,
        'is_open': ANY,
        'fee_open': ANY,
        'fee_open_cost': ANY,
        'fee_open_currency': ANY,
        'fee_close': fee.return_value,
        'fee_close_cost': ANY,
        'fee_close_currency': ANY,
        'open_rate_requested': ANY,
        'open_trade_value': ANY,
        'close_rate_requested': ANY,
        'sell_reason': ANY,
        'sell_order_status': ANY,
        'min_rate': ANY,
        'max_rate': ANY,
        'strategy': ANY,
        'timeframe': ANY,
        'open_order_id': ANY,
        'close_date': None,
        'close_timestamp': None,
        'open_rate': 1.098e-05,
        'close_rate': None,
        'current_rate': ANY,
        'amount': 91.07468123,
        'amount_requested': 91.07468123,
        'trade_duration': ANY,
        'trade_duration_s': ANY,
        'stake_amount': 0.001,
        'close_profit': None,
        'close_profit_pct': None,
        'close_profit_abs': None,
        'current_profit': ANY,
        'current_profit_pct': ANY,
        'current_profit_abs': ANY,
        'profit_ratio': ANY,
        'profit_pct': ANY,
        'profit_abs': ANY,
        'profit_fiat': ANY,
        'stop_loss_abs': 9.882e-06,
        'stop_loss_pct': -10.0,
        'stop_loss_ratio': -0.1,
        'stoploss_order_id': None,
        'stoploss_last_update': ANY,
        'stoploss_last_update_timestamp': ANY,
        'initial_stop_loss_abs': 9.882e-06,
        'initial_stop_loss_pct': -10.0,
        'initial_stop_loss_ratio': -0.1,
        'stoploss_current_dist': ANY,
        'stoploss_current_dist_ratio': ANY,
        'stoploss_current_dist_pct': ANY,
        'stoploss_entry_dist': -0.00010475,
        'stoploss_entry_dist_ratio': -0.10448878,
        'open_order': None,
        'exchange': 'bittrex',
    }
예제 #4
0
def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, limit_sell_order):
    ftbot, client = botclient
    patch_get_signal(ftbot, (True, False))
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_balances=MagicMock(return_value=ticker),
        fetch_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(return_value=markets)
    )

    rc = client_get(client, f"{BASE_URI}/profit")
    assert_response(rc, 200)
    assert rc.json()['trade_count'] == 0

    ftbot.enter_positions()
    trade = Trade.query.first()

    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)
    rc = client_get(client, f"{BASE_URI}/profit")
    assert_response(rc, 200)
    # One open trade
    assert rc.json()['trade_count'] == 1
    assert rc.json()['best_pair'] == ''
    assert rc.json()['best_rate'] == 0

    trade = Trade.query.first()
    trade.update(limit_sell_order)

    trade.close_date = datetime.utcnow()
    trade.is_open = False

    rc = client_get(client, f"{BASE_URI}/profit")
    assert_response(rc)
    assert rc.json() == {'avg_duration': ANY,
                         'best_pair': 'ETH/BTC',
                         'best_rate': 6.2,
                         'first_trade_date': 'just now',
                         'first_trade_timestamp': ANY,
                         'latest_trade_date': 'just now',
                         'latest_trade_timestamp': ANY,
                         'profit_all_coin': 6.217e-05,
                         'profit_all_fiat': 0.76748865,
                         'profit_all_percent': 6.2,
                         'profit_all_percent_mean': 6.2,
                         'profit_all_ratio_mean': 0.06201058,
                         'profit_all_percent_sum': 6.2,
                         'profit_all_ratio_sum': 0.06201058,
                         'profit_closed_coin': 6.217e-05,
                         'profit_closed_fiat': 0.76748865,
                         'profit_closed_percent': 6.2,
                         'profit_closed_ratio_mean': 0.06201058,
                         'profit_closed_percent_mean': 6.2,
                         'profit_closed_ratio_sum': 0.06201058,
                         'profit_closed_percent_sum': 6.2,
                         'trade_count': 1,
                         'closed_trade_count': 1,
                         'winning_trades': 1,
                         'losing_trades': 0,
                         }
예제 #5
0
def test_api_status(botclient, mocker, ticker, fee, markets):
    ftbot, client = botclient
    patch_get_signal(ftbot, (True, False))
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_balances=MagicMock(return_value=ticker),
        fetch_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(return_value=markets)
    )

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc, 200)
    assert rc.json() == []

    ftbot.enter_positions()
    trades = Trade.get_open_trades()
    trades[0].open_order_id = None
    ftbot.exit_positions(trades)
    Trade.session.flush()

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc)
    assert len(rc.json()) == 1
    assert rc.json() == [{
        'amount': 91.07468123,
        'amount_requested': 91.07468123,
        'base_currency': 'BTC',
        'close_date': None,
        'close_date_hum': None,
        'close_timestamp': None,
        'close_profit': None,
        'close_profit_pct': None,
        'close_profit_abs': None,
        'close_rate': None,
        'current_profit': -0.00408133,
        'current_profit_pct': -0.41,
        'current_profit_abs': -4.09e-06,
        'profit_ratio': -0.00408133,
        'profit_pct': -0.41,
        'profit_abs': -4.09e-06,
        'current_rate': 1.099e-05,
        'open_date': ANY,
        'open_date_hum': 'just now',
        'open_timestamp': ANY,
        'open_order': None,
        'open_rate': 1.098e-05,
        'pair': 'ETH/BTC',
        'stake_amount': 0.001,
        'stop_loss_abs': 9.882e-06,
        'stop_loss_pct': -10.0,
        'stop_loss_ratio': -0.1,
        'stoploss_order_id': None,
        'stoploss_last_update': ANY,
        'stoploss_last_update_timestamp': ANY,
        'initial_stop_loss_abs': 9.882e-06,
        'initial_stop_loss_pct': -10.0,
        'initial_stop_loss_ratio': -0.1,
        'stoploss_current_dist': -1.1080000000000002e-06,
        'stoploss_current_dist_ratio': -0.10081893,
        'stoploss_current_dist_pct': -10.08,
        'stoploss_entry_dist': -0.00010475,
        'stoploss_entry_dist_ratio': -0.10448878,
        'trade_id': 1,
        'close_rate_requested': None,
        'current_rate': 1.099e-05,
        'fee_close': 0.0025,
        'fee_close_cost': None,
        'fee_close_currency': None,
        'fee_open': 0.0025,
        'fee_open_cost': None,
        'fee_open_currency': None,
        'open_date': ANY,
        'is_open': True,
        'max_rate': 1.099e-05,
        'min_rate': 1.098e-05,
        'open_order_id': None,
        'open_rate_requested': 1.098e-05,
        'open_trade_value': 0.0010025,
        'sell_reason': None,
        'sell_order_status': None,
        'strategy': 'DefaultStrategy',
        'timeframe': 5,
        'exchange': 'bittrex',
    }]
예제 #6
0
def test_rpc_balance_handle(default_conf, mocker, tickers):
    mock_balance = {
        'BTC': {
            'free': 10.0,
            'total': 12.0,
            'used': 2.0,
        },
        'ETH': {
            'free': 1.0,
            'total': 5.0,
            'used': 4.0,
        },
        'USDT': {
            'free': 5.0,
            'total': 10.0,
            'used': 5.0,
        }
    }

    mocker.patch.multiple(
        'freqtrade.rpc.fiat_convert.CoinGeckoAPI',
        get_price=MagicMock(return_value={'bitcoin': {
            'usd': 15000.0
        }}),
    )
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_balances=MagicMock(return_value=mock_balance),
                          get_tickers=tickers,
                          get_valid_pair_combination=MagicMock(
                              side_effect=lambda a, b: f"{b}/{a}"
                              if a == "USDT" else f"{a}/{b}"))
    default_conf['dry_run'] = False
    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)
    rpc._fiat_converter = CryptoToFiatConverter()

    result = rpc._rpc_balance(default_conf['stake_currency'],
                              default_conf['fiat_display_currency'])
    assert prec_satoshi(result['total'], 12.309096315)
    assert prec_satoshi(result['value'], 184636.44472997)
    assert 'USD' == result['symbol']
    assert result['currencies'] == [{
        'currency': 'BTC',
        'free': 10.0,
        'balance': 12.0,
        'used': 2.0,
        'est_stake': 12.0,
        'stake': 'BTC',
    }, {
        'free': 1.0,
        'balance': 5.0,
        'currency': 'ETH',
        'est_stake': 0.30794,
        'used': 4.0,
        'stake': 'BTC',
    }, {
        'free': 5.0,
        'balance': 10.0,
        'currency': 'USDT',
        'est_stake': 0.0011563153318162476,
        'used': 5.0,
        'stake': 'BTC',
    }]
    assert result['total'] == 12.309096315331816
예제 #7
0
def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())

    cancel_order_mock = MagicMock()
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        cancel_order=cancel_order_mock,
        fetch_order=MagicMock(return_value={
            'status': 'closed',
            'type': 'limit',
            'side': 'buy',
            'filled': 0.0,
        }),
        get_fee=fee,
    )
    mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=1000)

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)

    freqtradebot.state = State.STOPPED
    with pytest.raises(RPCException, match=r'.*trader is not running*'):
        rpc._rpc_forcesell(None)

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*invalid argument*'):
        rpc._rpc_forcesell(None)

    msg = rpc._rpc_forcesell('all')
    assert msg == {'result': 'Created sell orders for all open trades.'}

    freqtradebot.enter_positions()
    msg = rpc._rpc_forcesell('all')
    assert msg == {'result': 'Created sell orders for all open trades.'}

    freqtradebot.enter_positions()
    msg = rpc._rpc_forcesell('1')
    assert msg == {'result': 'Created sell order for trade 1.'}

    freqtradebot.state = State.STOPPED
    with pytest.raises(RPCException, match=r'.*trader is not running*'):
        rpc._rpc_forcesell(None)

    with pytest.raises(RPCException, match=r'.*trader is not running*'):
        rpc._rpc_forcesell('all')

    freqtradebot.state = State.RUNNING
    assert cancel_order_mock.call_count == 0
    freqtradebot.enter_positions()
    # make an limit-buy open trade
    trade = Trade.query.filter(Trade.id == '1').first()
    filled_amount = trade.amount / 2
    # Fetch order - it's open first, and closed after cancel_order is called.
    mocker.patch('freqtrade.exchange.Exchange.fetch_order',
                 side_effect=[{
                     'id': '1234',
                     'status': 'open',
                     'type': 'limit',
                     'side': 'buy',
                     'filled': filled_amount
                 }, {
                     'id': '1234',
                     'status': 'closed',
                     'type': 'limit',
                     'side': 'buy',
                     'filled': filled_amount
                 }])
    # check that the trade is called, which is done by ensuring exchange.cancel_order is called
    # and trade amount is updated
    rpc._rpc_forcesell('1')
    assert cancel_order_mock.call_count == 1
    assert trade.amount == filled_amount

    mocker.patch('freqtrade.exchange.Exchange.fetch_order',
                 return_value={
                     'status': 'open',
                     'type': 'limit',
                     'side': 'buy',
                     'filled': filled_amount
                 })

    freqtradebot.config['max_open_trades'] = 3
    freqtradebot.enter_positions()
    trade = Trade.query.filter(Trade.id == '2').first()
    amount = trade.amount
    # make an limit-buy open trade, if there is no 'filled', don't sell it
    mocker.patch('freqtrade.exchange.Exchange.fetch_order',
                 return_value={
                     'status': 'open',
                     'type': 'limit',
                     'side': 'buy',
                     'filled': None
                 })
    # check that the trade is called, which is done by ensuring exchange.cancel_order is called
    msg = rpc._rpc_forcesell('2')
    assert msg == {'result': 'Created sell order for trade 2.'}
    assert cancel_order_mock.call_count == 2
    assert trade.amount == amount

    # make an limit-sell open trade
    mocker.patch('freqtrade.exchange.Exchange.fetch_order',
                 return_value={
                     'status': 'open',
                     'type': 'limit',
                     'side': 'sell',
                     'amount': amount,
                     'remaining': amount,
                     'filled': 0.0
                 })
    msg = rpc._rpc_forcesell('3')
    assert msg == {'result': 'Created sell order for trade 3.'}
    # status quo, no exchange calls
    assert cancel_order_mock.call_count == 3
def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
                      limit_sell_order, mocker) -> None:
    default_conf['max_open_trades'] = 1
    mocker.patch(
        'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
        return_value=15000.0
    )
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        get_fee=fee,
    )
    msg_mock = MagicMock()
    mocker.patch.multiple(
        'freqtrade.rpc.telegram.Telegram',
        _init=MagicMock(),
        _send_msg=msg_mock
    )

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    telegram = Telegram(freqtradebot)

    # Create some test data
    freqtradebot.create_trades()
    trade = Trade.query.first()
    assert trade

    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Simulate fulfilled LIMIT_SELL order for trade
    trade.update(limit_sell_order)

    trade.close_date = datetime.utcnow()
    trade.is_open = False

    # Try valid data
    # /daily 2
    context = MagicMock()
    context.args = ["2"]
    telegram._daily(update=update, context=context)
    assert msg_mock.call_count == 1
    assert 'Daily' in msg_mock.call_args_list[0][0][0]
    assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
    assert str('  0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
    assert str('  0.933 USD') in msg_mock.call_args_list[0][0][0]
    assert str('  1 trade') in msg_mock.call_args_list[0][0][0]
    assert str('  0 trade') in msg_mock.call_args_list[0][0][0]

    # Reset msg_mock
    msg_mock.reset_mock()
    freqtradebot.config['max_open_trades'] = 2
    # Add two other trades
    freqtradebot.create_trades()

    trades = Trade.query.all()
    for trade in trades:
        trade.update(limit_buy_order)
        trade.update(limit_sell_order)
        trade.close_date = datetime.utcnow()
        trade.is_open = False

    # /daily 1
    context = MagicMock()
    context.args = ["1"]
    telegram._daily(update=update, context=context)
    assert str('  0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
    assert str('  2.798 USD') in msg_mock.call_args_list[0][0][0]
    assert str('  3 trades') in msg_mock.call_args_list[0][0][0]
예제 #9
0
파일: test_rpc.py 프로젝트: ssssi/freqtrade
def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
    mocker.patch.multiple(
        'freqtrade.rpc.fiat_convert.CoinGeckoAPI',
        get_price=MagicMock(return_value={'bitcoin': {
            'usd': 15000.0
        }}),
    )
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
    )
    del default_conf['fiat_display_currency']
    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot)
    rpc = RPC(freqtradebot)

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*no active trade*'):
        rpc._rpc_status_table(default_conf['stake_currency'], 'USD')

    freqtradebot.enter_positions()

    result, headers, fiat_profit_sum = rpc._rpc_status_table(
        default_conf['stake_currency'], 'USD')
    assert "Since" in headers
    assert "Pair" in headers
    assert 'instantly' == result[0][2]
    assert 'ETH/BTC' in result[0][1]
    assert '-0.41%' == result[0][3]
    assert isnan(fiat_profit_sum)
    # Test with fiatconvert

    rpc._fiat_converter = CryptoToFiatConverter()
    result, headers, fiat_profit_sum = rpc._rpc_status_table(
        default_conf['stake_currency'], 'USD')
    assert "Since" in headers
    assert "Pair" in headers
    assert len(result[0]) == 4
    assert 'instantly' == result[0][2]
    assert 'ETH/BTC' in result[0][1]
    assert '-0.41% (-0.06)' == result[0][3]
    assert '-0.06' == f'{fiat_profit_sum:.2f}'

    rpc._config['position_adjustment_enable'] = True
    rpc._config['max_entry_position_adjustment'] = 3
    result, headers, fiat_profit_sum = rpc._rpc_status_table(
        default_conf['stake_currency'], 'USD')
    assert "# Entries" in headers
    assert len(result[0]) == 5
    # 4th column should be 1/4 - as 1 order filled (a total of 4 is possible)
    # 3 on top of the initial one.
    assert result[0][4] == '1/4'

    mocker.patch(
        'freqtrade.exchange.Exchange.get_rate',
        MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
    result, headers, fiat_profit_sum = rpc._rpc_status_table(
        default_conf['stake_currency'], 'USD')
    assert 'instantly' == result[0][2]
    assert 'ETH/BTC' in result[0][1]
    assert 'nan%' == result[0][3]
    assert isnan(fiat_profit_sum)
예제 #10
0
def test_rpc_balance_handle(default_conf, mocker):
    mock_balance = {
        'BTC': {
            'free': 10.0,
            'total': 12.0,
            'used': 2.0,
        },
        'ETH': {
            'free': 1.0,
            'total': 5.0,
            'used': 4.0,
        },
        'PAX': {
            'free': 5.0,
            'total': 10.0,
            'used': 5.0,
        }
    }

    mocker.patch.multiple(
        'freqtrade.rpc.fiat_convert.Market',
        ticker=MagicMock(return_value={'price_usd': 15000.0}),
    )
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_balances=MagicMock(return_value=mock_balance),
        get_ticker=MagicMock(side_effect=lambda p, r: {'bid': 100}
                             if p == "BTC/PAX" else {'bid': 0.01}),
        get_valid_pair_combination=MagicMock(
            side_effect=lambda a, b: f"{b}/{a}" if a == "PAX" else f"{a}/{b}"))

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)
    rpc._fiat_converter = CryptoToFiatConverter()

    result = rpc._rpc_balance(default_conf['fiat_display_currency'])
    assert prec_satoshi(result['total'], 12.15)
    assert prec_satoshi(result['value'], 182250)
    assert 'USD' == result['symbol']
    assert result['currencies'] == [{
        'currency': 'BTC',
        'free': 10.0,
        'balance': 12.0,
        'used': 2.0,
        'est_btc': 12.0,
    }, {
        'free': 1.0,
        'balance': 5.0,
        'currency': 'ETH',
        'est_btc': 0.05,
        'used': 4.0
    }, {
        'free': 5.0,
        'balance': 10.0,
        'currency': 'PAX',
        'est_btc': 0.1,
        'used': 5.0
    }]
    assert result['total'] == 12.15
예제 #11
0
def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker,
        get_fee=fee,
    )

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*no active trade*'):
        rpc._rpc_trade_status()

    freqtradebot.enter_positions()
    results = rpc._rpc_trade_status()
    assert {
        'trade_id': 1,
        'pair': 'ETH/BTC',
        'base_currency': 'BTC',
        'open_date': ANY,
        'open_date_hum': ANY,
        'close_date': None,
        'close_date_hum': None,
        'open_rate': 1.099e-05,
        'close_rate': None,
        'current_rate': 1.098e-05,
        'amount': 90.99181074,
        'stake_amount': 0.001,
        'close_profit': None,
        'current_profit': -0.59,
        'stop_loss': 0.0,
        'initial_stop_loss': 0.0,
        'initial_stop_loss_pct': None,
        'stop_loss_pct': None,
        'open_order': '(limit buy rem=0.00000000)'
    } == results[0]

    mocker.patch(
        'freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
        MagicMock(
            side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
    results = rpc._rpc_trade_status()
    assert isnan(results[0]['current_profit'])
    assert isnan(results[0]['current_rate'])
    assert {
        'trade_id': 1,
        'pair': 'ETH/BTC',
        'base_currency': 'BTC',
        'open_date': ANY,
        'open_date_hum': ANY,
        'close_date': None,
        'close_date_hum': None,
        'open_rate': 1.099e-05,
        'close_rate': None,
        'current_rate': ANY,
        'amount': 90.99181074,
        'stake_amount': 0.001,
        'close_profit': None,
        'current_profit': ANY,
        'stop_loss': 0.0,
        'initial_stop_loss': 0.0,
        'initial_stop_loss_pct': None,
        'stop_loss_pct': None,
        'open_order': '(limit buy rem=0.00000000)'
    } == results[0]
예제 #12
0
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
                              limit_buy_order, limit_sell_order,
                              mocker) -> None:
    mocker.patch.multiple(
        'freqtrade.rpc.fiat_convert.Market',
        ticker=MagicMock(return_value={'price_usd': 15000.0}),
    )
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        get_fee=fee,
    )

    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
    patch_get_signal(freqtradebot, (True, False))
    stake_currency = default_conf['stake_currency']
    fiat_display_currency = default_conf['fiat_display_currency']

    rpc = RPC(freqtradebot)
    rpc._fiat_converter = CryptoToFiatConverter()

    with pytest.raises(RPCException, match=r'.*no closed trade*'):
        rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)

    # Create some test data
    freqtradebot.create_trades()
    trade = Trade.query.first()
    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Update the ticker with a market going up
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_ticker=ticker_sell_up)
    trade.update(limit_sell_order)
    trade.close_date = datetime.utcnow()
    trade.is_open = False

    freqtradebot.create_trades()
    trade = Trade.query.first()
    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Update the ticker with a market going up
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_ticker=ticker_sell_up)
    trade.update(limit_sell_order)
    trade.close_date = datetime.utcnow()
    trade.is_open = False

    stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
    assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05)
    assert prec_satoshi(stats['profit_closed_percent'], 6.2)
    assert prec_satoshi(stats['profit_closed_fiat'], 0.93255)
    assert prec_satoshi(stats['profit_all_coin'], 5.632e-05)
    assert prec_satoshi(stats['profit_all_percent'], 2.81)
    assert prec_satoshi(stats['profit_all_fiat'], 0.8448)
    assert stats['trade_count'] == 2
    assert stats['first_trade_date'] == 'just now'
    assert stats['latest_trade_date'] == 'just now'
    assert stats['avg_duration'] == '0:00:00'
    assert stats['best_pair'] == 'ETH/BTC'
    assert prec_satoshi(stats['best_rate'], 6.2)

    # Test non-available pair
    mocker.patch(
        'freqtrade.exchange.Exchange.get_ticker',
        MagicMock(
            side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
    # invalidate ticker cache
    rpc._freqtrade.exchange._cached_ticker = {}
    stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
    assert stats['trade_count'] == 2
    assert stats['first_trade_date'] == 'just now'
    assert stats['latest_trade_date'] == 'just now'
    assert stats['avg_duration'] == '0:00:00'
    assert stats['best_pair'] == 'ETH/BTC'
    assert prec_satoshi(stats['best_rate'], 6.2)
    assert isnan(stats['profit_all_coin'])
예제 #13
0
def test_dca_short(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
    default_conf_usdt['position_adjustment_enable'] = True

    freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        fetch_ticker=ticker_usdt,
        get_fee=fee,
        amount_to_precision=lambda s, x, y: y,
        price_to_precision=lambda s, x, y: y,
    )

    patch_get_signal(freqtrade, enter_long=False, enter_short=True)
    freqtrade.enter_positions()

    assert len(Trade.get_trades().all()) == 1
    trade = Trade.get_trades().first()
    assert len(trade.orders) == 1
    assert pytest.approx(trade.stake_amount) == 60
    assert trade.open_rate == 2.02
    # No adjustment
    freqtrade.process()
    trade = Trade.get_trades().first()
    assert len(trade.orders) == 1
    assert pytest.approx(trade.stake_amount) == 60

    # Reduce bid amount
    ticker_usdt_modif = ticker_usdt.return_value
    ticker_usdt_modif['ask'] = ticker_usdt_modif['ask'] * 1.004
    mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value=ticker_usdt_modif)

    # additional buy order
    freqtrade.process()
    trade = Trade.get_trades().first()
    assert len(trade.orders) == 2
    for o in trade.orders:
        assert o.status == "closed"
    assert pytest.approx(trade.stake_amount) == 120

    # Open-rate averaged between 2.0 and 2.0 * 1.015
    assert trade.open_rate >= 2.02
    assert trade.open_rate < 2.02 * 1.015

    # No action - profit raised above 1% (the bar set in the strategy).
    freqtrade.process()
    trade = Trade.get_trades().first()
    assert len(trade.orders) == 2
    assert pytest.approx(trade.stake_amount) == 120
    # assert trade.orders[0].amount == 30
    assert trade.orders[1].amount == 60 / ticker_usdt_modif['ask']

    assert trade.amount == trade.orders[0].amount + trade.orders[1].amount
    assert trade.nr_of_successful_entries == 2

    # Buy
    patch_get_signal(freqtrade, enter_long=False, exit_short=True)
    freqtrade.process()
    trade = Trade.get_trades().first()
    assert trade.is_open is False
    # assert trade.orders[0].amount == 30
    assert trade.orders[0].side == 'sell'
    assert trade.orders[1].amount == 60 / ticker_usdt_modif['ask']
    # Sold everything
    assert trade.orders[-1].side == 'buy'
    assert trade.orders[2].amount == trade.amount

    assert trade.nr_of_successful_entries == 2
    assert trade.nr_of_successful_exits == 1
예제 #14
0
def test_forcebuy_last_unlimited(default_conf, ticker, fee, 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['force_entry_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),
        _notify_exit=MagicMock(),
    )
    should_sell_mock = MagicMock(side_effect=[
        ExitCheckTuple(exit_type=ExitType.NONE),
        ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
        ExitCheckTuple(exit_type=ExitType.NONE),
        ExitCheckTuple(exit_type=ExitType.NONE),
        ExitCheckTuple(exit_type=ExitType.NONE)]
    )
    mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", 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['exit'] = '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.wallets.get_trade_stake_amount('XRP/BTC') == result1

    rpc._rpc_force_entry('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.wallets.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
예제 #15
0
def test_may_execute_exit_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'
    stoploss_order_closed['filled'] = stoploss_order_closed['amount']

    # 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=[
        ExitCheckTuple(exit_type=ExitType.NONE),
        ExitCheckTuple(exit_type=ExitType.EXIT_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,
        fetch_stoploss_order=stoploss_order_mock,
        cancel_stoploss_order_with_result=cancel_order_mock,
    )

    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        create_stoploss_order=MagicMock(return_value=True),
        _notify_exit=MagicMock(),
    )
    mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", 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['exit'] = 'market'
    freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
    freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True)
    patch_get_signal(freqtrade)

    # Create some test data
    freqtrade.enter_positions()
    assert freqtrade.strategy.confirm_trade_entry.call_count == 3
    freqtrade.strategy.confirm_trade_entry.reset_mock()
    assert freqtrade.strategy.confirm_trade_exit.call_count == 0
    wallets_mock.reset_mock()

    trades = Trade.query.all()
    # Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
    for trade in trades:
        stoploss_order_closed['id'] = '3'
        oobj = Order.parse_from_ccxt_object(stoploss_order_closed, trade.pair, 'stoploss')

        trade.orders.append(oobj)
        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
    assert freqtrade.strategy.confirm_trade_entry.call_count == 0
    assert freqtrade.strategy.confirm_trade_exit.call_count == 1
    freqtrade.strategy.confirm_trade_exit.reset_mock()

    # 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, and will be updated again
    # during update_trade_state
    assert wallets_mock.call_count == 4

    trade = trades[0]
    assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
    assert not trade.is_open

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

    trade = trades[2]
    assert trade.exit_reason == ExitType.EXIT_SIGNAL.value
    assert not trade.is_open
예제 #16
0
def test_api_status(botclient, mocker, ticker, fee, markets):
    ftbot, client = botclient
    patch_get_signal(ftbot, (True, False))
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_balances=MagicMock(return_value=ticker),
                          fetch_ticker=ticker,
                          get_fee=fee,
                          markets=PropertyMock(return_value=markets))

    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc, 200)
    assert rc.json == []

    ftbot.enter_positions()
    rc = client_get(client, f"{BASE_URI}/status")
    assert_response(rc)
    assert len(rc.json) == 1
    assert rc.json == [{
        'amount': 91.07468124,
        'base_currency': 'BTC',
        'close_date': None,
        'close_date_hum': None,
        'close_timestamp': None,
        'close_profit': None,
        'close_profit_pct': None,
        'close_rate': None,
        'current_profit': -0.00408133,
        'current_profit_pct': -0.41,
        'current_rate': 1.099e-05,
        'initial_stop_loss': 0.0,
        'initial_stop_loss_pct': None,
        'open_date': ANY,
        'open_date_hum': 'just now',
        'open_timestamp': ANY,
        'open_order': '(limit buy rem=0.00000000)',
        'open_rate': 1.098e-05,
        'pair': 'ETH/BTC',
        'stake_amount': 0.001,
        'stop_loss': 0.0,
        'stop_loss_pct': None,
        'trade_id': 1,
        'close_rate_requested': None,
        'current_rate': 1.099e-05,
        'fee_close': 0.0025,
        'fee_close_cost': None,
        'fee_close_currency': None,
        'fee_open': 0.0025,
        'fee_open_cost': None,
        'fee_open_currency': None,
        'open_date': ANY,
        'is_open': True,
        'max_rate': 0.0,
        'min_rate': None,
        'open_order_id': ANY,
        'open_rate_requested': 1.098e-05,
        'open_trade_price': 0.0010025,
        'sell_reason': None,
        'sell_order_status': None,
        'strategy': 'DefaultStrategy',
        'ticker_interval': 5
    }]