diff --git a/__pycache__/config.cpython-311.pyc b/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000..8d742b9 Binary files /dev/null and b/__pycache__/config.cpython-311.pyc differ diff --git a/__pycache__/config.cpython-314.pyc b/__pycache__/config.cpython-314.pyc new file mode 100644 index 0000000..09ce9ea Binary files /dev/null and b/__pycache__/config.cpython-314.pyc differ diff --git a/__pycache__/functions.cpython-311.pyc b/__pycache__/functions.cpython-311.pyc new file mode 100644 index 0000000..d1d50ca Binary files /dev/null and b/__pycache__/functions.cpython-311.pyc differ diff --git a/__pycache__/functions.cpython-314.pyc b/__pycache__/functions.cpython-314.pyc new file mode 100644 index 0000000..685b8fa Binary files /dev/null and b/__pycache__/functions.cpython-314.pyc differ diff --git a/__pycache__/script.cpython-314.pyc b/__pycache__/script.cpython-314.pyc new file mode 100644 index 0000000..62a6324 Binary files /dev/null and b/__pycache__/script.cpython-314.pyc differ diff --git a/config.py b/config.py index 0de3a18..e1ab7f3 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,11 @@ -API_KEY = '' -API_SECRET = '' +import os -dias = 7 \ No newline at end of file +API_KEY = os.getenv("BINANCE_API_KEY", "") +API_SECRET = os.getenv("BINANCE_API_SECRET", "") + +dias = 30 +workers = 6 +max_retries = 6 +retry_base_delay = 1.0 +request_timeout = 10 +show_progress = True diff --git a/functions.py b/functions.py index dde3439..199c7ed 100644 --- a/functions.py +++ b/functions.py @@ -1,59 +1,106 @@ +import random +import time +from concurrent.futures import ThreadPoolExecutor, as_completed + import config from binance.client import Client -import time -dias = config.dias -client = Client(config.API_KEY, config.API_SECRET, tld='com') +# Configuración +dias = int(getattr(config, 'dias', 30)) +workers = max(1, int(getattr(config, 'workers', 6))) +max_retries = max(1, int(getattr(config, 'max_retries', 6))) +retry_base_delay = float(getattr(config, 'retry_base_delay', 1.0)) +request_timeout = int(getattr(config, 'request_timeout', 10)) +show_progress = bool(getattr(config, 'show_progress', True)) -listTiks = [] +client = Client( + getattr(config, 'API_KEY', ''), + getattr(config, 'API_SECRET', ''), + tld='com', + requests_params={'timeout': request_timeout}, +) -def buscarTicks(): - ticks = [] +def _log_error(error): + with open('log.txt', 'a', encoding='utf-8') as archivo: + mensaje = time.strftime('%d-%m-%Y %H:%M:%S', time.localtime()) + archivo.write(f"{mensaje} ERROR: {error}\n") - while True: - try: - list_of_tickers = client.futures_symbol_ticker() - except Exception as e: - print(e) - archivo = open("log.txt", "a") - mensaje = time.strftime('%d-%m-%Y %H:%M:%S', time.localtime()) + ' ERROR: ' + str(e) + "\n" - archivo.write(mensaje) - archivo.close() - time.sleep(2) - else: - break - - for tick in list_of_tickers: - if tick['symbol'][-4:] != 'USDT': - continue - ticks.append(tick['symbol']) - return ticks - -def analizarMoneda(tick): - while True: + +def _with_retry(fn, *args, **kwargs): + for attempt in range(1, max_retries + 1): try: - klines = client.futures_klines(symbol=tick, interval=client.KLINE_INTERVAL_1DAY, limit=dias) - except Exception as e: - print(e) - archivo = open("log.txt", "a") - mensaje = time.strftime('%d-%m-%Y %H:%M:%S', time.localtime()) + ' ERROR: ' + str(e) + "\n" - archivo.write(mensaje) - archivo.close() - time.sleep(2) - else: - break - - nKlines = len(klines)-1 - oldClose = float(klines[0][4]) - newClose = float(klines[nKlines][4]) - porcentaje = round((newClose - oldClose)/oldClose*100, 2) - - listTiks.append((tick, oldClose, newClose, porcentaje)) - #print(listTiks) - #print("TICK: "+tick+" OLD:"+str(oldClose)+" NEW: "+str(newClose)+" PORCENTAJE: "+str(porcentaje)+"%") - -def showResults(): - ordenar = sorted(listTiks, key=lambda result: result[3]) + return fn(*args, **kwargs) + except Exception as error: + print(f"ERROR attempt {attempt}/{max_retries}: {error}") + _log_error(error) + if attempt == max_retries: + raise + backoff = min(retry_base_delay * (2 ** (attempt - 1)), 30.0) + time.sleep(backoff + random.uniform(0.0, 0.3)) + + +def buscarTicks(): + list_of_tickers = _with_retry(client.futures_symbol_ticker) + return [tick['symbol'] for tick in list_of_tickers if tick['symbol'].endswith('USDT')] + + +def _analizar_moneda(tick): + klines = _with_retry( + client.futures_klines, + symbol=tick, + interval=client.KLINE_INTERVAL_1DAY, + limit=dias, + ) + + if not klines or len(klines) < 2: + return None + + old_close = float(klines[0][4]) + new_close = float(klines[-1][4]) + if old_close == 0: + return None + + porcentaje = round((new_close - old_close) / old_close * 100, 2) + return (tick, old_close, new_close, porcentaje) + + +def analizarMonedas(ticks): + resultados = [] + + if not ticks: + return resultados + + if workers == 1: + for index, tick in enumerate(ticks, start=1): + try: + resultado = _analizar_moneda(tick) + if resultado is not None: + resultados.append(resultado) + except Exception as error: + _log_error(error) + if show_progress and (index == len(ticks) or index % 25 == 0): + print(f"ANALIZADAS: {index}/{len(ticks)}") + return resultados + + with ThreadPoolExecutor(max_workers=workers) as executor: + future_to_tick = {executor.submit( + _analizar_moneda, tick): tick for tick in ticks} + for index, future in enumerate(as_completed(future_to_tick), start=1): + try: + resultado = future.result() + if resultado is not None: + resultados.append(resultado) + except Exception as error: + _log_error(error) + if show_progress and (index == len(ticks) or index % 25 == 0): + print(f"ANALIZADAS: {index}/{len(ticks)}") + + return resultados + + +def showResults(resultados=None): + datos = resultados or [] + ordenar = sorted(datos, key=lambda result: result[3]) for r in ordenar: - print("TICK: "+r[0]+" OLD:"+str(r[1])+" NEW: "+str(r[2])+" PORCENTAJE: "+str(r[3])+"%") + print(f"TICK: {r[0]} OLD:{r[1]} NEW:{r[2]} PORCENTAJE: {r[3]}%") diff --git a/script.py b/script.py index 253f49a..2cc11e6 100644 --- a/script.py +++ b/script.py @@ -1,9 +1,20 @@ -from functions import * +import time -ticks = buscarTicks() -ticksNumber = len(ticks) -print("NUMERO DE TICKS: " + str(ticksNumber)) +from functions import analizarMonedas, buscarTicks, dias, showResults -for tick in ticks: - analizarMoneda(tick) -showResults() + +def main(): + inicio = time.perf_counter() + ticks = buscarTicks() + print(f"NUMERO DE TICKS: {len(ticks)}") + print(f"NUMERO DE DIAS A ESTIMAR: {dias}") + + resultados = analizarMonedas(ticks) + showResults(resultados) + + duracion = round(time.perf_counter() - inicio, 2) + print(f"TIEMPO TOTAL: {duracion}s") + + +if __name__ == '__main__': + main()