<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jesus Corredor</title>
    <description>The latest articles on DEV Community by Jesus Corredor (@jesusaco).</description>
    <link>https://dev.to/jesusaco</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4089844%2F43b302f3-0c51-4566-95bd-2b72f6657850.png</url>
      <title>DEV Community: Jesus Corredor</title>
      <link>https://dev.to/jesusaco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jesusaco"/>
    <language>en</language>
    <item>
      <title>Por qué getenv("X") or default es una trampa</title>
      <dc:creator>Jesus Corredor</dc:creator>
      <pubDate>Sun, 13 Sep 2026 20:10:05 +0000</pubDate>
      <link>https://dev.to/jesusaco/por-que-getenvx-or-default-es-una-trampa-2ab6</link>
      <guid>https://dev.to/jesusaco/por-que-getenvx-or-default-es-una-trampa-2ab6</guid>
      <description>&lt;p&gt;Diario de un bot que opera con dinero real — Entrada #2:&lt;/p&gt;

&lt;p&gt;En la entrada anterior conté cómo un componente de mi sistema estuvo meses operando con un capital que nadie le asignó — un "par fantasma" que creía haber eliminado y seguía vivo. Toda la causa cabía en una línea de código. Una línea que probablemente tienes en tu proyecto ahora mismo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqhn1pv9gcuotbchilp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqhn1pv9gcuotbchilp1.png" alt=" " width="414" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se ve inofensiva. Se ve hasta responsable — "si la variable no está, uso un valor por defecto y el programa no se rompe". Ese razonamiento es la trampa. Te cuento por qué.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qué hace ese or&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En cristiano: "usa el valor de la variable; si no hay valor, usa &lt;strong&gt;133&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;Suena bien. El problema es qué cuenta como "no hay valor". Si por accidente borras esa variable —un despliegue que pisa el archivo, un backup que restauras, un typo en el nombre— &lt;strong&gt;el programa no se detiene, no da error, no avisa&lt;/strong&gt;. Simplemente empieza a usar 133 como si alguien lo hubiera decidido.&lt;/p&gt;

&lt;p&gt;En mi caso, ese &lt;strong&gt;133&lt;/strong&gt; era el capital con el que un bot operaba con dinero real. La variable que debía definirlo desapareció en un restore, y el default la reemplazó en silencio. El sistema no falló ruidosamente. Falló callado — que es peor, porque no deja rastro y lo descubres meses después.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La parte que engaña de verdad: el valor cero&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aquí está el detalle que casi me muerde. Supón que quieres desactivar ese componente poniendo su valor en cero. Lo natural: defines la variable como &lt;strong&gt;0&lt;/strong&gt;. Pues bien — dependiendo de dónde pongas el &lt;strong&gt;or&lt;/strong&gt;, obtienes cosas opuestas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcyhnxzced5xdbmra3nfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcyhnxzced5xdbmra3nfq.png" alt=" " width="665" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En el segundo caso pusiste &lt;strong&gt;0&lt;/strong&gt; y el programa te devolvió &lt;strong&gt;133&lt;/strong&gt;. ¿Por qué? Porque para el &lt;strong&gt;or&lt;/strong&gt;, el número &lt;strong&gt;0&lt;/strong&gt; cuenta como &lt;strong&gt;"vacío"&lt;/strong&gt; (en jerga: es falsy). Entonces el &lt;strong&gt;or&lt;/strong&gt; lo descarta y salta al default. Intentaste apagar algo poniéndolo en cero, y conseguiste justo lo contrario.&lt;/p&gt;

&lt;p&gt;Lo peligroso: &lt;strong&gt;este bug solo aparece con el valor cero&lt;/strong&gt;. Todos tus tests con valores normales pasan. El fallo espera callado hasta que alguien prueba el caso límite.&lt;/p&gt;

