<?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: Gueta Quant </title>
    <description>The latest articles on DEV Community by Gueta Quant  (@guetaquant).</description>
    <link>https://dev.to/guetaquant</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%2F4084951%2F5f236106-8f97-48b1-9a2b-d4f210066eb6.jpg</url>
      <title>DEV Community: Gueta Quant </title>
      <link>https://dev.to/guetaquant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guetaquant"/>
    <language>en</language>
    <item>
      <title>El bug silencioso de las calculadoras de lotaje: cuando la cuenta es pequeña, tu riesgo se duplica</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Tue, 08 Sep 2026 15:14:42 +0000</pubDate>
      <link>https://dev.to/guetaquant/el-bug-silencioso-de-las-calculadoras-de-lotaje-cuando-la-cuenta-es-pequena-tu-riesgo-se-duplica-18jf</link>
      <guid>https://dev.to/guetaquant/el-bug-silencioso-de-las-calculadoras-de-lotaje-cuando-la-cuenta-es-pequena-tu-riesgo-se-duplica-18jf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aviso.&lt;/strong&gt; GuetaQuant es un portal de educación cuantitativa independiente. Este artículo es material pedagógico sobre implementación de software de gestión de riesgo. No es asesoría financiera, ni recomendación de inversión, ni captación de fondos. Operar en mercados apalancados conlleva riesgo de pérdida total del capital.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Casi todo el material sobre dimensionamiento de posición se detiene en la misma ecuación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lotes = (balance × riesgo%) / (distancia_stop × valor_por_lote)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es correcta, y es la parte fácil. El problema no está en la fórmula: está en las tres líneas que vienen después, cuando hay que ajustar ese número al paso de lote y al mínimo que exige el broker.&lt;/p&gt;

