Merge branch 'develop' into partial_sell2

This commit is contained in:
மனோஜ்குமார் பழனிச்சாமி
2022-04-09 16:24:57 +05:30
committed by GitHub
62 changed files with 685 additions and 562 deletions

View File

@@ -140,9 +140,9 @@ class UnfilledTimeout(BaseModel):
class OrderTypes(BaseModel):
entry: OrderTypeValues
exit: OrderTypeValues
emergencyexit: Optional[OrderTypeValues]
forceexit: Optional[OrderTypeValues]
forceentry: Optional[OrderTypeValues]
emergency_exit: Optional[OrderTypeValues]
force_exit: Optional[OrderTypeValues]
force_entry: Optional[OrderTypeValues]
stoploss: OrderTypeValues
stoploss_on_exchange: bool
stoploss_on_exchange_interval: Optional[int]
@@ -174,7 +174,7 @@ class ShowConfig(BaseModel):
timeframe_min: int
exchange: str
strategy: Optional[str]
forcebuy_enabled: bool
force_entry_enable: bool
exit_pricing: Dict[str, Any]
entry_pricing: Dict[str, Any]
bot_name: str

View File

@@ -135,13 +135,13 @@ def show_config(rpc: Optional[RPC] = Depends(get_rpc_optional), config=Depends(g
return resp
# /forcebuy is deprecated with short addition. use ForceEntry instead
# /forcebuy is deprecated with short addition. use /forceentry instead
@router.post('/forceenter', response_model=ForceEnterResponse, tags=['trading'])
@router.post('/forcebuy', response_model=ForceEnterResponse, tags=['trading'])
def forceentry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)):
def force_entry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)):
ordertype = payload.ordertype.value if payload.ordertype else None
stake_amount = payload.stakeamount if payload.stakeamount else None
entry_tag = payload.entry_tag if payload.entry_tag else 'forceentry'
entry_tag = payload.entry_tag if payload.entry_tag else 'force_entry'
trade = rpc._rpc_force_entry(payload.pair, payload.price, order_side=payload.side,
order_type=ordertype, stake_amount=stake_amount,
@@ -154,11 +154,12 @@ def forceentry(payload: ForceEnterPayload, rpc: RPC = Depends(get_rpc)):
{"status": f"Error entering {payload.side} trade for pair {payload.pair}."})
# /forcesell is deprecated with short addition. use /forceexit instead
@router.post('/forceexit', response_model=ResultMsg, tags=['trading'])
@router.post('/forcesell', response_model=ResultMsg, tags=['trading'])
def forcesell(payload: ForceExitPayload, rpc: RPC = Depends(get_rpc)):
ordertype = payload.ordertype.value if payload.ordertype else None
return rpc._rpc_forceexit(payload.tradeid, ordertype)
return rpc._rpc_force_exit(payload.tradeid, ordertype)
@router.get('/blacklist', response_model=BlacklistResponse, tags=['info', 'pairlist'])

View File

@@ -86,7 +86,7 @@ class CryptoToFiatConverter:
return None
else:
return None
found = [x for x in self._coinlistings if x['symbol'] == crypto_symbol]
found = [x for x in self._coinlistings if x['symbol'].lower() == crypto_symbol]
if crypto_symbol in coingecko_mapping.keys():
found = [x for x in self._coinlistings if x['id'] == coingecko_mapping[crypto_symbol]]

View File