&lt;p&gt;La lección de fondo, en una frase: or &lt;strong&gt;no distingue entre "no hay valor" y "el valor es cero"&lt;/strong&gt;. Para configuración, esas dos cosas son totalmente distintas — pero &lt;strong&gt;or&lt;/strong&gt; las trata igual. Ahí vive el bug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No es solo Python&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si usas otro lenguaje, el mismo patrón te espera con otra cara. En JavaScript, &lt;strong&gt;process.env.VAR || "133"&lt;/strong&gt; tiene el problema idéntico con &lt;strong&gt;0&lt;/strong&gt;, "" y &lt;strong&gt;false&lt;/strong&gt;. (Por eso JS moderno introdujo ??, el &lt;strong&gt;nullish coalescing&lt;/strong&gt;, que solo cae al default cuando el valor es realmente nulo — creado justo para arreglar esto.) En &lt;strong&gt;Go&lt;/strong&gt; se disfraza de &lt;strong&gt;if val == "" { val = "133" }&lt;/strong&gt;, mezclando "no existe" con "cadena vacía".&lt;/p&gt;

&lt;p&gt;El patrón es universal porque el impulso que lo crea es universal: quiero un valor sensato si la config falla. Buena intención. Mala ejecución.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qué hacer en su lugar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;La regla: &lt;strong&gt;si un valor es importante, su ausencia no debe ser silenciosa&lt;/strong&gt;. Tres opciones, de más a menos estricta:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Si es obligatorio, que el programa grite&lt;/strong&gt;. No inventes default; exige que exista.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7lu2p23nzf4ys8y2s1bi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7lu2p23nzf4ys8y2s1bi.png" alt=" " width="444" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Un programa que se niega a arrancar sin su config es mucho más seguro que uno que arranca con un valor fantasma.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Si quieres un default, usa el argumento correcto&lt;/strong&gt; &lt;strong&gt;(no&lt;/strong&gt; or*&lt;em&gt;)&lt;/em&gt;*.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1e3l0l5bw0pfizvjvh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1e3l0l5bw0pfizvjvh1.png" alt=" " width="414" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El segundo argumento de getenv solo actúa cuando la variable no existe — no cuando vale cero. Que es lo que de verdad querías.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Si el default es a propósito, hazlo visible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj9w3gvq4mxtmdkv4pu7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj9w3gvq4mxtmdkv4pu7m.png" alt=" " width="591" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Así, si un restore borra la variable, no tienes un bug silencioso: tienes una línea en el log que te dice exactamente qué pasó.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esto no es solo trading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mi caso fue un bot con capital real, pero el patrón vive en cualquier sistema donde un valor equivocado importa: un &lt;strong&gt;límite de acceso&lt;/strong&gt; que cae a un default permisivo, una &lt;strong&gt;configuración de seguridad&lt;/strong&gt; que desaparece y se reemplaza sin avisar, un &lt;strong&gt;umbral&lt;/strong&gt; que silenciosamente vuelve a un valor de fábrica. En todos, un default silencioso convierte "se borró la config" en "el sistema hace algo que nadie pidió" — sin dejar rastro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La lección para llevarte&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Un default silencioso cambia un fallo que ves por uno que no ves&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;getenv("X") or default&lt;/strong&gt; parece robustez, pero es fragilidad disfrazada: en vez de detenerse y avisarte cuando falta algo, sigue adelante con un valor que nadie decidió.&lt;/p&gt;

&lt;p&gt;Un programa que se niega a arrancar te cuesta cinco minutos. Uno que arranca con el valor equivocado te cuesta encontrarlo cuando ya hizo daño. En mi caso, ese cambio de una línea fue la diferencia entre semanas de fuga silenciosa y un arranque limpio.&lt;/p&gt;

&lt;p&gt;Los valores por defecto no son gratis. Son una decisión sobre qué pasa cuando el mundo no es como esperabas — y esa decisión merece más que un or al final de una línea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En la próxima entrada cambio de escenario&lt;/strong&gt;: Binance movió silenciosamente uno de sus endpoints de la API, y mi bot llevaba días colocando órdenes de protección que en realidad no existían. Cómo se detecta que una plataforma de la que dependes cambió las reglas sin avisar — y cómo migrar sin quedarte expuesto.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;¿Cuál es el default silencioso más peligroso que has encontrado en código ajeno (o propio)? Los leo en los comentarios.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>trading</category>
      <category>python</category>
      <category>showdev</category>
      <category>spanish</category>
    </item>
    <item>
      <title>"El par fantasma: cómo un bot operaba con capital que nadie le asignó"</title>
      <dc:creator>Jesus Corredor</dc:creator>
      <pubDate>Sat, 29 Aug 2026 02:52:20 +0000</pubDate>
      <link>https://dev.to/jesusaco/diario-de-un-bot-que-opera-con-dinero-real-entrada-1-1gip</link>
      <guid>https://dev.to/jesusaco/diario-de-un-bot-que-opera-con-dinero-real-entrada-1-1gip</guid>
      <description>&lt;p&gt;Diario de un bot que opera con dinero real — Entrada #1: &lt;/p&gt;

&lt;p&gt;Hace unos meses eliminé un par de trading de mi bot de futuros. O eso creía.&lt;/p&gt;

&lt;p&gt;La semana pasada, durante una auditoría de rutina, encontré ese mismo par abriendo posiciones, reservando capital, y bloqueando a los demás. No lo había resucitado. Nunca se había ido.&lt;/p&gt;

&lt;p&gt;Esta es la primera de una serie de historias reales sobre un sistema que opera con dinero de verdad — donde los bugs no son un test que falla, sino capital moviéndose. Empiezo por esta: un bug silencioso que vivió meses en producción, y por qué "eliminar" algo de una forma frágil es peor que no eliminarlo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El síntoma&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Estaba revisando los logs del bot cuando una línea me detuvo:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[PAR-X] SNAP | ... | cap=135.34 | lev=3× | pos=FLAT&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ese par no debía estar ahí. Lo había sacado de la operación hacía meses. Y sin embargo, ahí estaba, con un capital asignado de ~$135 que yo no recordaba haber configurado. Peor: un par de ciclos después, otro par intentó abrir una posición y falló:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[PAR-X] ENTRY SKIP | USDT insuficiente: free=130.98 &amp;lt; needed=138.04&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;El par fantasma estaba acaparando capital, y por su culpa los pares que sí debían operar se quedaban sin fondos. Un componente que creía muerto competía por recursos con los vivos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La investigación&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lo primero fue ir a la fuente de configuración. El bot lee el capital de cada par desde un archivo de entorno (.env). Busqué la variable de ese par:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkj74f7zl2mjkwskmwl47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkj74f7zl2mjkwskmwl47.png" alt=" " width="237" height="29"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vacío. La variable no existía en el .env. Entonces, ¿de dónde salían los $135?&lt;/p&gt;

&lt;p&gt;La respuesta estaba en el código. El bot arma su lista de pares desde un diccionario de configuración, y cada par lee su capital así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkoc13jyolob98u0rvo5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkoc13jyolob98u0rvo5b.png" alt=" " width="504" height="34"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahí estaba el problema. &lt;code&gt;os.getenv("PAR_X_USDT")&lt;/code&gt; devuelve None cuando la variable no existe. Y None or "133" evalúa a "133". El bot, al no encontrar la variable en el .env, &lt;strong&gt;caía a un valor por defecto hardcodeado de $133&lt;/strong&gt; que alguien (yo, meses atrás) había dejado en el código como fallback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La causa raíz — y aquí está la lección real&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El bug no era solo el fallback. Era &lt;strong&gt;cómo había "eliminado" el par meses atrás.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En su momento, para desactivarlo, había puesto su capital en cero en el &lt;code&gt;.env (PAR_X_USDT=0)&lt;/code&gt;. Funcionó… hasta que un día restauré un backup del código por otra razón. Ese backup era anterior a mi cambio, o el .env se sobrescribió en el proceso. La variable desapareció. Y sin la variable, el código volvió a caer al fallback de $133.&lt;/p&gt;

