stable/scripts/rest_client.py

265 lines
7.2 KiB
Python
Raw Normal View History

2019-04-04 05:08:24 +00:00
#!/usr/bin/env python3
"""
Simple command line client into RPC commands
Can be used as an alternate to Telegram
2019-04-04 19:07:44 +00:00
Should not import anything from freqtrade,
so it can be used as a standalone script.
2019-04-04 05:08:24 +00:00
"""
2019-04-04 19:07:44 +00:00
import argparse
2019-04-09 04:40:15 +00:00
import json
2019-04-04 19:07:44 +00:00
import logging
2019-04-26 07:27:20 +00:00
import inspect
2019-04-25 18:32:10 +00:00
from urllib.parse import urlencode, urlparse, urlunparse
2019-04-09 04:40:15 +00:00
from pathlib import Path
2019-04-04 19:07:44 +00:00
2019-04-25 18:32:10 +00:00
import requests
2019-04-04 19:07:44 +00:00
from requests.exceptions import ConnectionError
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
)
logger = logging.getLogger("ft_rest_client")
2019-04-04 05:08:24 +00:00
2019-04-25 18:32:10 +00:00
class FtRestClient():
2019-05-25 12:14:09 +00:00
def __init__(self, serverurl, username=None, password=None):
2019-04-25 18:32:10 +00:00
2019-04-26 07:55:52 +00:00
self._serverurl = serverurl
self._session = requests.Session()
self._session.auth = (username, password)
2019-04-25 18:32:10 +00:00
2019-04-26 07:10:23 +00:00
def _call(self, method, apipath, params: dict = None, data=None, files=None):
2019-04-25 18:32:10 +00:00
if str(method).upper() not in ('GET', 'POST', 'PUT', 'DELETE'):
raise ValueError('invalid method <{0}>'.format(method))
2019-05-15 05:12:33 +00:00
basepath = f"{self._serverurl}/api/v1/{apipath}"
2019-04-25 18:32:10 +00:00
hd = {"Accept": "application/json",
"Content-Type": "application/json"
}
# Split url
2019-04-26 07:27:20 +00:00
schema, netloc, path, par, query, fragment = urlparse(basepath)
2019-04-25 18:32:10 +00:00
# URLEncode query string
2019-04-26 08:03:54 +00:00
query = urlencode(params) if params else ""
2019-04-25 18:32:10 +00:00
# recombine url
2019-04-26 07:27:20 +00:00
url = urlunparse((schema, netloc, path, par, query, fragment))
2019-04-26 07:55:52 +00:00
2019-04-25 18:32:10 +00:00
try:
resp = self._session.request(method, url, headers=hd, data=json.dumps(data))
2019-04-26 07:08:03 +00:00
# return resp.text
return resp.json()
2019-04-25 18:32:10 +00:00
except ConnectionError:
logger.warning("Connection error")
2019-04-26 07:27:20 +00:00
def _get(self, apipath, params: dict = None):
return self._call("GET", apipath, params=params)
def _post(self, apipath, params: dict = None, data: dict = None):
return self._call("POST", apipath, params=params, data=data)
2019-04-26 08:10:01 +00:00
def start(self):
"""
Start the bot if it's in stopped state.
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:10:01 +00:00
"""
return self._post("start")
def stop(self):
"""
Stop the bot. Use start to restart
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:10:01 +00:00
"""
return self._post("stop")
def stopbuy(self):
"""
Stop buying (but handle sells gracefully).
use reload_conf to reset
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:10:01 +00:00
"""
return self._post("stopbuy")
def reload_conf(self):
"""
Reload configuration
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:10:01 +00:00
"""
return self._post("reload_conf")
2019-04-26 07:55:52 +00:00
def balance(self):
2019-04-26 07:27:20 +00:00
"""
2019-04-26 08:12:39 +00:00
Get the account balance
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:27:20 +00:00
"""
2019-04-26 07:55:52 +00:00
return self._get("balance")
2019-04-26 07:27:20 +00:00
def count(self):
"""
Returns the amount of open trades
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:27:20 +00:00
"""
return self._get("count")
def daily(self, days=None):
"""
Returns the amount of open trades
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:27:20 +00:00
"""
return self._get("daily", params={"timescale": days} if days else None)
2019-04-26 08:06:46 +00:00
def edge(self):
"""
Returns information about edge
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:06:46 +00:00
"""
return self._get("edge")
2019-04-26 07:55:52 +00:00
def profit(self):
"""
Returns the profit summary
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:55:52 +00:00
"""
return self._get("profit")
2019-04-26 08:03:54 +00:00
def performance(self):
"""
Returns the performance of the different coins
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 08:03:54 +00:00
"""
return self._get("performance")
2019-04-26 07:55:52 +00:00
def status(self):
"""
Get the status of open trades
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:55:52 +00:00
"""
return self._get("status")
2019-04-26 08:06:46 +00:00
def version(self):
"""
Returns the version of the bot
2019-06-23 20:10:37 +00:00
:return: json object containing the version
2019-04-26 08:06:46 +00:00
"""
return self._get("version")
2019-04-26 07:55:52 +00:00
def whitelist(self):
"""
Show the current whitelist
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:55:52 +00:00
"""
return self._get("whitelist")
def blacklist(self, *args):
"""
Show the current blacklist
:param add: List of coins to add (example: "BNB/BTC")
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 07:55:52 +00:00
"""
if not args:
return self._get("blacklist")
else:
return self._post("blacklist", data={"blacklist": args})
2019-04-26 10:50:13 +00:00
def forcebuy(self, pair, price=None):
"""
Buy an asset
:param pair: Pair to buy (ETH/BTC)
:param price: Optional - price to buy
2019-06-23 20:10:37 +00:00
:return: json object of the trade
2019-04-26 10:50:13 +00:00
"""
data = {"pair": pair,
"price": price
}
return self._post("forcebuy", data=data)
def forcesell(self, tradeid):
"""
Force-sell a trade
:param tradeid: Id of the trade (can be received via status command)
2019-06-23 20:10:37 +00:00
:return: json object
2019-04-26 10:50:13 +00:00
"""
return self._post("forcesell", data={"tradeid": tradeid})
2019-04-25 18:32:10 +00:00
2019-04-04 19:07:44 +00:00
def add_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("command",
help="Positional argument defining the command to execute.")
2019-04-26 07:55:52 +00:00
parser.add_argument('--show',
help='Show possible methods with this client',
dest='show',
action='store_true',
default=False
)
2019-04-09 04:40:15 +00:00
parser.add_argument('-c', '--config',
help='Specify configuration file (default: %(default)s). ',
dest='config',
type=str,
metavar='PATH',
default='config.json'
)
2019-04-26 07:12:03 +00:00
parser.add_argument("command_arguments",
help="Positional arguments for the parameters for [command]",
nargs="*",
default=[]
)
2019-04-04 19:07:44 +00:00
args = parser.parse_args()
return vars(args)
2019-04-09 04:40:15 +00:00
def load_config(configfile):
file = Path(configfile)
if file.is_file():
with file.open("r") as f:
config = json.load(f)
return config
return {}
2019-04-09 04:40:15 +00:00
2019-05-18 08:24:01 +00:00
def print_commands():
2019-05-18 08:29:38 +00:00
# Print dynamic help for the different commands using the commands doc-strings
2019-05-18 08:24:01 +00:00
client = FtRestClient(None)
print("Possible commands:")
for x, y in inspect.getmembers(client):
if not x.startswith('_'):
print(f"{x} {getattr(client, x).__doc__}")
2019-04-04 19:07:44 +00:00
2019-04-26 07:55:52 +00:00
2019-05-18 08:24:01 +00:00
def main(args):
if args.get("help"):
print_commands()
2019-04-26 07:55:52 +00:00
2019-04-09 04:40:15 +00:00
config = load_config(args["config"])
url = config.get("api_server", {}).get("server_url", "127.0.0.1")
port = config.get("api_server", {}).get("listen_port", "8080")
2019-05-25 12:14:09 +00:00
username = config.get("api_server", {}).get("username")
password = config.get("api_server", {}).get("password")
2019-04-09 04:40:15 +00:00
server_url = f"http://{url}:{port}"
2019-05-25 12:14:09 +00:00
client = FtRestClient(server_url, username, password)
2019-04-09 04:40:15 +00:00
2019-04-26 07:27:20 +00:00
m = [x for x, y in inspect.getmembers(client) if not x.startswith('_')]
command = args["command"]
if command not in m:
logger.error(f"Command {command} not defined")
2019-05-18 08:24:01 +00:00
print_commands()
2019-04-26 07:27:20 +00:00
return
print(getattr(client, command)(*args["command_arguments"]))
2019-04-04 19:07:44 +00:00
if __name__ == "__main__":
args = add_arguments()
main(args)