def mock_trade_6(fee): """ Simulate prod entry with open sell order """ trade = Trade( pair='LTC/BTC', stake_amount=0.001, amount=2.0, amount_requested=2.0, open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=5), fee_open=fee.return_value, fee_close=fee.return_value, is_open=True, open_rate=0.15, exchange='binance', strategy='SampleStrategy', buy_tag='TEST2', open_order_id="prod_sell_6", timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_6(), 'LTC/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_6_sell(), 'LTC/BTC', 'sell') trade.orders.append(o) return trade
def mock_trade_2(fee): """ Closed trade... """ trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, close_rate=0.128, close_profit=0.005, close_profit_abs=0.000584127, exchange='binance', is_open=False, open_order_id='dry_run_sell_12345', strategy='StrategyTestV2', timeframe=5, buy_tag='TEST1', sell_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), ) o = Order.parse_from_ccxt_object(mock_order_2(), 'ETC/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_2_sell(), 'ETC/BTC', 'sell') trade.orders.append(o) return trade
def test_performance_handle(default_conf, ticker, limit_buy_order, fee, limit_sell_order, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), fetch_ticker=ticker, get_fee=fee, ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) patch_get_signal(freqtradebot) rpc = RPC(freqtradebot) # Create some test data freqtradebot.enter_positions() trade = Trade.query.first() assert trade # Simulate fulfilled LIMIT_BUY order for trade oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') trade.update_trade(oobj) # Simulate fulfilled LIMIT_SELL order for trade oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.utcnow() trade.is_open = False res = rpc._rpc_performance() assert len(res) == 1 assert res[0]['pair'] == 'ETH/BTC' assert res[0]['count'] == 1 assert prec_satoshi(res[0]['profit_pct'], 6.2)
def mock_trade_5(fee): """ Simulate prod entry with stoploss """ trade = Trade( pair='XRP/BTC', stake_amount=0.001, amount=123.0, amount_requested=124.0, fee_open=fee.return_value, fee_close=fee.return_value, open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=12), is_open=True, open_rate=0.123, exchange='binance', strategy='SampleStrategy', buy_tag='TEST1', stoploss_order_id='prod_stoploss_3455', timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_5(), 'XRP/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_5_stoploss(), 'XRP/BTC', 'stoploss') trade.orders.append(o) return trade
def mock_trade_usdt_7(fee): """ Simulate prod entry with open sell order """ trade = Trade( pair='LTC/USDT', stake_amount=20.0, amount=2.0, amount_requested=2.0, open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=5), fee_open=fee.return_value, fee_close=fee.return_value, is_open=False, open_rate=10.0, close_rate=8.0, close_profit=-0.2, close_profit_abs=-4.0, exchange='binance', strategy='SampleStrategy', open_order_id="prod_sell_6", timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_usdt_7(), 'LTC/USDT', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_usdt_7_sell(), 'LTC/USDT', 'sell') trade.orders.append(o) return trade
def mock_trade_3(fee): """ Closed trade """ trade = Trade( pair='XRP/BTC', stake_amount=0.001, amount=123.0, amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.05, close_rate=0.06, close_profit=0.01, close_profit_abs=0.000155, exchange='binance', is_open=False, strategy='StrategyTestV2', timeframe=5, sell_reason='roi', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc), ) o = Order.parse_from_ccxt_object(mock_order_3(), 'XRP/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_3_sell(), 'XRP/BTC', 'sell') trade.orders.append(o) return trade
def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, ticker_sell_up, limit_buy_order, limit_sell_order): mocker.patch.multiple( 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', get_price=MagicMock(return_value={'bitcoin': { 'usd': 15000.0 }}), ) mocker.patch( 'freqtrade.rpc.fiat_convert.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) stake_currency = default_conf['stake_currency'] fiat_display_currency = default_conf['fiat_display_currency'] rpc = RPC(freqtradebot) # Create some test data freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') trade.update_trade(oobj) # Update the ticker with a market going up mocker.patch.multiple('freqtrade.exchange.Exchange', fetch_ticker=ticker_sell_up, get_fee=fee) oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.utcnow() trade.is_open = False for trade in Trade.query.order_by(Trade.id).all(): trade.open_rate = None stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) assert prec_satoshi(stats['profit_closed_coin'], 0) assert prec_satoshi(stats['profit_closed_percent_mean'], 0) assert prec_satoshi(stats['profit_closed_fiat'], 0) assert prec_satoshi(stats['profit_all_coin'], 0) assert prec_satoshi(stats['profit_all_percent_mean'], 0) assert prec_satoshi(stats['profit_all_fiat'], 0) assert stats['trade_count'] == 1 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)
def test_rpc_daily_profit(default_conf, update, ticker, fee, limit_buy_order, limit_sell_order, markets, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple('freqtrade.exchange.Exchange', fetch_ticker=ticker, get_fee=fee, markets=PropertyMock(return_value=markets)) freqtradebot = get_patched_freqtradebot(mocker, default_conf) patch_get_signal(freqtradebot) stake_currency = default_conf['stake_currency'] fiat_display_currency = default_conf['fiat_display_currency'] rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() # Create some test data freqtradebot.enter_positions() trade = Trade.query.first() assert trade # Simulate buy & sell oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') trade.update_trade(oobj) oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.utcnow() trade.is_open = False # Try valid data update.message.text = '/daily 2' days = rpc._rpc_daily_profit(7, stake_currency, fiat_display_currency) assert len(days['data']) == 7 assert days['stake_currency'] == default_conf['stake_currency'] assert days['fiat_display_currency'] == default_conf[ 'fiat_display_currency'] for day in days['data']: # [datetime.date(2018, 1, 11), '0.00000000 BTC', '0.000 USD'] assert (day['abs_profit'] == 0.0 or day['abs_profit'] == 0.00006217) assert (day['fiat_value'] == 0.0 or day['fiat_value'] == 0.76748865) # ensure first day is current date assert str(days['data'][0]['date']) == str(datetime.utcnow().date()) # Try invalid data with pytest.raises(RPCException, match=r'.*must be an integer greater than 0*'): rpc._rpc_daily_profit(0, stake_currency, fiat_display_currency)
def mock_trade_5(fee): """ Simulate prod entry with stoploss """ trade = Trade(pair='XRP/BTC', stake_amount=0.001, amount=123.0, amount_requested=124.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', strategy='SampleStrategy', stoploss_order_id='prod_stoploss_3455') o = Order.parse_from_ccxt_object(mock_order_5(), 'XRP/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_5_stoploss(), 'XRP/BTC', 'stoploss') trade.orders.append(o) return trade
def mock_trade_6(fee): """ Simulate prod entry with open sell order """ trade = Trade( pair='LTC/BTC', stake_amount=0.001, amount=2.0, amount_requested=2.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.15, exchange='bittrex', strategy='SampleStrategy', open_order_id="prod_sell_6", ) o = Order.parse_from_ccxt_object(mock_order_6(), 'LTC/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_6_sell(), 'LTC/BTC', 'sell') trade.orders.append(o) return trade
def mock_trade_3(fee): """ Closed trade """ trade = Trade( pair='XRP/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.05, close_rate=0.06, close_profit=0.01, exchange='bittrex', is_open=False, ) o = Order.parse_from_ccxt_object(mock_order_3(), 'XRP/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_3_sell(), 'XRP/BTC', 'sell') trade.orders.append(o) return trade
def mock_trade_2(fee): """ Closed trade... """ trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, close_rate=0.128, close_profit=0.005, exchange='bittrex', is_open=False, open_order_id='dry_run_sell_12345', strategy='DefaultStrategy', ) o = Order.parse_from_ccxt_object(mock_order_2(), 'ETC/BTC', 'buy') trade.orders.append(o) o = Order.parse_from_ccxt_object(mock_order_2_sell(), 'ETC/BTC', 'sell') trade.orders.append(o) return trade
def mock_trade_1(fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=123.0, amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_buy_12345', strategy='DefaultStrategy', ) o = Order.parse_from_ccxt_object(mock_order_1(), 'ETH/BTC', 'buy') trade.orders.append(o) return trade
def mock_trade_1(fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=123.0, amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, is_open=True, open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), open_rate=0.123, exchange='binance', open_order_id='dry_run_buy_12345', strategy='StrategyTestV2', timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_1(), 'ETH/BTC', 'buy') trade.orders.append(o) return trade
def mock_trade_4(fee): """ Simulate prod entry """ trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, amount_requested=124.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='prod_buy_12345', strategy='DefaultStrategy', timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_4(), 'ETC/BTC', 'buy') trade.orders.append(o) return trade
def mock_trade_usdt_4(fee): """ Simulate prod entry """ trade = Trade( pair='ETC/USDT', stake_amount=20.0, amount=10.0, amount_requested=10.01, fee_open=fee.return_value, fee_close=fee.return_value, open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=14), is_open=True, open_rate=2.0, exchange='binance', open_order_id='prod_buy_12345', strategy='StrategyTestV2', timeframe=5, ) o = Order.parse_from_ccxt_object(mock_order_usdt_4(), 'ETC/USDT', 'buy') trade.orders.append(o) return trade
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
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) 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 oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'sell') trade.update_trade(oobj) # Update the ticker with a market going up mocker.patch.multiple('freqtrade.exchange.Exchange', fetch_ticker=ticker_sell_up) oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.utcnow() trade.is_open = False freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') trade.update_trade(oobj) # Update the ticker with a market going up mocker.patch.multiple('freqtrade.exchange.Exchange', fetch_ticker=ticker_sell_up) oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') trade.update_trade(oobj) 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'] in ('0:00:00', '0:00:01', '0:00:02') assert stats['best_pair'] == 'ETH/BTC' assert prec_satoshi(stats['best_rate'], 6.2) # Test non-available pair mocker.patch( 'freqtrade.exchange.Exchange.get_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'] in ('0:00:00', '0:00:01', '0:00:02') assert stats['best_pair'] == 'ETH/BTC' assert prec_satoshi(stats['best_rate'], 6.2) assert isnan(stats['profit_all_coin'])