&lt;p&gt;El par nunca estuvo eliminado de verdad. Seguía en el diccionario de configuración que el bot recorre en cada ciclo. Yo solo le había bajado el capital por una vía frágil — una variable de entorno — que un restore podía borrar. La eliminación real habría sido sacarlo del diccionario de configuración, en el código. No lo hice. Y el sistema, silenciosamente, lo revivió.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;La corrección definitiva fue eliminar el bloque del par directamente del diccionario de configuración en el código, no del .env. Con el protocolo de siempre:&lt;/p&gt;

&lt;p&gt;Verificar que el par no tuviera posición abierta (revisar su archivo de estado).&lt;br&gt;
Backup del archivo con timestamp.&lt;br&gt;
Eliminar el bloque de configuración.&lt;br&gt;
Validar la sintaxis &lt;code&gt;(python3 -c "import ast; ast.parse(...)")&lt;/code&gt;.&lt;br&gt;
Confirmar con grep que el par ya no aparecía en ningún lado.&lt;br&gt;
Reinicio manual.&lt;/p&gt;

&lt;p&gt;Tras el reinicio, el banner de arranque lo confirmó: el bot ahora recorría solo los pares correctos. El fantasma se había ido de verdad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El cuerpo del delito&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quedó un detalle que cierra la historia. Tras eliminar el par, su archivo de estado local quedó huérfano en el directorio. Lo abrí. Ahí seguía, congelado, con su última sesión registrada:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5gs7f8bsp9o1qikz9wub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5gs7f8bsp9o1qikz9wub.png" alt=" " width="257" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;initial_capital: 133. La evidencia física del fallback, escrita en disco. El par había estado operando todo ese tiempo con un capital que ningún archivo de configuración le asignó — solo un valor por defecto olvidado en una línea de código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La lección para llevarte&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Antes de las lecciones técnicas, la pregunta que me perseguía mientras lo corregía: &lt;strong&gt;¿cómo sobrevivió esto a las auditorías anteriores?&lt;/strong&gt; Había revisado este bot varias veces. ¿Cómo no lo vi?&lt;/p&gt;

&lt;p&gt;La respuesta me pareció más valiosa que el bug en sí. No lo detecté antes &lt;strong&gt;porque estaba auditando el código, y el código estaba bien&lt;/strong&gt;. El fallback or "133" no es un error de sintaxis, ni una excepción, ni nada que un grep de "bug" encuentre. Es una línea perfectamente válida que hace exactamente lo que dice — el problema no vivía en el código, vivía en la brecha entre el código y la configuración. El .env decía una cosa (nada), el código asumía otra (un default), y ninguna revisión de un solo lado podía ver la contradicción, porque cada lado, por separado, era correcto.&lt;/p&gt;

&lt;p&gt;El bug solo era visible cruzando ambos contra lo que el sistema hacía en vivo — leyendo los logs de ejecución real y preguntándose "¿por qué este par tiene capital si yo no se lo di?". Lo encontré no porque revisara mejor el código, sino porque miré lo que el bot realmente estaba haciendo y no cuadraba con lo que yo creía haber configurado.&lt;/p&gt;

&lt;p&gt;Esa es la lección de fondo: &lt;strong&gt;una auditoría que solo lee el código estático nunca atrapa un bug de configuración fantasma&lt;/strong&gt;. Los sistemas mienten por omisión. La verdad no está en el código ni en la config por separado, sino en el comportamiento observado. Si algo opera distinto de como crees haberlo configurado, esa discrepancia es el bug, aunque cada archivo por separado se vea impecable.&lt;/p&gt;

&lt;p&gt;De ahí, tres trampas concretas que me llevo:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Los defaults hardcodeados son deuda oculta&lt;/strong&gt;. Un &lt;code&gt;os.getenv("X")&lt;/code&gt; or "133" parece defensivo, pero convierte la ausencia de configuración en un valor silencioso. Si la variable desaparece, el sistema no se detiene ni avisa: sigue con un número que nadie decidió.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desactivar por la vía frágil no es desactivar&lt;/strong&gt;. Bajar un valor en un .env es reversible por accidente — un restore, una sobrescritura, un despliegue. Si algo debe estar fuera, sácalo de la estructura que el sistema recorre, no de un parámetro que la alimenta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Un backup puede resucitar tus bugs&lt;/strong&gt;. Restaurar código viejo no solo revierte features; revierte fixes. Cada restore debería venir con la pregunta: ¿qué correcciones posteriores estoy deshaciendo con esto?&lt;/p&gt;

&lt;p&gt;El par fantasma no me costó dinero — estaba en FLAT cuando lo encontré. Pero pudo haberlo hecho. Y lo más inquietante no es el bug en sí, sino cuánto tiempo vivió sin que ninguna auditoría lo viera. A veces lo más peligroso no es lo que falla ruidosamente, sino lo que funciona en silencio haciendo algo que no autorizaste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En la próxima entrada desarmo&lt;/strong&gt; la línea exacta que causó todo esto ese inocente &lt;code&gt;os.getenv("X") or default&lt;/code&gt; — y te muestro por qué es una trampa que probablemente tienes en tu propio código ahora mismo. Incluido el caso que casi me muerde a mí: cómo intentar apagar algo poniéndolo en cero puede encenderlo.&lt;/p&gt;

&lt;p&gt;¿Te ha pasado encontrar un componente haciendo algo que juraste haber desactivado? Cuéntamelo en los comentarios — colecciono estas historias.&lt;/p&gt;

</description>
      <category>trading</category>
      <category>spanish</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Empecé este bot por desconfianza, no por avaricia.</title>
      <dc:creator>Jesus Corredor</dc:creator>
      <pubDate>Sat, 22 Aug 2026 15:13:11 +0000</pubDate>
      <link>https://dev.to/jesusaco/empece-este-bot-por-desconfianza-no-por-avaricia-4f0a</link>
      <guid>https://dev.to/jesusaco/empece-este-bot-por-desconfianza-no-por-avaricia-4f0a</guid>
      <description>&lt;p&gt;Diario de un bot que opera con dinero real — Entrada #0: el origen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todo empezó con un tuit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uno de esos que seguramente también has visto: una captura de una wallet, "$100 convertidos en $10.000 en 24 horas con este bot de trading", flechas verdes, emojis de cohetes, y un "sígueme para más". Debajo, cientos de likes y gente pidiendo el enlace.&lt;/p&gt;

&lt;p&gt;Mi primera reacción no fue "quiero eso". Fue "eso es mentira".&lt;/p&gt;

&lt;p&gt;Y no hace falta ser matemático para verlo. Un retorno del 10.000% en un día no es una estrategia — es un billete de lotería premiado que alguien presenta como si fuera un método repetible. Si de verdad tuvieras un sistema que multiplica tu dinero por cien cada 24 horas, no lo estarías publicando en X pidiendo likes. Lo estarías usando en silencio hasta comprar una isla. El que regala el mapa del tesoro es porque el tesoro no existe — el verdadero producto que se vende en esos tuits no es el bot: eres tú, tu like, tu follow, tu atención.&lt;/p&gt;

&lt;p&gt;Así que no le di like. Pero me quedé pensando.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La pregunta que sí valía la pena&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Descartado el humo, quedaba una pregunta honesta debajo: despojado de la mentira del 10.000%, ¿hay algo real ahí?&lt;/p&gt;