&lt;p&gt;Ahí es donde encontramos un bug en nuestro propio código. Lo publicamos porque el patrón está en todas partes, y porque el error se concentra exactamente en las cuentas más pequeñas.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. El bug: &lt;code&gt;MathMax(minLot, lotes)&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Este es el cierre habitual de una función de lotaje. Aparece en foros de MQL5, en repositorios de GitHub y estaba en el fragmento que nosotros mismos publicábamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double lots = MathFloor(rawLot / lotStep) * lotStep;
return MathMax(minLot, MathMin(maxLot, lots));   // &amp;lt;-- aquí
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MathFloor&lt;/code&gt; está bien: redondear hacia abajo garantiza no pasarse del presupuesto. El problema es &lt;code&gt;MathMax(minLot, ...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cuando el lote presupuestado queda &lt;strong&gt;por debajo&lt;/strong&gt; del mínimo del broker, &lt;code&gt;MathFloor&lt;/code&gt; devuelve &lt;code&gt;0.00&lt;/code&gt;. &lt;code&gt;MathMax&lt;/code&gt; entonces lo sube a &lt;code&gt;minLot&lt;/code&gt;. La función devuelve un lote operable و no dice nada.&lt;/p&gt;

&lt;p&gt;Ese lote ya no respeta el presupuesto. Y la función sigue reportando el presupuesto original como si fuera el riesgo asumido.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. La medición
&lt;/h2&gt;

&lt;p&gt;Cuenta de 500 USD. Riesgo 0.5%. Stop de 500 ticks, valor del tick 1.00 USD.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concepto&lt;/th&gt;
&lt;th&gt;Valor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Presupuesto de riesgo (0.5% de 500)&lt;/td&gt;
&lt;td&gt;2.50 USD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lotes brutos&lt;/td&gt;
&lt;td&gt;0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;floor&lt;/code&gt; al paso de 0.01&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Devuelto tras &lt;code&gt;MathMax(minLot, …)&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Riesgo real de esos 0.01 lotes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.00 USD&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Riesgo reportado por la función&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.50 USD&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;El riesgo efectivo es &lt;strong&gt;el doble&lt;/strong&gt; del presupuestado, y nada en la respuesta lo indica.&lt;/p&gt;

&lt;p&gt;No es un caso de laboratorio: es una cuenta de 500 USD operando con riesgo conservador. Es el perfil de quien más necesita que el límite se respete.&lt;/p&gt;

&lt;h3&gt;
  
  
  El mismo problema con &lt;code&gt;round()&lt;/code&gt; en lugar de &lt;code&gt;floor()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Una variante frecuente es usar &lt;code&gt;round()&lt;/code&gt; en vez de &lt;code&gt;floor()&lt;/code&gt;. Buscamos por fuerza bruta el peor caso sobre una malla de balances (500–20.000 USD), stops (5–120 pips) y riesgos (0.5%, 1%, 2%):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Paso de lote&lt;/th&gt;
&lt;th&gt;Peor sobrepaso medido&lt;/th&gt;
&lt;th&gt;Caso&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+99.15%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;balance 1.175 USD, riesgo 0.5%, stop 117 pips&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+99.58%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;balance 12.025 USD, riesgo 0.5%, stop 120 pips&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En ambos casos los lotes brutos caen justo por encima de la mitad del paso (0.0050 y 0.0501), &lt;code&gt;round()&lt;/code&gt; sube al siguiente escalón y el riesgo casi se duplica. El sobrepaso no está acotado a "unos centavos": está acotado a medio paso de lote, que cerca del mínimo equivale a un 100% del presupuesto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Y un tercer caso: el valor del pip quemado en el código
&lt;/h3&gt;

&lt;p&gt;Muchas implementaciones asumen &lt;code&gt;valor_pip = 10 USD&lt;/code&gt;, que solo es cierto para pares con USD como divisa cotizada y lote estándar. En XAUUSD el valor real ronda 1 USD por pip.&lt;/p&gt;

&lt;p&gt;Con balance de 10.000 USD, riesgo 1% (presupuesto 100 USD) y stop de 320 pips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asumiendo 10 USD/pip: lotes brutos &lt;code&gt;0.0312&lt;/code&gt; → riesgo real &lt;strong&gt;9.60 USD&lt;/strong&gt;. Se arriesga &lt;strong&gt;una décima parte&lt;/strong&gt; de lo previsto, y la estrategia queda infra-dimensionada sin que nadie lo note.&lt;/li&gt;
&lt;li&gt;Con el valor real de 1 USD/pip: lotes brutos &lt;code&gt;0.3125&lt;/code&gt; → riesgo real &lt;strong&gt;99.20 USD&lt;/strong&gt;. Correcto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este falla en silencio y hacia abajo, que es peor de detectar: nadie revisa una función de riesgo porque esté arriesgando de menos.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. El arreglo
&lt;/h2&gt;

&lt;p&gt;La regla es simple: &lt;strong&gt;si el lote presupuestado no llega al mínimo del broker, la operación no cabe dentro del riesgo definido.&lt;/strong&gt; Subirla a &lt;code&gt;minLot&lt;/code&gt; no es un ajuste, es cambiar el presupuesto sin avisar.&lt;/p&gt;

&lt;p&gt;La función debe rechazar la entrada y devolver el dato para que decida la persona:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tamano_posicion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;riesgo_pct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sl_ticks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valor_tick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;paso_lote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lote_min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lote_max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;presupuesto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;riesgo_pct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="n"&gt;perdida_por_lote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sl_ticks&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;valor_tick&lt;/span&gt;
    &lt;span class="n"&gt;lotes_brutos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;presupuesto&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;perdida_por_lote&lt;/span&gt;

    &lt;span class="n"&gt;lotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lotes_brutos&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;paso_lote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;paso_lote&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lotes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;lote_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;operable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;motivo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;el lote presupuestado esta por debajo del minimo del broker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lotes_brutos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lotes_brutos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;presupuesto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presupuesto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;riesgo_si_usas_el_minimo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lote_min&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;perdida_por_lote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;lotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lote_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;riesgo_real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lotes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;perdida_por_lote&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;operable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lotes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;presupuesto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presupuesto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;riesgo_real&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;riesgo_real&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida real de las dos llamadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;tamano_posicion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;operable&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;motivo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;el lote presupuestado esta por debajo del minimo del broker&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lotes_brutos&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;presupuesto&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;riesgo_si_usas_el_minimo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;tamano_posicion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;operable&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lotes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;presupuesto&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;riesgo_real&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El primer caso no devuelve un lote. Devuelve el motivo y el número que hay que mirar: operar el mínimo cuesta 5.00 USD contra un presupuesto de 2.50. La decisión de aceptar ese riesgo es del trader, no de una línea de código que se lo oculta.&lt;/p&gt;

&lt;p&gt;Y en MQL5:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double lots = MathFloor(rawLot / lotStep) * lotStep;

// Si el lote presupuestado no alcanza el minimo del broker, la operacion NO cabe
// dentro del riesgo definido. Subirlo a minLot arriesgaria mas de lo presupuestado.
if(lots &amp;lt; minLot) return 0.0;

return MathMin(maxLot, lots);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Tres reglas para revisar tu propia implementación
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Nunca &lt;code&gt;round()&lt;/code&gt;, siempre &lt;code&gt;floor()&lt;/code&gt;.&lt;/strong&gt; El sobrepaso de &lt;code&gt;round()&lt;/code&gt; llega a medio paso de lote, que cerca del mínimo es ~100% del presupuesto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nunca subir a &lt;code&gt;minLot&lt;/code&gt; en silencio.&lt;/strong&gt; O se rechaza la entrada, o se devuelve el riesgo efectivo junto con una bandera de que hubo ajuste. Devolver solo el presupuesto teórico es reportar un número falso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nunca quemar el valor del pip.&lt;/strong&gt; Léelo del símbolo (&lt;code&gt;SYMBOL_TRADE_TICK_VALUE&lt;/code&gt; y &lt;code&gt;SYMBOL_TRADE_TICK_SIZE&lt;/code&gt; en MQL5). Un &lt;code&gt;10.0&lt;/code&gt; fijo rompe en oro, índices y cripto.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Nota de transparencia
&lt;/h2&gt;

&lt;p&gt;Este bug estaba en nuestro propio código, en el endpoint público &lt;code&gt;/api/position-size/&lt;/code&gt;, que devolvía &lt;code&gt;roundedLots: 0.01&lt;/code&gt; junto a &lt;code&gt;riskAmount: 2.5&lt;/code&gt; cuando el riesgo real era 5.00 USD. Ya está corregido: la respuesta ahora incluye &lt;code&gt;effectiveRiskAmount&lt;/code&gt;, &lt;code&gt;effectiveRiskPercent&lt;/code&gt;, &lt;code&gt;clampedToMin&lt;/code&gt; y &lt;code&gt;clampedToMax&lt;/code&gt;, y hay dos pruebas de regresión que fallan si alguien vuelve a ocultar el ajuste.&lt;/p&gt;

&lt;p&gt;La calculadora web sí mostraba la advertencia correctamente desde el principio; el fallo estaba en la librería que alimenta la API y en el fragmento MQL5 publicado. Publicamos el error porque un portal que enseña gestión de riesgo y esconde sus propios defectos no sirve para nada.&lt;/p&gt;

&lt;p&gt;La calculadora, la fórmula completa y el indicador en MQL5 bajo licencia AGPLv3 están acá:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://guetaquant.com/herramientas/" rel="noopener noreferrer"&gt;Calculadora de lotaje MT5 — GuetaQuant&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;¿Cómo maneja tu implementación el caso de lote por debajo del mínimo? Me interesa saber si alguien lo rechaza, lo clampa o lo reporta.&lt;/p&gt;

</description>
      <category>python</category>
      <category>quant</category>
      <category>trading</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Algorithmic Risk Management in MT5: ATR Volatility Position Sizing &amp; MQL5 Architecture</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Wed, 19 Aug 2026 12:30:02 +0000</pubDate>
      <link>https://dev.to/guetaquant/algorithmic-risk-management-in-mt5-atr-volatility-position-sizing-mql5-architecture-55nn</link>
      <guid>https://dev.to/guetaquant/algorithmic-risk-management-in-mt5-atr-volatility-position-sizing-mql5-architecture-55nn</guid>
      <description>&lt;h1&gt;
  
  
  Algorithmic Risk Management in MT5: Dynamic Position Sizing &amp;amp; MQL5 Architecture
&lt;/h1&gt;

&lt;p&gt;Most retail trading failures stem from static lot sizing. Trading a fixed 1.0 lot on EUR/USD creates vastly different dollar drawdowns compared to 1.0 lot on Gold (XAU/USD) or NASDAQ (NAS100) due to differing point values and underlying volatility regimes.&lt;/p&gt;

&lt;p&gt;In professional quantitative finance, position sizing is dynamically governed by the asset's Average True Range (ATR) and a fixed risk budget per trade:&lt;/p&gt;

&lt;p&gt;$$\text{Position Size (Lots)} = \frac{\text{Account Balance} \times \text{Risk \%}}{\text{Stop Loss Distance (Points)} \times \text{Tick Value}}$$&lt;/p&gt;

&lt;p&gt;In this technical guide, we implement an open-source, production-grade MQL5 risk engine that dynamically computes lot sizes and routes orders with slippage protection.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Original interactive tool and web calculator available at &lt;a href="https://guetaquant.com/herramientas/mt5-position-sizer/" rel="noopener noreferrer"&gt;GuetaQuant MT5 Position Sizer&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. MQL5 Dynamic Lot Calculation Class
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//+------------------------------------------------------------------+
//|                                             GQ_RiskEngine.mqh    |
//|                             Copyright 2026, Gueta Quant (AGPLv3) |
//|                                       https://guetaquant.com     |
//+------------------------------------------------------------------+
#property copyright "Gueta Quant"
#property link      "https://guetaquant.com"

class CGQRiskManager
{
private:
   string   m_symbol;
   double   m_risk_pct;

public:
   CGQRiskManager(string symbol, double risk_pct) : m_symbol(symbol), m_risk_pct(risk_pct) {}

   double CalculateLots(double sl_distance_price)
   {
      if (sl_distance_price &amp;lt;= 0) return 0.0;

      double balance     = AccountInfoDouble(ACCOUNT_BALANCE);
      double risk_amount = balance * (m_risk_pct / 100.0);

      double tick_size   = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_SIZE);
      double tick_value  = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_VALUE);
      double min_lot     = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MIN);
      double max_lot     = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MAX);
      double lot_step    = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_STEP);

      if (tick_size == 0 || tick_value == 0) return 0.0;

      double loss_per_lot = (sl_distance_price / tick_size) * tick_value;
      if (loss_per_lot &amp;lt;= 0) return 0.0;

      double raw_lots = risk_amount / loss_per_lot;

      // Normalize to broker lot step
      double normalized_lots = MathFloor(raw_lots / lot_step) * lot_step;

      if (normalized_lots &amp;lt; min_lot) normalized_lots = min_lot;
      if (normalized_lots &amp;gt; max_lot) normalized_lots = max_lot;

      return normalized_lots;
   }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. ATR Volatility Trailing Stops
