Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import time
- import sys
- import re
- from datetime import datetime, timedelta
- from selenium import webdriver
- from selenium.webdriver.common.by import By
- from selenium.webdriver.chrome.service import Service
- from selenium.webdriver.chrome.options import Options
- from webdriver_manager.chrome import ChromeDriverManager
- from selenium.webdriver.support.ui import WebDriverWait
- from selenium.webdriver.support import expected_conditions as EC
- # ---------- CONFIGURACIÓN ----------
- TRADE_WINDOW_MINUTES = 15 # Ventana de compra inicial en minutos
- BUY_THRESHOLD = 0.32
- TARGET_PROFIT = 0.20
- INITIAL_INVESTMENT = 10
- POLL_INTERVAL = 0.5
- USE_REAL_FUNDS = True # ⬅️ CAMBIA A True cuando operes con dinero real
- # Nuevos XPaths robustos
- XPATH_BUTTON_UP = "//button[.//span[contains(text(),'Up')]]"
- XPATH_BUTTON_DOWN = "//button[.//span[contains(text(),'Down')]]"
- XPATH_PRICE_INSIDE_BUTTON = ".//p[2]//span"
- # ---------- XPATHS PARA TRADING REAL ----------
- XPATH_AMOUNT_INPUT = "//input[@id='market-order-amount-input']"
- XPATH_TRADE_BUTTON = "//button[contains(@class,'trading-button') and @data-color='blue']"
- # ---------- XPATH POPUP SIN FONDOS ----------
- XPATH_POPUP_CLOSE = "//button[@data-testid='rk-close-button']"
- def cerrar_popup_si_existe(driver, timeout=2):
- """
- Cierra el popup que aparece al operar sin fondos reales.
- No hace nada si no aparece.
- """
- if USE_REAL_FUNDS:
- return
- try:
- btn = WebDriverWait(driver, timeout).until(
- EC.element_to_be_clickable((By.XPATH, XPATH_POPUP_CLOSE))
- )
- btn.click()
- print("ℹ️ Popup sin fondos cerrado")
- time.sleep(0.3)
- except:
- # No apareció popup → OK
- pass
- def ejecutar_compra_real(driver, side: str, amount: float):
- """
- Ejecuta una compra REAL en Polymarket.
- side: 'UP' o 'DOWN'
- amount: dólares a invertir
- Devuelve True si todo fue correcto, False si algo falló
- """
- try:
- # 1️⃣ Click en el lado correcto
- if side == "UP":
- driver.find_element(By.XPATH, XPATH_BUTTON_UP).click()
- elif side == "DOWN":
- driver.find_element(By.XPATH, XPATH_BUTTON_DOWN).click()
- else:
- print("❌ Lado inválido")
- return False
- time.sleep(0.3)
- # 2️⃣ Escribir el importe
- amount_input = driver.find_element(By.XPATH, XPATH_AMOUNT_INPUT)
- amount_input.click()
- amount_input.clear()
- amount_input.send_keys(str(round(amount, 2)))
- time.sleep(0.3)
- # 3️⃣ Click en Trade
- trade_btn = driver.find_element(By.XPATH, XPATH_TRADE_BUTTON)
- trade_btn.click()
- time.sleep(0.5)
- # 4️⃣ Cerrar popup si estamos sin fondos
- cerrar_popup_si_existe(driver)
- print(f"✅ COMPRA REAL EJECUTADA → {side} ${amount}")
- return True
- except Exception as e:
- print(f"❌ ERROR EJECUTANDO COMPRA REAL: {e}")
- return False
- # ---------- PARSE DE PRECIOS ----------
- def parse_price_text_to_float(s: str):
- if not s:
- return None
- s = s.strip()
- if "¢" in s:
- try:
- return float(s.replace("¢", "").strip()) / 100
- except:
- return None
- cleaned = s.replace("$", "").replace(",", ".")
- try:
- return float(cleaned)
- except:
- return None
- def format_price_usd(value):
- if value is None:
- return "—"
- return f"{value:.2f}"
- # ---------- LECTURA DE PRECIOS ----------
- def read_price(driver, xpath_button):
- try:
- btn = driver.find_element(By.XPATH, xpath_button)
- price_span = btn.find_element(By.XPATH, XPATH_PRICE_INSIDE_BUTTON)
- raw = price_span.text
- val = parse_price_text_to_float(raw)
- if val is not None:
- return val
- except:
- pass
- # Fallback JS
- try:
- script = """
- const btns = [...document.querySelectorAll("button")];
- for (const b of btns) {
- if (arguments[0] === "UP" && b.innerText.includes("Up")) {
- const m = b.innerText.match(/(\\d+¢|\\d+\\.\\d+)/);
- return m ? m[0] : null;
- }
- if (arguments[0] === "DOWN" && b.innerText.includes("Down")) {
- const m = b.innerText.match(/(\\d+¢|\\d+\\.\\d+)/);
- return m ? m[0] : null;
- }
- }
- return null;
- """
- raw = driver.execute_script(script, "UP" if "Up" in xpath_button else "DOWN")
- return parse_price_text_to_float(raw)
- except:
- return None
- # ---------- INTERVALOS DE 15 MIN ----------
- def tiempo_restante_intervalo():
- now = datetime.now()
- next_minute = (now.minute // 15 + 1) * 15
- if next_minute == 60:
- next_time = now.replace(hour=now.hour + 1, minute=0, second=0, microsecond=0)
- else:
- next_time = now.replace(minute=next_minute, second=0, microsecond=0)
- delta = next_time - now
- mins, secs = divmod(delta.seconds, 60)
- return mins, secs
- # ---------- CAMBIO DE URL ----------
- def siguiente_evento_url(url_actual: str):
- try:
- base = url_actual.split("?")[0]
- m = re.search(r"/event/(.+)-15m-(\d+)$", base)
- if not m:
- print("❌ No se pudo parsear la URL actual")
- return None
- slug = m.group(1)
- current_ts = int(m.group(2))
- next_ts = current_ts + 900
- nueva_url = f"https://polymarket.com/event/{slug}-15m-{next_ts}"
- return nueva_url
- except Exception as e:
- print(f"❌ Error generando siguiente URL: {e}")
- return None
- # ---------- COBERTURA ----------
- def calcular_cobertura_estimada(entry_price, entry_amount, opposite_price, target_profit):
- if entry_price is None or opposite_price is None or entry_amount <= 0:
- return None, None, None
- try:
- p1 = float(entry_price)
- p2 = float(opposite_price)
- I1 = float(entry_amount)
- desired_profit = I1 * float(target_profit)
- shares_entry = I1 / p1
- upper_y = shares_entry - I1 - desired_profit
- if p2 <= 0 or p2 >= 1:
- return None, None, None
- denom = (1.0 / p2) - 1.0
- if denom <= 0:
- return None, None, None
- lower_y = (I1 + desired_profit) / denom
- if lower_y <= upper_y and upper_y > 0:
- y = round(lower_y, 2)
- return y, round(lower_y, 2), round(upper_y, 2)
- return None, round(lower_y, 2), round(upper_y, 2)
- except:
- return None, None, None
- # ---------- LOG ----------
- def iniciar_logger():
- log_filename = f"polymarket_log_{datetime.now():%Y-%m-%d_%H-%M-%S}.txt"
- log_file = open(log_filename, "a", buffering=1, encoding="utf-8")
- class Tee:
- def __init__(self, *files):
- self.files = files
- def write(self, obj):
- for f in self.files:
- f.write(obj)
- f.flush()
- def flush(self):
- for f in self.files:
- f.flush()
- sys.stdout = Tee(sys.__stdout__, log_file)
- sys.stderr = Tee(sys.__stderr__, log_file)
- print(f"📜 Log activo: {log_filename}\n")
- # ---------- MAIN ----------
- def main():
- iniciar_logger()
- results_file = open("results.txt", "a", encoding="utf-8")
- options = Options()
- options.add_argument("--start-maximized")
- options.add_experimental_option("excludeSwitches", ["enable-automation"])
- options.add_experimental_option("useAutomationExtension", False)
- driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
- driver.get("https://polymarket.com")
- print("Chrome abierto en polymarket.com")
- input("Navega al mercado 15m y pulsa ENTER...")
- start_time = datetime.now()
- main_side = None
- main_price = None
- main_amount = 0
- main_time = None
- hedge_time = None
- hedge_side = None
- hedge_price = None
- hedge_amount = 0
- profit_secured = 0
- hedge_recorded = False
- print("\nComenzando monitoreo...\n")
- try:
- while True:
- mins, secs = tiempo_restante_intervalo()
- up_val = read_price(driver, XPATH_BUTTON_UP)
- down_val = read_price(driver, XPATH_BUTTON_DOWN)
- up_str = format_price_usd(up_val)
- down_str = format_price_usd(down_val)
- print(f"UP {up_str} | DOWN {down_str} | Time left: {mins}:{secs:02d}")
- # ----- Cambio automático de sesión -----
- if mins == 0 and secs == 0:
- now = datetime.now()
- session_time = now.replace(minute=(now.minute // 15) * 15, second=0, microsecond=0)
- results_file.write(f"\n===== SESSION {session_time:%Y-%m-%d %H:%M} =====\n")
- if main_side:
- results_file.write(f"BUY | TIME: {main_time:%H:%M:%S} | SIDE: {main_side} | AMOUNT: {main_amount}$ | PRICE: {main_price:.2f}\n")
- if hedge_side:
- results_file.write(f"ARB | TIME: {hedge_time:%H:%M:%S} | SIDE: {hedge_side} | AMOUNT: {hedge_amount}$ | PRICE: {hedge_price:.2f} | PROFIT: {profit_secured:.2f}$\n")
- results_file.flush()
- # Reset variables
- main_side = None
- main_price = None
- main_amount = 0
- hedge_side = None
- hedge_price = None
- hedge_amount = 0
- profit_secured = 0
- hedge_recorded = False
- main_time = None
- hedge_time = None
- # Cambiar URL
- current_url = driver.current_url
- next_url = siguiente_evento_url(current_url)
- if next_url:
- print(f"⏭ Pasando al siguiente evento: {next_url}")
- driver.get(next_url)
- start_time = datetime.now()
- time.sleep(5)
- continue
- # ----- Trading -----
- mins_passed = (datetime.now() - start_time).total_seconds() / 60
- # Compra principal solo si estamos dentro de la ventana
- if main_side is None:
- if mins_passed <= TRADE_WINDOW_MINUTES:
- if up_val is not None and up_val <= BUY_THRESHOLD:
- if ejecutar_compra_real(driver, "UP", INITIAL_INVESTMENT):
- main_side = "UP"
- main_price = up_val
- main_amount = INITIAL_INVESTMENT
- main_time = datetime.now()
- print(f"🟢 Comprado UP a {main_price:.2f}")
- elif down_val is not None and down_val <= BUY_THRESHOLD:
- if ejecutar_compra_real(driver, "DOWN", INITIAL_INVESTMENT):
- main_side = "DOWN"
- main_price = down_val
- main_amount = INITIAL_INVESTMENT
- main_time = datetime.now()
- print(f"🔴 Comprado DOWN a {main_price:.2f}")
- else:
- print(f"⚠️ ERROR: Se pasó el tiempo de {TRADE_WINDOW_MINUTES} minutos para comprar. No se puede operar.")
- # Cobertura / arbitraje
- if main_side == "UP" and down_val:
- y, low, high = calcular_cobertura_estimada(main_price, main_amount, down_val, TARGET_PROFIT)
- if y and not hedge_recorded:
- if ejecutar_compra_real(driver, "DOWN", y):
- hedge_side = "DOWN"
- hedge_time = datetime.now()
- hedge_price = down_val
- hedge_amount = y
- profit_secured = TARGET_PROFIT * main_amount
- hedge_recorded = True
- print(f"🔔 ARBITRAJE EJECUTADO: DOWN {hedge_amount} a {hedge_price:.2f}")
- else:
- print(f"🕓 Esperando cobertura: DOWN actualmente {down_val:.2f}, rango válido {low}-{high}")
- elif main_side == "DOWN" and up_val:
- y, low, high = calcular_cobertura_estimada(main_price, main_amount, up_val, TARGET_PROFIT)
- if y and not hedge_recorded:
- if ejecutar_compra_real(driver, "UP", y):
- hedge_side = "UP"
- hedge_time = datetime.now()
- hedge_price = up_val
- hedge_amount = y
- profit_secured = TARGET_PROFIT * main_amount
- hedge_recorded = True
- print(f"🔔 ARBITRAJE EJECUTADO: UP {hedge_amount} a {hedge_price:.2f}")
- else:
- print(f"🕓 Esperando cobertura: UP actualmente {up_val:.2f}, rango válido {low}-{high}")
- time.sleep(POLL_INTERVAL)
- print()
- except KeyboardInterrupt:
- print("Saliendo...")
- results_file.close()
- driver.quit()
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment