diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 7444d32b7..d1f363733 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -20,8 +20,8 @@ We recommend you start by taking a look at `hyperopt.py` file located in [freqtr ### Configure your Guards and Triggers There are two places you need to change to add a new buy strategy for testing: -- Inside [populate_buy_trend()](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L278-L294). -- Inside [hyperopt_space()](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L218-L229) +- Inside [populate_buy_trend()](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L231-L264). +- Inside [hyperopt_space()](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/optimize/hyperopt.py#L213-L224) and the associated methods `indicator_space`, `roi_space`, `stoploss_space`. There you have two different type of indicators: 1. `guards` and 2. `triggers`. diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index c26d74015..02267ac21 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -4,7 +4,7 @@ This module contains the class to persist trades into SQLite import logging from datetime import datetime -from decimal import Decimal, getcontext +from decimal import Decimal from typing import Any, Dict, Optional import arrow @@ -241,7 +241,6 @@ class Trade(_DECL_BASE): logger.info('Updating trade (id=%d) ...', self.id) - getcontext().prec = 8 # Bittrex do not go above 8 decimal if order_type == 'limit' and order['side'] == 'buy': # Update open rate and actual amount self.open_rate = Decimal(order['price']) @@ -278,7 +277,6 @@ class Trade(_DECL_BASE): If rate is not set self.fee will be used :return: Price in BTC of the open trade """ - getcontext().prec = 8 buy_trade = (Decimal(self.amount) * Decimal(self.open_rate)) fees = buy_trade * Decimal(fee or self.fee_open) @@ -296,7 +294,6 @@ class Trade(_DECL_BASE): If rate is not set self.close_rate will be used :return: Price in BTC of the open trade """ - getcontext().prec = 8 if rate is None and not self.close_rate: return 0.0 @@ -336,7 +333,6 @@ class Trade(_DECL_BASE): :param fee: fee to use on the close rate (optional). :return: profit in percentage as float """ - getcontext().prec = 8 open_trade_price = self.calc_open_trade_price() close_trade_price = self.calc_close_trade_price( diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 7031086d8..d653ea176 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -84,9 +84,7 @@ class RPC(object): """ # Fetch open trade trades = Trade.query.filter(Trade.is_open.is_(True)).all() - if self._freqtrade.state != State.RUNNING: - raise RPCException('trader is not running') - elif not trades: + if not trades: raise RPCException('no active trade') else: results = [] @@ -118,9 +116,7 @@ class RPC(object): def _rpc_status_table(self) -> DataFrame: trades = Trade.query.filter(Trade.is_open.is_(True)).all() - if self._freqtrade.state != State.RUNNING: - raise RPCException('trader is not running') - elif not trades: + if not trades: raise RPCException('no active order') else: trades_list = [] @@ -385,8 +381,6 @@ class RPC(object): Handler for performance. Shows a performance statistic from finished trades """ - if self._freqtrade.state != State.RUNNING: - raise RPCException('trader is not running') pair_rates = Trade.session.query(Trade.pair, sql.func.sum(Trade.close_profit).label('profit_sum'), diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index b6ad047b5..040f053f1 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -307,11 +307,14 @@ class Telegram(RPC): result = self._rpc_balance(self._config.get('fiat_display_currency', '')) output = '' for currency in result['currencies']: - output += "*{currency}:*\n" \ - "\t`Available: {available: .8f}`\n" \ - "\t`Balance: {balance: .8f}`\n" \ - "\t`Pending: {pending: .8f}`\n" \ - "\t`Est. BTC: {est_btc: .8f}`\n".format(**currency) + if currency['est_btc'] > 0.0001: + output += "*{currency}:*\n" \ + "\t`Available: {available: .8f}`\n" \ + "\t`Balance: {balance: .8f}`\n" \ + "\t`Pending: {pending: .8f}`\n" \ + "\t`Est. BTC: {est_btc: .8f}`\n".format(**currency) + else: + output += "*{currency}:* not showing <1$ amount \n".format(**currency) output += "\n*Estimated Value*:\n" \ "\t`BTC: {total: .8f}`\n" \ diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index a17867b3a..3ea0f240c 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -534,7 +534,7 @@ def test_backtest(default_conf, fee, mocker) -> None: expected = pd.DataFrame( {'pair': [pair, pair], - 'profit_percent': [0.00029975, 0.00056708], + 'profit_percent': [0.00029977, 0.00056716], 'profit_abs': [1.49e-06, 7.6e-07], 'open_time': [Arrow(2018, 1, 29, 18, 40, 0).datetime, Arrow(2018, 1, 30, 3, 30, 0).datetime], diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index efc136777..88bf5e9ad 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -40,10 +40,6 @@ def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None: 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_trade_status() - freqtradebot.state = State.RUNNING with pytest.raises(RPCException, match=r'.*no active trade*'): rpc._rpc_trade_status() @@ -81,10 +77,6 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None: 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_status_table() - freqtradebot.state = State.RUNNING with pytest.raises(RPCException, match=r'.*no active order*'): rpc._rpc_status_table() diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 182c1d2e7..45e01aa57 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -250,9 +250,10 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No telegram = Telegram(freqtradebot) freqtradebot.state = State.STOPPED + # Status is also enabled when stopped telegram._status(bot=MagicMock(), update=update) assert msg_mock.call_count == 1 - assert 'trader is not running' in msg_mock.call_args_list[0][0][0] + assert 'no active trade' in msg_mock.call_args_list[0][0][0] msg_mock.reset_mock() freqtradebot.state = State.RUNNING @@ -295,9 +296,10 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker) telegram = Telegram(freqtradebot) freqtradebot.state = State.STOPPED + # Status table is also enabled when stopped telegram._status_table(bot=MagicMock(), update=update) assert msg_mock.call_count == 1 - assert 'trader is not running' in msg_mock.call_args_list[0][0][0] + assert 'no active order' in msg_mock.call_args_list[0][0][0] msg_mock.reset_mock() freqtradebot.state = State.RUNNING @@ -507,7 +509,12 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: 'total': 10.0, 'free': 10.0, 'used': 0.0 - } + }, + 'XRP': { + 'total': 1.0, + 'free': 1.0, + 'used': 0.0 + } } def mock_ticker(symbol, refresh): @@ -517,7 +524,12 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: 'ask': 10000.00, 'last': 10000.00, } - + elif symbol == 'XRP/BTC': + return { + 'bid': 0.00001, + 'ask': 0.00001, + 'last': 0.00001, + } return { 'bid': 0.1, 'ask': 0.1, @@ -548,7 +560,8 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None: assert '*USDT:*' in result assert 'Balance:' in result assert 'Est. BTC:' in result - assert 'BTC: 14.00000000' in result + assert 'BTC: 12.00000000' in result + assert '*XRP:* not showing <1$ amount' in result def test_balance_handle_empty_response(default_conf, update, mocker) -> None: @@ -712,7 +725,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, - 'profit_percent': 0.06110514, + 'profit_percent': 0.0611052, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -765,7 +778,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, - 'profit_percent': -0.05478343, + 'profit_percent': -0.05478342, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -810,7 +823,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker 'open_rate': 1.099e-05, 'current_rate': 1.098e-05, 'profit_amount': -5.91e-06, - 'profit_percent': -0.00589292, + 'profit_percent': -0.00589291, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == msg @@ -895,26 +908,6 @@ def test_performance_handle(default_conf, update, ticker, fee, assert 'ETH/BTC\t6.20% (1)' in msg_mock.call_args_list[0][0][0] -def test_performance_handle_invalid(default_conf, update, mocker) -> None: - patch_coinmarketcap(mocker) - patch_exchange(mocker) - msg_mock = MagicMock() - mocker.patch.multiple( - 'freqtrade.rpc.telegram.Telegram', - _init=MagicMock(), - _send_msg=msg_mock - ) - freqtradebot = FreqtradeBot(default_conf) - patch_get_signal(freqtradebot, (True, False)) - telegram = Telegram(freqtradebot) - - # Trader is not running - freqtradebot.state = State.STOPPED - telegram._performance(bot=MagicMock(), update=update) - assert msg_mock.call_count == 1 - assert 'not running' in msg_mock.call_args_list[0][0][0] - - def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> None: patch_coinmarketcap(mocker) patch_exchange(mocker) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index cad2f654d..6b13da35f 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -167,11 +167,6 @@ def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None freqtrade._gen_pair_whitelist(base_currency='BTC') -@pytest.mark.skip(reason="Test not implemented") -def test_refresh_whitelist() -> None: - pass - - def test_get_trade_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -804,7 +799,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, trade.update(limit_sell_order) assert trade.close_rate == 0.00001173 - assert trade.close_profit == 0.06201057 + assert trade.close_profit == 0.06201058 assert trade.calc_profit() == 0.00006217 assert trade.close_date is not None @@ -1231,7 +1226,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, - 'profit_percent': 0.06110514, + 'profit_percent': 0.0611052, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -1277,7 +1272,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, - 'profit_percent': -0.05478343, + 'profit_percent': -0.05478342, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -1324,7 +1319,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee, 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, - 'profit_percent': 0.06110514, + 'profit_percent': 0.0611052, } == last_msg @@ -1370,7 +1365,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee, 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, - 'profit_percent': -0.05478343, + 'profit_percent': -0.05478342, } == last_msg diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 7584537e2..5e0647dff 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -113,7 +113,7 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee): trade.update(limit_sell_order) assert trade.open_order_id is None assert trade.close_rate == 0.00001173 - assert trade.close_profit == 0.06201057 + assert trade.close_profit == 0.06201058 assert trade.close_date is not None @@ -129,16 +129,16 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee): trade.open_order_id = 'something' trade.update(limit_buy_order) - assert trade.calc_open_trade_price() == 0.001002500 + assert trade.calc_open_trade_price() == 0.0010024999999225068 trade.update(limit_sell_order) - assert trade.calc_close_trade_price() == 0.0010646656 + assert trade.calc_close_trade_price() == 0.0010646656050132426 # Profit in BTC assert trade.calc_profit() == 0.00006217 # Profit in percent - assert trade.calc_profit_percent() == 0.06201057 + assert trade.calc_profit_percent() == 0.06201058 @pytest.mark.usefixtures("init_persistence") @@ -207,10 +207,10 @@ def test_calc_open_trade_price(limit_buy_order, fee): trade.update(limit_buy_order) # Buy @ 0.00001099 # Get the open rate price with the standard fee rate - assert trade.calc_open_trade_price() == 0.001002500 + assert trade.calc_open_trade_price() == 0.0010024999999225068 # Get the open rate price with a custom fee rate - assert trade.calc_open_trade_price(fee=0.003) == 0.001003000 + assert trade.calc_open_trade_price(fee=0.003) == 0.001002999999922468 @pytest.mark.usefixtures("init_persistence") @@ -226,14 +226,14 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order, fee): trade.update(limit_buy_order) # Buy @ 0.00001099 # Get the close rate price with a custom close rate and a regular fee rate - assert trade.calc_close_trade_price(rate=0.00001234) == 0.0011200318 + assert trade.calc_close_trade_price(rate=0.00001234) == 0.0011200318470471794 # Get the close rate price with a custom close rate and a custom fee rate - assert trade.calc_close_trade_price(rate=0.00001234, fee=0.003) == 0.0011194704 + assert trade.calc_close_trade_price(rate=0.00001234, fee=0.003) == 0.0011194704275749754 # Test when we apply a Sell order, and ask price with a custom fee rate trade.update(limit_sell_order) - assert trade.calc_close_trade_price(fee=0.005) == 0.0010619972 + assert trade.calc_close_trade_price(fee=0.005) == 0.0010619972701635854 @pytest.mark.usefixtures("init_persistence") @@ -281,17 +281,17 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee): trade.update(limit_buy_order) # Buy @ 0.00001099 # Get percent of profit with a custom rate (Higher than open rate) - assert trade.calc_profit_percent(rate=0.00001234) == 0.1172387 + assert trade.calc_profit_percent(rate=0.00001234) == 0.11723875 # Get percent of profit with a custom rate (Lower than open rate) - assert trade.calc_profit_percent(rate=0.00000123) == -0.88863827 + assert trade.calc_profit_percent(rate=0.00000123) == -0.88863828 # Test when we apply a Sell order. Sell higher than open rate @ 0.00001173 trade.update(limit_sell_order) - assert trade.calc_profit_percent() == 0.06201057 + assert trade.calc_profit_percent() == 0.06201058 # Test with a custom fee rate on the close trade - assert trade.calc_profit_percent(fee=0.003) == 0.0614782 + assert trade.calc_profit_percent(fee=0.003) == 0.06147824 def test_clean_dry_run_db(default_conf, fee): diff --git a/requirements.txt b/requirements.txt index a5f22fec2..461125418 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,18 @@ -ccxt==1.17.375 +ccxt==1.17.402 SQLAlchemy==1.2.12 python-telegram-bot==11.1.0 arrow==0.12.1 cachetools==2.1.0 -requests==2.19.1 -urllib3==1.23 +requests==2.20.0 +urllib3==1.24 wrapt==1.10.11 pandas==0.23.4 scikit-learn==0.20.0 scipy==1.1.0 jsonschema==2.6.0 -numpy==1.15.2 +numpy==1.15.3 TA-Lib==0.4.17 -pytest==3.8.2 +pytest==3.9.2 pytest-mock==1.10.0 pytest-asyncio==0.9.0 pytest-cov==2.6.0