Fix issue #248: missing configuration when executing /forcesell
This is not a beautiful workaround, I am not proud of it, but a redesigning of main.py and telegram.py will be necessary for a better integration. Any better solution is welcome.
This commit is contained in:
parent
9f5f0ddaaa
commit
c8c8c626b0
@ -55,7 +55,7 @@ use the `last` price and values between those interpolate between ask and last
|
|||||||
price. Using `ask` price will guarantee quick success in bid, but bot will also
|
price. Using `ask` price will guarantee quick success in bid, but bot will also
|
||||||
end up paying more then would probably have been necessary.
|
end up paying more then would probably have been necessary.
|
||||||
|
|
||||||
`fiat_currency` set the fiat to use for the conversion form coin to
|
`fiat_display_currency` set the fiat to use for the conversion form coin to
|
||||||
fiat in Telegram. The valid value are: "AUD", "BRL", "CAD", "CHF",
|
fiat in Telegram. The valid value are: "AUD", "BRL", "CAD", "CHF",
|
||||||
"CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS",
|
"CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS",
|
||||||
"INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
|
"INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
|
||||||
|
@ -124,26 +124,39 @@ def execute_sell(trade: Trade, limit: float) -> None:
|
|||||||
fmt_exp_profit = round(trade.calc_profit_percent(rate=limit) * 100, 2)
|
fmt_exp_profit = round(trade.calc_profit_percent(rate=limit) * 100, 2)
|
||||||
profit_trade = trade.calc_profit(rate=limit)
|
profit_trade = trade.calc_profit(rate=limit)
|
||||||
|
|
||||||
fiat_converter = CryptoToFiatConverter()
|
message = '*{exchange}:* Selling [{pair}]({pair_url}) with limit `{limit:.8f}`'.format(
|
||||||
profit_fiat = fiat_converter.convert_amount(
|
exchange=trade.exchange,
|
||||||
profit_trade,
|
pair=trade.pair.replace('_', '/'),
|
||||||
_CONF['stake_currency'],
|
pair_url=exchange.get_pair_detail_url(trade.pair),
|
||||||
_CONF['fiat_display_currency']
|
limit=limit
|
||||||
)
|
)
|
||||||
|
|
||||||
rpc.send_msg('*{exchange}:* Selling [{pair}]({pair_url}) with limit `{limit:.8f}`'
|
# For regular case, when the configuration exists
|
||||||
'` (profit: ~{profit_percent:.2f}%, {profit_coin:.8f} {coin}`'
|
if 'stake_currency' in _CONF and 'fiat_display_currency' in _CONF:
|
||||||
'` / {profit_fiat:.3f} {fiat})`'.format(
|
fiat_converter = CryptoToFiatConverter()
|
||||||
exchange=trade.exchange,
|
profit_fiat = fiat_converter.convert_amount(
|
||||||
pair=trade.pair.replace('_', '/'),
|
profit_trade,
|
||||||
pair_url=exchange.get_pair_detail_url(trade.pair),
|
_CONF['stake_currency'],
|
||||||
limit=limit,
|
_CONF['fiat_display_currency']
|
||||||
|
)
|
||||||
|
message += '` (profit: ~{profit_percent:.2f}%, {profit_coin:.8f} {coin}`' \
|
||||||
|
'` / {profit_fiat:.3f} {fiat})`'.format(
|
||||||
profit_percent=fmt_exp_profit,
|
profit_percent=fmt_exp_profit,
|
||||||
profit_coin=profit_trade,
|
profit_coin=profit_trade,
|
||||||
coin=_CONF['stake_currency'],
|
coin=_CONF['stake_currency'],
|
||||||
profit_fiat=profit_fiat,
|
profit_fiat=profit_fiat,
|
||||||
fiat=_CONF['fiat_display_currency'],
|
fiat=_CONF['fiat_display_currency'],
|
||||||
))
|
)
|
||||||
|
# Because telegram._forcesell does not have the configuration
|
||||||
|
# Ignore the FIAT value and does not show the stake_currency as well
|
||||||
|
else:
|
||||||
|
message += '` (profit: ~{profit_percent:.2f}%, {profit_coin:.8f})`'.format(
|
||||||
|
profit_percent=fmt_exp_profit,
|
||||||
|
profit_coin=profit_trade
|
||||||
|
)
|
||||||
|
|
||||||
|
# Send the message
|
||||||
|
rpc.send_msg(message)
|
||||||
Trade.session.flush()
|
Trade.session.flush()
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,6 +280,7 @@ CONF_SCHEMA = {
|
|||||||
'max_open_trades',
|
'max_open_trades',
|
||||||
'stake_currency',
|
'stake_currency',
|
||||||
'stake_amount',
|
'stake_amount',
|
||||||
|
'fiat_display_currency',
|
||||||
'dry_run',
|
'dry_run',
|
||||||
'minimal_roi',
|
'minimal_roi',
|
||||||
'bid_strategy',
|
'bid_strategy',
|
||||||
|
@ -11,7 +11,7 @@ from freqtrade import DependencyException, OperationalException
|
|||||||
from freqtrade.analyze import SignalType
|
from freqtrade.analyze import SignalType
|
||||||
from freqtrade.exchange import Exchanges
|
from freqtrade.exchange import Exchanges
|
||||||
from freqtrade.main import create_trade, handle_trade, init, \
|
from freqtrade.main import create_trade, handle_trade, init, \
|
||||||
get_target_bid, _process
|
get_target_bid, _process, execute_sell
|
||||||
from freqtrade.misc import get_state, State
|
from freqtrade.misc import get_state, State
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
|
|
||||||
@ -314,3 +314,104 @@ def test_balance_fully_last_side(mocker):
|
|||||||
def test_balance_bigger_last_ask(mocker):
|
def test_balance_bigger_last_ask(mocker):
|
||||||
mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}})
|
mocker.patch.dict('freqtrade.main._CONF', {'bid_strategy': {'ask_last_balance': 1.0}})
|
||||||
assert get_target_bid({'ask': 5, 'last': 10}) == 5
|
assert get_target_bid({'ask': 5, 'last': 10}) == 5
|
||||||
|
|
||||||
|
|
||||||
|
def test_execute_sell_up(default_conf, ticker, ticker_sell_up, mocker):
|
||||||
|
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||||
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
|
||||||
|
mocker.patch('freqtrade.rpc.init', MagicMock())
|
||||||
|
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker)
|
||||||
|
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
|
||||||
|
ticker=MagicMock(return_value={'price_usd': 15000.0}),
|
||||||
|
_cache_symbols=MagicMock(return_value={'BTC': 1}))
|
||||||
|
init(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
# Create some test data
|
||||||
|
create_trade(0.001)
|
||||||
|
|
||||||
|
trade = Trade.query.first()
|
||||||
|
assert trade
|
||||||
|
|
||||||
|
# Increase the price and sell it
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker_sell_up)
|
||||||
|
|
||||||
|
execute_sell(trade=trade, limit=ticker_sell_up()['bid'])
|
||||||
|
|
||||||
|
assert rpc_mock.call_count == 2
|
||||||
|
assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert 'profit: ~6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_execute_sell_down(default_conf, ticker, ticker_sell_down, mocker):
|
||||||
|
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||||
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
|
||||||
|
mocker.patch('freqtrade.rpc.init', MagicMock())
|
||||||
|
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.rpc.telegram',
|
||||||
|
_CONF=default_conf,
|
||||||
|
init=MagicMock(),
|
||||||
|
send_msg=MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker)
|
||||||
|
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
|
||||||
|
ticker=MagicMock(return_value={'price_usd': 15000.0}),
|
||||||
|
_cache_symbols=MagicMock(return_value={'BTC': 1}))
|
||||||
|
init(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
# Create some test data
|
||||||
|
create_trade(0.001)
|
||||||
|
|
||||||
|
trade = Trade.query.first()
|
||||||
|
assert trade
|
||||||
|
|
||||||
|
# Decrease the price and sell it
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker_sell_down)
|
||||||
|
|
||||||
|
execute_sell(trade=trade, limit=ticker_sell_down()['bid'])
|
||||||
|
|
||||||
|
assert rpc_mock.call_count == 2
|
||||||
|
assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert 'profit: ~-5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_execute_sell_without_conf(default_conf, ticker, ticker_sell_up, mocker):
|
||||||
|
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||||
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
|
||||||
|
mocker.patch('freqtrade.rpc.init', MagicMock())
|
||||||
|
rpc_mock = mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker)
|
||||||
|
init(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
# Create some test data
|
||||||
|
create_trade(0.001)
|
||||||
|
|
||||||
|
trade = Trade.query.first()
|
||||||
|
assert trade
|
||||||
|
|
||||||
|
# Increase the price and sell it
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker_sell_up)
|
||||||
|
mocker.patch('freqtrade.main._CONF', {})
|
||||||
|
|
||||||
|
execute_sell(trade=trade, limit=ticker_sell_up()['bid'])
|
||||||
|
|
||||||
|
assert rpc_mock.call_count == 2
|
||||||
|
assert 'Selling [BTC/ETH]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert '(profit: ~6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
assert 'USD' not in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
Loading…
Reference in New Issue
Block a user