@@ -136,7 +136,7 @@ class RPC:
) if 'timeframe' in config else 0,
'exchange': config['exchange']['name'],
'strategy': config['strategy'],
'forcebuy_enabled': config.get('forcebuy_enable', False),
'force_entry_enable': config.get('force_entry_enable', False),
'exit_pricing': config.get('exit_pricing', {}),
'entry_pricing': config.get('entry_pricing', {}),
'state': str(botstate),
@@ -684,7 +684,7 @@ class RPC:
return {'status': 'No more buy will occur from now. Run /reload_config to reset.'}
def _rpc_forceexit(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>.
Sells the given trade at current price
@@ -695,7 +695,7 @@ class RPC:
if trade.open_order_id:
order = self._freqtrade.exchange.fetch_order(trade.open_order_id, trade.pair)
if order['side'] == trade.enter_side:
if order['side'] == trade.entry_side:
fully_canceled = self._freqtrade.handle_cancel_enter(
trade, order, CANCEL_REASON['FORCE_EXIT'])
@@ -709,7 +709,7 @@ class RPC:
trade.pair, side='exit', is_short=trade.is_short, refresh=True)
exit_check = ExitCheckTuple(exit_type=ExitType.FORCE_EXIT)
order_type = ordertype or self._freqtrade.strategy.order_types.get(
"forceexit", self._freqtrade.strategy.order_types["exit"])
"force_exit", self._freqtrade.strategy.order_types["exit"])
self._freqtrade.execute_trade_exit(
trade, current_rate, exit_check, ordertype=order_type)
@@ -732,7 +732,7 @@ class RPC:
trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True), ]
).first()
if not trade:
logger.warning('forceexit: Invalid argument received')
logger.warning('force_exit: Invalid argument received')
raise RPCException('invalid argument')
_exec_forcesell(trade)
@@ -744,14 +744,14 @@ class RPC:
order_type: Optional[str] = None,
order_side: SignalDirection = SignalDirection.LONG,
stake_amount: Optional[float] = None,
enter_tag: Optional[str] = 'forceentry') -> Optional[Trade]:
enter_tag: Optional[str] = 'force_entry') -> Optional[Trade]:
"""
Handler for forcebuy <asset> <price>
Buys a pair trade at the given or current price
"""
if not self._freqtrade.config.get('forcebuy_enable', False):
raise RPCException('Forceentry not enabled.')
if not self._freqtrade.config.get('force_entry_enable', False):
raise RPCException('Force_entry not enabled.')
if self._freqtrade.state != State.RUNNING:
raise RPCException('trader is not running')
@@ -781,7 +781,7 @@ class RPC:
# execute buy
if not order_type:
order_type = self._freqtrade.strategy.order_types.get(
'forceentry', self._freqtrade.strategy.order_types['entry'])
'force_entry', self._freqtrade.strategy.order_types['entry'])
if self._freqtrade.execute_entry(pair, stake_amount, price,
ordertype=order_type, trade=trade,
is_short=is_short,
@@ -791,7 +791,7 @@ class RPC:
trade = Trade.get_trades([Trade.is_open.is_(True), Trade.pair == pair]).first()
return trade
else:
return None
raise RPCException(f'Failed to enter position for {pair}.')
def _rpc_delete(self, trade_id: int) -> Dict[str, Union[str, int]]:
"""

View File

@@ -153,11 +153,11 @@ class Telegram(RPCHandler):
CommandHandler('balance', self._balance),
CommandHandler('start', self._start),
CommandHandler('stop', self._stop),
CommandHandler(['forcesell', 'forceexit'], self._forceexit),
CommandHandler(['forcesell', 'forceexit', 'fx'], self._force_exit),
CommandHandler(['forcebuy', 'forcelong'], partial(
self._forceenter, order_side=SignalDirection.LONG)),
self._force_enter, order_side=SignalDirection.LONG)),
CommandHandler('forceshort', partial(
self._forceenter, order_side=SignalDirection.SHORT)),
self._force_enter, order_side=SignalDirection.SHORT)),
CommandHandler('trades', self._trades),
CommandHandler('delete', self._delete_trade),
CommandHandler('performance', self._performance),
@@ -197,7 +197,7 @@ class Telegram(RPCHandler):
pattern='update_exit_reason_performance'),
CallbackQueryHandler(self._mix_tag_performance, pattern='update_mix_tag_performance'),
CallbackQueryHandler(self._count, pattern='update_count'),
CallbackQueryHandler(self._forceenter_inline),
CallbackQueryHandler(self._force_enter_inline),
]
for handle in handles:
self._updater.dispatcher.add_handler(handle)
@@ -233,11 +233,11 @@ class Telegram(RPCHandler):
is_fill = msg['type'] in [RPCMessageType.ENTRY_FILL]
emoji = '\N{CHECK MARK}' if is_fill else '\N{LARGE BLUE CIRCLE}'
enter_side = ({'enter': 'Long', 'entered': 'Longed'} if msg['direction'] == 'Long'
entry_side = ({'enter': 'Long', 'entered': 'Longed'} if msg['direction'] == 'Long'
else {'enter': 'Short', 'entered': 'Shorted'})
message = (
f"{emoji} *{msg['exchange']}:*"
f" {enter_side['entered'] if is_fill else enter_side['enter']} {msg['pair']}"
f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}"
f" (#{msg['trade_id']})\n"
)
message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag', None) else ""
@@ -974,7 +974,7 @@ class Telegram(RPCHandler):
self._send_msg('Status: `{status}`'.format(**msg))
@authorized_only
def _forceexit(self, update: Update, context: CallbackContext) -> None:
def _force_exit(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /forcesell <id>.
Sells the given trade at current price
@@ -988,20 +988,20 @@ class Telegram(RPCHandler):
self._send_msg("You must specify a trade-id or 'all'.")
return
try:
msg = self._rpc._rpc_forceexit(trade_id)
self._send_msg('Forceexit Result: `{result}`'.format(**msg))
msg = self._rpc._rpc_force_exit(trade_id)
self._send_msg('Force_exit Result: `{result}`'.format(**msg))
except RPCException as e:
self._send_msg(str(e))
def _forceenter_action(self, pair, price: Optional[float], order_side: SignalDirection):
def _force_enter_action(self, pair, price: Optional[float], order_side: SignalDirection):
if pair != 'cancel':
try:
self._rpc._rpc_force_entry(pair, price, order_side=order_side)
except RPCException as e:
self._send_msg(str(e))
def _forceenter_inline(self, update: Update, _: CallbackContext) -> None:
def _force_enter_inline(self, update: Update, _: CallbackContext) -> None:
if update.callback_query:
query = update.callback_query
if query.data and '_||_' in query.data:
@@ -1009,7 +1009,7 @@ class Telegram(RPCHandler):
order_side = SignalDirection(side)
query.answer()
query.edit_message_text(text=f"Manually entering {order_side} for {pair}")
self._forceenter_action(pair, None, order_side)
self._force_enter_action(pair, None, order_side)
@staticmethod
def _layout_inline_keyboard(buttons: List[InlineKeyboardButton],
@@ -1017,7 +1017,7 @@ class Telegram(RPCHandler):
return [buttons[i:i + cols] for i in range(0, len(buttons), cols)]
@authorized_only
def _forceenter(
def _force_enter(
self, update: Update, context: CallbackContext, order_side: SignalDirection) -> None:
"""
Handler for /forcelong <asset> <price> and `/forceshort <asset> <price>
@@ -1029,7 +1029,7 @@ class Telegram(RPCHandler):
if context.args:
pair = context.args[0]
price = float(context.args[1]) if len(context.args) > 1 else None
self._forceenter_action(pair, price, order_side)
self._force_enter_action(pair, price, order_side)
else:
whitelist = self._rpc._rpc_whitelist()['whitelist']
pair_buttons = [
@@ -1407,23 +1407,25 @@ class Telegram(RPCHandler):
:param update: message update
:return: None
"""
forceenter_text = ("*/forcelong <pair> [<rate>]:* `Instantly buys the given pair. "
"Optionally takes a rate at which to buy "
"(only applies to limit orders).` \n"
)
force_enter_text = ("*/forcelong <pair> [<rate>]:* `Instantly buys the given pair. "
"Optionally takes a rate at which to buy "
"(only applies to limit orders).` \n"
)
if self._rpc._freqtrade.trading_mode != TradingMode.SPOT:
forceenter_text += ("*/forceshort <pair> [<rate>]:* `Instantly shorts the given pair. "
"Optionally takes a rate at which to sell "
"(only applies to limit orders).` \n")
force_enter_text += ("*/forceshort <pair> [<rate>]:* `Instantly shorts the given pair. "
"Optionally takes a rate at which to sell "
"(only applies to limit orders).` \n")
message = (
"_BotControl_\n"
"------------\n"
"*/start:* `Starts the trader`\n"
"*/stop:* Stops the trader\n"
"*/stopbuy:* `Stops buying, but handles open trades gracefully` \n"
# TODO: forceenter forceshort forcelong missing
"*/forceexit <trade_id>|all:* `Instantly exits the given trade or all trades, "
"regardless of profit`\n"
f"{forceenter_text if self._config.get('forcebuy_enable', False) else ''}"
"*/fe <trade_id>|all:* `Alias to /forceexit`"
f"{force_enter_text if self._config.get('force_entry_enable', False) else ''}"
"*/delete <trade_id>:* `Instantly delete the given trade in the database`\n"
"*/whitelist:* `Show current whitelist` \n"
"*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs "