Refactor RPC modules so handlers don't inherit RPC directly
This commit is contained in:
parent
1508e08ea5
commit
a87c273903
@ -1,3 +1,3 @@
|
|||||||
# flake8: noqa: F401
|
# flake8: noqa: F401
|
||||||
from .rpc import RPC, RPCException, RPCMessageType
|
from .rpc import RPC, RPCException, RPCHandler, RPCMessageType
|
||||||
from .rpc_manager import RPCManager
|
from .rpc_manager import RPCManager
|
||||||
|
@ -20,7 +20,7 @@ from freqtrade.__init__ import __version__
|
|||||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, USERPATH_STRATEGIES
|
from freqtrade.constants import DATETIME_PRINT_FORMAT, USERPATH_STRATEGIES
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc.rpc import RPC, RPCException
|
from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -78,7 +78,7 @@ def shutdown_session(exception=None):
|
|||||||
Trade.session.remove()
|
Trade.session.remove()
|
||||||
|
|
||||||
|
|
||||||
class ApiServer(RPC):
|
class ApiServer(RPCHandler):
|
||||||
"""
|
"""
|
||||||
This class runs api server and provides rpc.rpc functionality to it
|
This class runs api server and provides rpc.rpc functionality to it
|
||||||
|
|
||||||
@ -89,13 +89,14 @@ class ApiServer(RPC):
|
|||||||
return (safe_str_cmp(username, self._config['api_server'].get('username')) and
|
return (safe_str_cmp(username, self._config['api_server'].get('username')) and
|
||||||
safe_str_cmp(password, self._config['api_server'].get('password')))
|
safe_str_cmp(password, self._config['api_server'].get('password')))
|
||||||
|
|
||||||
def __init__(self, freqtrade) -> None:
|
def __init__(self, rpc: RPC, config: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Init the api server, and init the super class RPC
|
Init the api server, and init the super class RPCHandler
|
||||||
:param freqtrade: Instance of a freqtrade bot
|
:param rpc: instance of RPC Helper class
|
||||||
|
:param config: Configuration object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
super().__init__(freqtrade)
|
super().__init__(rpc, config)
|
||||||
|
|
||||||
self.app = Flask(__name__)
|
self.app = Flask(__name__)
|
||||||
self._cors = CORS(self.app,
|
self._cors = CORS(self.app,
|
||||||
@ -282,7 +283,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /start.
|
Handler for /start.
|
||||||
Starts TradeThread in bot if stopped.
|
Starts TradeThread in bot if stopped.
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_start()
|
msg = self._rpc._rpc_start()
|
||||||
return jsonify(msg)
|
return jsonify(msg)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -292,7 +293,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /stop.
|
Handler for /stop.
|
||||||
Stops TradeThread in bot if running
|
Stops TradeThread in bot if running
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_stop()
|
msg = self._rpc._rpc_stop()
|
||||||
return jsonify(msg)
|
return jsonify(msg)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -302,7 +303,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /stopbuy.
|
Handler for /stopbuy.
|
||||||
Sets max_open_trades to 0 and gracefully sells all open trades
|
Sets max_open_trades to 0 and gracefully sells all open trades
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_stopbuy()
|
msg = self._rpc._rpc_stopbuy()
|
||||||
return jsonify(msg)
|
return jsonify(msg)
|
||||||
|
|
||||||
@rpc_catch_errors
|
@rpc_catch_errors
|
||||||
@ -326,7 +327,7 @@ class ApiServer(RPC):
|
|||||||
"""
|
"""
|
||||||
Prints the bot's version
|
Prints the bot's version
|
||||||
"""
|
"""
|
||||||
return jsonify(RPC._rpc_show_config(self._config, self._freqtrade.state))
|
return jsonify(RPC._rpc_show_config(self._config, self._rpc._freqtrade.state))
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@rpc_catch_errors
|
@rpc_catch_errors
|
||||||
@ -335,7 +336,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /reload_config.
|
Handler for /reload_config.
|
||||||
Triggers a config file reload
|
Triggers a config file reload
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_reload_config()
|
msg = self._rpc._rpc_reload_config()
|
||||||
return jsonify(msg)
|
return jsonify(msg)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -345,7 +346,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /count.
|
Handler for /count.
|
||||||
Returns the number of trades running
|
Returns the number of trades running
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_count()
|
msg = self._rpc._rpc_count()
|
||||||
return jsonify(msg)
|
return jsonify(msg)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -355,7 +356,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /locks.
|
Handler for /locks.
|
||||||
Returns the currently active locks.
|
Returns the currently active locks.
|
||||||
"""
|
"""
|
||||||
return jsonify(self._rpc_locks())
|
return jsonify(self._rpc._rpc_locks())
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@rpc_catch_errors
|
@rpc_catch_errors
|
||||||
@ -368,7 +369,7 @@ class ApiServer(RPC):
|
|||||||
timescale = request.args.get('timescale', 7)
|
timescale = request.args.get('timescale', 7)
|
||||||
timescale = int(timescale)
|
timescale = int(timescale)
|
||||||
|
|
||||||
stats = self._rpc_daily_profit(timescale,
|
stats = self._rpc._rpc_daily_profit(timescale,
|
||||||
self._config['stake_currency'],
|
self._config['stake_currency'],
|
||||||
self._config.get('fiat_display_currency', '')
|
self._config.get('fiat_display_currency', '')
|
||||||
)
|
)
|
||||||
@ -394,7 +395,7 @@ class ApiServer(RPC):
|
|||||||
Returns information related to Edge.
|
Returns information related to Edge.
|
||||||
:return: edge stats
|
:return: edge stats
|
||||||
"""
|
"""
|
||||||
stats = self._rpc_edge()
|
stats = self._rpc._rpc_edge()
|
||||||
|
|
||||||
return jsonify(stats)
|
return jsonify(stats)
|
||||||
|
|
||||||
@ -408,7 +409,7 @@ class ApiServer(RPC):
|
|||||||
:return: stats
|
:return: stats
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stats = self._rpc_trade_statistics(self._config['stake_currency'],
|
stats = self._rpc._rpc_trade_statistics(self._config['stake_currency'],
|
||||||
self._config.get('fiat_display_currency')
|
self._config.get('fiat_display_currency')
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -422,7 +423,7 @@ class ApiServer(RPC):
|
|||||||
Returns a Object with "durations" and "sell_reasons" as keys.
|
Returns a Object with "durations" and "sell_reasons" as keys.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stats = self._rpc_stats()
|
stats = self._rpc._rpc_stats()
|
||||||
|
|
||||||
return jsonify(stats)
|
return jsonify(stats)
|
||||||
|
|
||||||
@ -435,7 +436,7 @@ class ApiServer(RPC):
|
|||||||
Returns a cumulative performance statistics
|
Returns a cumulative performance statistics
|
||||||
:return: stats
|
:return: stats
|
||||||
"""
|
"""
|
||||||
stats = self._rpc_performance()
|
stats = self._rpc._rpc_performance()
|
||||||
|
|
||||||
return jsonify(stats)
|
return jsonify(stats)
|
||||||
|
|
||||||
@ -448,7 +449,7 @@ class ApiServer(RPC):
|
|||||||
Returns the current status of the trades in json format
|
Returns the current status of the trades in json format
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
results = self._rpc_trade_status()
|
results = self._rpc._rpc_trade_status()
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
except RPCException:
|
except RPCException:
|
||||||
return jsonify([])
|
return jsonify([])
|
||||||
@ -461,7 +462,7 @@ class ApiServer(RPC):
|
|||||||
|
|
||||||
Returns the current status of the trades in json format
|
Returns the current status of the trades in json format
|
||||||
"""
|
"""
|
||||||
results = self._rpc_balance(self._config['stake_currency'],
|
results = self._rpc._rpc_balance(self._config['stake_currency'],
|
||||||
self._config.get('fiat_display_currency', ''))
|
self._config.get('fiat_display_currency', ''))
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@ -474,7 +475,7 @@ class ApiServer(RPC):
|
|||||||
Returns the X last trades in json format
|
Returns the X last trades in json format
|
||||||
"""
|
"""
|
||||||
limit = int(request.args.get('limit', 0))
|
limit = int(request.args.get('limit', 0))
|
||||||
results = self._rpc_trade_history(limit)
|
results = self._rpc._rpc_trade_history(limit)
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -487,7 +488,7 @@ class ApiServer(RPC):
|
|||||||
param:
|
param:
|
||||||
tradeid: Numeric trade-id assigned to the trade.
|
tradeid: Numeric trade-id assigned to the trade.
|
||||||
"""
|
"""
|
||||||
result = self._rpc_delete(tradeid)
|
result = self._rpc._rpc_delete(tradeid)
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -496,7 +497,7 @@ class ApiServer(RPC):
|
|||||||
"""
|
"""
|
||||||
Handler for /whitelist.
|
Handler for /whitelist.
|
||||||
"""
|
"""
|
||||||
results = self._rpc_whitelist()
|
results = self._rpc._rpc_whitelist()
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -506,7 +507,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /blacklist.
|
Handler for /blacklist.
|
||||||
"""
|
"""
|
||||||
add = request.json.get("blacklist", None) if request.method == 'POST' else None
|
add = request.json.get("blacklist", None) if request.method == 'POST' else None
|
||||||
results = self._rpc_blacklist(add)
|
results = self._rpc._rpc_blacklist(add)
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -519,7 +520,7 @@ class ApiServer(RPC):
|
|||||||
price = request.json.get("price", None)
|
price = request.json.get("price", None)
|
||||||
price = float(price) if price is not None else price
|
price = float(price) if price is not None else price
|
||||||
|
|
||||||
trade = self._rpc_forcebuy(asset, price)
|
trade = self._rpc._rpc_forcebuy(asset, price)
|
||||||
if trade:
|
if trade:
|
||||||
return jsonify(trade.to_json())
|
return jsonify(trade.to_json())
|
||||||
else:
|
else:
|
||||||
@ -532,7 +533,7 @@ class ApiServer(RPC):
|
|||||||
Handler for /forcesell.
|
Handler for /forcesell.
|
||||||
"""
|
"""
|
||||||
tradeid = request.json.get("tradeid")
|
tradeid = request.json.get("tradeid")
|
||||||
results = self._rpc_forcesell(tradeid)
|
results = self._rpc._rpc_forcesell(tradeid)
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -554,7 +555,7 @@ class ApiServer(RPC):
|
|||||||
if not pair or not timeframe:
|
if not pair or not timeframe:
|
||||||
return self.rest_error("Mandatory parameter missing.", 400)
|
return self.rest_error("Mandatory parameter missing.", 400)
|
||||||
|
|
||||||
results = self._rpc_analysed_dataframe(pair, timeframe, limit)
|
results = self._rpc._rpc_analysed_dataframe(pair, timeframe, limit)
|
||||||
return jsonify(results)
|
return jsonify(results)
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@ -593,7 +594,7 @@ class ApiServer(RPC):
|
|||||||
"""
|
"""
|
||||||
Handler for /plot_config.
|
Handler for /plot_config.
|
||||||
"""
|
"""
|
||||||
return jsonify(self._rpc_plot_config())
|
return jsonify(self._rpc._rpc_plot_config())
|
||||||
|
|
||||||
@require_login
|
@require_login
|
||||||
@rpc_catch_errors
|
@rpc_catch_errors
|
||||||
|
@ -65,6 +65,32 @@ class RPCException(Exception):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RPCHandler:
|
||||||
|
|
||||||
|
def __init__(self, rpc: 'RPC', config: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Initializes RPCHandlers
|
||||||
|
:param rpc: instance of RPC Helper class
|
||||||
|
:param config: Configuration object
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self._rpc = rpc
|
||||||
|
self._config: Dict[str, Any] = config
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
""" Returns the lowercase name of the implementation """
|
||||||
|
return self.__class__.__name__.lower()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def cleanup(self) -> None:
|
||||||
|
""" Cleanup pending module resources """
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_msg(self, msg: Dict[str, str]) -> None:
|
||||||
|
""" Sends a message to all registered rpc modules """
|
||||||
|
|
||||||
|
|
||||||
class RPC:
|
class RPC:
|
||||||
"""
|
"""
|
||||||
RPC class can be used to have extra feature, like bot data, and access to DB data
|
RPC class can be used to have extra feature, like bot data, and access to DB data
|
||||||
@ -83,19 +109,6 @@ class RPC:
|
|||||||
if self._config.get('fiat_display_currency', None):
|
if self._config.get('fiat_display_currency', None):
|
||||||
self._fiat_converter = CryptoToFiatConverter()
|
self._fiat_converter = CryptoToFiatConverter()
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
""" Returns the lowercase name of the implementation """
|
|
||||||
return self.__class__.__name__.lower()
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def cleanup(self) -> None:
|
|
||||||
""" Cleanup pending module resources """
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def send_msg(self, msg: Dict[str, str]) -> None:
|
|
||||||
""" Sends a message to all registered rpc modules """
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _rpc_show_config(config, botstate: State) -> Dict[str, Any]:
|
def _rpc_show_config(config, botstate: State) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
|
@ -4,7 +4,7 @@ This module contains class to manage RPC communications (Telegram, Slack, ...)
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from freqtrade.rpc import RPC, RPCMessageType
|
from freqtrade.rpc import RPC, RPCHandler, RPCMessageType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -16,25 +16,26 @@ class RPCManager:
|
|||||||
"""
|
"""
|
||||||
def __init__(self, freqtrade) -> None:
|
def __init__(self, freqtrade) -> None:
|
||||||
""" Initializes all enabled rpc modules """
|
""" Initializes all enabled rpc modules """
|
||||||
self.registered_modules: List[RPC] = []
|
self.registered_modules: List[RPCHandler] = []
|
||||||
|
self._rpc = RPC(freqtrade)
|
||||||
|
config = freqtrade.config
|
||||||
# Enable telegram
|
# Enable telegram
|
||||||
if freqtrade.config.get('telegram', {}).get('enabled', False):
|
if config.get('telegram', {}).get('enabled', False):
|
||||||
logger.info('Enabling rpc.telegram ...')
|
logger.info('Enabling rpc.telegram ...')
|
||||||
from freqtrade.rpc.telegram import Telegram
|
from freqtrade.rpc.telegram import Telegram
|
||||||
self.registered_modules.append(Telegram(freqtrade))
|
self.registered_modules.append(Telegram(self._rpc, config))
|
||||||
|
|
||||||
# Enable Webhook
|
# Enable Webhook
|
||||||
if freqtrade.config.get('webhook', {}).get('enabled', False):
|
if config.get('webhook', {}).get('enabled', False):
|
||||||
logger.info('Enabling rpc.webhook ...')
|
logger.info('Enabling rpc.webhook ...')
|
||||||
from freqtrade.rpc.webhook import Webhook
|
from freqtrade.rpc.webhook import Webhook
|
||||||
self.registered_modules.append(Webhook(freqtrade))
|
self.registered_modules.append(Webhook(self._rpc, config))
|
||||||
|
|
||||||
# Enable local rest api server for cmd line control
|
# Enable local rest api server for cmd line control
|
||||||
if freqtrade.config.get('api_server', {}).get('enabled', False):
|
if config.get('api_server', {}).get('enabled', False):
|
||||||
logger.info('Enabling rpc.api_server')
|
logger.info('Enabling rpc.api_server')
|
||||||
from freqtrade.rpc.api_server import ApiServer
|
from freqtrade.rpc.api_server import ApiServer
|
||||||
self.registered_modules.append(ApiServer(freqtrade))
|
self.registered_modules.append(ApiServer(self._rpc, config))
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def cleanup(self) -> None:
|
||||||
""" Stops all enabled rpc modules """
|
""" Stops all enabled rpc modules """
|
||||||
|
@ -18,7 +18,7 @@ from telegram.utils.helpers import escape_markdown
|
|||||||
|
|
||||||
from freqtrade.__init__ import __version__
|
from freqtrade.__init__ import __version__
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.rpc import RPC, RPCException, RPCMessageType
|
from freqtrade.rpc import RPC, RPCException, RPCHandler, RPCMessageType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -62,16 +62,18 @@ def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]:
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class Telegram(RPC):
|
class Telegram(RPCHandler):
|
||||||
""" This class handles all telegram communication """
|
""" This class handles all telegram communication """
|
||||||
|
|
||||||
def __init__(self, freqtrade) -> None:
|
def __init__(self, rpc: RPC, config: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Init the Telegram call, and init the super class RPC
|
Init the Telegram call, and init the super class RPCHandler
|
||||||
:param freqtrade: Instance of a freqtrade bot
|
:param rpc: instance of RPC Helper class
|
||||||
|
:param config: Configuration object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
super().__init__(freqtrade)
|
super().__init__(rpc, config)
|
||||||
|
|
||||||
self._updater: Updater
|
self._updater: Updater
|
||||||
self._init_keyboard()
|
self._init_keyboard()
|
||||||
@ -181,8 +183,8 @@ class Telegram(RPC):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if msg['type'] == RPCMessageType.BUY_NOTIFICATION:
|
if msg['type'] == RPCMessageType.BUY_NOTIFICATION:
|
||||||
if self._fiat_converter:
|
if self._rpc._fiat_converter:
|
||||||
msg['stake_amount_fiat'] = self._fiat_converter.convert_amount(
|
msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount(
|
||||||
msg['stake_amount'], msg['stake_currency'], msg['fiat_currency'])
|
msg['stake_amount'], msg['stake_currency'], msg['fiat_currency'])
|
||||||
else:
|
else:
|
||||||
msg['stake_amount_fiat'] = 0
|
msg['stake_amount_fiat'] = 0
|
||||||
@ -222,8 +224,8 @@ class Telegram(RPC):
|
|||||||
# 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 /forcesell
|
||||||
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._fiat_converter):
|
and self._rpc._fiat_converter):
|
||||||
msg['profit_fiat'] = self._fiat_converter.convert_amount(
|
msg['profit_fiat'] = self._rpc._fiat_converter.convert_amount(
|
||||||
msg['profit_amount'], msg['stake_currency'], msg['fiat_currency'])
|
msg['profit_amount'], msg['stake_currency'], msg['fiat_currency'])
|
||||||
message += (' `({gain}: {profit_amount:.8f} {stake_currency}'
|
message += (' `({gain}: {profit_amount:.8f} {stake_currency}'
|
||||||
' / {profit_fiat:.3f} {fiat_currency})`').format(**msg)
|
' / {profit_fiat:.3f} {fiat_currency})`').format(**msg)
|
||||||
@ -275,7 +277,7 @@ class Telegram(RPC):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = self._rpc_trade_status()
|
results = self._rpc._rpc_trade_status()
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
for r in results:
|
for r in results:
|
||||||
@ -325,8 +327,9 @@ class Telegram(RPC):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
statlist, head = self._rpc_status_table(self._config['stake_currency'],
|
statlist, head = self._rpc._rpc_status_table(
|
||||||
self._config.get('fiat_display_currency', ''))
|
self._config['stake_currency'], self._config.get('fiat_display_currency', ''))
|
||||||
|
|
||||||
message = tabulate(statlist, headers=head, tablefmt='simple')
|
message = tabulate(statlist, headers=head, tablefmt='simple')
|
||||||
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML)
|
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
@ -348,7 +351,7 @@ class Telegram(RPC):
|
|||||||
except (TypeError, ValueError, IndexError):
|
except (TypeError, ValueError, IndexError):
|
||||||
timescale = 7
|
timescale = 7
|
||||||
try:
|
try:
|
||||||
stats = self._rpc_daily_profit(
|
stats = self._rpc._rpc_daily_profit(
|
||||||
timescale,
|
timescale,
|
||||||
stake_cur,
|
stake_cur,
|
||||||
fiat_disp_cur
|
fiat_disp_cur
|
||||||
@ -382,7 +385,7 @@ class Telegram(RPC):
|
|||||||
stake_cur = self._config['stake_currency']
|
stake_cur = self._config['stake_currency']
|
||||||
fiat_disp_cur = self._config.get('fiat_display_currency', '')
|
fiat_disp_cur = self._config.get('fiat_display_currency', '')
|
||||||
|
|
||||||
stats = self._rpc_trade_statistics(
|
stats = self._rpc._rpc_trade_statistics(
|
||||||
stake_cur,
|
stake_cur,
|
||||||
fiat_disp_cur)
|
fiat_disp_cur)
|
||||||
profit_closed_coin = stats['profit_closed_coin']
|
profit_closed_coin = stats['profit_closed_coin']
|
||||||
@ -433,7 +436,7 @@ class Telegram(RPC):
|
|||||||
Handler for /stats
|
Handler for /stats
|
||||||
Show stats of recent trades
|
Show stats of recent trades
|
||||||
"""
|
"""
|
||||||
stats = self._rpc_stats()
|
stats = self._rpc._rpc_stats()
|
||||||
|
|
||||||
reason_map = {
|
reason_map = {
|
||||||
'roi': 'ROI',
|
'roi': 'ROI',
|
||||||
@ -473,7 +476,7 @@ class Telegram(RPC):
|
|||||||
def _balance(self, update: Update, context: CallbackContext) -> None:
|
def _balance(self, update: Update, context: CallbackContext) -> None:
|
||||||
""" Handler for /balance """
|
""" Handler for /balance """
|
||||||
try:
|
try:
|
||||||
result = self._rpc_balance(self._config['stake_currency'],
|
result = self._rpc._rpc_balance(self._config['stake_currency'],
|
||||||
self._config.get('fiat_display_currency', ''))
|
self._config.get('fiat_display_currency', ''))
|
||||||
|
|
||||||
output = ''
|
output = ''
|
||||||
@ -517,7 +520,7 @@ class Telegram(RPC):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_start()
|
msg = self._rpc._rpc_start()
|
||||||
self._send_msg('Status: `{status}`'.format(**msg))
|
self._send_msg('Status: `{status}`'.format(**msg))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
@ -529,7 +532,7 @@ class Telegram(RPC):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_stop()
|
msg = self._rpc._rpc_stop()
|
||||||
self._send_msg('Status: `{status}`'.format(**msg))
|
self._send_msg('Status: `{status}`'.format(**msg))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
@ -541,7 +544,7 @@ class Telegram(RPC):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_reload_config()
|
msg = self._rpc._rpc_reload_config()
|
||||||
self._send_msg('Status: `{status}`'.format(**msg))
|
self._send_msg('Status: `{status}`'.format(**msg))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
@ -553,7 +556,7 @@ class Telegram(RPC):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
msg = self._rpc_stopbuy()
|
msg = self._rpc._rpc_stopbuy()
|
||||||
self._send_msg('Status: `{status}`'.format(**msg))
|
self._send_msg('Status: `{status}`'.format(**msg))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
@ -571,7 +574,7 @@ class Telegram(RPC):
|
|||||||
self._send_msg("You must specify a trade-id or 'all'.")
|
self._send_msg("You must specify a trade-id or 'all'.")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
msg = self._rpc_forcesell(trade_id)
|
msg = self._rpc._rpc_forcesell(trade_id)
|
||||||
self._send_msg('Forcesell Result: `{result}`'.format(**msg))
|
self._send_msg('Forcesell Result: `{result}`'.format(**msg))
|
||||||
|
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
@ -590,7 +593,7 @@ class Telegram(RPC):
|
|||||||
pair = context.args[0]
|
pair = context.args[0]
|
||||||
price = float(context.args[1]) if len(context.args) > 1 else None
|
price = float(context.args[1]) if len(context.args) > 1 else None
|
||||||
try:
|
try:
|
||||||
self._rpc_forcebuy(pair, price)
|
self._rpc._rpc_forcebuy(pair, price)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -609,7 +612,7 @@ class Telegram(RPC):
|
|||||||
except (TypeError, ValueError, IndexError):
|
except (TypeError, ValueError, IndexError):
|
||||||
nrecent = 10
|
nrecent = 10
|
||||||
try:
|
try:
|
||||||
trades = self._rpc_trade_history(
|
trades = self._rpc._rpc_trade_history(
|
||||||
nrecent
|
nrecent
|
||||||
)
|
)
|
||||||
trades_tab = tabulate(
|
trades_tab = tabulate(
|
||||||
@ -642,7 +645,7 @@ class Telegram(RPC):
|
|||||||
if not context.args or len(context.args) == 0:
|
if not context.args or len(context.args) == 0:
|
||||||
raise RPCException("Trade-id not set.")
|
raise RPCException("Trade-id not set.")
|
||||||
trade_id = int(context.args[0])
|
trade_id = int(context.args[0])
|
||||||
msg = self._rpc_delete(trade_id)
|
msg = self._rpc._rpc_delete(trade_id)
|
||||||
self._send_msg((
|
self._send_msg((
|
||||||
'`{result_msg}`\n'
|
'`{result_msg}`\n'
|
||||||
'Please make sure to take care of this asset on the exchange manually.'
|
'Please make sure to take care of this asset on the exchange manually.'
|
||||||
@ -661,7 +664,7 @@ class Telegram(RPC):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
trades = self._rpc_performance()
|
trades = self._rpc._rpc_performance()
|
||||||
stats = '\n'.join('{index}.\t<code>{pair}\t{profit:.2f}% ({count})</code>'.format(
|
stats = '\n'.join('{index}.\t<code>{pair}\t{profit:.2f}% ({count})</code>'.format(
|
||||||
index=i + 1,
|
index=i + 1,
|
||||||
pair=trade['pair'],
|
pair=trade['pair'],
|
||||||
@ -683,7 +686,7 @@ class Telegram(RPC):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
counts = self._rpc_count()
|
counts = self._rpc._rpc_count()
|
||||||
message = tabulate({k: [v] for k, v in counts.items()},
|
message = tabulate({k: [v] for k, v in counts.items()},
|
||||||
headers=['current', 'max', 'total stake'],
|
headers=['current', 'max', 'total stake'],
|
||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
@ -700,7 +703,7 @@ class Telegram(RPC):
|
|||||||
Returns the currently active locks
|
Returns the currently active locks
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
locks = self._rpc_locks()
|
locks = self._rpc._rpc_locks()
|
||||||
message = tabulate([[
|
message = tabulate([[
|
||||||
lock['pair'],
|
lock['pair'],
|
||||||
lock['lock_end_time'],
|
lock['lock_end_time'],
|
||||||
@ -720,7 +723,7 @@ class Telegram(RPC):
|
|||||||
Shows the currently active whitelist
|
Shows the currently active whitelist
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
whitelist = self._rpc_whitelist()
|
whitelist = self._rpc._rpc_whitelist()
|
||||||
|
|
||||||
message = f"Using whitelist `{whitelist['method']}` with {whitelist['length']} pairs\n"
|
message = f"Using whitelist `{whitelist['method']}` with {whitelist['length']} pairs\n"
|
||||||
message += f"`{', '.join(whitelist['whitelist'])}`"
|
message += f"`{', '.join(whitelist['whitelist'])}`"
|
||||||
@ -738,7 +741,7 @@ class Telegram(RPC):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
blacklist = self._rpc_blacklist(context.args)
|
blacklist = self._rpc._rpc_blacklist(context.args)
|
||||||
errmsgs = []
|
errmsgs = []
|
||||||
for pair, error in blacklist['errors'].items():
|
for pair, error in blacklist['errors'].items():
|
||||||
errmsgs.append(f"Error adding `{pair}` to blacklist: `{error['error_msg']}`")
|
errmsgs.append(f"Error adding `{pair}` to blacklist: `{error['error_msg']}`")
|
||||||
@ -792,7 +795,7 @@ class Telegram(RPC):
|
|||||||
Shows information related to Edge
|
Shows information related to Edge
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
edge_pairs = self._rpc_edge()
|
edge_pairs = self._rpc._rpc_edge()
|
||||||
edge_pairs_tab = tabulate(edge_pairs, headers='keys', tablefmt='simple')
|
edge_pairs_tab = tabulate(edge_pairs, headers='keys', tablefmt='simple')
|
||||||
message = f'<b>Edge only validated following pairs:</b>\n<pre>{edge_pairs_tab}</pre>'
|
message = f'<b>Edge only validated following pairs:</b>\n<pre>{edge_pairs_tab}</pre>'
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
self._send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
@ -862,7 +865,7 @@ class Telegram(RPC):
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
val = RPC._rpc_show_config(self._freqtrade.config, self._freqtrade.state)
|
val = RPC._rpc_show_config(self._config, self._rpc._freqtrade.state)
|
||||||
|
|
||||||
if val['trailing_stop']:
|
if val['trailing_stop']:
|
||||||
sl_info = (
|
sl_info = (
|
||||||
|
@ -6,7 +6,7 @@ from typing import Any, Dict
|
|||||||
|
|
||||||
from requests import RequestException, post
|
from requests import RequestException, post
|
||||||
|
|
||||||
from freqtrade.rpc import RPC, RPCMessageType
|
from freqtrade.rpc import RPC, RPCHandler, RPCMessageType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -14,16 +14,17 @@ logger = logging.getLogger(__name__)
|
|||||||
logger.debug('Included module rpc.webhook ...')
|
logger.debug('Included module rpc.webhook ...')
|
||||||
|
|
||||||
|
|
||||||
class Webhook(RPC):
|
class Webhook(RPCHandler):
|
||||||
""" This class handles all webhook communication """
|
""" This class handles all webhook communication """
|
||||||
|
|
||||||
def __init__(self, freqtrade) -> None:
|
def __init__(self, rpc: RPC, config: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Init the Webhook class, and init the super class RPC
|
Init the Webhook class, and init the super class RPCHandler
|
||||||
:param freqtrade: Instance of a freqtrade bot
|
:param rpc: instance of RPC Helper class
|
||||||
|
:param config: Configuration object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
super().__init__(freqtrade)
|
super().__init__(rpc, config)
|
||||||
|
|
||||||
self._url = self._config['webhook']['url']
|
self._url = self._config['webhook']['url']
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ from requests.auth import _basic_auth_str
|
|||||||
from freqtrade.__init__ import __version__
|
from freqtrade.__init__ import __version__
|
||||||
from freqtrade.loggers import setup_logging, setup_logging_pre
|
from freqtrade.loggers import setup_logging, setup_logging_pre
|
||||||
from freqtrade.persistence import PairLocks, Trade
|
from freqtrade.persistence import PairLocks, Trade
|
||||||
|
from freqtrade.rpc import RPC
|
||||||
from freqtrade.rpc.api_server import BASE_URI, ApiServer
|
from freqtrade.rpc.api_server import BASE_URI, ApiServer
|
||||||
from freqtrade.state import RunMode, State
|
from freqtrade.state import RunMode, State
|
||||||
from tests.conftest import create_mock_trades, get_patched_freqtradebot, log_has, patch_get_signal
|
from tests.conftest import create_mock_trades, get_patched_freqtradebot, log_has, patch_get_signal
|
||||||
@ -36,8 +37,9 @@ def botclient(default_conf, mocker):
|
|||||||
}})
|
}})
|
||||||
|
|
||||||
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
|
rpc = RPC(ftbot)
|
||||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
||||||
apiserver = ApiServer(ftbot)
|
apiserver = ApiServer(rpc, default_conf)
|
||||||
yield ftbot, apiserver.app.test_client()
|
yield ftbot, apiserver.app.test_client()
|
||||||
# Cleanup ... ?
|
# Cleanup ... ?
|
||||||
|
|
||||||
@ -179,8 +181,7 @@ def test_api__init__(default_conf, mocker):
|
|||||||
}})
|
}})
|
||||||
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
|
||||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
||||||
|
apiserver = ApiServer(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
|
||||||
assert apiserver._config == default_conf
|
assert apiserver._config == default_conf
|
||||||
|
|
||||||
|
|
||||||
@ -197,7 +198,7 @@ def test_api_run(default_conf, mocker, caplog):
|
|||||||
server_mock = MagicMock()
|
server_mock = MagicMock()
|
||||||
mocker.patch('freqtrade.rpc.api_server.make_server', server_mock)
|
mocker.patch('freqtrade.rpc.api_server.make_server', server_mock)
|
||||||
|
|
||||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
apiserver = ApiServer(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
|
|
||||||
assert apiserver._config == default_conf
|
assert apiserver._config == default_conf
|
||||||
apiserver.run()
|
apiserver.run()
|
||||||
@ -251,7 +252,7 @@ def test_api_cleanup(default_conf, mocker, caplog):
|
|||||||
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
|
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
|
||||||
mocker.patch('freqtrade.rpc.api_server.make_server', MagicMock())
|
mocker.patch('freqtrade.rpc.api_server.make_server', MagicMock())
|
||||||
|
|
||||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
apiserver = ApiServer(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
apiserver.run()
|
apiserver.run()
|
||||||
stop_mock = MagicMock()
|
stop_mock = MagicMock()
|
||||||
stop_mock.shutdown = MagicMock()
|
stop_mock.shutdown = MagicMock()
|
||||||
|
@ -20,7 +20,7 @@ from freqtrade.exceptions import OperationalException
|
|||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.loggers import setup_logging
|
from freqtrade.loggers import setup_logging
|
||||||
from freqtrade.persistence import PairLocks, Trade
|
from freqtrade.persistence import PairLocks, Trade
|
||||||
from freqtrade.rpc import RPCMessageType
|
from freqtrade.rpc import RPC, RPCMessageType
|
||||||
from freqtrade.rpc.telegram import Telegram, authorized_only
|
from freqtrade.rpc.telegram import Telegram, authorized_only
|
||||||
from freqtrade.state import RunMode, State
|
from freqtrade.state import RunMode, State
|
||||||
from freqtrade.strategy.interface import SellType
|
from freqtrade.strategy.interface import SellType
|
||||||
@ -32,8 +32,8 @@ class DummyCls(Telegram):
|
|||||||
"""
|
"""
|
||||||
Dummy class for testing the Telegram @authorized_only decorator
|
Dummy class for testing the Telegram @authorized_only decorator
|
||||||
"""
|
"""
|
||||||
def __init__(self, freqtrade) -> None:
|
def __init__(self, rpc: RPC, config) -> None:
|
||||||
super().__init__(freqtrade)
|
super().__init__(rpc, config)
|
||||||
self.state = {'called': False}
|
self.state = {'called': False}
|
||||||
|
|
||||||
def _init(self):
|
def _init(self):
|
||||||
@ -54,7 +54,7 @@ class DummyCls(Telegram):
|
|||||||
raise Exception('test')
|
raise Exception('test')
|
||||||
|
|
||||||
|
|
||||||
def get_telegram_testobject(mocker, default_conf, mock=True):
|
def get_telegram_testobject(mocker, default_conf, mock=True, ftbot=None):
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
if mock:
|
if mock:
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -62,8 +62,10 @@ def get_telegram_testobject(mocker, default_conf, mock=True):
|
|||||||
_init=MagicMock(),
|
_init=MagicMock(),
|
||||||
_send_msg=msg_mock
|
_send_msg=msg_mock
|
||||||
)
|
)
|
||||||
|
if not ftbot:
|
||||||
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
telegram = Telegram(ftbot)
|
rpc = RPC(ftbot)
|
||||||
|
telegram = Telegram(rpc, default_conf)
|
||||||
|
|
||||||
return telegram, ftbot, msg_mock
|
return telegram, ftbot, msg_mock
|
||||||
|
|
||||||
@ -112,8 +114,10 @@ def test_authorized_only(default_conf, mocker, caplog, update) -> None:
|
|||||||
|
|
||||||
default_conf['telegram']['enabled'] = False
|
default_conf['telegram']['enabled'] = False
|
||||||
bot = FreqtradeBot(default_conf)
|
bot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(bot)
|
||||||
|
dummy = DummyCls(rpc, default_conf)
|
||||||
|
|
||||||
patch_get_signal(bot, (True, False))
|
patch_get_signal(bot, (True, False))
|
||||||
dummy = DummyCls(bot)
|
|
||||||
dummy.dummy_handler(update=update, context=MagicMock())
|
dummy.dummy_handler(update=update, context=MagicMock())
|
||||||
assert dummy.state['called'] is True
|
assert dummy.state['called'] is True
|
||||||
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
|
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
|
||||||
@ -129,8 +133,10 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
|
|||||||
|
|
||||||
default_conf['telegram']['enabled'] = False
|
default_conf['telegram']['enabled'] = False
|
||||||
bot = FreqtradeBot(default_conf)
|
bot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(bot)
|
||||||
|
dummy = DummyCls(rpc, default_conf)
|
||||||
|
|
||||||
patch_get_signal(bot, (True, False))
|
patch_get_signal(bot, (True, False))
|
||||||
dummy = DummyCls(bot)
|
|
||||||
dummy.dummy_handler(update=update, context=MagicMock())
|
dummy.dummy_handler(update=update, context=MagicMock())
|
||||||
assert dummy.state['called'] is False
|
assert dummy.state['called'] is False
|
||||||
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
|
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
|
||||||
@ -144,8 +150,9 @@ def test_authorized_only_exception(default_conf, mocker, caplog, update) -> None
|
|||||||
default_conf['telegram']['enabled'] = False
|
default_conf['telegram']['enabled'] = False
|
||||||
|
|
||||||
bot = FreqtradeBot(default_conf)
|
bot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(bot)
|
||||||
|
dummy = DummyCls(rpc, default_conf)
|
||||||
patch_get_signal(bot, (True, False))
|
patch_get_signal(bot, (True, False))
|
||||||
dummy = DummyCls(bot)
|
|
||||||
|
|
||||||
dummy.dummy_exception(update=update, context=MagicMock())
|
dummy.dummy_exception(update=update, context=MagicMock())
|
||||||
assert dummy.state['called'] is False
|
assert dummy.state['called'] is False
|
||||||
@ -160,8 +167,10 @@ def test_telegram_status(default_conf, update, mocker) -> None:
|
|||||||
default_conf['telegram']['chat_id'] = "123"
|
default_conf['telegram']['chat_id'] = "123"
|
||||||
|
|
||||||
status_table = MagicMock()
|
status_table = MagicMock()
|
||||||
|
mocker.patch('freqtrade.rpc.telegram.Telegram._status_table', status_table)
|
||||||
|
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.rpc.telegram.Telegram',
|
'freqtrade.rpc.rpc.RPC',
|
||||||
_rpc_trade_status=MagicMock(return_value=[{
|
_rpc_trade_status=MagicMock(return_value=[{
|
||||||
'trade_id': 1,
|
'trade_id': 1,
|
||||||
'pair': 'ETH/BTC',
|
'pair': 'ETH/BTC',
|
||||||
@ -188,7 +197,6 @@ def test_telegram_status(default_conf, update, mocker) -> None:
|
|||||||
'open_order': '(limit buy rem=0.00000000)',
|
'open_order': '(limit buy rem=0.00000000)',
|
||||||
'is_open': True
|
'is_open': True
|
||||||
}]),
|
}]),
|
||||||
_status_table=status_table,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||||
@ -642,8 +650,9 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
|||||||
)
|
)
|
||||||
|
|
||||||
freqtradebot = FreqtradeBot(default_conf)
|
freqtradebot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(freqtradebot)
|
||||||
|
telegram = Telegram(rpc, default_conf)
|
||||||
patch_get_signal(freqtradebot, (True, False))
|
patch_get_signal(freqtradebot, (True, False))
|
||||||
telegram = Telegram(freqtradebot)
|
|
||||||
|
|
||||||
# Create some test data
|
# Create some test data
|
||||||
freqtradebot.enter_positions()
|
freqtradebot.enter_positions()
|
||||||
@ -698,8 +707,9 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
|
|||||||
)
|
)
|
||||||
|
|
||||||
freqtradebot = FreqtradeBot(default_conf)
|
freqtradebot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(freqtradebot)
|
||||||
|
telegram = Telegram(rpc, default_conf)
|
||||||
patch_get_signal(freqtradebot, (True, False))
|
patch_get_signal(freqtradebot, (True, False))
|
||||||
telegram = Telegram(freqtradebot)
|
|
||||||
|
|
||||||
# Create some test data
|
# Create some test data
|
||||||
freqtradebot.enter_positions()
|
freqtradebot.enter_positions()
|
||||||
@ -756,8 +766,9 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
|||||||
)
|
)
|
||||||
default_conf['max_open_trades'] = 4
|
default_conf['max_open_trades'] = 4
|
||||||
freqtradebot = FreqtradeBot(default_conf)
|
freqtradebot = FreqtradeBot(default_conf)
|
||||||
|
rpc = RPC(freqtradebot)
|
||||||
|
telegram = Telegram(rpc, default_conf)
|
||||||
patch_get_signal(freqtradebot, (True, False))
|
patch_get_signal(freqtradebot, (True, False))
|
||||||
telegram = Telegram(freqtradebot)
|
|
||||||
|
|
||||||
# Create some test data
|
# Create some test data
|
||||||
freqtradebot.enter_positions()
|
freqtradebot.enter_positions()
|
||||||
@ -1216,8 +1227,8 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
|||||||
|
|
||||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||||
|
|
||||||
old_convamount = telegram._fiat_converter.convert_amount
|
old_convamount = telegram._rpc._fiat_converter.convert_amount
|
||||||
telegram._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
||||||
telegram.send_msg({
|
telegram.send_msg({
|
||||||
'type': RPCMessageType.SELL_NOTIFICATION,
|
'type': RPCMessageType.SELL_NOTIFICATION,
|
||||||
'exchange': 'Binance',
|
'exchange': 'Binance',
|
||||||
@ -1274,15 +1285,15 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
|||||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
|
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
|
||||||
'*Profit:* `-57.41%`')
|
'*Profit:* `-57.41%`')
|
||||||
# Reset singleton function to avoid random breaks
|
# Reset singleton function to avoid random breaks
|
||||||
telegram._fiat_converter.convert_amount = old_convamount
|
telegram._rpc._fiat_converter.convert_amount = old_convamount
|
||||||
|
|
||||||
|
|
||||||
def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
|
def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
|
||||||
|
|
||||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||||
|
|
||||||
old_convamount = telegram._fiat_converter.convert_amount
|
old_convamount = telegram._rpc._fiat_converter.convert_amount
|
||||||
telegram._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
||||||
telegram.send_msg({
|
telegram.send_msg({
|
||||||
'type': RPCMessageType.SELL_CANCEL_NOTIFICATION,
|
'type': RPCMessageType.SELL_CANCEL_NOTIFICATION,
|
||||||
'exchange': 'Binance',
|
'exchange': 'Binance',
|
||||||
@ -1303,7 +1314,7 @@ def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
|
|||||||
assert msg_mock.call_args[0][0] \
|
assert msg_mock.call_args[0][0] \
|
||||||
== ('\N{WARNING SIGN} *Binance:* Cancelling Open Sell Order for KEY/ETH. Reason: timeout')
|
== ('\N{WARNING SIGN} *Binance:* Cancelling Open Sell Order for KEY/ETH. Reason: timeout')
|
||||||
# Reset singleton function to avoid random breaks
|
# Reset singleton function to avoid random breaks
|
||||||
telegram._fiat_converter.convert_amount = old_convamount
|
telegram._rpc._fiat_converter.convert_amount = old_convamount
|
||||||
|
|
||||||
|
|
||||||
def test_send_msg_status_notification(default_conf, mocker) -> None:
|
def test_send_msg_status_notification(default_conf, mocker) -> None:
|
||||||
@ -1449,6 +1460,7 @@ def test__send_msg_keyboard(default_conf, mocker, caplog) -> None:
|
|||||||
bot = MagicMock()
|
bot = MagicMock()
|
||||||
bot.send_message = MagicMock()
|
bot.send_message = MagicMock()
|
||||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
|
rpc = RPC(freqtradebot)
|
||||||
|
|
||||||
invalid_keys_list = [['/not_valid', '/profit'], ['/daily'], ['/alsoinvalid']]
|
invalid_keys_list = [['/not_valid', '/profit'], ['/daily'], ['/alsoinvalid']]
|
||||||
default_keys_list = [['/daily', '/profit', '/balance'],
|
default_keys_list = [['/daily', '/profit', '/balance'],
|
||||||
@ -1461,7 +1473,7 @@ def test__send_msg_keyboard(default_conf, mocker, caplog) -> None:
|
|||||||
custom_keyboard = ReplyKeyboardMarkup(custom_keys_list)
|
custom_keyboard = ReplyKeyboardMarkup(custom_keys_list)
|
||||||
|
|
||||||
def init_telegram(freqtradebot):
|
def init_telegram(freqtradebot):
|
||||||
telegram = Telegram(freqtradebot)
|
telegram = Telegram(rpc, default_conf)
|
||||||
telegram._updater = MagicMock()
|
telegram._updater = MagicMock()
|
||||||
telegram._updater.bot = bot
|
telegram._updater.bot = bot
|
||||||
return telegram
|
return telegram
|
||||||
|
@ -5,7 +5,7 @@ from unittest.mock import MagicMock
|
|||||||
import pytest
|
import pytest
|
||||||
from requests import RequestException
|
from requests import RequestException
|
||||||
|
|
||||||
from freqtrade.rpc import RPCMessageType
|
from freqtrade.rpc import RPC, RPCMessageType
|
||||||
from freqtrade.rpc.webhook import Webhook
|
from freqtrade.rpc.webhook import Webhook
|
||||||
from freqtrade.strategy.interface import SellType
|
from freqtrade.strategy.interface import SellType
|
||||||
from tests.conftest import get_patched_freqtradebot, log_has
|
from tests.conftest import get_patched_freqtradebot, log_has
|
||||||
@ -45,7 +45,7 @@ def get_webhook_dict() -> dict:
|
|||||||
|
|
||||||
def test__init__(mocker, default_conf):
|
def test__init__(mocker, default_conf):
|
||||||
default_conf['webhook'] = {'enabled': True, 'url': "https://DEADBEEF.com"}
|
default_conf['webhook'] = {'enabled': True, 'url': "https://DEADBEEF.com"}
|
||||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
assert webhook._config == default_conf
|
assert webhook._config == default_conf
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def test_send_msg(default_conf, mocker):
|
|||||||
default_conf["webhook"] = get_webhook_dict()
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
# Test buy
|
# Test buy
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
@ -172,7 +172,7 @@ def test_exception_send_msg(default_conf, mocker, caplog):
|
|||||||
default_conf["webhook"] = get_webhook_dict()
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
del default_conf["webhook"]["webhookbuy"]
|
del default_conf["webhook"]["webhookbuy"]
|
||||||
|
|
||||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
webhook.send_msg({'type': RPCMessageType.BUY_NOTIFICATION})
|
webhook.send_msg({'type': RPCMessageType.BUY_NOTIFICATION})
|
||||||
assert log_has(f"Message type '{RPCMessageType.BUY_NOTIFICATION}' not configured for webhooks",
|
assert log_has(f"Message type '{RPCMessageType.BUY_NOTIFICATION}' not configured for webhooks",
|
||||||
caplog)
|
caplog)
|
||||||
@ -181,7 +181,7 @@ def test_exception_send_msg(default_conf, mocker, caplog):
|
|||||||
default_conf["webhook"]["webhookbuy"]["value1"] = "{DEADBEEF:8f}"
|
default_conf["webhook"]["webhookbuy"]["value1"] = "{DEADBEEF:8f}"
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
msg = {
|
msg = {
|
||||||
'type': RPCMessageType.BUY_NOTIFICATION,
|
'type': RPCMessageType.BUY_NOTIFICATION,
|
||||||
'exchange': 'Bittrex',
|
'exchange': 'Bittrex',
|
||||||
@ -209,7 +209,7 @@ def test_exception_send_msg(default_conf, mocker, caplog):
|
|||||||
|
|
||||||
def test__send_msg(default_conf, mocker, caplog):
|
def test__send_msg(default_conf, mocker, caplog):
|
||||||
default_conf["webhook"] = get_webhook_dict()
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
|
||||||
msg = {'value1': 'DEADBEEF',
|
msg = {'value1': 'DEADBEEF',
|
||||||
'value2': 'ALIVEBEEF',
|
'value2': 'ALIVEBEEF',
|
||||||
'value3': 'FREQTRADE'}
|
'value3': 'FREQTRADE'}
|
||||||
|
Loading…
Reference in New Issue
Block a user