diff --git a/freqtrade/rpc/local_rest_server.py b/freqtrade/rpc/local_rest_server.py index 0c9fad16b..24d9a6594 100644 --- a/freqtrade/rpc/local_rest_server.py +++ b/freqtrade/rpc/local_rest_server.py @@ -5,43 +5,11 @@ import json from flask import Flask, request from flask_restful import Resource, Api from json import dumps -from freqtrade.rpc.rpc import RPC +from freqtrade.rpc.rpc import RPC, RPCException logger = logging.getLogger(__name__) - -class Daily(Resource): - # called by http://127.0.0.1:/daily?timescale=7 - # where 7 is the number of days to report back with - - def __init__(self, freqtrade) -> None: - """ - Initializes all enabled rpc modules - :param freqtrade: Instance of a freqtrade bot - :return: None - """ - self.freqtrade = freqtrade - self._config = freqtrade.config - - - def get(self): - timescale = request.args.get('timescale') - logger.info("LocalRPC - Daily Command Called") - timescale = int(timescale) - - (error, stats) = RPC.rpc_daily_profit(self, timescale, - self._config['stake_currency'], - self._config['fiat_display_currency'] - ) - if error == False: - stats = dumps(stats, indent=4, sort_keys=True, default=str) - return stats - else: - json.dumps(error) - return error - - class LocalRestSuperWrap(RPC): """ This class is for REST cmd line client @@ -61,23 +29,85 @@ class LocalRestSuperWrap(RPC): thread = threading.Thread(target=self.run, args=(freqtrade,)) # extra comma as ref ! Tuple thread.daemon = True # Daemonize thread - thread.start() # Start the execution + thread.start() # Start the execution + def run(self, freqtrade): """ Method that runs forever """ self._config = freqtrade.config - - - # TODO add IP address / port to bind to in config.json and use in below. - logger.info('Starting Local Rest Server') - - my_freqtrade = freqtrade app = Flask(__name__) - api = Api(app) - # Our resources for restful apps go here, pass freqtrade object across - api.add_resource(Daily, '/daily', methods=['GET'], - resource_class_kwargs={'freqtrade': my_freqtrade}) # Route for returning daily + """ + Define the application routes here + each Telegram command should have a like local substitute + """ + @app.route("/") + def hello(): + # For simple rest server testing via browser + # cmds = 'Try uri:/daily?timescale=7 /profit /balance /status + # /status /table /performance /count, + # /start /stop /help' - #run the server - app.run(port='5002') + rest_cmds ='Commands implemented:
' \ + '/daily?timescale=7' \ + '
' \ + '/stop' \ + '
' \ + '/start' + return rest_cmds + + @app.route('/daily', methods=['GET']) + def daily(): + try: + timescale = request.args.get('timescale') + logger.info("LocalRPC - Daily Command Called") + timescale = int(timescale) + + stats = self._rpc_daily_profit(timescale, + self._config['stake_currency'], + self._config['fiat_display_currency'] + ) + + stats = dumps(stats, indent=4, sort_keys=True, default=str) + return stats + except RPCException as e: + return e + + @app.route('/start', methods=['GET']) + def start(): + """ + Handler for /start. + Starts TradeThread + """ + msg = self._rpc_start() + print("msg is", msg) + return msg + + @app.route('/stop', methods=['GET']) + def stop(): + """ + Handler for /stop. + Stops TradeThread + """ + msg = self._rpc_stop() + print("msg is", msg) + return msg + + """ + Section to handle configuration and running of the Rest serve + also to check and warn if not bound to 127.0.0.1 as a security risk + """ + + rest_ip = self._config['rest_cmd_line']['listen_ip_address'] + rest_port = self._config['rest_cmd_line']['listen_port'] + + if rest_ip != "127.0.0.1": + i=0 + while i < 10: + logger.info("SECURITY WARNING - Local Rest Server listening to external connections") + logger.info("SECURITY WARNING - This is insecure please set to 127.0.0.1 in config.json") + i += 1 + + # Run the Server + logger.info('Starting Local Rest Server') + app.run(host=rest_ip, port=rest_port) diff --git a/freqtrade/rpc/rest_client.py b/freqtrade/rpc/rest_client.py index 928e1798c..c5007970f 100755 --- a/freqtrade/rpc/rest_client.py +++ b/freqtrade/rpc/rest_client.py @@ -4,12 +4,20 @@ Simple command line client into RPC commands Can be used as an alternate to Telegram """ +import time from requests import get from sys import argv + + +#TODO - use argparse to clean this up +#TODO - use IP and Port from config.json not hardcode + if len(argv) == 1: print('\nThis script accepts the following arguments') print('- daily (int) - Where int is the number of days to report back. daily 3') + print('- start - this will start the trading thread') + print('- stop - this will start the trading thread') print('- there will be more....\n') if len(argv) == 3 and argv[1] == "daily": @@ -20,4 +28,26 @@ if len(argv) == 3 and argv[1] == "daily": else: print("\nThe second argument to daily must be an integer, 1,2,3 etc") +if len(argv) == 2 and argv[1] == "start": + get_url = 'http://localhost:5002/start' + d = get(get_url).text + print(d) + + if "already" not in d: + time.sleep(2) + d = get(get_url).text + print(d) + +if len(argv) == 2 and argv[1] == "stop": + get_url = 'http://localhost:5002/stop' + d = get(get_url).text + print(d) + + if "already" not in d: + time.sleep(2) + d = get(get_url).text + print(d) + + + diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index ef71ff3a9..21e54f488 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -1,13 +1,10 @@ """ -This module contains class to manage RPC communications (Telegram, Slack, ....) +This module contains class to manage RPC communications (Telegram, Slack, Rest ...) """ -from typing import Any, List import logging -import time - -from freqtrade.rpc.telegram import Telegram -from freqtrade.rpc.local_rest_server import LocalRestSuperWrap +from typing import List +from freqtrade.rpc.rpc import RPC logger = logging.getLogger(__name__) @@ -17,42 +14,29 @@ class RPCManager(object): Class to manage RPC objects (Telegram, Slack, ...) """ def __init__(self, freqtrade) -> None: - """ - Initializes all enabled rpc modules - :param config: config to use - :return: None - """ - self.freqtrade = freqtrade + """ Initializes all enabled rpc modules """ + self.registered_modules: List[RPC] = [] - self.registered_modules: List[str] = [] - self.telegram: Any = None - self._init() - - def _init(self) -> None: - """ - Init RPC modules - :return: - """ - if self.freqtrade.config['telegram'].get('enabled', False): + # Enable telegram + if freqtrade.config['telegram'].get('enabled', False): logger.info('Enabling rpc.telegram ...') - self.registered_modules.append('telegram') - self.telegram = Telegram(self.freqtrade) + from freqtrade.rpc.telegram import Telegram + self.registered_modules.append(Telegram(freqtrade)) - # Added another RPC client - for cmdline local client. - # Uses existing superclass RPC build for Telegram - if self.freqtrade.config['rest_cmd'].get('enabled', False): - self.localRPC = LocalRestSuperWrap(self.freqtrade) - time.sleep(1) + # Enable local rest server for cmd line control + if freqtrade.config['rest_cmd_line'].get('enabled', False): + logger.info('Enabling rpc.local_rest_server ...') + from freqtrade.rpc.local_rest_server import LocalRestSuperWrap + self.registered_modules.append(LocalRestSuperWrap(freqtrade)) def cleanup(self) -> None: - """ - Stops all enabled rpc modules - :return: None - """ - if 'telegram' in self.registered_modules: - logger.info('Cleaning up rpc.telegram ...') - self.registered_modules.remove('telegram') - self.telegram.cleanup() + """ Stops all enabled rpc modules """ + logger.info('Cleaning up rpc modules ...') + while self.registered_modules: + mod = self.registered_modules.pop() + logger.debug('Cleaning up rpc.%s ...', mod.name) + mod.cleanup() + del mod def send_msg(self, msg: str) -> None: """ @@ -60,6 +44,7 @@ class RPCManager(object): :param msg: message :return: None """ - logger.info(msg) - if 'telegram' in self.registered_modules: - self.telegram.send_msg(msg) + logger.info('Sending rpc message: %s', msg) + for mod in self.registered_modules: + logger.debug('Forwarding message to rpc.%s', mod.name) + mod.send_msg(msg)