&lt;p&gt;Porque los bots de trading existen. La automatización de estrategias es legítima. Los mercados operan 24/7 y un programa no duerme ni entra en pánico. La idea de fondo —dejar que un sistema ejecute una estrategia con disciplina, sin la emoción que arruina las decisiones humanas— no es una estafa. La estafa es el número. La estafa es prometer un retorno imposible para vender seguidores.&lt;/p&gt;

&lt;p&gt;Entonces me hice la pregunta que inició todo esto: &lt;strong&gt;¿qué pasa si alguien escéptico construye un bot de trading de verdad, con expectativas sobrias, y documenta la verdad completa — incluida la parte donde todavía no sabe si funciona?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esa es la serie que estás empezando a leer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo que es, y lo que no es&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para que no haya malentendidos, porque tú y yo ya sabemos cómo suele terminar este tipo de contenido:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esto no es&lt;/strong&gt; un tutorial de "hazte rico". No voy a mostrarte una wallet inflada. No hay enlace de afiliado, no hay curso al final, no voy a decirte que copies mi estrategia y te retires en un año.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esto sí es&lt;/strong&gt; el registro honesto de construir un sistema real que mueve dinero real: los bugs que encontré (algunos que me pusieron los pelos de punta), las auditorías, las decisiones tomadas con datos en vez de con ilusión, y los errores que documenté justamente para no repetirlos.&lt;/p&gt;

&lt;p&gt;Y aquí viene la parte que ningún tuit de captura de wallet te va a decir jamás: &lt;strong&gt;al momento de escribir esto, mi bot no ha demostrado que gane dinero de forma sostenida&lt;/strong&gt;. Tiene meses de trabajo de ingeniería sólida detrás, sobrevive a fallos que tumbarían a otros, y hay evidencia de que su estrategia podría tener una ventaja real. Pero "podría" no es "tiene". Estoy en pleno proceso de validar, con dinero real y en vivo, si esa ventaja existe de verdad o si es un espejismo de los datos históricos.&lt;/p&gt;

&lt;p&gt;Eso es lo más honesto que puedo ofrecerte, y es exactamente lo contrario del tuit que me trajo aquí. El estafador te vende certeza que no tiene. Yo te ofrezco un proceso honesto cuyo desenlace ni yo conozco todavía.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por qué escribo esto&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Porque el espacio está tan lleno de humo que la verdad, por aburrida que sea a veces, es refrescante.&lt;/p&gt;

&lt;p&gt;Cada entrada de esta serie es un post-mortem real: algo que salió mal, cómo lo investigué, qué aprendí. No hay finales felices garantizados. Hay un componente que operó meses con dinero que nadie le asignó. Hay protecciones que el bot creía tener y no tenía. Hay una fuga silenciosa que tardé meses en detectar. Y hay decisiones —como cerrar proyectos que no funcionaban— tomadas sin dejar que el orgullo o el dinero ya invertido nublaran el juicio.&lt;/p&gt;

&lt;p&gt;Si buscabas el bot que convierte $100 en $10.000, esta no es tu serie, y con cariño te digo que esa serie no existe en ningún lado — solo existe el tuit que te la promete.&lt;/p&gt;

&lt;p&gt;Pero si te interesa cómo se construye de verdad un sistema que opera con dinero, con toda la honestidad de sus errores y la incertidumbre honesta de su resultado, quédate. Empecé esto por desconfianza. Y resulta que la desconfianza, bien usada, es el mejor punto de partida para construir algo real.&lt;br&gt;
&lt;strong&gt;En la próxima entrada empieza lo bueno:&lt;/strong&gt; cómo encontré un componente de mi bot operando con un capital que nadie le asignó — un "par fantasma" que creía haber eliminado meses atrás, y que seguía vivo, acaparando recursos, escondido a plena vista.&lt;/p&gt;

&lt;p&gt;¿Tú también llegaste a los bots de trading a través de una promesa que sabías que era falsa? ¿Qué te hizo dudar? Cuéntamelo en los comentarios.&lt;/p&gt;

</description>
      <category>trading</category>
      <category>python</category>
      <category>spanish</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