&lt;/h2&gt;

&lt;p&gt;Using historical volatility avoids getting stopped out during normal market noise while protecting capital during structural trend shifts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double GetATRDistance(string symbol, ENUM_TIMEFRAMES tf, int period, double multiplier)
{
   int handle = iATR(symbol, tf, period);
   if (handle == INVALID_HANDLE) return 0.0;

   double atr_val[1];
   if (CopyBuffer(handle, 0, 0, 1, atr_val) &amp;lt;= 0) return 0.0;

   return atr_val[0] * multiplier;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Open Source Tools Ecosystem
&lt;/h2&gt;

&lt;p&gt;All our quantitative software is published under open-source AGPLv3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;44 Open Source Trading Tools:&lt;/strong&gt; &lt;a href="https://github.com/guetaquant-byte/guetaquant-tools" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CERN Zenodo DOI Registry:&lt;/strong&gt; &lt;a href="https://doi.org/10.5281/zenodo.22012203" rel="noopener noreferrer"&gt;DOI 10.5281/zenodo.22012203&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local-First Trading Journal:&lt;/strong&gt; &lt;a href="https://guetaquant.com/journal/" rel="noopener noreferrer"&gt;GuetaQuant Journal&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Compliance: Strictly educational and research material. Does not constitute financial advice. Compliant with Colombian SFC Decreto 2555/2010.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mql5</category>
      <category>metatrader5</category>
      <category>quant</category>
    </item>
    <item>
      <title>Pine Script v6 in 2026: math.sum, math.tanh, User Defined Types &amp; Risk Management Engine</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Wed, 19 Aug 2026 11:52:14 +0000</pubDate>
      <link>https://dev.to/guetaquant/pine-script-v6-in-2026-mathsum-mathtanh-user-defined-types-risk-management-engine-53b4</link>
      <guid>https://dev.to/guetaquant/pine-script-v6-in-2026-mathsum-mathtanh-user-defined-types-risk-management-engine-53b4</guid>
      <description>&lt;h2&gt;
  
  
  Overview: Pine Script v6 &amp;amp; Institutional Risk Architecture
&lt;/h2&gt;

&lt;p&gt;TradingView's &lt;strong&gt;Pine Script v6&lt;/strong&gt; introduced critical architectural upgrades for quantitative developers. Moving beyond basic visual scripts, v6 provides strict type enforcement, built-in tensor-like math functions (&lt;code&gt;math.sum()&lt;/code&gt;, &lt;code&gt;math.tanh()&lt;/code&gt;), User-Defined Types (UDTs), and native webhook JSON formatting for institutional order routing.&lt;/p&gt;

&lt;p&gt;In this guide, we break down the most essential v6 syntax upgrades and build a full production-ready risk engine with volatility-adjusted sizing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Original in-depth research published at &lt;a href="https://guetaquant.com/pine-script-v6/" rel="noopener noreferrer"&gt;GuetaQuant&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Key Mathematical Upgrades in Pine Script v6
&lt;/h2&gt;

&lt;p&gt;In previous versions (v5), performing mathematical reductions across arrays or custom series required cumbersome loops. Pine Script v6 optimizes computational performance by executing core vector operations natively in C++:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;math.sum()&lt;/code&gt; &amp;amp; &lt;code&gt;math.tanh()&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=6
indicator("Pine Script v6 Math &amp;amp; Non-Linear Activation", overlay=false)

// Native vector sum across an array of returns
var float[] log_returns = array.new_float(0)
float current_return = math.log(close / close[1])
array.push(log_returns, current_return)
if array.size(log_returns) &amp;gt; 50
    array.shift(log_returns)

// Hyperbolic tangent non-linear activation (useful for signal bounding [-1.0, 1.0])
float normalized_zscore = (close - ta.sma(close, 20)) / ta.stdev(close, 20)
float bounded_signal = math.tanh(normalized_zscore)

plot(bounded_signal, "Tanh Signal", color=color.emerald)
hline(0.8, "Upper Bound", color=color.gray)
hline(-0.8, "Lower Bound", color=color.gray)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Object-Oriented Architecture with User-Defined Types (UDTs)
&lt;/h2&gt;

&lt;p&gt;Pine Script v6 fully embraces struct-like User-Defined Types. This allows you to encapsulate complete trade contexts (entry, stop loss, risk budget, target) into a single object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=6
indicator("GQ Trade Context Engine", overlay=true)

type TradeRiskContext
    string symbol
    float entryPrice
    float stopLossPrice
    float lotSize
    float riskAmountUSD

// Factory method to calculate ATR-based risk
fn_create_context(float risk_pct, int atr_len, float atr_mult) =&amp;gt;
    float atr_val = ta.atr(atr_len)
    float sl_distance = atr_val * atr_mult
    float sl_price = close - sl_distance
    float risk_dollars = (strategy.equity * risk_pct) / 100.0
    float calculated_lots = risk_dollars / (sl_distance * 10.0) // 10 USD per pip standard

    TradeRiskContext.new(syminfo.ticker, close, sl_price, calculated_lots, risk_dollars)

var TradeRiskContext active_trade = na
if ta.crossover(ta.ema(close, 9), ta.ema(close, 21))
    active_trade := fn_create_context(1.0, 14, 2.5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Webhook JSON Alert Formatting for Automated Execution
&lt;/h2&gt;

&lt;p&gt;Routing alerts to MetaTrader 5 (MT5), cTrader, or custom Python execution servers requires strictly formatted JSON payloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//@version=6
strategy("GQ Webhook Strategy - Pine v6", overlay=true, initial_capital=10000)

fn_build_order_json(string action, float size, float sl_price) =&amp;gt;
    '{"action":"' + action + '","symbol":"' + syminfo.ticker + '","lots":' + str.tostring(size) + ',"sl":' + str.tostring(sl_price) + '}'

if ta.crossover(ta.sma(close, 20), ta.sma(close, 50))
    string payload = fn_build_order_json("BUY", 0.50, close - 2.5 * ta.atr(14))
    strategy.entry("Long", strategy.long, alert_message=payload)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Explore More Open-Source Tools
&lt;/h2&gt;

&lt;p&gt;All our MQL5 EAs, cTrader cBots, and Pine Script v6 indicators are open-source under AGPLv3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;44 Open Source Quantitative Tools:&lt;/strong&gt; &lt;a href="https://github.com/guetaquant-byte/guetaquant-tools" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive MT5 Lot Size Calculator:&lt;/strong&gt; &lt;a href="https://guetaquant.com/herramientas/mt5-position-sizer/" rel="noopener noreferrer"&gt;GuetaQuant MT5 Position Sizer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local-First Quantitative Trading Journal:&lt;/strong&gt; &lt;a href="https://guetaquant.com/journal/" rel="noopener noreferrer"&gt;GuetaQuant Journal&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Disclaimer: Educational research only. Does not constitute investment advice. Compliance with SFC Colombia Decreto 2555/2010.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tradingview</category>
      <category>algorithmictrading</category>
      <category>pinescript</category>
      <category>quant</category>
    </item>
    <item>
      <title>Pine Script v6 in 2026: math.sum, math.tanh, User Defined Types &amp; Risk Management Engine</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Wed, 19 Aug 2026 11:44:24 +0000</pubDate>
      <link>https://dev.to/guetaquant/pine-script-v6-in-2026-mathsum-mathtanh-user-defined-types-risk-management-engine-2426</link>
      <guid>https://dev.to/guetaquant/pine-script-v6-in-2026-mathsum-mathtanh-user-defined-types-risk-management-engine-2426</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endraw'&lt;/p&gt;
</description>
      <category>tradingview</category>
      <category>algorithmictrading</category>
      <category>pinescript</category>
      <category>quant</category>
    </item>
  </channel>
</rss>
