Update more terminology to forceexit
This commit is contained in:
parent
77c840c2a4
commit
68fe7476c9
@ -417,7 +417,7 @@ class Backtesting:
|
|||||||
roi_entry, roi = self.strategy.min_roi_reached_entry(trade_dur)
|
roi_entry, roi = self.strategy.min_roi_reached_entry(trade_dur)
|
||||||
if roi is not None and roi_entry is not None:
|
if roi is not None and roi_entry is not None:
|
||||||
if roi == -1 and roi_entry % self.timeframe_min == 0:
|
if roi == -1 and roi_entry % self.timeframe_min == 0:
|
||||||
# When forceselling with ROI=-1, the roi time will always be equal to trade_dur.
|
# When force_exiting with ROI=-1, the roi time will always be equal to trade_dur.
|
||||||
# If that entry is a multiple of the timeframe (so on candle open)
|
# If that entry is a multiple of the timeframe (so on candle open)
|
||||||
# - we'll use open instead of close
|
# - we'll use open instead of close
|
||||||
return row[OPEN_IDX]
|
return row[OPEN_IDX]
|
||||||
|
@ -157,7 +157,7 @@ def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)):
|
|||||||
# /forcesell is deprecated with short addition. use /forceexit instead
|
# /forcesell is deprecated with short addition. use /forceexit instead
|
||||||
@router.post('/forceexit', response_model=ResultMsg, tags=['trading'])
|
@router.post('/forceexit', response_model=ResultMsg, tags=['trading'])
|
||||||
@router.post('/forcesell', response_model=ResultMsg, tags=['trading'])
|
@router.post('/forcesell', response_model=ResultMsg, tags=['trading'])
|
||||||
def forcesell(payload: ForceExitPayload, rpc: RPC = Depends(get_rpc)):
|
def forceexit(payload: ForceExitPayload, rpc: RPC = Depends(get_rpc)):
|
||||||
ordertype = payload.ordertype.value if payload.ordertype else None
|
ordertype = payload.ordertype.value if payload.ordertype else None
|
||||||
return rpc._rpc_force_exit(payload.tradeid, ordertype)
|
return rpc._rpc_force_exit(payload.tradeid, ordertype)
|
||||||
|
|
||||||
|
@ -690,10 +690,10 @@ class RPC:
|
|||||||
|
|
||||||
def _rpc_force_exit(self, trade_id: str, ordertype: Optional[str] = None) -> Dict[str, str]:
|
def _rpc_force_exit(self, trade_id: str, ordertype: Optional[str] = None) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Handler for forcesell <id>.
|
Handler for forceexit <id>.
|
||||||
Sells the given trade at current price
|
Sells the given trade at current price
|
||||||
"""
|
"""
|
||||||
def _exec_forcesell(trade: Trade) -> None:
|
def _exec_force_exit(trade: Trade) -> None:
|
||||||
# Check if there is there is an open order
|
# Check if there is there is an open order
|
||||||
fully_canceled = False
|
fully_canceled = False
|
||||||
if trade.open_order_id:
|
if trade.open_order_id:
|
||||||
@ -726,7 +726,7 @@ class RPC:
|
|||||||
if trade_id == 'all':
|
if trade_id == 'all':
|
||||||
# Execute sell for all open orders
|
# Execute sell for all open orders
|
||||||
for trade in Trade.get_open_trades():
|
for trade in Trade.get_open_trades():
|
||||||
_exec_forcesell(trade)
|
_exec_force_exit(trade)
|
||||||
Trade.commit()
|
Trade.commit()
|
||||||
self._freqtrade.wallets.update()
|
self._freqtrade.wallets.update()
|
||||||
return {'result': 'Created sell orders for all open trades.'}
|
return {'result': 'Created sell orders for all open trades.'}
|
||||||
@ -739,7 +739,7 @@ class RPC:
|
|||||||
logger.warning('force_exit: Invalid argument received')
|
logger.warning('force_exit: Invalid argument received')
|
||||||
raise RPCException('invalid argument')
|
raise RPCException('invalid argument')
|
||||||
|
|
||||||
_exec_forcesell(trade)
|
_exec_force_exit(trade)
|
||||||
Trade.commit()
|
Trade.commit()
|
||||||
self._freqtrade.wallets.update()
|
self._freqtrade.wallets.update()
|
||||||
return {'result': f'Created sell order for trade {trade_id}.'}
|
return {'result': f'Created sell order for trade {trade_id}.'}
|
||||||
|
@ -274,7 +274,7 @@ class Telegram(RPCHandler):
|
|||||||
else "")
|
else "")
|
||||||
|
|
||||||
# Check if all sell properties are available.
|
# Check if all sell properties are available.
|
||||||
# This might not be the case if the message origin is triggered by /forcesell
|
# This might not be the case if the message origin is triggered by /forceexit
|
||||||
if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency'])
|
if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency'])
|
||||||
and self._rpc._fiat_converter):
|
and self._rpc._fiat_converter):
|
||||||
msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount(
|
msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount(
|
||||||
|
@ -275,14 +275,14 @@ class FtRestClient():
|
|||||||
}
|
}
|
||||||
return self._post("force_enter", data=data)
|
return self._post("force_enter", data=data)
|
||||||
|
|
||||||
def forcesell(self, tradeid):
|
def forceexit(self, tradeid):
|
||||||
"""Force-sell a trade.
|
"""Force-exit a trade.
|
||||||
|
|
||||||
:param tradeid: Id of the trade (can be received via status command)
|
:param tradeid: Id of the trade (can be received via status command)
|
||||||
:return: json object
|
:return: json object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self._post("forcesell", data={"tradeid": tradeid})
|
return self._post("forceexit", data={"tradeid": tradeid})
|
||||||
|
|
||||||
def strategies(self):
|
def strategies(self):
|
||||||
"""Lists available strategies
|
"""Lists available strategies
|
||||||
|
@ -251,7 +251,7 @@ tc15 = BTContainer(data=[
|
|||||||
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)]
|
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test 16: Buy, hold for 65 min, then forcesell using roi=-1
|
# Test 16: Buy, hold for 65 min, then forceexit using roi=-1
|
||||||
# Causes negative profit even though sell-reason is ROI.
|
# Causes negative profit even though sell-reason is ROI.
|
||||||
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 65 minutes (limits trade duration)
|
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 65 minutes (limits trade duration)
|
||||||
tc16 = BTContainer(data=[
|
tc16 = BTContainer(data=[
|
||||||
@ -259,14 +259,14 @@ tc16 = BTContainer(data=[
|
|||||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||||
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
||||||
[3, 4975, 5000, 4940, 4962, 6172, 0, 0], # ForceSell on ROI (roi=-1)
|
[3, 4975, 5000, 4940, 4962, 6172, 0, 0], # Forceexit on ROI (roi=-1)
|
||||||
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.10, roi={"0": 0.10, "65": -1}, profit_perc=-0.012,
|
stop_loss=-0.10, roi={"0": 0.10, "65": -1}, profit_perc=-0.012,
|
||||||
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
|
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test 17: Buy, hold for 120 mins, then forcesell using roi=-1
|
# Test 17: Buy, hold for 120 mins, then forceexit using roi=-1
|
||||||
# Causes negative profit even though sell-reason is ROI.
|
# Causes negative profit even though sell-reason is ROI.
|
||||||
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
|
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
|
||||||
# Uses open as sell-rate (special case) - since the roi-time is a multiple of the timeframe.
|
# Uses open as sell-rate (special case) - since the roi-time is a multiple of the timeframe.
|
||||||
@ -275,7 +275,7 @@ tc17 = BTContainer(data=[
|
|||||||
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
|
||||||
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||||
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
|
||||||
[3, 4980, 5000, 4940, 4962, 6172, 0, 0], # ForceSell on ROI (roi=-1)
|
[3, 4980, 5000, 4940, 4962, 6172, 0, 0], # Forceexit on ROI (roi=-1)
|
||||||
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.10, roi={"0": 0.10, "120": -1}, profit_perc=-0.004,
|
stop_loss=-0.10, roi={"0": 0.10, "120": -1}, profit_perc=-0.004,
|
||||||
|
@ -1182,7 +1182,7 @@ def test_api_force_entry(botclient, mocker, fee, endpoint):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_api_forcesell(botclient, mocker, ticker, fee, markets):
|
def test_api_forceexit(botclient, mocker, ticker, fee, markets):
|
||||||
ftbot, client = botclient
|
ftbot, client = botclient
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
@ -1194,15 +1194,15 @@ def test_api_forcesell(botclient, mocker, ticker, fee, markets):
|
|||||||
)
|
)
|
||||||
patch_get_signal(ftbot)
|
patch_get_signal(ftbot)
|
||||||
|
|
||||||
rc = client_post(client, f"{BASE_URI}/forcesell",
|
rc = client_post(client, f"{BASE_URI}/forceexit",
|
||||||
data='{"tradeid": "1"}')
|
data='{"tradeid": "1"}')
|
||||||
assert_response(rc, 502)
|
assert_response(rc, 502)
|
||||||
assert rc.json() == {"error": "Error querying /api/v1/forcesell: invalid argument"}
|
assert rc.json() == {"error": "Error querying /api/v1/forceexit: invalid argument"}
|
||||||
Trade.query.session.rollback()
|
Trade.query.session.rollback()
|
||||||
|
|
||||||
ftbot.enter_positions()
|
ftbot.enter_positions()
|
||||||
|
|
||||||
rc = client_post(client, f"{BASE_URI}/forcesell",
|
rc = client_post(client, f"{BASE_URI}/forceexit",
|
||||||
data='{"tradeid": "1"}')
|
data='{"tradeid": "1"}')
|
||||||
assert_response(rc)
|
assert_response(rc)
|
||||||
assert rc.json() == {'result': 'Created sell order for trade 1.'}
|
assert rc.json() == {'result': 'Created sell order for trade 1.'}
|
||||||
|
@ -1005,7 +1005,7 @@ def test_reload_config_handle(default_conf, update, mocker) -> None:
|
|||||||
assert 'Reloading config' in msg_mock.call_args_list[0][0][0]
|
assert 'Reloading config' in msg_mock.call_args_list[0][0][0]
|
||||||
|
|
||||||
|
|
||||||
def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
def test_telegram_forceexit_handle(default_conf, update, ticker, fee,
|
||||||
ticker_sell_up, mocker) -> None:
|
ticker_sell_up, mocker) -> None:
|
||||||
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
|
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||||
msg_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
msg_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
||||||
@ -1033,7 +1033,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
|||||||
# Increase the price and sell it
|
# Increase the price and sell it
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', ticker_sell_up)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', ticker_sell_up)
|
||||||
|
|
||||||
# /forcesell 1
|
# /forceexit 1
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
context.args = ["1"]
|
context.args = ["1"]
|
||||||
telegram._force_exit(update=update, context=context)
|
telegram._force_exit(update=update, context=context)
|
||||||
@ -1101,7 +1101,7 @@ def test_telegram_force_exit_down_handle(default_conf, update, ticker, fee,
|
|||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
assert trade
|
assert trade
|
||||||
|
|
||||||
# /forcesell 1
|
# /forceexit 1
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
context.args = ["1"]
|
context.args = ["1"]
|
||||||
telegram._force_exit(update=update, context=context)
|
telegram._force_exit(update=update, context=context)
|
||||||
@ -1137,7 +1137,7 @@ def test_telegram_force_exit_down_handle(default_conf, update, ticker, fee,
|
|||||||
} == last_msg
|
} == last_msg
|
||||||
|
|
||||||
|
|
||||||
def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None:
|
def test_forceexit_all_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
|
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
|
||||||
return_value=15000.0)
|
return_value=15000.0)
|
||||||
@ -1160,7 +1160,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
|||||||
freqtradebot.enter_positions()
|
freqtradebot.enter_positions()
|
||||||
msg_mock.reset_mock()
|
msg_mock.reset_mock()
|
||||||
|
|
||||||
# /forcesell all
|
# /forceexit all
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
context.args = ["all"]
|
context.args = ["all"]
|
||||||
telegram._force_exit(update=update, context=context)
|
telegram._force_exit(update=update, context=context)
|
||||||
@ -1196,7 +1196,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
|||||||
} == msg
|
} == msg
|
||||||
|
|
||||||
|
|
||||||
def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
def test_forceexit_handle_invalid(default_conf, update, mocker) -> None:
|
||||||
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
|
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
|
||||||
return_value=15000.0)
|
return_value=15000.0)
|
||||||
|
|
||||||
@ -1205,7 +1205,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
|||||||
|
|
||||||
# Trader is not running
|
# Trader is not running
|
||||||
freqtradebot.state = State.STOPPED
|
freqtradebot.state = State.STOPPED
|
||||||
# /forcesell 1
|
# /forceexit 1
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
context.args = ["1"]
|
context.args = ["1"]
|
||||||
telegram._force_exit(update=update, context=context)
|
telegram._force_exit(update=update, context=context)
|
||||||
@ -1215,7 +1215,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
|||||||
# Invalid argument
|
# Invalid argument
|
||||||
msg_mock.reset_mock()
|
msg_mock.reset_mock()
|
||||||
freqtradebot.state = State.RUNNING
|
freqtradebot.state = State.RUNNING
|
||||||
# /forcesell 123456
|
# /forceexit 123456
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
context.args = ["123456"]
|
context.args = ["123456"]
|
||||||
telegram._force_exit(update=update, context=context)
|
telegram._force_exit(update=update, context=context)
|
||||||
|
Loading…
Reference in New Issue
Block a user