diff --git a/libraries/colors.py b/libraries/colors.py new file mode 100644 index 0000000..d5d87c5 --- /dev/null +++ b/libraries/colors.py @@ -0,0 +1,12 @@ +class colors: + ''' + Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + ''' + yellow = "\033[0;33;40m" + green = "\033[0;32;40m" + red = "\033[0;31;40m" + blue = "\033[0;34;40m" + cyan = "\033[0;36;40m" + bright_white = "\033[0;97;40m" + bright_green = "\033[0;92;40m" + white = "\033[0;37;40m" \ No newline at end of file diff --git a/libraries/earner.py b/libraries/earner.py index cd4245c..738e45a 100644 --- a/libraries/earner.py +++ b/libraries/earner.py @@ -1,5 +1,6 @@ import time from libraries.balance_accounts import balance_accounts +from libraries.colors import colors class earner: @@ -31,37 +32,60 @@ class earner: self.is_paused = not self.is_paused return self.is_paused + def get_is_paused(self): + return self.is_paused + def set_step_size(self, step_size): - self.step_size = step_size - return self.step_size + try: + self.step_size = float(step_size) + return self.step_size + except Exception as e: + print(e) + return 0 def get_step_size(self): return self.step_size def set_percentage(self, percentage): - self.percentage = percentage - return self.percentage + try: + self.percentage = float(percentage) + return self.percentage + except Exception as e: + print(e) + return 0 def get_percentage(self): return self.percentage def set_minimum_amount_in_trading_account(self, minimum_amount_in_trading_account): - self.minimum_amount_in_trading_account = minimum_amount_in_trading_account - return self.minimum_amount_in_trading_account + try: + self.minimum_amount_in_trading_account = float(minimum_amount_in_trading_account) + return self.minimum_amount_in_trading_account + except Exception as e: + print(e) + return 0 def get_minimum_amount_in_trading_account(self): return self.minimum_amount_in_trading_account def set_time_between_subscriptions(self, time_between_subscriptions): - self.time_between_subscriptions = time_between_subscriptions - return self.time_between_subscriptions + try: + self.time_between_subscriptions = float(time_between_subscriptions) + return self.time_between_subscriptions + except Exception as e: + print(e) + return 0 def get_time_between_subscriptions(self): return self.time_between_subscriptions def set_time_between_redemptions(self, time_between_redemptions): - self.time_between_redemptions = time_between_redemptions - return self.time_between_redemptions + try: + self.time_between_redemptions = float(time_between_redemptions) + return self.time_between_redemptions + except Exception as e: + print(e) + return 0 def get_time_between_redemptions(self): return self.time_between_redemptions @@ -143,11 +167,11 @@ class earner: self.redeem(-earning_delta) print(f"{str(self.connector)} - Difference: {earning_delta}") else: - paused_string = "| PAUSED - NOT SUBSCRIBING NOR REDEEMING" + paused_string = "| "+colors.yellow+"PAUSED"+colors.white #Output status to status_string balances_string = f"Trading balance: {float(self.trading_balance):.2f} {self.currency} | Earning balance: {float(self.earning_balance):.2f} {self.currency}" percentages_string = f"On earn: {float(self.earning_balance)/float(self.trading_balance):.2%} {paused_string}" - self.status_string = f"{self} | {balances_string} | {percentages_string}" + self.status_string = f"{colors.cyan}{self}{colors.white} | {balances_string} | {percentages_string}" \ No newline at end of file diff --git a/main.py b/main.py index 0657ed9..8547ed6 100644 --- a/main.py +++ b/main.py @@ -4,13 +4,16 @@ from libraries.wrappers import earn_kucoin from libraries.wrappers import earn_okx from libraries.wrappers import earn_gateio from libraries.earner import earner +from libraries.colors import colors from threading import Thread from flask import Flask, jsonify, request +from waitress import serve import time import datetime import json import sqlite3 + def load_keys_from_db(file_name: str) -> list: ''' Load valid API keys @@ -71,8 +74,6 @@ def main(): item.join() #Print status - print("="*80) - subscriptions = [] redemptions = [] for item in earners: @@ -99,9 +100,10 @@ def main(): print("-"*80) total_on_trading = sum([item.get_trading_balance() for item in earners]) total_on_earning = sum([item.get_earning_balance() for item in earners]) - print(f"Version {version} | Total funds: {total_on_trading+total_on_earning:.2f} | Total on earn: {total_on_earning:.2f} ({total_on_earning/total_on_trading*100:.2f}%)") + time_of_day = datetime.datetime.now().strftime('[%Y/%m/%d %H:%M:%S]') + print(f"{time_of_day} | Version {version} | Total funds: {total_on_trading+total_on_earning:.2f} | Total on earn: {total_on_earning:.2f} ({total_on_earning/total_on_trading*100:.2f}%)") print(f"Uptime: {seconds_to_time(time.time()-start_time)} | Last subscription: {last_subscription_key} - {last_subscription_value} | Last redemption: {last_redemption_key} - {last_redemption_value}") - + print(colors.blue+"="*80+colors.white) #Wait for next lap time.sleep(config["lap_time"]) @@ -120,20 +122,277 @@ def toggle_pause(): Parameters: broker: str - ''' - + ''' + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] if request.json is None: return jsonify({'Error': 'request.json is None'}) broker = request.json["broker"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) for item in earners: if str(item.connector)==broker: item.toggle_pause() - return jsonify({'Status': item.is_paused}) + return jsonify({'Status': item.get_is_paused()}) return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key invalid'}), 401 + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_step_size", methods=["GET"]) +def get_step_size(): + ''' + GET request + + Parameters: + broker: str + ''' + + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'step_size': item.get_step_size()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/set_step_size", methods=["POST"]) +def set_step_size(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_step_size = request.json["new_step_size"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + if new_step_size is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_step_size(new_step_size) + return jsonify({'step_size': new_step_size}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_percentage", methods=["GET"]) +def get_percentage(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'percentage': item.get_percentage()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/set_percentage", methods=["POST"]) +def set_percentage(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_percentage = request.json["new_percentage"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + if new_percentage is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_percentage(new_percentage) + return jsonify({'percentage': new_percentage}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 +@earn_api.route("/get_time_between_subscriptions", methods=["GET"]) +def get_time_between_subscriptions(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'time_between_subscriptions': item.get_time_between_subscriptions()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/set_time_between_subscriptions", methods=["POST"]) +def set_time_between_subscriptions(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_time_between_subscriptions = request.json["new_time_between_subscriptions"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + if new_time_between_subscriptions is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_time_between_subscriptions(new_time_between_subscriptions) + return jsonify({'percentage': new_time_between_subscriptions}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_time_between_redemptions", methods=["GET"]) +def get_time_between_redemptions(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'time_between_redemptions': item.get_time_between_redemptions()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/set_time_between_redemptions", methods=["POST"]) +def set_time_between_redemptions(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_time_between_redemptions = request.json["new_time_between_redemptions"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + if new_time_between_redemptions is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_time_between_redemptions(new_time_between_redemptions) + return jsonify({'percentage': new_time_between_redemptions}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_minimum_amount_in_trading_account", methods=["GET"]) +def get_minimum_amount_in_trading_account(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'minimum_amount_in_trading_account': item.get_minimum_amount_in_trading_account()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/set_minimum_amount_in_trading_account", methods=["POST"]) +def set_minimum_amount_in_trading_account(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.json["broker"] + new_minimum_amount_in_trading_account = request.json["new_minimum_amount_in_trading_account"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + if new_minimum_amount_in_trading_account is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_minimum_amount_in_trading_account(new_minimum_amount_in_trading_account) + return jsonify({'percentage': new_minimum_amount_in_trading_account}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_last_subscription", methods=["GET"]) +def get_last_subscription(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'last_subscription': item.get_last_subscription()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_last_redemption", methods=["GET"]) +def get_last_redemption(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'last_redemption': item.get_last_redemption()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + + +@earn_api.route("/get_total_balance", methods=["GET"]) +def get_total_balance(): + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + valid_brokers = [str(item.connector) for item in earners] + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_brokers: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'trading_balance': item.get_trading_balance(), 'earning_balance': item.get_earning_balance()}) + return jsonify({'Error': 'broker not found'}) + return jsonify({'Error': 'API key not valid'}), 401 + +''' +Missing endpoints: + /get_total_balance +''' + + +def run_API(): + serve(earn_api, host="0.0.0.0", port=5011) + + if __name__=="__main__": version = "2025.01.07" @@ -153,8 +412,14 @@ if __name__=="__main__": #Load valid API keys valid_keys = load_keys_from_db("keys/api_credentials.db") - - main() + + #Threads to run: main loop and flask api + main_threads = [Thread(target=main),Thread(target=run_API)] + + #Iterate indefinitely: + for m in main_threads: + m.start() +