<?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>Deriv in Colombia: COP Deposits, Synthetic Indices and Pip Math</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Tue, 13 Oct 2026 14:01:10 +0000</pubDate>
      <link>https://dev.to/guetaquant/deriv-in-colombia-cop-deposits-synthetic-indices-and-pip-math-1jej</link>
      <guid>https://dev.to/guetaquant/deriv-in-colombia-cop-deposits-synthetic-indices-and-pip-math-1jej</guid>
      <description>&lt;p&gt;Two questions dominate Colombian search around Deriv: &lt;em&gt;does it accept Colombian pesos (COP)?&lt;/em&gt; and &lt;em&gt;what are synthetic indices, mathematically?&lt;/em&gt; This post answers both with verifiable mechanics — no signals, no account handling, no return claims.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc63wxx7w1mvec6rswgc2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc63wxx7w1mvec6rswgc2.webp" alt="Guía Deriv Colombia 2026: depósitos en pesos COP, índices sintéticos 24/7 y cálculo de pips" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. COP Deposits: Routes, Not Promises
&lt;/h2&gt;

&lt;p&gt;Deriv is a foreign broker (not supervised by Colombia's SFC — same framework as every international CFD broker in our &lt;a href="https://guetaquant.com/brokers-regulados-colombia/" rel="noopener noreferrer"&gt;Colombia brokers guide&lt;/a&gt;). For funding from Colombia, the routes that exist in practice are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local payment rails&lt;/strong&gt; (where available): cards and e-wallets that settle in COP and convert at the processor's rate. Availability changes — verify on Deriv's cashier page before assuming anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P2P / payment agents&lt;/strong&gt;: third-party exchangers. Highest counterparty risk of the three; never share account credentials, and test with a minimum amount first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crypto on-ramp&lt;/strong&gt;: fund with crypto, convert inside. Adds a second volatile leg — track the conversion rate separately from trading P&amp;amp;L.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;General rule: the COP→USD conversion cost is part of your trading cost. A 2–3% round-trip conversion drag means your strategy must earn that back before it earns anything. Log it like commission.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Synthetic Indices: RNG Markets, 24/7
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2s0la6k87s3ceotupoe6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2s0la6k87s3ceotupoe6.webp" alt="Diagrama de índices sintéticos Deriv: generador auditado, volatilidad constante y operación 24/7" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Synthetic indices are &lt;strong&gt;audited random-number-generator markets&lt;/strong&gt; with constant volatility parameters (e.g., Volatility 100 claims roughly constant 100% annualized vol). Consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They trade 24/7 — no sessions, no fundamentals, no closes. Your backtest has no weekend gaps to handle, but also no mean-reverting session effects to exploit.&lt;/li&gt;
&lt;li&gt;Price is path-independent noise by design. Trend-following assumptions imported from Forex need re-validation; falsify them on demo before sizing up.&lt;/li&gt;
&lt;li&gt;Spikes and jumps are part of the generator spec on crash/boom variants — read the contract specs, don't discover them with real money.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Pip and Lot Math on Deriv
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzxqhd28w5p38tbj4x3z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzxqhd28w5p38tbj4x3z.webp" alt="Cálculo de pips y lotaje en Deriv: del presupuesto en USD al tamaño de posición" width="800" height="447"&gt;&lt;/a&gt;&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="c1"&gt;# Generic pip-value sketch (verify contract size per symbol on Deriv first)
&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;risk_pct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;500.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;
&lt;span class="n"&gt;stop_pips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pip_value_per_lot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;   &lt;span class="c1"&gt;# EXAMPLE values, not Deriv quotes
&lt;/span&gt;&lt;span class="n"&gt;lots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;risk_pct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop_pips&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pip_value_per_lot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Budgeted lots: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lots&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two Deriv-specific traps: (a) contract sizes differ per synthetic — never reuse a Forex lot figure; (b) multipliers/options have built-in stops with different payoff math than spot CFDs. Paper-trade each instrument type separately — our &lt;a href="https://guetaquant.com/herramientas/mt5-position-sizer/" rel="noopener noreferrer"&gt;MT5 position sizer&lt;/a&gt; explains the clamp bug that silently doubles small-account risk when minimums bind.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Taxes and Legality in One Paragraph
&lt;/h2&gt;

&lt;p&gt;Own-account trading with a foreign broker is the same SFC/DIAN framework as everywhere on this site: the SFC does not supervise Deriv, you carry counterparty risk, and profits are declarable income in Colombia (see the &lt;a href="https://guetaquant.com/declarar-ganancias-trading-colombia/" rel="noopener noreferrer"&gt;DIAN guide&lt;/a&gt;). Full mechanics in Spanish: &lt;a href="https://guetaquant.com/deriv-colombia/" rel="noopener noreferrer"&gt;Deriv en Colombia&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Study material under Colombia SFC Decreto 2555 de 2010 — education, not advice. No signals.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Gueta Quant.*&lt;/p&gt;

</description>
      <category>python</category>
      <category>quant</category>
      <category>trading</category>
      <category>forex</category>
    </item>
    <item>
      <title>Statistical Arbitrage &amp; Cointegration in LATAM Equities (BVC) with Python</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:33:23 +0000</pubDate>
      <link>https://dev.to/guetaquant/statistical-arbitrage-cointegration-in-latam-equities-bvc-with-python-3gj8</link>
      <guid>https://dev.to/guetaquant/statistical-arbitrage-cointegration-in-latam-equities-bvc-with-python-3gj8</guid>
      <description>&lt;p&gt;Two stocks can rise together for years and still be untradeable as a pair. Correlation measures co-movement; pairs trading needs &lt;strong&gt;cointegration&lt;/strong&gt; — a stationary, mean-reverting spread. This post builds the standard test pipeline in Python and shows where most LATAM pairs fail.&lt;/p&gt;

&lt;p&gt;Educational content: methodology, no signals, no return claims.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Correlation Lies, Cointegration Trades
&lt;/h2&gt;

&lt;p&gt;Correlated prices drift apart permanently (both trend up, spread widens forever). A cointegrated pair has a spread that reverts to a stable mean, which is what a long/short entry bets on. The Engle–Granger (1987) two-step procedure tests exactly this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Regress Y on X by OLS → hedge ratio β.&lt;/li&gt;
&lt;li&gt;Run an Augmented Dickey–Fuller (ADF) test on the residual spread. Only a &lt;strong&gt;stationary&lt;/strong&gt; spread (low ADF p-value) is tradeable.
&lt;/li&gt;
&lt;/ol&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;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;statsmodels.api&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statsmodels.tsa.stattools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;coint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adfuller&lt;/span&gt;

&lt;span class="c1"&gt;# y, x: aligned log-price series of the two candidate assets
&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pvalue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;coint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# Engle-Granger cointegration test
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EG p-value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pvalue&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# tradeable only if clearly &amp;lt; 0.05
&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;beta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                    &lt;span class="c1"&gt;# hedge ratio: short beta units of X per 1 of Y
&lt;/span&gt;&lt;span class="n"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;beta&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;adf_stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adf_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;adfuller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spread&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A p-value above conventional significance is not a "weak pair" — it is a &lt;strong&gt;rejection&lt;/strong&gt;. Discard it. Most random pairs fail; that is the expected outcome, not bad luck. (Our falsification-first protocol for backtests is documented in &lt;a href="https://coderlegion.com/26601/why-perfect-backtests-fail-walk-forward-optimization-and-deflated-sharpe-in-python" rel="noopener noreferrer"&gt;Why Perfect Backtests Fail&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Half-Life: How Fast Does It Revert?
&lt;/h2&gt;

&lt;p&gt;A stationary spread that reverts once a year is untradeable. Estimate the half-life with a simple AR(1) regression of spread changes on lagged spread:&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="n"&gt;d_spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;beta_hl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;polyfit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d_spread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;halflife&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;beta_hl&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Half-life: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;halflife&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; bars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Practical rule: half-life should sit comfortably between transaction-cost frequency (too fast = costs eat everything) and your holding horizon (too slow = capital sits idle). Both extremes fail — for opposite reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Entries on the Z-Score, Exits on Discipline
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# Enter when |z| &amp;gt; 2.0 (long the laggard, short the leader),
# exit when z crosses back through ~0.25 — never "wait for full reversion".
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hard stops still apply: cointegration &lt;strong&gt;breaks&lt;/strong&gt; (mergers, regime changes, delistings). A pair that held for three years can decouple in a week. Size every pair as if the spread can go to 3–4σ and stay there.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Why LATAM (BVC) Pairs Are Harder
&lt;/h2&gt;

&lt;p&gt;Applying this to Colombian equities (BVC) adds three frictions US textbook examples ignore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Liquidity:&lt;/strong&gt; wider spreads and thin books mean your backtest fill assumptions are fiction unless you model slippage explicitly. Test with volume-capped fills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costs:&lt;/strong&gt; commissions, exchange fees and taxes compound on a strategy that trades often. Recompute the half-life economics &lt;em&gt;after&lt;/em&gt; costs — many "profitable" spreads die here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short access:&lt;/strong&gt; pairs trading needs both legs. If you cannot reliably short one side, the strategy is long-only spread timing, a different (usually worse) trade. Verify borrow availability before any capital.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No specific pairs are recommended here — universes change, and any named pair would be stale on arrival. Run the pipeline above on current data instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Validation Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In-sample cointegration + out-of-sample spread stability (Walk-Forward, not one fit).&lt;/li&gt;
&lt;li&gt;Half-life compatible with costs and horizon.&lt;/li&gt;
&lt;li&gt;Break scenario sized and stop-defined before the first trade.&lt;/li&gt;
&lt;li&gt;60+ days paper trading the exact execution path.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Study material under Colombia SFC Decreto 2555 de 2010 — financial-engineering education, not investment advice. No signals, no managed accounts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Gueta Quant — research notes at &lt;a href="https://guetaquant.com/blog/" rel="noopener noreferrer"&gt;guetaquant.com/blog&lt;/a&gt;. Related: &lt;a href="https://guetaquant.com/pine-script-v6/" rel="noopener noreferrer"&gt;Pine Script v6 guide&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>python</category>
      <category>quant</category>
      <category>algorithmictrading</category>
      <category>statistics</category>
    </item>
    <item>
      <title>Building an Automated Broker Risk &amp; Tier-1 Regulatory Auditor in Python</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Mon, 05 Oct 2026 09:42:31 +0000</pubDate>
      <link>https://dev.to/guetaquant/building-an-automated-broker-risk-tier-1-regulatory-auditor-in-python-4cnb</link>
      <guid>https://dev.to/guetaquant/building-an-automated-broker-risk-tier-1-regulatory-auditor-in-python-4cnb</guid>
      <description>&lt;p&gt;When algorithmic traders design risk models, they rigorously calculate Kelly fractions, Value at Risk (VaR), and dynamic ATR trailing stops. Yet, one catastrophic risk is almost universally ignored in retail algorithm architecture: &lt;strong&gt;counterparty custody failure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your broker becomes insolvent, executes negative slippage with impunity, or freezes withdrawals during an extreme volatility event, mathematical edge is meaningless.&lt;/p&gt;

&lt;p&gt;In emerging markets across Latin America, Southeast Asia, and Africa, retail traders are especially vulnerable to &lt;strong&gt;Regulatory Arbitrage&lt;/strong&gt; and &lt;strong&gt;Entity Switching&lt;/strong&gt;: a global broker advertises its prestigious UK FCA or Australian ASIC license, but quietly routes local clients to an unregulated shell company in St. Vincent or Seychelles.&lt;/p&gt;

&lt;p&gt;This engineering guide explains the fiduciary mechanics of broker regulation and provides a complete, reusable Python engine to score broker counterparty risk programmatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Fiduciary Mechanics of Tier-1 vs. Offshore Regulation
&lt;/h2&gt;

&lt;p&gt;Financial regulators exist on a strict hierarchy of fiduciary protection, capital adequacy requirements, and legal enforceability:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Regulatory Tier&lt;/th&gt;
&lt;th&gt;Primary Jurisdictions&lt;/th&gt;
&lt;th&gt;Statutory Capital Requirement&lt;/th&gt;
&lt;th&gt;Retail Leverage Limits&lt;/th&gt;
&lt;th&gt;Client Money Segregation &amp;amp; Compensation Scheme&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tier-1 (Institutional)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UK (FCA), Australia (ASIC), USA (CFTC/NFA)&lt;/td&gt;
&lt;td&gt;$\ge \$1\text{M} - \$20\text{M}$&lt;/td&gt;
&lt;td&gt;Capped at 1:30 (ESMA/FCA) or 1:50 (NFA)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Mandatory trust segregation&lt;/strong&gt;. UK FSCS covers up to &lt;strong&gt;£85,000&lt;/strong&gt; per eligible claimant.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tier-2 (Moderate)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cyprus (CySEC), UAE (DFSA)&lt;/td&gt;
&lt;td&gt;$\ge \$750\text{k}$&lt;/td&gt;
&lt;td&gt;1:30 retail, higher professional&lt;/td&gt;
&lt;td&gt;Segregated accounts. CySEC ICF covers up to &lt;strong&gt;€20,000&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tier-3 / Offshore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seychelles (FSA), Bahamas (SCB), St. Vincent&lt;/td&gt;
&lt;td&gt;Minimal ($&amp;lt;\$50\text{k}$) or None&lt;/td&gt;
&lt;td&gt;Uncapped (1:500 to 1:2000)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No statutory compensation scheme&lt;/strong&gt;. Zero regulatory recourse for foreign residents.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Under Tier-1 regulations, client deposits are held in &lt;strong&gt;statutory trust accounts&lt;/strong&gt; segregated from the broker’s operational funds. If the broker defaults or enters liquidation, institutional creditors cannot seize client trading funds. Under offshore jurisdictions, commingling of funds is legal or virtually unmonitored.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Detecting the "Entity Switching" Pattern
&lt;/h2&gt;

&lt;p&gt;How do brokers pull off entity switching?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Top-Level Domain (TLD) Cloaking:&lt;/strong&gt; The main domain (&lt;code&gt;broker.com&lt;/code&gt;) displays FCA and ASIC license badges prominently in the header.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geotargeted Client Routing:&lt;/strong&gt; An automated IP lookup detects a visitor connecting from Colombia, Argentina, or Mexico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract Fine Print:&lt;/strong&gt; The sign-up form automatically selects the offshore subsidiary (e.g., &lt;code&gt;Broker Ltd (Seychelles)&lt;/code&gt; instead of &lt;code&gt;Broker UK Ltd&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waiver of Rights:&lt;/strong&gt; The trader inadvertently agrees to terms that strip all Tier-1 Ombudsman dispute resolution mechanisms and FSCS deposit insurance.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. The Python Broker Risk &amp;amp; Fiduciary Auditor
&lt;/h2&gt;

&lt;p&gt;The following Python script models an automated risk assessment pipeline. It parses contract metadata, evaluates leverage limits, verifies corporate identity match, and computes a &lt;strong&gt;Fiduciary Safety Index (0 to 100)&lt;/strong&gt;:&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Broker Counterparty Fiduciary Risk Auditor
Gueta Quant Open Research — AGPLv3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrokerEntity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;brand_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;contracted_legal_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;regulator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;license_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;max_offered_leverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;negative_balance_protection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;segregated_tier1_bank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;regulatory_tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;  &lt;span class="c1"&gt;# 1 = FCA/ASIC, 2 = CySEC/DFSA, 3 = Offshore/None
&lt;/span&gt;    &lt;span class="n"&gt;dispute_resolution_scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrokerAuditor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Regulatory weights for quantitative risk scoring
&lt;/span&gt;    &lt;span class="n"&gt;TIER_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&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="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;audit_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BrokerEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;critical_red_flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;positive_factors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="c1"&gt;# 1. Primary Regulatory Tier Check (Max 45 pts)
&lt;/span&gt;        &lt;span class="n"&gt;tier_pts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TIER_WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regulatory_tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;tier_pts&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regulatory_tier&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;positive_factors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tier-1 Oversight (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regulator&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) with statutory protection.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regulatory_tier&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;critical_red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Offshore jurisdiction (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regulator&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) — No statutory depositor safety net.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2. Segregated Trust Accounts (Max 25 pts)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segregated_tier1_bank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
            &lt;span class="n"&gt;positive_factors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Client capital segregated in Tier-1 custodian bank.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;critical_red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;High commingling risk: lack of verified Tier-1 custodian segregation.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 3. Negative Balance Protection (Max 15 pts)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;negative_balance_protection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
            &lt;span class="n"&gt;positive_factors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Guaranteed negative balance protection.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;critical_red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No negative balance guarantee — account can owe debt after market gaps.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 4. Leverage Sanity Check (Max 15 pts)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_offered_leverage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
            &lt;span class="n"&gt;positive_factors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Institutional retail leverage cap (1:30 ESMA/FCA standard).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_offered_leverage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Extreme leverage (1:500+) strongly indicates B-book / offshore dealing desk
&lt;/span&gt;            &lt;span class="n"&gt;critical_red_flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Excessive leverage (1:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_offered_leverage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) indicates dealing desk insolvency risk.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Determine Classification
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grade A: Institutional / Highly Safe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grade B: Acceptable with Prudent Position Sizing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grade C: High Counterparty Risk / Unregulated&lt;/span&gt;&lt;span class="sh"&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;Brand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;brand_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Contracting Entity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contracted_legal_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fiduciary Safety Score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/100&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;Rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Positive Factors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;positive_factors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Critical Red Flags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;critical_red_flags&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Test Entity 1: Tier-1 Verified Provider
&lt;/span&gt;    &lt;span class="n"&gt;tier1_broker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BrokerEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;brand_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global FX UK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;contracted_legal_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global FX Financial Services Ltd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;regulator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FCA&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;license_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_offered_leverage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;negative_balance_protection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;segregated_tier1_bank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;regulatory_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;dispute_resolution_scheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Test Entity 2: Offshore Subsidiary (The Common Retail Trap)
&lt;/span&gt;    &lt;span class="n"&gt;offshore_broker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BrokerEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;brand_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global FX (Offshore Branch)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;contracted_legal_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global FX Markets Ltd (Seychelles)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;regulator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FSA Seychelles&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;license_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SD-099&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_offered_leverage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;negative_balance_protection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;segregated_tier1_bank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;regulatory_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;dispute_resolution_scheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=== TIER-1 AUDIT ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BrokerAuditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;audit_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tier1_broker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;=== OFFSHORE AUDIT ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BrokerAuditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;audit_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offshore_broker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. The Colombian Benchmark: SFC Decreto 2555 de 2010
&lt;/h2&gt;

&lt;p&gt;In Colombia, the legal framework provides a clear boundary:&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;Decreto 2555 de 2010 (Parte 4)&lt;/strong&gt; and &lt;strong&gt;SFC Concepto 2015112607-002&lt;/strong&gt;, foreign institutions offering financial services or derivatives must establish an official representative office (&lt;em&gt;oficina de representación&lt;/em&gt;) or execute a formal correspondent contract (&lt;em&gt;contrato de corresponsalía&lt;/em&gt;) with an authorized local broker (&lt;em&gt;Sociedad Comisionista de Bolsa&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Furthermore, the &lt;strong&gt;Superintendencia Financiera de Colombia (SFC)&lt;/strong&gt; explicitly declared on September 3, 2021, that &lt;strong&gt;no foreign CFD/Forex platform holds direct local authorization to operate or promote financial markets within Colombia&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For Colombian and Latin American traders operating under the free convertibility regime (Banco de la República Resolución Externa 1 de 2018), counterparty risk is borne entirely by the individual. Therefore, verifying that your foreign provider is subject to enforceable Tier-1 supervision (FCA or ASIC) is not an option—it is the foundational prerequisite of solvency.&lt;/p&gt;

&lt;p&gt;To review the complete regulatory inventory, audited licenses, and the official SFC warning checklist:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://guetaquant.com/brokers-regulados-colombia/?utm_source=coderlegion&amp;amp;utm_medium=referral&amp;amp;utm_campaign=broker_regulation_audit" rel="noopener noreferrer"&gt;Guía y Lista Maestra: Brokers Regulados y Autorizados en Colombia (SFC &amp;amp; Tier-1)&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The 4-Step Verification Protocol
&lt;/h2&gt;

&lt;p&gt;Before funding any live account:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inspect Footer Terms:&lt;/strong&gt; Never rely on the homepage marketing banner. Scroll to the footer of the legal agreement and extract the exact company name signing your contract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search the Official Register:&lt;/strong&gt; Navigate directly to &lt;code&gt;register.fca.org.uk&lt;/code&gt; or &lt;code&gt;asic.gov.au&lt;/code&gt; and check that the company name and approved domains match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Check SFC Warnings:&lt;/strong&gt; Ensure the broker does not appear on the SFC Colombia &lt;em&gt;Lista de Firmas No Autorizadas&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Withdrawal Channels:&lt;/strong&gt; Execute a small deposit and immediate withdrawal test via bank wire or regulated payment rails before allocating meaningful algorithmic capital.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Educational research paper strictly compliant with SFC Colombia Decreto 2555 de 2010. No investment advice, no signals, no managed accounts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Founder &amp;amp; Product Builder at Gueta Quant. Open-source tools available at &lt;a href="https://guetaquant.com" rel="noopener noreferrer"&gt;guetaquant.com&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>python</category>
      <category>fintech</category>
      <category>quant</category>
      <category>algorithmictrading</category>
    </item>
    <item>
      <title>Auditing Broker Execution Latency, FIX Protocol &amp; Asymmetric Slippage in Algorithmic Trading</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Mon, 05 Oct 2026 09:41:52 +0000</pubDate>
      <link>https://dev.to/guetaquant/auditing-broker-execution-latency-fix-protocol-asymmetric-slippage-in-algorithmic-trading-1j7n</link>
      <guid>https://dev.to/guetaquant/auditing-broker-execution-latency-fix-protocol-asymmetric-slippage-in-algorithmic-trading-1j7n</guid>
      <description>&lt;p&gt;Most quantitative trading models fail when transitioned from historical backtest to live execution not because the mathematical alpha was flawed, but because the backtesting engine assumed frictionless, zero-latency execution.&lt;/p&gt;

&lt;p&gt;In a simulation, your order fills instantly at the exact millisecond bar close. In live market routing, every order traverses network topologies, broker matching engines, liquidity provider aggregation pools, and clearing gateways. During that round-trip window (50ms to 400ms), asset prices move. &lt;/p&gt;

&lt;p&gt;When that movement is structurally skewed against you, your edge evaporates to &lt;strong&gt;asymmetric slippage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This engineering paper details how to model, record, and audit broker execution quality programmatically, measure round-trip time (RTT), and verify whether your counterparty operates under enforceable regulatory execution standards.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Zero-Latency Fallacy in Retail Backtests
&lt;/h2&gt;

&lt;p&gt;Retail backtesting frameworks (such as standard vectorbt, TradingView Pine Script, or naive MT5 tick simulations) make three fatal assumptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Infinitely Deep Top-of-Book:&lt;/strong&gt; The entire order volume fills at the posted Best Bid / Best Offer without price impact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Fill Price:&lt;/strong&gt; &lt;code&gt;Fill Price = Order Price&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symmetric Slippage Distribution:&lt;/strong&gt; If slippage occurs, price variance is assumed to be a Gaussian normal distribution centered at zero ($\mu = 0$).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In real-world retail CFD and FX execution, slippage is &lt;strong&gt;asymmetric&lt;/strong&gt;. Market makers and B-book brokers frequently route trades where favorable price movement (positive slippage) during the execution lag is swallowed by the dealer or requoted, while unfavorable price movement (negative slippage) is passed entirely to the client account.&lt;/p&gt;

&lt;p&gt;Even a modest execution drag of 0.3 pips per side destroys high-frequency and intraday momentum strategies where the expected payoff per trade is only 1.5 to 2.5 pips.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Anatomy of FIX Protocol 4.4 Execution Lag
&lt;/h2&gt;

&lt;p&gt;For algorithmic traders connecting via FIX (Financial Information eXchange) Protocol 4.4 or broker REST/WebSocket APIs, the execution lifecycle consists of discrete network and processing hops:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Quant Server]                 [Broker Gateway]              [Liquidity Provider]
      |                                |                               |
   T0 |-- NewOrderSingle (35=D) ------&amp;gt;|                               |
      |                                |-- Order Routing (A/B-Book) --&amp;gt;|
      |                                |                               |-- Fill Match
      |                                |&amp;lt;-- ExecutionReport (35=8) ----|
   T1 |&amp;lt;-- ExecutionReport (35=8) -----|                               |
      |    (ExecType=0 New/Ack)        |                               |
      |                                |                               |
   T2 |&amp;lt;-- ExecutionReport (35=8) -----|                               |
      |    (ExecType=F Filled)         |                               |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical metric is the &lt;strong&gt;Tick-to-Fill Latency&lt;/strong&gt; ($\Delta T_{fill} = T2 - T0$), composed of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network Ingress / Egress:&lt;/strong&gt; Distance between client VPS and broker server (e.g., Equinix LD4 London or NY4 New York).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Queue Delay:&lt;/strong&gt; The broker's internal risk check (pre-trade margin validation and book routing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LP Fill &amp;amp; Acknowledgment:&lt;/strong&gt; Market execution by external Tier-1 liquidity providers or internal matching engine.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Detecting Asymmetric Slippage: The Python Audit Engine
&lt;/h2&gt;

&lt;p&gt;To audit your broker objectively, log the target signal price ($P_{target}$), the requested order price ($P_{order}$), the actual executed price ($P_{fill}$), and the round-trip latency ($\Delta T$) on every single order.&lt;/p&gt;

&lt;p&gt;Here is a standalone Python analytics engine to compute the &lt;strong&gt;Execution Drag Index (EDI)&lt;/strong&gt; and test for statistical asymmetry using the Wilcoxon signed-rank test:&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Broker Execution Quality &amp;amp; Asymmetric Slippage Auditor
Gueta Quant Open Research — AGPLv3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;scipy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stats&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;audit_broker_execution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trades_df&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pip_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Analyzes execution records for asymmetric slippage and latency drag.

    Expected DataFrame columns:
    - order_type: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BUY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SELL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
    - target_price: float (price when signal triggered)
    - fill_price: float (actual executed price from broker)
    - rtt_ms: float (round-trip execution time in milliseconds)
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trades_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Calculate slippage in pips
&lt;/span&gt;    &lt;span class="c1"&gt;# For BUY: Fill &amp;gt; Target is negative slippage (worse price)
&lt;/span&gt;    &lt;span class="c1"&gt;# For SELL: Fill &amp;lt; Target is negative slippage (worse price)
&lt;/span&gt;    &lt;span class="n"&gt;is_buy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;order_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BUY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;is_buy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target_price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fill_price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Positive if filled better, negative if worse
&lt;/span&gt;        &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fill_price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target_price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pip_size&lt;/span&gt;

    &lt;span class="c1"&gt;# Segment positive vs negative slippage
&lt;/span&gt;    &lt;span class="n"&gt;positive_slip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;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;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;negative_slip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;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;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;zero_slip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;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;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;total_trades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;neg_slip_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;negative_slip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;pos_slip_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positive_slip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;mean_slippage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;median_slippage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Asymmetry ratio: Negative volume / Positive volume
&lt;/span&gt;    &lt;span class="n"&gt;total_neg_pips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;negative_slip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;total_pos_pips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positive_slip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;asymmetry_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_neg_pips&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_pos_pips&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1e-9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Statistical Hypothesis Testing: H0: Slippage distribution is symmetric around 0
&lt;/span&gt;    &lt;span class="c1"&gt;# Wilcoxon signed-rank test
&lt;/span&gt;    &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wilcoxon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slippage_pips&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="nf"&gt;else &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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="c1"&gt;# Execution Drag Index (EDI): Average pip drag per 100ms latency
&lt;/span&gt;    &lt;span class="n"&gt;mean_rtt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rtt_ms&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;edi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean_slippage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean_rtt&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mean_rtt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&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;Total Trades Audited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mean Round-Trip Latency (ms)&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;mean_rtt&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;Negative Slippage Frequency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;neg_slip_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&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;Positive Slippage Frequency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pos_slip_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&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;Zero Slippage Frequency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zero_slip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_trades&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&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;Mean Net Slippage (pips)&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;mean_slippage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Median Slippage (pips)&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;median_slippage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Asymmetry Ratio (Loss/Gain)&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;asymmetry_ratio&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;P-Value (Asymmetry Significance)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p_value&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&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;Is Systematically Skewed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p_value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;mean_slippage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;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;Execution Drag Index (pips/100ms)&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;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Simulated sample of 200 trades from a questionable dealer:
&lt;/span&gt;    &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;
    &lt;span class="c1"&gt;# Skewed execution: 65% suffer adverse slippage, only 15% get positive
&lt;/span&gt;    &lt;span class="n"&gt;slips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concatenate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exponential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.65&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# adverse
&lt;/span&gt;        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exponential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;      &lt;span class="c1"&gt;# positive
&lt;/span&gt;        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;                                     &lt;span class="c1"&gt;# zero slip
&lt;/span&gt;    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;rtts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slips&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;mock_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUY&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;SELL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slips&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fill_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0850&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slips&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtt_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rtts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;audit_broker_execution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mock_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the p-value is below $0.05$ and the &lt;strong&gt;Asymmetry Ratio exceeds 2.0x&lt;/strong&gt;, your broker is not providing symmetric market execution. You are absorbing the costs of a dealing desk.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Regulatory Layer: Offshore Subsidiarity vs. Tier-1 Mandates
&lt;/h2&gt;

&lt;p&gt;Why does this happen predominantly in retail emerging markets (Latin America, Southeast Asia)?&lt;/p&gt;

&lt;p&gt;Brokers operating under Tier-1 regimes (such as the UK &lt;strong&gt;FCA&lt;/strong&gt; or Australian &lt;strong&gt;ASIC&lt;/strong&gt;) are legally bound by &lt;strong&gt;Best Execution&lt;/strong&gt; mandates (formerly RTS 27/28 in MiFID II). Under these frameworks, brokers must publish quarterly execution quality metrics and demonstrate that positive slippage is passed to retail clients in full.&lt;/p&gt;

&lt;p&gt;However, retail brokers frequently employ &lt;strong&gt;Entity Switching&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They market the reputation of their UK FCA or Australian ASIC license.&lt;/li&gt;
&lt;li&gt;When an algorithmic trader or resident from Colombia, Mexico, or Chile registers, they are onboarded under a subsidiary domiciled in the Bahamas, Seychelles, or St. Vincent.&lt;/li&gt;
&lt;li&gt;Under these offshore subsidiaries, statutory protections (such as the UK FSCS £85,000 compensation fund) and Best Execution auditing are legally null and void.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Colombia, the &lt;strong&gt;Superintendencia Financiera de Colombia (SFC)&lt;/strong&gt; explicitly notes under Decreto 2555 de 2010 that foreign CFD brokers possess no banking license within Colombian territory, and counterparty risks are assumed 100% by the investor.&lt;/p&gt;

&lt;p&gt;To verify whether your broker operates with genuine Tier-1 regulatory backing or an offshore pass-through entity, refer to our comprehensive independent audit:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://guetaquant.com/brokers-regulados-colombia/?utm_source=coderlegion&amp;amp;utm_medium=referral&amp;amp;utm_campaign=broker_regulation_audit" rel="noopener noreferrer"&gt;Brokers Regulados y Autorizados en Colombia: Auditoría Legal y de Ejecución&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Pre-Deployment Execution Checklist
&lt;/h2&gt;

&lt;p&gt;Before deploying real capital to an algorithmic strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Audit Contract Multipliers:&lt;/strong&gt; Confirm &lt;code&gt;SYMBOL_TRADE_CONTRACT_SIZE&lt;/code&gt; and &lt;code&gt;SYMBOL_TRADE_TICK_VALUE&lt;/code&gt; in MT5 or cTrader to avoid position-sizing explosions on non-USD quote pairs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure Tick Latency to Matching Engine:&lt;/strong&gt; Ensure VPS latency to the broker's real trading server is $&amp;lt;5\text{ms}$.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log Fill Discrepancies:&lt;/strong&gt; Record every fill price against local quote prices during news releases (CPI, NFP) to compute the Execution Drag Index.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect Regulatory Jurisdiction:&lt;/strong&gt; Always demand proof of account segregation and check the registration number directly on the regulator's portal (&lt;code&gt;register.fca.org.uk&lt;/code&gt; or &lt;code&gt;asic.gov.au&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Educational research paper strictly compliant with SFC Colombia Decreto 2555 de 2010. No investment advice, no signals, no managed accounts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Founder &amp;amp; Product Builder at Gueta Quant. Explore open-source quantitative toolkits at &lt;a href="https://guetaquant.com" rel="noopener noreferrer"&gt;guetaquant.com&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>algorithmictrading</category>
      <category>quant</category>
      <category>python</category>
      <category>trading</category>
    </item>
    <item>
      <title>Monte Carlo Permutation Testing in Python: How Random Trade Order Falsifies Your Equity Curve</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Mon, 28 Sep 2026 06:18:04 +0000</pubDate>
      <link>https://dev.to/guetaquant/monte-carlo-permutation-testing-in-python-how-random-trade-order-falsifies-your-equity-curve-fh5</link>
      <guid>https://dev.to/guetaquant/monte-carlo-permutation-testing-in-python-how-random-trade-order-falsifies-your-equity-curve-fh5</guid>
      <description>&lt;p&gt;Your backtest equity curve is merely &lt;strong&gt;one historical trajectory out of millions of equally probable alternatives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The total profit of your trading system is invariant to order: 100 closed trades will yield the exact same ending dollar return whether the winning trades arrive first or last. However, &lt;strong&gt;path-dependent survivability metrics&lt;/strong&gt;—Maximum Drawdown, Ulcer Index, Margin Call Probability, and Time-to-Recovery—are dominated by trade sequence.&lt;/p&gt;

&lt;p&gt;If a cluster of 6 normal consecutive losses strikes at trade #1 instead of trade #70, an account operating under a strict 10% risk floor (common in institutional mandates and proprietary evaluation rules) is liquidated before the positive edge ever materializes.&lt;/p&gt;

&lt;p&gt;In this article, we formulate and implement a &lt;strong&gt;vectorized Monte Carlo permutation engine in Python&lt;/strong&gt; to rigorously falsify equity curves before committing live capital.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Permutation vs. Bootstrap: The Critical Distinction
&lt;/h2&gt;

&lt;p&gt;Many trading platforms market "Monte Carlo analysis" without disclosing their resampling methodology. In quantitative finance, the distinction is fundamental:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Permutation Testing (Without Replacement)&lt;/th&gt;
&lt;th&gt;Bootstrap Resampling (With Replacement)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mechanism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Random shuffle of historical trade order&lt;/td&gt;
&lt;td&gt;Random draw where any trade can be selected $k$ times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P&amp;amp;L Distribution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;100% Identical&lt;/strong&gt; to sample (same mean, win rate, skewness)&lt;/td&gt;
&lt;td&gt;Creates synthetic distributions with altered win rates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Statistical Target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolates &lt;strong&gt;sequence risk&lt;/strong&gt; alone&lt;/td&gt;
&lt;td&gt;Estimates sampling error under $i.i.d.$ assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vulnerability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Assumes trades are conditionally independent&lt;/td&gt;
&lt;td&gt;Heavily distorts tail risk if outliers are oversampled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For validating an existing trading journal or strategy backtest, &lt;strong&gt;Permutation Testing is the strict falsification baseline&lt;/strong&gt;. It asks the minimal, humble question: &lt;em&gt;"Given the exact trades we actually took, what percentage of alternate timelines would have breached our risk budget?"&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The 4 Path Metrics That Expose Hidden Ruin
&lt;/h2&gt;

&lt;p&gt;Looking solely at backtest Sharpe ratio or nominal net profit hides ruin. When running $N=5,000$ permutations, evaluate these four metrics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Probability of Ruin ($P_{\text{ruin}}$):&lt;/strong&gt; The percentage of shuffled paths whose equity breaches the hard drawdown barrier (e.g., $9,000$ on a $\$10,000$ starting balance) at any point along the horizon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Median Max Drawdown ($MDD_{50}$):&lt;/strong&gt; The central tendency of drawdown. If your backtest showed a 7% drawdown but the median shuffled drawdown is 16%, your historical curve was an unusually lucky sequence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;95th Percentile Max Drawdown ($MDD_{95}$):&lt;/strong&gt; The stress-test boundary. 95% of simulated timelines experienced a drawdown less severe than this number; 5% suffered worse. This is your true operational capital requirement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawdown Dispersion Ratio:&lt;/strong&gt; $MDD_{95} / MDD_{50}$. A high ratio indicates severe tail-sequence vulnerability.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Vectorized Python Implementation (NumPy)
&lt;/h2&gt;

&lt;p&gt;Iterating across 5,000 simulations using Python loops is computationally inefficient. Below is a high-performance, fully vectorized implementation using &lt;code&gt;numpy.random.default_rng().permuted&lt;/code&gt;:&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;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_monte_carlo_permutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;trades&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;initial_capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ruin_capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;9000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Vectorized Monte Carlo Permutation Test (Resampling Without Replacement).
    Evaluates sequence risk and ruin probability on trade P&amp;amp;L arrays.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;trades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;n_trades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trades&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n_trades&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;At least 10 trades required for meaningful permutation testing.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rng&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_rng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Broadcast and independently shuffle across simulations (without replacement)
&lt;/span&gt;    &lt;span class="n"&gt;sim_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;shuffled_trades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permuted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sim_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Vectorized cumulative equity trajectories
&lt;/span&gt;    &lt;span class="n"&gt;cumulative_pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cumsum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shuffled_trades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initial_col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;initial_capital&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;equity_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hstack&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;initial_col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_capital&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cumulative_pnl&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Peak equity and path drawdowns
&lt;/span&gt;    &lt;span class="n"&gt;running_peaks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accumulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;equity_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;drawdowns_dollar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;running_peaks&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;equity_paths&lt;/span&gt;
    &lt;span class="n"&gt;drawdowns_pct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;drawdowns_dollar&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;running_peaks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Max drawdown per trajectory
&lt;/span&gt;    &lt;span class="n"&gt;max_mdd_pct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;drawdowns_pct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. Ruin evaluation (breaching floor at any point in time)
&lt;/span&gt;    &lt;span class="n"&gt;min_equity_per_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&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;equity_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ruin_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_equity_per_path&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ruin_capital&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prob_ruin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruin_paths&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;100.0&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;n_trades&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n_trades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;initial_capital&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;initial_capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruin_capital&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ruin_capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nominal_net_pnl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trades&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;num_simulations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prob_ruin_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&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;prob_ruin&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;mdd_p05_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;percentile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_mdd_pct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;mdd_p50_median_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;percentile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_mdd_pct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&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;mdd_p95_worst_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;percentile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_mdd_pct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;95&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;falsification_verdict&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;REJECT_EXCESSIVE_RUIN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prob_ruin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PASS_ROBUST_SEQUENCE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Empirical Case Study: The "Profitable" Strategy That Blows Up
&lt;/h2&gt;

&lt;p&gt;Consider a 100-trade sample with a &lt;strong&gt;52% win rate&lt;/strong&gt; and positive net expectation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;52 winning trades (mean profit ~\$170)&lt;/li&gt;
&lt;li&gt;48 losing trades (mean loss ~-\$170, with occasional -\$350 tail losses)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nominal Net P&amp;amp;L:&lt;/strong&gt; &lt;code&gt;+$505.39&lt;/code&gt; on a &lt;code&gt;\$10,000&lt;/code&gt; account (profitable on paper).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we execute &lt;code&gt;run_monte_carlo_permutation&lt;/code&gt; over 5,000 shuffles:&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="c1"&gt;# Empirical verification run
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_monte_carlo_permutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;trades&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;trades_sample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;initial_capital&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ruin_capital&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;9000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 10% maximum drawdown ceiling
&lt;/span&gt;    &lt;span class="n"&gt;num_simulations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exact Output:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"n_trades"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"initial_capital"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ruin_capital"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nominal_net_pnl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;505.39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"num_simulations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prob_ruin_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;42.64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mdd_p05_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;11.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mdd_p50_median_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;16.77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mdd_p95_worst_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;25.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"falsification_verdict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REJECT_EXCESSIVE_RUIN"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Institutional Reality:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Even though the original single backtest ended with &lt;strong&gt;+$505.39 net profit&lt;/strong&gt;, &lt;strong&gt;42.64% of all possible alternate histories breached the 10% drawdown barrier&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In 95% of histories, the drawdown reached up to &lt;strong&gt;25.50%&lt;/strong&gt;—more than double the allowable risk budget.&lt;/li&gt;
&lt;li&gt;Without Monte Carlo permutation, a developer deploying this system would falsely attribute failure to "market regime change" or "bad luck", when in reality the strategy was statistically insolvent against basic sequence risk from day one.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Methodological Boundaries (What Monte Carlo Cannot Do)
&lt;/h2&gt;

&lt;p&gt;A rigorous quant must understand the falsification limits of permutation testing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Serial Autocorrelation Breakdown:&lt;/strong&gt; Permutation randomly destroys the temporal ordering of trades. If your strategy has positive autocorrelation in losses (e.g., clustered losses during high-volatility macro announcements), permutation may underestimate clustering severity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-Distribution Shocks:&lt;/strong&gt; Shuffling only explores combinations of &lt;em&gt;events that already occurred&lt;/em&gt;. It cannot simulate a 5-sigma liquidity flash crash if none was present in your historical log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Journal vs. Market:&lt;/strong&gt; Monte Carlo evaluates the statistical fragility of the &lt;em&gt;trade sequence&lt;/em&gt;, not the underlying market microstructure.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. Open Source Implementation &amp;amp; References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scientific DOI:&lt;/strong&gt; Reproducible quant code registered under CERN Zenodo: &lt;a href="https://doi.org/10.5281/zenodo.22012203" rel="noopener noreferrer"&gt;&lt;code&gt;10.5281/zenodo.22012203&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/guetaquant-byte/guetaquant-tools" rel="noopener noreferrer"&gt;&lt;code&gt;guetaquant-byte/guetaquant-tools&lt;/code&gt;&lt;/a&gt; (AGPLv3).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Tool:&lt;/strong&gt; Browser-based Monte Carlo permutation is integrated into the client-side &lt;a href="https://guetaquant.com/journal/" rel="noopener noreferrer"&gt;Local-First Trading Journal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-Depth Study:&lt;/strong&gt; Full mathematical derivation and percentile bands at &lt;a href="https://guetaquant.com/blog/monte-carlo-trading/" rel="noopener noreferrer"&gt;Gueta Quant Monte Carlo Analysis&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Aviso Regulatorio (SFC Colombia — Decreto 2555 de 2010): Este artículo tiene un propósito 100% pedagógico, educativo y de investigación en ingeniería de software financiero. Gueta Quant no presta asesoría financiera ni emite señales de inversión.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Founder of Gueta Quant.*&lt;/p&gt;

</description>
      <category>python</category>
      <category>quant</category>
      <category>algorithmictrading</category>
      <category>datascience</category>
    </item>
    <item>
      <title>cTrader cBot Risk Engine: High-Precision C# Dynamic Stop-Loss Architecture</title>
      <dc:creator>Gueta Quant </dc:creator>
      <pubDate>Mon, 21 Sep 2026 08:36:17 +0000</pubDate>
      <link>https://dev.to/guetaquant/ctrader-cbot-risk-engine-high-precision-c-dynamic-stop-loss-architecture-3kpc</link>
      <guid>https://dev.to/guetaquant/ctrader-cbot-risk-engine-high-precision-c-dynamic-stop-loss-architecture-3kpc</guid>
      <description>&lt;p&gt;Static stop-losses break across volatility regimes. A fixed 20-pip stop that is conservative on EUR/USD during Asia session is noise-level on XAU/USD during New York open. In cTrader Automate (C#), the robust pattern is a dedicated risk engine: signal logic decides direction, the engine decides size and stop distance from live volatility.&lt;/p&gt;

&lt;p&gt;This post documents the architecture — educational, no trade signals, no return claims.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Separate Sizing From Signals
&lt;/h2&gt;

&lt;p&gt;The most common cBot flaw is inline risk math inside &lt;code&gt;OnBar()&lt;/code&gt;: volume computed next to entry conditions, stop distance hardcoded. When volatility doubles, the same stop gets hunted and the same volume carries twice the dollar risk.&lt;/p&gt;

&lt;p&gt;Split the cBot into two units:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signal module&lt;/strong&gt; — produces direction only (e.g., breakout, trend filter).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk engine&lt;/strong&gt; — given direction, computes stop distance from ATR and volume from a fixed monetary budget.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// RiskEngine.cs — pure logic, no cTrader dependencies (unit-testable)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RiskEngine&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;StopDistancePrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;VolumeInUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;riskMoney&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;stopDistancePrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;tickValuePerUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;pipSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;volumeMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;volumeMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;volumeStep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;clampedToMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;effectiveRisk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;riskMoney&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopDistancePrice&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pipSize&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tickValuePerUnit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;floored&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&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;raw&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;volumeStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;volumeStep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;clampedToMin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;floored&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;volumeMin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;floored&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;volumeMin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;clampedToMin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;finalVolume&lt;/span&gt; &lt;span class="p"&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;Min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;floored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;volumeMax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;effectiveRisk&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;finalVolume&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopDistancePrice&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pipSize&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tickValuePerUnit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;finalVolume&lt;/span&gt;&lt;span class="p"&gt;;&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;Note the &lt;code&gt;clampedToMin&lt;/code&gt; flag: when the budgeted volume falls below the broker minimum, the engine clamps up &lt;strong&gt;and reports the effective risk&lt;/strong&gt;, which now exceeds the budget. Silently reporting the original budget while carrying higher exposure is the exact failure we dissected in &lt;a href="https://coderlegion.com/27300/the-silent-position-sizer-bug-when-accounts-are-small-your-risk-inadvertently-doubles" rel="noopener noreferrer"&gt;The Silent Position Sizer Bug&lt;/a&gt; — never repeat it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. ATR-Based Dynamic Stops
&lt;/h2&gt;

&lt;p&gt;Average True Range adapts the stop to current volatility. A 1.5x–2.0x ATR stop keeps the exit outside normal noise on any symbol and any session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;GetAtrStopPips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;atrPeriod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Indicators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AverageTrueRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;atrPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MovingAverageType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exponential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;stopPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastValue&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stopPrice&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipSize&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;Because the stop distance is measured, not assumed, the same cBot behaves sanely on a 0.0001-pip Forex pair and a 2-decimal metal without retuning magic numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Wiring It Into the cBot
&lt;/h2&gt;

&lt;p&gt;Volume in cTrader is expressed in units (100,000 units = 1.0 standard lot on FX). Always read the broker limits from the symbol — never hardcode them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Positions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&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="c1"&gt;// single-position example&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="nf"&gt;GetSignal&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="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;stopPips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetAtrStopPips&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;stopPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stopPips&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RiskEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;VolumeInUnits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;RiskMoney&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TickValue&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TickSize&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VolumeInUnitsMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VolumeInUnitsMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VolumeInUnitsStep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;clamped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;effectiveRisk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clamped&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"WARNING: volume clamped to broker minimum. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
              &lt;span class="s"&gt;"Effective risk {0} exceeds budget {1}."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;effectiveRisk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RiskMoney&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;ExecuteMarketOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TradeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SymbolName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="s"&gt;"atr-risk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopPips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&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;h2&gt;
  
  
  4. Trailing Without Chasing
&lt;/h2&gt;

&lt;p&gt;Move the stop only when price has banked a multiple of the ATR distance — ratcheting on every tick bleeds to spread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TrailAtr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;atrDistancePrice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;newStop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bid&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;atrDistancePrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// long example&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newStop&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StopLoss&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;ModifyPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newStop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TakeProfit&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;h2&gt;
  
  
  5. Validation Checklist (Demo First)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run 60 days on demo across at least two volatility regimes (e.g., Forex + metal).&lt;/li&gt;
&lt;li&gt;Log every clamp event; if clamps exceed ~5% of trades, the risk budget is too small for the account — top up or widen the stop, never silence the warning.&lt;/li&gt;
&lt;li&gt;Backtest with real-tick data; reject any result you cannot reproduce forward on demo.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Educational content under Colombia SFC Decreto 2555 de 2010: this is financial-engineering study material, not investment advice. No signals, no managed accounts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By **Mahdi Goodarzi&lt;/em&gt;* (&lt;a href="https://g.dev/mahdigoodarzi" rel="noopener noreferrer"&gt;g.dev/mahdigoodarzi&lt;/a&gt;), Gueta Quant — interactive risk tools at &lt;a href="https://guetaquant.com" rel="noopener noreferrer"&gt;guetaquant.com&lt;/a&gt;. Companion guide: &lt;a href="https://guetaquant.com/ctrader-copy-trading/" rel="noopener noreferrer"&gt;cTrader Copy setup in Colombia&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>ctrader</category>
      <category>algorithmictrading</category>
      <category>quant</category>
    </item>
    <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>
