Merge pull request #4469 from freqtrade/rpc/locks
Add RPC methods to remove locks
This commit is contained in:
@@ -765,6 +765,7 @@ class PairLock(_DECL_BASE):
|
||||
|
||||
def to_json(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'id': self.id,
|
||||
'pair': self.pair,
|
||||
'lock_time': self.lock_time.strftime(DATETIME_PRINT_FORMAT),
|
||||
'lock_timestamp': int(self.lock_time.replace(tzinfo=timezone.utc).timestamp() * 1000),
|
||||
|
@@ -210,6 +210,7 @@ class ForceBuyResponse(BaseModel):
|
||||
|
||||
|
||||
class LockModel(BaseModel):
|
||||
id: int
|
||||
active: bool
|
||||
lock_end_time: str
|
||||
lock_end_timestamp: int
|
||||
@@ -224,6 +225,11 @@ class Locks(BaseModel):
|
||||
locks: List[LockModel]
|
||||
|
||||
|
||||
class DeleteLockRequest(BaseModel):
|
||||
pair: Optional[str]
|
||||
lockid: Optional[int]
|
||||
|
||||
|
||||
class Logs(BaseModel):
|
||||
log_count: int
|
||||
logs: List[List]
|
||||
|
@@ -11,13 +11,14 @@ from freqtrade.data.history import get_datahandler
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.rpc import RPC
|
||||
from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, BlacklistPayload,
|
||||
BlacklistResponse, Count, Daily, DeleteTrade,
|
||||
ForceBuyPayload, ForceBuyResponse,
|
||||
ForceSellPayload, Locks, Logs, OpenTradeSchema,
|
||||
PairHistory, PerformanceEntry, Ping, PlotConfig,
|
||||
Profit, ResultMsg, ShowConfig, Stats, StatusMsg,
|
||||
StrategyListResponse, StrategyResponse,
|
||||
TradeResponse, Version, WhitelistResponse)
|
||||
BlacklistResponse, Count, Daily,
|
||||
DeleteLockRequest, DeleteTrade, ForceBuyPayload,
|
||||
ForceBuyResponse, ForceSellPayload, Locks, Logs,
|
||||
OpenTradeSchema, PairHistory, PerformanceEntry,
|
||||
Ping, PlotConfig, Profit, ResultMsg, ShowConfig,
|
||||
Stats, StatusMsg, StrategyListResponse,
|
||||
StrategyResponse, TradeResponse, Version,
|
||||
WhitelistResponse)
|
||||
from freqtrade.rpc.api_server.deps import get_config, get_rpc, get_rpc_optional
|
||||
from freqtrade.rpc.rpc import RPCException
|
||||
|
||||
@@ -136,11 +137,21 @@ def whitelist(rpc: RPC = Depends(get_rpc)):
|
||||
return rpc._rpc_whitelist()
|
||||
|
||||
|
||||
@router.get('/locks', response_model=Locks, tags=['info'])
|
||||
@router.get('/locks', response_model=Locks, tags=['info', 'locks'])
|
||||
def locks(rpc: RPC = Depends(get_rpc)):
|
||||
return rpc._rpc_locks()
|
||||
|
||||
|
||||
@router.delete('/locks/{lockid}', response_model=Locks, tags=['info', 'locks'])
|
||||
def delete_lock(lockid: int, rpc: RPC = Depends(get_rpc)):
|
||||
return rpc._rpc_delete_lock(lockid=lockid)
|
||||
|
||||
|
||||
@router.post('/locks/delete', response_model=Locks, tags=['info', 'locks'])
|
||||
def delete_lock_pair(payload: DeleteLockRequest, rpc: RPC = Depends(get_rpc)):
|
||||
return rpc._rpc_delete_lock(lockid=payload.lockid, pair=payload.pair)
|
||||
|
||||
|
||||
@router.get('/logs', response_model=Logs, tags=['info'])
|
||||
def logs(limit: Optional[int] = None, rpc: RPC = Depends(get_rpc)):
|
||||
return rpc._rpc_get_logs(limit)
|
||||
|
@@ -3,7 +3,7 @@ This module contains class to define a RPC communications
|
||||
"""
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
from datetime import date, datetime, timedelta
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from enum import Enum
|
||||
from math import isnan
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
@@ -20,6 +20,7 @@ from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
||||
from freqtrade.loggers import bufferHandler
|
||||
from freqtrade.misc import shorten_date
|
||||
from freqtrade.persistence import PairLocks, Trade
|
||||
from freqtrade.persistence.models import PairLock
|
||||
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||
from freqtrade.state import State
|
||||
@@ -663,7 +664,7 @@ class RPC:
|
||||
}
|
||||
|
||||
def _rpc_locks(self) -> Dict[str, Any]:
|
||||
""" Returns the current locks"""
|
||||
""" Returns the current locks """
|
||||
|
||||
locks = PairLocks.get_pair_locks(None)
|
||||
return {
|
||||
@@ -671,6 +672,25 @@ class RPC:
|
||||
'locks': [lock.to_json() for lock in locks]
|
||||
}
|
||||
|
||||
def _rpc_delete_lock(self, lockid: Optional[int] = None,
|
||||
pair: Optional[str] = None) -> Dict[str, Any]:
|
||||
""" Delete specific lock(s) """
|
||||
locks = []
|
||||
|
||||
if pair:
|
||||
locks = PairLocks.get_pair_locks(pair)
|
||||
if lockid:
|
||||
locks = PairLock.query.filter(PairLock.id == lockid).all()
|
||||
|
||||
for lock in locks:
|
||||
lock.active = False
|
||||
lock.lock_end_time = datetime.now(timezone.utc)
|
||||
|
||||
# session is always the same
|
||||
PairLock.session.flush()
|
||||
|
||||
return self._rpc_locks()
|
||||
|
||||
def _rpc_whitelist(self) -> Dict:
|
||||
""" Returns the currently active whitelist"""
|
||||
res = {'method': self._freqtrade.pairlists.name_list,
|
||||
|
@@ -6,6 +6,7 @@ This module manage Telegram communication
|
||||
import json
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from html import escape
|
||||
from itertools import chain
|
||||
from typing import Any, Callable, Dict, List, Union
|
||||
|
||||
@@ -144,6 +145,7 @@ class Telegram(RPCHandler):
|
||||
CommandHandler('daily', self._daily),
|
||||
CommandHandler('count', self._count),
|
||||
CommandHandler('locks', self._locks),
|
||||
CommandHandler(['unlock', 'delete_locks'], self._delete_locks),
|
||||
CommandHandler(['reload_config', 'reload_conf'], self._reload_config),
|
||||
CommandHandler(['show_config', 'show_conf'], self._show_config),
|
||||
CommandHandler('stopbuy', self._stopbuy),
|
||||
@@ -719,19 +721,35 @@ class Telegram(RPCHandler):
|
||||
Handler for /locks.
|
||||
Returns the currently active locks
|
||||
"""
|
||||
try:
|
||||
locks = self._rpc._rpc_locks()
|
||||
message = tabulate([[
|
||||
lock['pair'],
|
||||
lock['lock_end_time'],
|
||||
lock['reason']] for lock in locks['locks']],
|
||||
headers=['Pair', 'Until', 'Reason'],
|
||||
tablefmt='simple')
|
||||
message = "<pre>{}</pre>".format(message)
|
||||
logger.debug(message)
|
||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||
except RPCException as e:
|
||||
self._send_msg(str(e))
|
||||
locks = self._rpc._rpc_locks()
|
||||
message = tabulate([[
|
||||
lock['id'],
|
||||
lock['pair'],
|
||||
lock['lock_end_time'],
|
||||
lock['reason']] for lock in locks['locks']],
|
||||
headers=['ID', 'Pair', 'Until', 'Reason'],
|
||||
tablefmt='simple')
|
||||
message = f"<pre>{escape(message)}</pre>"
|
||||
logger.debug(message)
|
||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||
|
||||
@authorized_only
|
||||
def _delete_locks(self, update: Update, context: CallbackContext) -> None:
|
||||
"""
|
||||
Handler for /delete_locks.
|
||||
Returns the currently active locks
|
||||
"""
|
||||
arg = context.args[0] if context.args and len(context.args) > 0 else None
|
||||
lockid = None
|
||||
pair = None
|
||||
if arg:
|
||||
try:
|
||||
lockid = int(arg)
|
||||
except ValueError:
|
||||
pair = arg
|
||||
|
||||
self._rpc._rpc_delete_lock(lockid=lockid, pair=pair)
|
||||
self._locks(update, context)
|
||||
|
||||
@authorized_only
|
||||
def _whitelist(self, update: Update, context: CallbackContext) -> None:
|
||||
@@ -850,6 +868,7 @@ class Telegram(RPCHandler):
|
||||
"Avg. holding durationsfor buys and sells.`\n"
|
||||
"*/count:* `Show number of active trades compared to allowed number of trades`\n"
|
||||
"*/locks:* `Show currently locked pairs`\n"
|
||||
"*/unlock <pair|id>:* `Unlock this Pair (or this lock id if it's numeric)`\n"
|
||||
"*/balance:* `Show account balance per currency`\n"
|
||||
"*/stopbuy:* `Stops buying, but handles open trades gracefully` \n"
|
||||
"*/reload_config:* `Reload configuration file` \n"
|
||||
|
Reference in New Issue
Block a user