From a18469445b2fad426a822a2687aee7d02440d1fc Mon Sep 17 00:00:00 2001 From: T Zacks <106902748+TZEG@users.noreply.github.com> Date: Wed, 5 Oct 2022 17:44:42 +0200 Subject: [PATCH] Delete helpers directory --- helpers/badcoins.py | 245 --------- helpers/logging.py | 213 -------- helpers/misc.py | 338 ------------- helpers/threecommas.py | 1084 ---------------------------------------- 4 files changed, 1880 deletions(-) delete mode 100644 helpers/badcoins.py delete mode 100644 helpers/logging.py delete mode 100644 helpers/misc.py delete mode 100644 helpers/threecommas.py diff --git a/helpers/badcoins.py b/helpers/badcoins.py deleted file mode 100644 index 73d8286..0000000 --- a/helpers/badcoins.py +++ /dev/null @@ -1,245 +0,0 @@ -# manipulated_coins = ["YFIUSDT", -# "UNIUSDT", -# "AAVEUSDT", -# "C98USDT", -# "USTCUSDT", -# "BNBUSDT", -# "TRUUSDT", -# "CAKEUSDT", -# "FISUSDT", -# "RUNEUSDT", -# "SHIBUSDT", -# "BZRXUSDT", -# "DEXEUSDT", -# "MFTUSDT", -# "WBTCUSDT", -# "WINUSDT", -# "HEGICUSDT", -# "XVSUSDT", -# "AKROUSDT", -# "COMPUSDT", -# "PERPUSDT", -# "RAMPUSDT", -# "SRMUSDT", -# "RAYUSDT", -# "MIRUSDT", -# "UMAUSDT", -# "DFUSDT", -# "GVTUSDT", -# "FARMUSDT", -# "MLNUSDT", -# "RENUSDT", -# "TROYUSDT", -# "BETAUSDT", -# "KAVAUSDT", -# "REEFUSDT", -# "BONDUSDT", -# "OMUSDT", -# "ALPHAUSDT", -# "SUNUSDT", -# "BADGERUSDT", -# "ALPACAUSDT", -# "DYDXUSDT", -# "SAFEMOONUSDT", -# "BELUSDT", -# "IDEXUSDT", -# "KCSUSDT", -# "USTUSDT", -# "BUSDUSDT", -# "USDCUSDT", -# "TUSDUSDT", -# "USDPUSDT", -# "EURUSDT", -# "AUDUSDT", -# "SHIBUSDT", -# "GBPUSDT", -# "SUSDUSDT", -# "EURTUSDT", -# "DIAUSDT", -# "MIMUSDT", -# "FRAXUSDT", -# "SUSHIUSDT", -# "LUSDUSDT", -# "NUSDUSDT", -# "XUATUSDT", -# "HUSDUSDT", -# "OUSDUSDT", -# "ALUSDUSDT", -# "GUSDUSDT", -# "CUSDUSDT", -# "MUSDUSDT", -# "CEURUSDT", -# "USDKUSDT", -# "RSVUSDT", -# "EOSDTUSDT", -# "SAUDUSDT", -# "BITCNYUSDT", -# "YFIIUSDT", -# "ESDUSDT", -# "PARUSDT", -# "DUSDUSDT", -# "DSDUSDT", -# "USDAPUSDT", -# "ARTHUSDT", -# "ZUSDUSDT", -# "WUSDUSDT", -# "ONCUSDT", -# "DEBASEUSDT", -# "BSDUSDT", -# "SACUSDT", -# "COUSDUSDT", -# "NZDSUSDT", -# "USDUSDT", -# "XDAIUSDT", -# "FLEXUSDUSDT", -# "BDOUSDT", -# "THKDUSDT", -# "USNBTUSDT", -# "IRONUSDT", -# "WUSDUSDT", -# "USDOUSDT", -# "QCUSDT", -# "JEURUSDT", -# "JGBPUSDT", -# "JCHFUSDT", -# "MALTUSDT", -# "XUSDUSDT", -# "IRONUSDT", -# "USDSUSDT", -# "OUSDUSDT", -# "JPYCUSDT", -# "HBTCUSDT", -# "WBTCUSDT", -# "STETHUSDT", -# "BNBUSDT", -# "MKRUSDT", -# "CETHUSDT", -# "CREAMUSDT", -# "CDAIUSDT", -# "TUSDT", -# "BCCUSDT", -# "BTTCUSDT", -# "YFIBUSD", -# "UNIBUSD", -# "AAVEBUSD", -# "C98BUSD", -# "BNBBUSD", -# "TRUBUSD", -# "CAKEBUSD", -# "FISBUSD", -# "RUNEBUSD", -# "SHIBBUSD", -# "BZRXBUSD", -# "DEXEBUSD", -# "MFTBUSD", -# "WBTCBUSD", -# "WINBUSD", -# "HEGICBUSD", -# "XVSBUSD", -# "AKROBUSD", -# "COMPBUSD", -# "PERPBUSD", -# "RAMPBUSD", -# "SRMBUSD", -# "USTCBUSD", -# "RAYBUSD", -# "MIRBUSD", -# "UMABUSD", -# "DFBUSD", -# "GVTBUSD", -# "FARMBUSD", -# "MLNBUSD", -# "RENBUSD", -# "TROYBUSD", -# "BETABUSD", -# "KAVABUSD", -# "REEFBUSD", -# "BONDBUSD", -# "OMBUSD", -# "ALPHABUSD", -# "SUNBUSD", -# "BADGERBUSD", -# "ALPACABUSD", -# "DYDXBUSD", -# "SAFEMOONBUSD", -# "BELBUSD", -# "IDEXBUSD", -# "KCSBUSD", -# "USTBUSD", -# "BUSDBUSD", -# "USDCBUSD", -# "TUSDBUSD", -# "USDPBUSD", -# "EURBUSD", -# "AUDBUSD", -# "SHIBBUSD", -# "GBPBUSD", -# "SUSDBUSD", -# "EURTBUSD", -# "DIABUSD", -# "MIMBUSD", -# "FRAXBUSD", -# "SUSHIBUSD", -# "LUSDBUSD", -# "NUSDBUSD", -# "XUATBUSD", -# "HUSDBUSD", -# "OUSDBUSD", -# "ALUSDBUSD", -# "GUSDBUSD", -# "CUSDBUSD", -# "MUSDBUSD", -# "CEURBUSD", -# "USDKBUSD", -# "RSVBUSD", -# "EOSDTBUSD", -# "SAUDBUSD", -# "BITCNYBUSD", -# "YFIIBUSD", -# "ESDBUSD", -# "PARBUSD", -# "DUSDBUSD", -# "DSDBUSD", -# "USDAPBUSD", -# "ARTHBUSD", -# "ZUSDBUSD", -# "WUSDBUSD", -# "ONCBUSD", -# "DEBASEBUSD", -# "BSDBUSD", -# "SACBUSD", -# "COUSDBUSD", -# "NZDSBUSD", -# "USDBUSD", -# "XDAIBUSD", -# "FLEXUSDBUSD", -# "BDOBUSD", -# "THKDBUSD", -# "USNBTBUSD", -# "IRONBUSD", -# "WUSDBUSD", -# "USDOBUSD", -# "QCBUSD", -# "JEURBUSD", -# "JGBPBUSD", -# "JCHFBUSD", -# "MALTBUSD", -# "XUSDBUSD", -# "IRONBUSD", -# "USDSBUSD", -# "OUSDBUSD", -# "JPYCBUSD", -# "HBTCBUSD", -# "WBTCBUSD", -# "STETHBUSD", -# "BNBBUSD", -# "MKRBUSD", -# "CETHBUSD", -# "CREAMBUSD", -# "CDAIBUSD", -# "TBUSD", -# "BCCBUSD", -# "BTTCUSDT"] - -manipulated_coins = ["ICXUSDT", "LDOUSDT", "EPSUSDT", "BCHSVUSDT", "USDPUSDT", "GALAXUSDT", "OLEUSDT", "FORTUSDT", - "CSPRUSDT", "REV3LUSDT", "CULTUSDT", "WEMIXUSDT", "WELLUSDT"] diff --git a/helpers/logging.py b/helpers/logging.py deleted file mode 100644 index 637e8ec..0000000 --- a/helpers/logging.py +++ /dev/null @@ -1,213 +0,0 @@ -""" ZCrypto bot helpers.""" -import json -import logging -import os -import queue -import threading -import time -from logging.handlers import TimedRotatingFileHandler as _TimedRotatingFileHandler -from colorama import Fore, init -import sys - -init(autoreset=True) -import apprise - - -class NotificationHandler: - """Notification class.""" - - def __init__(self, program, enabled=False, notify_urls=None): - self.program = program - self.message = "" - - if enabled and notify_urls: - self.apobj = apprise.Apprise() - urls = json.loads(notify_urls) - for url in urls: - self.apobj.add(url) - self.queue = queue.Queue() - self.start_worker() - self.enabled = True - else: - self.enabled = False - - def start_worker(self): - """Start notification worker.""" - threading.Thread(target=self.process_queue, daemon=True).start() - - def process_queue(self): - """Process the queue.""" - while True: - message, attachments = self.queue.get() - if attachments: - self.apobj.notify(body=message, attach=attachments) - else: - self.apobj.notify(body=message) - self.queue.task_done() - - def queue_notification(self, message): - """Queue notification messages.""" - if self.enabled: - message.encode(encoding='UTF-8', errors='strict') - self.message += f"{message}\n\n" - - def send_notification(self): - """Send the notification messages if there are any.""" - if self.enabled and self.message: - msg = f"-|- ZCrypto {self.program} -|- \n\n" + self.message - self.queue.put((msg, [])) - self.message = "" - - -class TimedRotatingFileHandler(_TimedRotatingFileHandler): - """Override original code to fix bug with not deleting old logfiles.""" - - def __init__(self, filename="", when="midnight", interval=1, backupCount=7, encoding='utf-8'): - super().__init__( - filename=filename, - when=when, - interval=int(interval), - backupCount=int(backupCount), - encoding=encoding - ) - - def getFilesToDelete(self): - """Find all logfiles present.""" - dirname, basename = os.path.split(self.baseFilename) - filenames = os.listdir(dirname) - result = [] - prefix = basename + "." - plen = len(prefix) - for filename in filenames: - if filename[:plen] == prefix: - suffix = filename[plen:] - if self.extMatch.match(suffix): - result.append(os.path.join(dirname, filename)) - result.sort() - if len(result)0: - for oldlog in self.getFilesToDelete(): - os.remove(oldlog) - - self.stream = open(self.baseFilename, "w") - - currenttime = int(time.time()) - newrolloverat = self.computeRollover(currenttime) - while newrolloverat<=currenttime: - newrolloverat = newrolloverat + self.interval - - self.rolloverAt = newrolloverat - - -class Logger: - """Logger class.""" - - my_logger = None - - def __init__( - self, - datadir, - program, - notificationhandler, - logstokeep, - debug_enabled, - notify_enabled, - ): - """Logger init.""" - self.my_logger = logging.getLogger() - self.datadir = datadir - self.program = program - self.notify_enabled = notify_enabled - self.notificationhandler = notificationhandler - - if debug_enabled: - self.my_logger.setLevel(logging.DEBUG) - self.my_logger.propagate = False - else: - self.my_logger.setLevel(logging.INFO) - self.my_logger.propagate = False - - date_fmt = "%Y-%m-%d %H:%M:%S" - - formatter = logging.Formatter( - f"%(asctime)s - {program} - %(levelname)s - %(message)s", date_fmt - ) - console_formatter = logging.Formatter( - f"%(asctime)s - {program} - %(levelname)s - %(message)s", date_fmt - ) - # Create directory if not exists - if not os.path.exists(f"{self.datadir}/logs"): - os.makedirs(f"{self.datadir}/logs") - - # Log to file and rotate if needed - file_handle = TimedRotatingFileHandler( - filename=f"{self.datadir}/logs/{self.program}.log", backupCount=logstokeep, encoding='utf-8' - ) - file_handle.setFormatter(formatter) - self.my_logger.addHandler(file_handle) - - # Log to console - console_handle = logging.StreamHandler() - console_handle.setLevel(logging.INFO) - console_handle.setFormatter(console_formatter) - self.my_logger.addHandler(console_handle) - - self.info(f"ZCrypto {program}") - self.info("Started on %s" % time.strftime("%A %H:%M:%S %Y-%m-%d")) - - if self.notify_enabled: - self.info("Notifications are enabled") - else: - self.info("Notifications are disabled") - - def log(self, message, level="info"): - """Call the log levels.""" - if level == "info": - self.my_logger.info(message) - elif level == "warning": - self.my_logger.warning(message) - elif level == "error": - self.my_logger.error(message) - elif level == "debug": - self.my_logger.debug(message) - - def info(self, message, notify=False): - """Info level.""" - self.log(Fore.LIGHTWHITE_EX + message, "info") - if self.notify_enabled and notify: - self.notificationhandler.queue_notification(message) - - def warning(self, message, notify=True): - """Warning level.""" - self.log(Fore.LIGHTYELLOW_EX + message, "warning") - if self.notify_enabled and notify: - self.notificationhandler.queue_notification(message) - - def error(self, message, notify=True): - """Error level.""" - self.log(Fore.LIGHTRED_EX + message, "error") - if self.notify_enabled and notify: - self.notificationhandler.queue_notification(message) - - def debug(self, message, notify=False): - """Debug level.""" - self.log(message, "debug") - if self.notify_enabled and notify: - self.notificationhandler.queue_notification(message) diff --git a/helpers/misc.py b/helpers/misc.py deleted file mode 100644 index e034b01..0000000 --- a/helpers/misc.py +++ /dev/null @@ -1,338 +0,0 @@ -"""Cyberjunky's ZCrypto bot helpers.""" -import datetime -import time -import re - -import requests -from bs4 import BeautifulSoup - -PAIREXCLUDE_EXT = "pairexclude" - - -def wait_time_interval(logger, notification, time_interval, notify=True): - """Wait for time interval.""" - - if time_interval>0: - localtime = time.time() - nexttime = localtime + int(time_interval) - timeresult = time.strftime("%H:%M:%S", time.localtime(nexttime)) - logger.info( - "Next update in %s at %s" % (str(datetime.timedelta(seconds=time_interval)), timeresult), notify - ) - notification.send_notification() - time.sleep(time_interval) - return True - - notification.send_notification() - time.sleep(2) - - return False - - -def futures_pair(pair): - pair = "USDT_" + pair.upper() + "USDT" - return pair - - -def spot_pair(pair): - pair = "USDT_" + pair.upper() - return pair - - -def back_to_binance(pair): - """Convert a binance/tradingview formatted pair to threecommas format.""" - a = pair.split("_") - pair = a[1] + a[0] - return pair - - -def binance_pair(pair): - pair = pair.upper() + "USDT" - return pair - - -def populate_pair_lists(pair, blacklist, blackpairs, badpairs, newpairs, tickerlist): - """Create pair lists.""" - - # Check if pair is in tickerlist and on 3Commas blacklist - if pair in tickerlist: - if pair in blacklist: - blackpairs.append(pair) - else: - newpairs.append(pair) - else: - badpairs.append(pair) - - -def get_lunarcrush_data(logger, program, config, usdtbtcprice): - """Get the top x GalaxyScore, AltRank or Volatile coins from LunarCrush.""" - - lccoins = {} - lcapikey = config.get("settings", "lc-apikey") - lcfetchlimit = config.get("settings", "lc-fetchlimit") - - # Construct query for LunarCrush data - if "altrank" in program: - parms = { - "data": "market", - "type": "fast", - "sort": "acr", - "limit": lcfetchlimit, - "key": lcapikey, - } - elif "galaxyscore" in program: - parms = { - "data": "market", - "type": "fast", - "sort": "gs", - "limit": lcfetchlimit, - "key": lcapikey, - "desc": True, - } - elif "volatility" in program: - parms = { - "data": "market", - "type": "fast", - "sort": "vt", - "limit": lcfetchlimit, - "key": lcapikey, - "desc": True, - } - - try: - result = requests.get("https://api.lunarcrush.com/v2", params=parms) - result.raise_for_status() - data = result.json() - - if "data" in data.keys(): - for i, crush in enumerate(data["data"], start=1): - crush["categories"] = ( - list(crush["categories"].split(",")) if crush["categories"] else [] - ) - crush["rank"] = i - crush["volbtc"] = crush["v"] / float(usdtbtcprice) - logger.debug( - f"rank:{crush['rank']:3d} acr:{crush['acr']:4d} gs:{crush['gs']:3.1f} " - f"s:{crush['s']:8s} '{crush['n']:25}' volume in btc:{crush['volbtc']:12.2f}" - f" categories:{crush['categories']}" - ) - lccoins = data["data"] - - except requests.exceptions.HTTPError as err: - logger.error("Fetching LunarCrush data failed with error: %s" % err) - return {} - - logger.info("Fetched LunarCrush ranking OK (%s coins)" % (len(lccoins))) - - return lccoins - - -def get_coinmarketcap_data(logger, cmc_apikey, start_number, limit): - """Get the data from CoinMarketCap.""" - - cmcdict = {} - - # Construct query for CoinMarketCap data - parms = { - "start": start_number, - "limit": limit, - "convert": "BTC", - "aux": "cmc_rank", - } - - headrs = { - "X-CMC_PRO_API_KEY": cmc_apikey, - } - - try: - result = requests.get( - "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest", - params=parms, - headers=headrs, - ) - result.raise_for_status() - data = result.json() - - if "data" in data.keys(): - for i, cmc in enumerate(data["data"], start=1): - cmc["rank"] = i - logger.debug( - f"rank:{cmc['rank']:3d} cmc_rank:{cmc['cmc_rank']:3d} s:{cmc['symbol']:8} " - f"'{cmc['name']:25}' volume_24h:{cmc['quote']['BTC']['volume_24h']:12.2f} " - f"volume_change_24h:{cmc['quote']['BTC']['volume_change_24h']:5.2f} " - f"market_cap:{cmc['quote']['BTC']['market_cap']:12.2f}" - ) - cmcdict = data["data"] - - except requests.exceptions.HTTPError as err: - logger.error("Fetching CoinMarketCap data failed with error: %s" % err) - return {} - - logger.info("Fetched CoinMarketCap data OK (%s coins)" % (len(cmcdict))) - - return cmcdict - - -def check_deal(cursor, dealid): - """Check if deal was already logged.""" - - return cursor.execute(f"SELECT * FROM deals WHERE dealid = {dealid}").fetchone() - - -def format_pair(logger, marketcode, base, coin): - """Format pair depending on exchange.""" - - # Construct pair based on bot settings (BTC stays BTC, but USDT can become BUSD) - if marketcode == "binance_futures": - pair = f"{base}_{coin}{base}" - elif marketcode == "ftx_futures": - pair = f"{base}_{coin}-PERP" - else: - pair = f"{base}_{coin}" - - logger.debug("New pair constructed: %s" % pair) - - return pair - - -def get_round_digits(pair): - """Get the number of digits for the round function.""" - - numberofdigits = 4 - - if pair: - base = pair.split("_")[0] - - if base in ("BTC", "BNB", "ETH"): - numberofdigits = 8 - - return numberofdigits - - -def remove_prefix(text, prefix): - """Get the string without prefix, required for Python < 3.9.""" - - if text.startswith(prefix): - return text[len(prefix):] - return text - - -def get_botassist_data(logger, botassistlist, start_number, limit): - """Get the top pairs from 3c-tools bot-assist explorer.""" - - url = "https://www.3c-tools.com/markets/bot-assist-explorer" - parms = {"list": botassistlist} - - pairs = list() - try: - result = requests.get(url, params=parms) - result.raise_for_status() - soup = BeautifulSoup(result.text, features="html.parser") - data = soup.find("table", class_="table table-striped table-sm") - - columncount = 0 - columndict = {} - - # Build list of columns we are interested in - tablecolumns = data.find_all("th") - for column in tablecolumns: - if column.text not in ("#", "symbol"): - columndict[columncount] = column.text - - columncount += 1 - - tablerows = data.find_all("tr") - for row in tablerows: - rowcolums = row.find_all("td") - if len(rowcolums)>0: - rank = int(rowcolums[0].text) - if rank0: - newpairs.remove(pair) - - -def load_bot_excluded_coins(logger, share_dir, bot_id, extension): - """Load excluded coins from file, for the specified bot""" - - excludedlist = [] - excludefilename = f"{share_dir}/{bot_id}.{extension}" - - try: - with open(excludefilename, "r") as file: - excludedlist = file.read().splitlines() - if excludedlist: - logger.info( - "Reading exclude file '%s' OK (%s coins)" - % (excludefilename, len(excludedlist)) - ) - except FileNotFoundError: - logger.info( - "Exclude file (%s) not found for bot '%s'; no coins to exclude." - % (excludefilename, bot_id) - ) - - return excludedlist - - -def unix_timestamp_to_string(timestamp, date_time_format): - """Convert the given timestamp to a readable date/time in the specified format""" - - return datetime.datetime.fromtimestamp(timestamp).strftime(date_time_format) - - -def format_pair_three(pair): - """Convert a binance/tradingview formatted pair to threecommas format.""" - - for coin in ["BTC", "USDT", "BUSD"]: - x = re.search(f"{coin}$", pair) - if x: - y = re.split(f"{coin}$", pair) - pair = f"{coin}_{y[0]}" - - return pair - - return None \ No newline at end of file diff --git a/helpers/threecommas.py b/helpers/threecommas.py deleted file mode 100644 index 570a4fb..0000000 --- a/helpers/threecommas.py +++ /dev/null @@ -1,1084 +0,0 @@ -"""Cyberjunky bot helpers.""" -from py3cw.request import Py3CW - - -def load_blacklist(logger, api, blacklistfile): - """Return blacklist data to be used.""" - - # Return file based blacklist - if blacklistfile: - newblacklist = [] - try: - with open(blacklistfile, "r") as file: - newblacklist = file.read().splitlines() - if newblacklist: - logger.info( - "Reading local blacklist file '%s' OK (%s pairs)" - % (blacklistfile, len(newblacklist)) - ) - except FileNotFoundError: - logger.error( - "Reading local blacklist file '%s' failed with error: File not found" - % blacklistfile - ) - - return newblacklist - - # Return defined blacklist from 3Commaas - return get_threecommas_blacklist(logger, api) - - -def init_threecommas_api(cfg): - """Init the 3commas API.""" - - return Py3CW( - key=cfg.get("settings", "3c-apikey"), - secret=cfg.get("settings", "3c-apisecret"), - request_options={ - "request_timeout": 10, - "nr_of_retries": 3, - "retry_status_codes": [502, 429], - "retry_backoff_factor": 1, - }, - ) - - -def get_threecommas_blacklist(logger, api): - """Get the pair blacklist from 3Commas.""" - - newblacklist = list() - error, data = api.request( - entity="bots", - action="pairs_black_list", - ) - if data: - logger.info( - "Fetched 3Commas pairs blacklist OK (%s pairs)" % len(data["pairs"]) - ) - newblacklist = data["pairs"] - else: - if "msg" in error: - logger.error( - "Fetching 3Commas pairs blacklist failed with error: %s" % error["msg"] - ) - else: - logger.error("Fetching 3Commas pairs blacklist failed") - - return newblacklist - - -def get_threecommas_btcusd(logger, api): - """Get current USDT_BTC value to calculate BTC volume24h in USDT.""" - - price = 60000 - error, data = api.request( - entity="accounts", - action="currency_rates", - payload={"market_code": "binance", "pair": "USDT_BTC"}, - ) - if data: - logger.info("Fetched 3Commas BTC price OK (%s USDT)" % data["last"]) - price = data["last"] - else: - if error and "msg" in error: - logger.error( - "Fetching 3Commas BTC price in USDT failed with error: %s" - % error["msg"] - ) - else: - logger.error("Fetching 3Commas BTC price in USDT failed") - - logger.debug("Current price of BTC is %s USDT" % price) - return price - - -def get_threecommas_accounts_paper(logger, api): - """Get all data for an account.""" - - # Fetch all account data, in real mode - error, data = api.request( - entity="accounts", - action="", - additional_headers={"Forced-Mode": "paper"}, - ) - if data: - return data - - if error and "msg" in error: - logger.error("Fetching 3Commas accounts data failed error: %s" % error["msg"]) - else: - logger.error("Fetching 3Commas accounts data failed") - - return None - - -def get_threecommas_accounts(logger, api): - """Get all data for an account.""" - - # Fetch all account data, in real mode - error, data = api.request( - entity="accounts", - action="", - additional_headers={"Forced-Mode": "real"}, - ) - if data: - return data - - if error and "msg" in error: - logger.error("Fetching 3Commas accounts data failed error: %s" % error["msg"]) - else: - logger.error("Fetching 3Commas accounts data failed") - - return None - - -def get_threecommas_account(logger, api, accountid): - """Get account details.""" - - # Find account data for accountid, in real mode - error, data = api.request( - entity="accounts", - action="account_info", - action_id=str(accountid), - additional_headers={"Forced-Mode": "real"}, - ) - if data: - return data - - if error and "msg" in error: - logger.error( - "Fetching 3Commas account data failed for id %s error: %s" - % (accountid, error["msg"]) - ) - else: - logger.error("Fetching 3Commas account data failed for id %s", accountid) - - return None - - -def get_threecommas_account_marketcode(logger, api, accountid): - """Get market_code for account.""" - - # get account data for accountid, in real mode - error, data = api.request( - entity="accounts", - action="account_info", - action_id=str(accountid), - additional_headers={"Forced-Mode": "real"}, - ) - if data: - marketcode = data["market_code"] - logger.info( - "Fetched 3Commas account market code in real mode OK (%s)" % marketcode - ) - return marketcode - - if error and "msg" in error: - logger.error( - "Fetching 3Commas account market code failed for id %s error: %s" - % (accountid, error["msg"]) - ) - else: - logger.error("Fetching 3Commas account market code failed for id %s", accountid) - - return None - - -def get_threecommas_account_balance(logger, api, accountid): - """Get account balances.""" - - # Fetch account balance data for accountid, in real mode - error, data = api.request( - entity="accounts", - action="load_balances", - action_id=str(accountid), - additional_headers={"Forced-Mode": "real"}, - ) - if data: - return data - - if error and "msg" in error: - logger.error( - "Fetching 3Commas account balances data failed for id %s error: %s" - % (accountid, error["msg"]) - ) - else: - logger.error( - "Fetching 3Commas account balances data failed for id %s", accountid - ) - - return None - - -def get_threecommas_account_balance_chart_data( - logger, api, accountid, begindate, enddate -): - """Get account balance chart data.""" - - # Fetch account balance chart data for accountid, in real mode - error, data = api.request( - entity="accounts", - action="balance_chart_data", - action_id=str(accountid), - additional_headers={"Forced-Mode": "real"}, - payload={"date_from": begindate, "date_to": enddate}, - ) - if data: - return data - - if error and "msg" in error: - logger.error( - "Fetching 3Commas account balance chart data failed for id %s error: %s" - % (accountid, error["msg"]) - ) - else: - logger.error("Fetching 3Commas account balance chart data for id %s", accountid) - - return None - - -def get_threecommas_market(logger, api, market_code): - """Get all the valid pairs for market_code from 3Commas account.""" - - tickerlist = [] - error, data = api.request( - entity="accounts", - action="market_pairs", - payload={"market_code": market_code}, - ) - if data: - tickerlist = data - logger.info( - "Fetched 3Commas market data for '%s' OK (%s pairs)" - % (market_code, len(tickerlist)) - ) - else: - if error and "msg" in error: - logger.error( - "Fetching 3Commas market data failed for market code %s with error: %s" - % (market_code, error["msg"]) - ) - else: - logger.error( - "Fetching 3Commas market data failed for market code %s", market_code - ) - - return tickerlist - - -def set_threecommas_ss(logger, api, thebot, raw_pairs, ss, notify=True, notify_uptodate=True): - """Update bot with ss.""" - - error, data = api.request( - entity="bots", - action="update", - action_id=str(thebot["id"]), - payload={ - "name": str(thebot["name"]), - "pairs": str(thebot["pairs"]), - "base_order_volume": float(thebot["base_order_volume"]), - "take_profit": float(thebot["take_profit"]), - "safety_order_volume": float(thebot["safety_order_volume"]), - "martingale_volume_coefficient": float( - thebot["martingale_volume_coefficient"] - ), - "martingale_step_coefficient": ss, - "max_safety_orders": int(thebot["max_safety_orders"]), - "max_active_deals": int(thebot["max_active_deals"]), - "active_safety_orders_count": int(thebot["active_safety_orders_count"]), - "safety_order_step_percentage": float( - thebot["safety_order_step_percentage"] - ), - "take_profit_type": thebot["take_profit_type"], - "strategy_list": thebot["strategy_list"], - "leverage_type": thebot["leverage_type"], - "leverage_custom_value": thebot["leverage_custom_value"], - "bot_id": int(thebot["id"]), - }, - ) - if data: - logger.debug("Bot pair(s) updated: %s" % data) - if ss: - newss = round(ss, 2) - logger.info( - "Bot '%s' with id '%s' updated with ss '%s'" - % (thebot["name"], thebot["id"], newss), - notify, - ) - # else: - # logger.info( - # "Bot '%s' with id '%s' updated with %d SS" - # % ( - # thebot["name"], - # thebot["id"], - # ss - # ), - # notify, - # ) - - else: - if error and "msg" in error: - logger.error( - "Error occurred while updating bot '%s' error: %s" - % (thebot["name"], error["msg"]), - True, - ) - else: - logger.error( - "Error occurred while updating bot '%s'" % thebot["name"], - True, - ) - - -def set_threecommas_bot_pairs(logger, api, thebot, newpairs, newmaxdeals, notify=True, notify_uptodate=True): - """Update bot with new pairs.""" - - # Do we already use these pairs? - if newpairs == thebot["pairs"]: - logger.info( - "Bot '%s' with id '%s' is already using the new pair(s)" - % (thebot["name"], thebot["id"]), - notify_uptodate, - ) - return - - if not newmaxdeals: - maxactivedeals = thebot["max_active_deals"] - else: - maxactivedeals = newmaxdeals - - logger.debug("Current pair(s): %s\nNew pair(s): %s" % (thebot["pairs"], newpairs)) - - error, data = api.request( - entity="bots", - action="update", - action_id=str(thebot["id"]), - payload={ - "name": str(thebot["name"]), - "pairs": newpairs, - "base_order_volume": float(thebot["base_order_volume"]), - "take_profit": float(thebot["take_profit"]), - "safety_order_volume": float(thebot["safety_order_volume"]), - "martingale_volume_coefficient": float( - thebot["martingale_volume_coefficient"] - ), - "martingale_step_coefficient": float(thebot["martingale_step_coefficient"]), - "max_safety_orders": int(thebot["max_safety_orders"]), - "max_active_deals": int(maxactivedeals), - "active_safety_orders_count": int(thebot["active_safety_orders_count"]), - "safety_order_step_percentage": float( - thebot["safety_order_step_percentage"] - ), - "take_profit_type": thebot["take_profit_type"], - "strategy_list": thebot["strategy_list"], - "leverage_type": thebot["leverage_type"], - "leverage_custom_value": thebot["leverage_custom_value"], - "bot_id": int(thebot["id"]), - }, - ) - if data: - logger.debug("Bot pair(s) updated: %s" % data) - if len(newpairs) == 1: - logger.info( - "Bot '%s' with id '%s' updated with pair '%s'" - % (thebot["name"], thebot["id"], newpairs[0]), - notify, - ) - else: - logger.info( - "Bot '%s' with id '%s' updated with %d pairs %s" - % ( - thebot["name"], - thebot["id"], - len(newpairs), - newpairs - ), - notify, - ) - if newmaxdeals: - logger.info( - "Max active deals changed to %s" % newmaxdeals, - notify, - ) - else: - if error and "msg" in error: - logger.error( - "Error occurred while updating bot '%s' error: %s" - % (thebot["name"], error["msg"]), - True, - ) - else: - logger.error( - "Error occurred while updating bot '%s'" % thebot["name"], - True, - ) - - -def set_threecommas_bot_hmss(logger, api, thebot, newpairs, newmaxdeals, pdi, notify=True, notify_uptodate=True): - """Update bot with new pairs.""" - - # Do we already use these pairs? - if newpairs == thebot["pairs"]: - if pdi: - pdi_new = round(pdi, 2) - logger.info( - "Bot '%s' with id '%s' is already using the new pair(s) and SS of '%s" - % (thebot["name"], thebot["id"], pdi_new), - notify_uptodate, - ) - return - - if not newmaxdeals: - maxactivedeals = thebot["max_active_deals"] - else: - maxactivedeals = newmaxdeals - - logger.debug("Current pair(s): %s\nNew pair(s): %s" % (thebot["pairs"], newpairs)) - - error, data = api.request( - entity="bots", - action="update", - action_id=str(thebot["id"]), - payload={ - "name": str(thebot["name"]), - "pairs": newpairs, - "base_order_volume": float(thebot["base_order_volume"]), - "take_profit": float(thebot["take_profit"]), - "safety_order_volume": float(thebot["safety_order_volume"]), - "martingale_volume_coefficient": float( - thebot["martingale_volume_coefficient"] - ), - "martingale_step_coefficient": pdi, - "max_safety_orders": int(thebot["max_safety_orders"]), - "max_active_deals": int(maxactivedeals), - "active_safety_orders_count": int(thebot["active_safety_orders_count"]), - "safety_order_step_percentage": float( - thebot["safety_order_step_percentage"] - ), - "take_profit_type": thebot["take_profit_type"], - "strategy_list": thebot["strategy_list"], - "leverage_type": thebot["leverage_type"], - "leverage_custom_value": thebot["leverage_custom_value"], - "bot_id": int(thebot["id"]), - }, - ) - if data: - logger.debug("Bot pair(s) updated: %s" % data) - if len(newpairs) == 1: - if pdi: - pdi_new = round(pdi, 2) - logger.info( - "Bot '%s' with id '%s' updated with pair '%s' and SS of '%s" - % (thebot["name"], thebot["id"], newpairs[0], pdi_new), - notify, - ) - else: - if pdi: - pdi_new = round(pdi, 2) - logger.info( - "Bot '%s' with id '%s' updated with %d pairs %s and SS of '%s" - % ( - thebot["name"], - thebot["id"], - len(newpairs), - newpairs, - pdi_new - ), - notify, - ) - if newmaxdeals: - logger.info( - "Max active deals changed to %s" % newmaxdeals, - notify, - ) - if pdi: - newss = round(pdi, 2) - logger.info( - "Bot '%s' with id '%s' updated with ss '%s'" - % (thebot["name"], thebot["id"], newss), - notify, - ) - else: - if error and "msg" in error: - logger.error( - "Error occurred while updating bot '%s' error: %s" - % (thebot["name"], error["msg"]), - True, - ) - else: - logger.error( - "Error occurred while updating bot '%s'" % thebot["name"], - True, - ) - - -def trigger_threecommas_bot_deal(logger, api, thebot, pair, skip_checks=False): - """Trigger bot to start deal asap.""" - - error, data = api.request( - entity="bots", - action="start_new_deal", - action_id=str(thebot["id"]), - payload={"pair": pair, "skip_signal_checks": skip_checks, "bot_id": thebot["id"]}, - ) - if data: - logger.debug("Bot deal triggered: %s" % data) - logger.info( - "Bot '%s' with id '%s' triggered start_new_deal for: %s" - % (thebot["name"], thebot["id"], pair), - True, - ) - else: - if error and "msg" in error: - logger.error( - "Error occurred while triggering start_new_deal bot '%s' error: %s" - % (thebot["name"], error["msg"]), - ) - else: - logger.error( - "Error occurred while triggering start_new_deal bot '%s'" - % thebot["name"], - ) - - -def control_threecommas_bots(logger, api, thebot, cmd): - """Enable or disable a bot.""" - - error, data = api.request( - entity="bots", - action=cmd, - action_id=str(thebot["id"]), - ) - if data: - logger.debug(f"Bot {cmd}: {data}") - logger.info( - "Bot '%s' is %sd" % (thebot["name"], cmd), - True, - ) - else: - if error and "msg" in error: - logger.error( - "Error occurred while '%s' bot was %sd error: %s" - % (thebot["name"], cmd, error["msg"]), - ) - else: - logger.error( - "Error occurred while '%s' bot was %sd" % (thebot["name"], cmd), - ) - - -def get_threecommas_deals(logger, api, botid, actiontype="finished"): - """Get all deals from 3Commas linked to a bot.""" - - data = None - if actiontype == "finished": - payload = { - "scope": "finished", - "bot_id": str(botid), - "limit": 100, - "order": "closed_at", - } - else: - payload = { - "scope": "active", - "bot_id": str(botid), - "limit": 100, - } - - error, data = api.request( - entity="deals", - action="", - payload=payload, - ) - if error: - if "msg" in error: - logger.error( - "Error occurred while fetching deals error: %s" % error["msg"], - ) - else: - logger.error("Error occurred while fetching deals") - else: - logger.info("Fetched the deals for bot OK (%s deals)" % len(data)) - - return data - - -def close_threecommas_deal(logger, api, dealid, pair): - """Close deal with certain id.""" - - data = None - error, data = api.request( - entity="deals", - action="panic_sell", - action_id=str(dealid), - ) - if error: - if "msg" in error: - logger.error( - "Error occurred while closing deal error: %s" % error["msg"], - ) - else: - logger.error("Error occurred while closing deal") - else: - logger.info( - "Closed deal (panic_sell) for deal with id '%s' and pair '%s'" - % (dealid, pair), - True, - ) - - return data - - -def smart_trades(cfg, logger, api, pair, posvalue, stoploss, accountid, notify=True, notify_uptodate=True): - """Get all data for an account.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="new", - payload={ - "account_id": accountid, - "pair": pair, - "position": { - "type": "buy", - "units": { - "value": posvalue - }, - "order_type": "market" - }, - "take_profit": { - "enabled": "false" - }, - "stop_loss": { - "enabled": "true", - "order_type": "market", - "conditional": { - "price": { - "value": stoploss, - "type": "bid" - } - } - } - } - ) - if data: - logger.info( - "Opening a deal for '%s' successes " - % pair, - notify - ) - - elif error and "msg" in error: - logger.error(f"Opening a deal for : failed error: %s" % error["msg"], notify) - - return None - - -def update_smart_trades(cfg, logger, api, accountid, notify=True, notify_uptodate=True): - """Get all data for an account.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="", - payload={ - "account_id": accountid}) - if data: - print(data) - - elif error and "msg" in error: - logger.error(f"Opening a deal for : failed error: %s" % error["msg"], notify) - - return None - - -def smart_spot_trades(cfg, logger, api, pair, posvalue, accountid, stoploss, tp1, tp2, tp3, tp4, tp5, notify=True, - notify_uptodate=True): - """Get all data for an account.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="new", - payload={ - "account_id": accountid, - "pair": pair, - "position": { - "type": "buy", - "units": { - "value": posvalue - }, - "order_type": "market" - }, - "take_profit": { - "enabled": "true", - "steps": [ - { - "order_type": "limit", - "price": { - "value": tp1, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp2, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp3, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp4, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp5, - "type": "bid" - }, - "volume": 20 - } - ] - }, - "stop_loss": { - "enabled": "true", - "breakeven": "true", - "order_type": "market", - "conditional": { - "price": { - "value": stoploss, - "type": "bid" - } - } - } - } - ) - if data: - logger.info( - f"\ndeal for pair {pair}\nposition size: {round(posvalue, 2)}\n " - f"successfully opened from Smart Trade account : {accountid}", - True - ) - - elif error: - if "msg" in error: - logger.error(f"Order has Invalid parameters\n{error['msg']}", - True - ) - else: - logger.error("UNKNOWN ERROR") - return None - - -def smart_lev_trades(cfg, logger, api, pair, posvalue, lev, accountid, side, stoploss, tp1, tp2, tp3, tp4, tp5, - true=True, - notify=True, - notify_uptodate=True): - """Smart Trade with lev.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="new", - payload={ - "account_id": accountid, - "pair": pair, - "position": { - "type": side, - "units": { - "value": posvalue - }, - "order_type": "market" - }, - "take_profit": { - "enabled": "true", - "steps": [ - { - "order_type": "limit", - "price": { - "value": tp1, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp2, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp3, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp4, - "type": "bid" - }, - "volume": 20 - }, - { - "order_type": "limit", - "price": { - "value": tp5, - "type": "bid" - }, - "volume": 20 - } - ] - }, - "leverage": { - "enabled": true, - "type": "cross", - "value": lev, - }, - "stop_loss": { - "enabled": "true", - "breakeven": "true", - "order_type": "market", - "conditional": { - "price": { - "value": stoploss, - "type": "bid" - } - } - } - } - ) - if data: - logger.info( - f"\ndeal for pair {pair} \n, position size: {round(posvalue, 2)} \n " - f"successfully opened from Smart Trade account : {accountid}", - True - ) - elif error: - if "msg" in error: - logger.error(f"Order has Invalid parameters\n{error['msg']}", - True - ) - else: - logger.error("UNKNOWN ERROR") - return None - - -# -def get_active_smart_trades(cfg, logger, api): - dealsid = [] - """Get all data for an account.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="", - payload={ - - "status": "active" - } - ) - if data: - for deal in data: - dealsid.append(deal["id"]) - elif error: - logger.error("NO Active Deals", - True, - ) - else: - logger.error("NO Active Deals", - True, - ) - return dealsid - - -def panic_close_smart(cfg, logger, api, deals): - for deal in deals: - error, data = api.request( - entity="smart_trades_v2", - action="close_by_market", - action_id=str(deal), - ) - if data: - logger.info(f"Deal : {deal} has been closed", - True, - ) - elif error: - logger.error(f"NO Active Deals or any other errors f{error}", - True, - ) - else: - logger.error(f"NO Active Deals or any other errors f{error}", - True, - ) - - -# lev Smart Trades with RR strategy - - -def smart_lev_trades_risk_reward(cfg, logger, api, pair, posvalue, lev, accountid, side, stoploss, tp1, tp2, price, - true=True, - notify=True, - notify_uptodate=True): - """Smart Trade with lev.""" - # Fetch all account data, in real mode - error, data = api.request( - entity="smart_trades_v2", - action="new", - payload={ - "account_id": accountid, - "pair": pair, - "position": { - "type": side, - "units": { - "value": posvalue - }, - "price": { - "value": price - }, - "order_type": "limit" - }, - "take_profit": { - "enabled": "true", - "steps": [ - { - "order_type": "limit", - "price": { - "value": tp1, - "type": "bid" - }, - "volume": float(cfg.get("settings", "vol1")) - }, - { - "order_type": "limit", - "price": { - "value": tp2, - "type": "bid" - }, - "volume": float(cfg.get("settings", "vol2")) - }, - ] - }, - "leverage": { - "enabled": true, - "type": "cross", - "value": lev, - }, - "stop_loss": { - "enabled": "true", - "breakeven": "true", - "order_type": "market", - "conditional": { - "price": { - "value": stoploss, - "type": "bid" - } - } - } - } - ) - if data: - logger.info( - f"\ndeal for pair {pair} \n, position size: {round(posvalue, 2)} \n " - f"successfully opened from Smart Trade account : {accountid}", - True - ) - elif error: - if "msg" in error: - logger.error(f"Order has Invalid parameters\n{error['msg']}", - True - ) - else: - logger.error("UNKNOWN ERROR") - return None - - -# SPOT Smart trade with RR strategy - - -def smart_spot_trades_risk_reward(cfg, logger, api, pair, posvalue, accountid, stoploss, tp1, tp2, price, - notify=True, - notify_uptodate=True): - """Get all data for an account.""" - # Fetch all account data, in real mode - print(f"price from {price}") - error, data = api.request( - entity="smart_trades_v2", - action="new", - payload={ - "account_id": accountid, - "pair": pair, - "position": { - "type": "buy", - "units": { - "value": posvalue - }, - "price": { - "value": price - }, - "order_type": "limit" - }, - "take_profit": { - "enabled": "true", - "steps": [ - { - "order_type": "limit", - "price": { - "value": tp1, - "type": "bid" - }, - "volume": float(cfg.get("settings", "vol1")) - }, - { - "order_type": "limit", - "price": { - "value": tp2, - "type": "bid" - }, - "volume": float(cfg.get("settings", "vol2")) - }, - ] - }, - "stop_loss": { - "enabled": "true", - "breakeven": cfg.get("settings", "break_even"), - "order_type": "market", - "conditional": { - "price": { - "value": stoploss, - "type": "bid" - } - } - } - } - ) - if data: - logger.info( - f"\ndeal for pair {pair}\nposition size: {round(posvalue, 2)}\n " - f"successfully opened from Smart Trade account : {accountid}", - True - ) - - elif error: - if "msg" in error: - logger.error(f"Order has Invalid parameters\n{error['msg']}", - True - ) - else: - logger.error("UNKNOWN ERROR") - return None