X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=helper.py;fp=helper.py;h=0000000000000000000000000000000000000000;hb=1f117ac79e10c3c9728d3b267d134dec2a165603;hp=8f726d5a831b25c12929af9ff8e1b9e5c5a98979;hpb=f9226903cb53a9b303a26de562e321159349f8df;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FCryptoportfolio%2FTrader.git diff --git a/helper.py b/helper.py deleted file mode 100644 index 8f726d5..0000000 --- a/helper.py +++ /dev/null @@ -1,320 +0,0 @@ -from datetime import datetime -import argparse -import configparser -import psycopg2 -import os -import sys - -import portfolio - -def make_order(market, value, currency, action="acquire", - close_if_possible=False, base_currency="BTC", follow=True, - compute_value="average"): - """ - Make an order on market - "market": The market on which to place the order - "value": The value in *base_currency* to acquire, - or in *currency* to dispose. - use negative for margin trade. - "action": "acquire" or "dispose". - "acquire" will buy long or sell short, - "dispose" will sell long or buy short. - "currency": The currency to acquire or dispose - "base_currency": The base currency. The value is expressed in that - currency (default: BTC) - "follow": Whether to follow the order once run (default: True) - "close_if_possible": Whether to try to close the position at the end - of the trade, i.e. reach exactly 0 at the end - (only meaningful in "dispose"). May have - unwanted effects if the end value of the - currency is not 0. - "compute_value": Compute value to place the order - """ - market.report.log_stage("make_order_begin") - market.balances.fetch_balances(tag="make_order_begin") - if action == "acquire": - trade = portfolio.Trade( - portfolio.Amount(base_currency, 0), - portfolio.Amount(base_currency, value), - currency, market) - else: - amount = portfolio.Amount(currency, value) - trade = portfolio.Trade( - amount.in_currency(base_currency, market, compute_value=compute_value), - portfolio.Amount(base_currency, 0), - currency, market) - market.trades.all.append(trade) - order = trade.prepare_order( - close_if_possible=close_if_possible, - compute_value=compute_value) - market.report.log_orders([order], None, compute_value) - market.trades.run_orders() - if follow: - market.follow_orders() - market.balances.fetch_balances(tag="make_order_end") - else: - market.report.log_stage("make_order_end_not_followed") - return order - market.report.log_stage("make_order_end") - -def get_user_market(config_path, user_id, debug=False): - import market - pg_config, report_path = main_parse_config(config_path) - market_config = list(main_fetch_markets(pg_config, str(user_id)))[0][0] - return market.Market.from_config(market_config, debug=debug) - -def main_parse_args(argv): - parser = argparse.ArgumentParser( - description="Run the trade bot") - - parser.add_argument("-c", "--config", - default="config.ini", - required=False, - help="Config file to load (default: config.ini)") - parser.add_argument("--before", - default=False, action='store_const', const=True, - help="Run the steps before the cryptoportfolio update") - parser.add_argument("--after", - default=False, action='store_const', const=True, - help="Run the steps after the cryptoportfolio update") - parser.add_argument("--debug", - default=False, action='store_const', const=True, - help="Run in debug mode") - parser.add_argument("--user", - default=None, required=False, help="Only run for that user") - parser.add_argument("--action", - action='append', - help="Do a different action than trading (add several times to chain)") - - args = parser.parse_args(argv) - - if not os.path.exists(args.config): - print("no config file found, exiting") - sys.exit(1) - - return args - -def main_parse_config(config_file): - config = configparser.ConfigParser() - config.read(config_file) - - if "postgresql" not in config: - print("no configuration for postgresql in config file") - sys.exit(1) - - if "app" in config and "report_path" in config["app"]: - report_path = config["app"]["report_path"] - - if not os.path.exists(report_path): - os.makedirs(report_path) - else: - report_path = None - - return [config["postgresql"], report_path] - -def main_fetch_markets(pg_config, user): - connection = psycopg2.connect(**pg_config) - cursor = connection.cursor() - - if user is None: - cursor.execute("SELECT config,user_id FROM market_configs") - else: - cursor.execute("SELECT config,user_id FROM market_configs WHERE user_id = %s", user) - - for row in cursor: - yield row - -def main_process_market(user_market, actions, before=False, after=False): - if len(actions or []) == 0: - if before: - Processor(user_market).process("sell_all", steps="before") - if after: - Processor(user_market).process("sell_all", steps="after") - else: - for action in actions: - if action in globals(): - (globals()[action])(user_market) - else: - raise NotImplementedError("Unknown action {}".format(action)) - -def main_store_report(report_path, user_id, user_market): - try: - if report_path is not None: - report_file = "{}/{}_{}.json".format(report_path, datetime.now().isoformat(), user_id) - with open(report_file, "w") as f: - f.write(user_market.report.to_json()) - except Exception as e: - print("impossible to store report file: {}; {}".format(e.__class__.__name__, e)) - -def print_orders(market, base_currency="BTC"): - market.report.log_stage("print_orders") - market.balances.fetch_balances(tag="print_orders") - market.prepare_trades(base_currency=base_currency, compute_value="average") - market.trades.prepare_orders(compute_value="average") - -def print_balances(market, base_currency="BTC"): - market.report.log_stage("print_balances") - market.balances.fetch_balances() - if base_currency is not None: - market.report.print_log("total:") - market.report.print_log(sum(market.balances.in_currency(base_currency).values())) - -class Processor: - scenarios = { - "sell_needed": [ - { - "name": "wait", - "number": 0, - "before": False, - "after": True, - "wait_for_recent": {}, - }, - { - "name": "sell", - "number": 1, - "before": False, - "after": True, - "fetch_balances": ["begin", "end"], - "prepare_trades": {}, - "prepare_orders": { "only": "dispose", "compute_value": "average" }, - "run_orders": {}, - "follow_orders": {}, - "close_trades": {}, - }, - { - "name": "buy", - "number": 2, - "before": False, - "after": True, - "fetch_balances": ["begin", "end"], - "prepare_trades": { "only": "acquire" }, - "prepare_orders": { "only": "acquire", "compute_value": "average" }, - "move_balances": {}, - "run_orders": {}, - "follow_orders": {}, - "close_trades": {}, - }, - ], - "sell_all": [ - { - "name": "all_sell", - "number": 1, - "before": True, - "after": False, - "fetch_balances": ["begin", "end"], - "prepare_trades": { "repartition": { "base_currency": (1, "long") } }, - "prepare_orders": { "compute_value": "average" }, - "run_orders": {}, - "follow_orders": {}, - "close_trades": {}, - }, - { - "name": "wait", - "number": 2, - "before": False, - "after": True, - "wait_for_recent": {}, - }, - { - "name": "all_buy", - "number": 3, - "before": False, - "after": True, - "fetch_balances": ["begin", "end"], - "prepare_trades": {}, - "prepare_orders": { "compute_value": "average" }, - "move_balances": {}, - "run_orders": {}, - "follow_orders": {}, - "close_trades": {}, - }, - ] - } - - ordered_actions = [ - "wait_for_recent", "prepare_trades", "prepare_orders", - "move_balances", "run_orders", "follow_orders", - "close_trades"] - - def __init__(self, market): - self.market = market - - def select_steps(self, scenario, step): - if step == "all": - return scenario - elif step == "before" or step == "after": - return list(filter(lambda x: step in x and x[step], scenario)) - elif type(step) == int: - return [scenario[step-1]] - elif type(step) == str: - return list(filter(lambda x: x["name"] == step, scenario)) - else: - raise TypeError("Unknown step {}".format(step)) - - def process(self, scenario_name, steps="all", **kwargs): - scenario = self.scenarios[scenario_name] - selected_steps = [] - - if type(steps) == str or type(steps) == int: - selected_steps += self.select_steps(scenario, steps) - else: - for step in steps: - selected_steps += self.select_steps(scenario, step) - for step in selected_steps: - self.process_step(scenario_name, step, kwargs) - - def process_step(self, scenario_name, step, kwargs): - process_name = "process_{}__{}_{}".format(scenario_name, step["number"], step["name"]) - self.market.report.log_stage("{}_begin".format(process_name)) - if "begin" in step.get("fetch_balances", []): - self.market.balances.fetch_balances(tag="{}_begin".format(process_name)) - - for action in self.ordered_actions: - if action in step: - self.run_action(action, step[action], kwargs) - - if "end" in step.get("fetch_balances", []): - self.market.balances.fetch_balances(tag="{}_end".format(process_name)) - self.market.report.log_stage("{}_end".format(process_name)) - - def method_arguments(self, action): - import inspect - - if action == "wait_for_recent": - method = portfolio.Portfolio.wait_for_recent - elif action == "prepare_trades": - method = self.market.prepare_trades - elif action == "prepare_orders": - method = self.market.trades.prepare_orders - elif action == "move_balances": - method = self.market.move_balances - elif action == "run_orders": - method = self.market.trades.run_orders - elif action == "follow_orders": - method = self.market.follow_orders - elif action == "close_trades": - method = self.market.trades.close_trades - - signature = inspect.getfullargspec(method) - defaults = signature.defaults or [] - kwargs = signature.args[-len(defaults):] - - return [method, kwargs] - - def parse_args(self, action, default_args, kwargs): - method, allowed_arguments = self.method_arguments(action) - args = {k: v for k, v in {**default_args, **kwargs}.items() if k in allowed_arguments } - - if "repartition" in args and "base_currency" in args["repartition"]: - r = args["repartition"] - r[args.get("base_currency", "BTC")] = r.pop("base_currency") - - return method, args - - def run_action(self, action, default_args, kwargs): - method, args = self.parse_args(action, default_args, kwargs) - - if action == "wait_for_recent": - method(self.market, **args) - else: - method(**args)