Merge pull request #942 from xmatthias/feat/buy_on_sell_first

Introduce ignore_roi_if_buy_signal parameter to avoid sell/buy scenarios
This commit is contained in:
Michael Egger 2018-06-23 13:42:03 +02:00 committed by GitHub
commit df9015a7f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 19 deletions

View File

@ -31,7 +31,8 @@
},
"experimental": {
"use_sell_signal": false,
"sell_profit_only": false
"sell_profit_only": false,
"ignore_roi_if_buy_signal": false
},
"telegram": {
"enabled": true,

View File

@ -38,7 +38,8 @@
},
"experimental": {
"use_sell_signal": false,
"sell_profit_only": false
"sell_profit_only": false,
"ignore_roi_if_buy_signal": false
},
"telegram": {
"enabled": true,

View File

@ -31,6 +31,7 @@ The table below will list all configuration parameters.
| `exchange.pair_blacklist` | [] | No | List of currency the bot must avoid. Useful when using `--dynamic-whitelist` param.
| `experimental.use_sell_signal` | false | No | Use your sell strategy in addition of the `minimal_roi`.
| `experimental.sell_profit_only` | false | No | waits until you have made a positive profit before taking a sell decision.
| `experimental.ignore_roi_if_buy_signal` | false | No | Does not sell if the buy-signal is still active. Takes preference over `minimal_roi` and `use_sell_signal`
| `telegram.enabled` | true | Yes | Enable or not the usage of Telegram.
| `telegram.token` | token | No | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
| `telegram.chat_id` | chat_id | No | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.

View File

@ -172,33 +172,45 @@ class Analyze(object):
if the threshold is reached and updates the trade record.
:return: True if trade should be sold, False otherwise
"""
current_profit = trade.calc_profit_percent(rate)
if self.stop_loss_reached(current_profit=current_profit):
return True
experimental = self.config.get('experimental', {})
if buy and experimental.get('ignore_roi_if_buy_signal', False):
logger.debug('Buy signal still active - not selling.')
return False
# Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee)
if self.min_roi_reached(trade=trade, current_rate=rate, current_time=date):
if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date):
logger.debug('Required profit reached. Selling..')
return True
# Experimental: Check if the trade is profitable before selling it (avoid selling at loss)
if self.config.get('experimental', {}).get('sell_profit_only', False):
if experimental.get('sell_profit_only', False):
logger.debug('Checking if trade is profitable..')
if trade.calc_profit(rate=rate) <= 0:
return False
if sell and not buy and self.config.get('experimental', {}).get('use_sell_signal', False):
if sell and not buy and experimental.get('use_sell_signal', False):
logger.debug('Sell signal received. Selling..')
return True
return False
def min_roi_reached(self, trade: Trade, current_rate: float, current_time: datetime) -> bool:
def stop_loss_reached(self, current_profit: float) -> bool:
"""Based on current profit of the trade and configured stoploss, decides to sell or not"""
if self.strategy.stoploss is not None and current_profit < self.strategy.stoploss:
logger.debug('Stop loss hit.')
return True
return False
def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool:
"""
Based an earlier trade and current price and ROI configuration, decides whether bot should
sell
:return True if bot should sell at current rate
"""
current_profit = trade.calc_profit_percent(current_rate)
if self.strategy.stoploss is not None and current_profit < self.strategy.stoploss:
logger.debug('Stop loss hit.')
return True
# Check if time matches and current rate is above threshold
time_diff = (current_time.timestamp() - trade.open_date.timestamp()) / 60

View File

@ -73,7 +73,8 @@ CONF_SCHEMA = {
'type': 'object',
'properties': {
'use_sell_signal': {'type': 'boolean'},
'sell_profit_only': {'type': 'boolean'}
'sell_profit_only': {'type': 'boolean'},
"ignore_roi_if_buy_signal_true": {'type': 'boolean'}
}
},
'telegram': {

View File

@ -423,8 +423,8 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
current_rate = self.exchange.get_ticker(trade.pair)['bid']
(buy, sell) = (False, False)
if self.config.get('experimental', {}).get('use_sell_signal'):
experimental = self.config.get('experimental', {})
if experimental.get('use_sell_signal') or experimental.get('ignore_roi_if_buy_signal'):
(buy, sell) = self.analyze.get_signal(self.exchange,
trade.pair, self.analyze.get_ticker_interval())

View File

@ -1274,7 +1274,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker
patch_get_signal(mocker)
patch_RPCManager(mocker)
patch_coinmarketcap(mocker)
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=False)
mocker.patch('freqtrade.freqtradebot.Analyze.stop_loss_reached', return_value=False)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
@ -1312,9 +1312,9 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
'bid': 0.00000172,
'ask': 0.00000173,
'last': 0.00000172
'bid': 0.0000172,
'ask': 0.0000173,
'last': 0.0000172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
@ -1335,6 +1335,83 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke
assert freqtrade.handle_trade(trade) is True
def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> None:
"""
Test sell_profit_only feature when enabled and we have a loss
"""
patch_get_signal(mocker)
patch_RPCManager(mocker)
patch_coinmarketcap(mocker)
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=True)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
'bid': 0.0000172,
'ask': 0.0000173,
'last': 0.0000172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
conf = deepcopy(default_conf)
conf['experimental'] = {
'ignore_roi_if_buy_signal': True
}
freqtrade = FreqtradeBot(conf)
freqtrade.create_trade()
trade = Trade.query.first()
trade.update(limit_buy_order)
patch_get_signal(mocker, value=(True, True))
assert freqtrade.handle_trade(trade) is False
# Test if buy-signal is absent (should sell due to roi = true)
patch_get_signal(mocker, value=(False, True))
assert freqtrade.handle_trade(trade) is True
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> None:
"""
Test sell_profit_only feature when enabled and we have a loss
"""
patch_get_signal(mocker)
patch_RPCManager(mocker)
patch_coinmarketcap(mocker)
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=True)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
get_ticker=MagicMock(return_value={
'bid': 0.00000172,
'ask': 0.00000173,
'last': 0.00000172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
conf = deepcopy(default_conf)
conf['experimental'] = {
'ignore_roi_if_buy_signal': False
}
freqtrade = FreqtradeBot(conf)
freqtrade.create_trade()
trade = Trade.query.first()
trade.update(limit_buy_order)
# Sell due to min_roi_reached
patch_get_signal(mocker, value=(True, True))
assert freqtrade.handle_trade(trade) is True
# Test if buy-signal is absent
patch_get_signal(mocker, value=(False, True))
assert freqtrade.handle_trade(trade) is True
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
"""
Test get_real_amount - fee in quote currency