<?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: aymeric leon</title>
    <description>The latest articles on DEV Community by aymeric leon (@aymeric_leon_5057b9072e0f).</description>
    <link>https://dev.to/aymeric_leon_5057b9072e0f</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%2F4069886%2F4dbd4751-0fd1-4c93-a8ed-6681ffdd268c.png</url>
      <title>DEV Community: aymeric leon</title>
      <link>https://dev.to/aymeric_leon_5057b9072e0f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aymeric_leon_5057b9072e0f"/>
    <language>en</language>
    <item>
      <title>Votre backtest bat-il vraiment le hasard ? Le test de permutation, en Python</title>
      <dc:creator>aymeric leon</dc:creator>
      <pubDate>Mon, 17 Aug 2026 09:34:31 +0000</pubDate>
      <link>https://dev.to/aymeric_leon_5057b9072e0f/votre-backtest-bat-il-vraiment-le-hasard-le-test-de-permutation-en-python-275l</link>
      <guid>https://dev.to/aymeric_leon_5057b9072e0f/votre-backtest-bat-il-vraiment-le-hasard-le-test-de-permutation-en-python-275l</guid>
      <description>&lt;p&gt;Un backtest qui rend +40 % sur six ans ne prouve rien. Le marché lui-même a&lt;br&gt;
peut-être fait +200 % sur la période. La seule question qui compte est de savoir&lt;br&gt;
si votre règle fait mieux qu'un tirage au sort soumis aux &lt;strong&gt;mêmes contraintes&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Le témoin doit avoir la même densité
&lt;/h2&gt;

&lt;p&gt;L'erreur classique est de comparer sa stratégie à « acheter et conserver ». Ce&lt;br&gt;
n'est pas un témoin valable : elle n'a ni le même nombre de positions, ni les&lt;br&gt;
mêmes durées, ni la même exposition.&lt;/p&gt;

&lt;p&gt;Le bon témoin tire ses entrées &lt;strong&gt;au hasard&lt;/strong&gt;, mais reproduit exactement le reste :&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;temoin_aleatoire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dates_possibles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_signaux&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jours_detention&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;entrees&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;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dates_possibles&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="n"&gt;n_signaux&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replace&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;jours_detention&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;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entrees&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On répète ce tirage 1 000 fois, on calcule l'espérance de chaque tirage, et on&lt;br&gt;
regarde où tombe la stratégie réelle dans cette distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lire le résultat
&lt;/h2&gt;

&lt;p&gt;La p-valeur est la proportion de tirages aléatoires qui font aussi bien ou mieux&lt;br&gt;
que la stratégie. Si 3 tirages sur 1 000 la battent, p = 0,003.&lt;/p&gt;

&lt;p&gt;Sur mes deux moteurs directionnels retenus, la barre était fixée &lt;strong&gt;avant&lt;/strong&gt; de&lt;br&gt;
regarder : au moins 60 signaux, espérance positive, p &amp;lt; 0,05, et au moins&lt;br&gt;
4 années positives. Un moteur qui échoue à un seul de ces critères est écarté,&lt;br&gt;
même s'il « a l'air » bon.&lt;/p&gt;

&lt;p&gt;Fixer la barre avant est ce qui distingue une mesure d'une justification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le piège qui reste
&lt;/h2&gt;

&lt;p&gt;Un test de permutation ne protège pas du surapprentissage. Si vous avez essayé&lt;br&gt;
200 variantes de paramètres et gardé la meilleure, votre p-valeur est fausse :&lt;br&gt;
avec 200 essais, obtenir p &amp;lt; 0,05 par pur hasard est presque certain.&lt;/p&gt;

&lt;p&gt;La parade est la validation &lt;em&gt;walk-forward&lt;/em&gt; : on optimise sur une fenêtre, on&lt;br&gt;
teste sur la suivante, jamais vue, et on avance. Ce qui survit à ça a une chance&lt;br&gt;
d'exister en dehors du tableur.&lt;/p&gt;

&lt;p&gt;Le filtre le plus rentable de mon système n'est d'ailleurs pas une règle&lt;br&gt;
d'entrée : c'est une règle d'abstention. Il coupe les moteurs directionnels&lt;br&gt;
42 % du temps. Sans lui, la stratégie n'est positive que 4 années&lt;br&gt;
sur 7 ; avec lui, aucune année perdante sur 6 ans.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ce billet documente un projet réel : un bot de signaux crypto entièrement automatisé, dont le code, les backtests et les résultats — gagnants comme perdants — sont publics. Le détail est sur &lt;a href="https://crypto-signals-bot-site.signalytics.workers.dev" rel="noopener noreferrer"&gt;le site&lt;/a&gt;, et les signaux sont publiés en clair sur &lt;a href="https://t.me/ProSignauxPublic" rel="noopener noreferrer"&gt;un canal Telegram ouvert&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>statistics</category>
      <category>backtesting</category>
    </item>
    <item>
      <title>Building a 100% Transparent Crypto Trading Bot Backtested Over 6 Years (2020-2026)</title>
      <dc:creator>aymeric leon</dc:creator>
      <pubDate>Thu, 13 Aug 2026 22:20:21 +0000</pubDate>
      <link>https://dev.to/aymeric_leon_5057b9072e0f/building-a-100-transparent-crypto-trading-bot-backtested-over-6-years-2020-2026-1nlj</link>
      <guid>https://dev.to/aymeric_leon_5057b9072e0f/building-a-100-transparent-crypto-trading-bot-backtested-over-6-years-2020-2026-1nlj</guid>
      <description>&lt;p&gt;Most crypto signal services online are pure marketing illusions: they show +500% leverage screenshots, delete losing trades, and sell fake promises.&lt;/p&gt;

&lt;p&gt;As a developer and quantitative trader, I decided to build the exact opposite: a &lt;strong&gt;100% transparent, automated crypto signal system&lt;/strong&gt; backtested on 6 years of tick data (2020–2026) where &lt;strong&gt;every single trade—including every loss—is archived in real-time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the breakdown of how the architecture works, the quantitative engines, and the realistic expectations.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Core Engines
&lt;/h3&gt;

&lt;p&gt;Rather than relying on a single indicator, the system splits capital across 5 distinct quantitative engines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Funding Rate Carry (Market-Neutral):&lt;/strong&gt; Captures perp funding rate differentials while holding spot. &lt;strong&gt;84.2% win rate&lt;/strong&gt; with an average net yield of +0.57% per trade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relative Strength (Bullish Regime):&lt;/strong&gt; Active only when BTC &amp;gt; 200-day MA. Scans 40 altcoins for top relative strength. &lt;strong&gt;48.3% win rate&lt;/strong&gt; with +2.83% expectancy per signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4H Momentum (Bearish Regime):&lt;/strong&gt; Active only when BTC &amp;lt; 200-day MA. Ranks short-term 4-hour momentum to capture quick swings during choppy markets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Channel Breakouts &amp;amp; Volatility Expansion:&lt;/strong&gt; Trend-following rules with strict volatility expansion triggers.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  2. The Regime Filter (Why Silence Saved -70.9%)
&lt;/h3&gt;

&lt;p&gt;The most important rule in quantitative trading is knowing &lt;strong&gt;when NOT to trade&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When Bitcoin trades below its 200-day moving average, directional breakout models get chopped to pieces. By enforcing a strict regime filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In 2022, the system remained &lt;strong&gt;completely silent&lt;/strong&gt; during the market crash, avoiding a -70.9% drawdown.&lt;/li&gt;
&lt;li&gt;In 2026, it saved -39.4% during market rangebound phases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Silence is not a bug; it is a feature.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Radical Transparency &amp;amp; Real-Time Archiving
&lt;/h3&gt;

&lt;p&gt;To eliminate trust issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No deleted posts:&lt;/strong&gt; Every entry, stop-loss, and take-profit level is timestamped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed 3-day max hold:&lt;/strong&gt; Every trade exits at 3 days regardless of noise, preventing bag-holding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realistic expectancy:&lt;/strong&gt; 48.3% win rate for directional trades. Rentability comes from positive risk-reward asymmetry (cutting losses at -2% to -3% while letting wins run to +10%+).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Open Dashboard &amp;amp; Live Results
&lt;/h3&gt;

&lt;p&gt;You can inspect the full 6-year backtests, live performance, and daily logs on our public dashboard:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Live Site:&lt;/strong&gt; &lt;a href="https://crypto-signals-bot-site.signalytics.workers.dev/" rel="noopener noreferrer"&gt;crypto-signals-bot-site.signalytics.workers.dev&lt;/a&gt;&lt;br&gt;&lt;br&gt;
👉 &lt;strong&gt;Public Telegram Journal:&lt;/strong&gt; &lt;a href="https://t.me/ProSignauxPublic" rel="noopener noreferrer"&gt;t.me/ProSignauxPublic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>algorithms</category>
      <category>crypto</category>
      <category>backend</category>
    </item>
    <item>
      <title>J'ai mesuré ma propre stratégie de trading, elle perdait. Je l'ai supprimée.</title>
      <dc:creator>aymeric leon</dc:creator>
      <pubDate>Mon, 10 Aug 2026 10:11:48 +0000</pubDate>
      <link>https://dev.to/aymeric_leon_5057b9072e0f/jai-mesure-ma-propre-strategie-de-trading-elle-perdait-je-lai-supprimee-3h2</link>
      <guid>https://dev.to/aymeric_leon_5057b9072e0f/jai-mesure-ma-propre-strategie-de-trading-elle-perdait-je-lai-supprimee-3h2</guid>
      <description>&lt;p&gt;Pendant des mois, mon bot a publié des signaux issus d'un croisement de moyennes&lt;br&gt;
mobiles EMA 9/21 filtré par le RSI. C'est la stratégie la plus enseignée du&lt;br&gt;
trading amateur, et elle a l'avantage d'être facile à coder.&lt;/p&gt;

&lt;p&gt;Puis je l'ai mesurée correctement, et c'était la mauvaise nouvelle.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ce qui a changé dans la mesure
&lt;/h2&gt;

&lt;p&gt;Trois erreurs de méthode rendaient les résultats précédents inutilisables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le biais du survivant.&lt;/strong&gt; Je backtestais sur les paires qui existent&lt;br&gt;
&lt;em&gt;aujourd'hui&lt;/em&gt;. Or les cryptos qui ont disparu entre-temps sont précisément&lt;br&gt;
celles qui se sont effondrées. Mesurer une stratégie sur les seules survivantes&lt;br&gt;
revient à demander aux gagnants d'un casino s'ils ont gagné. En restreignant à&lt;br&gt;
18 paires non contaminées, la performance s'est effondrée.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le regard vers le futur.&lt;/strong&gt; Évaluer la bougie &lt;em&gt;k&lt;/em&gt; d'un DataFrame complet ne&lt;br&gt;
donne pas le même résultat qu'évaluer la dernière bougie d'un DataFrame tronqué&lt;br&gt;
à &lt;em&gt;k&lt;/em&gt;, si le moindre indicateur regarde en avant. La propriété à tester est&lt;br&gt;
simple, et elle mérite son propre test automatisé :&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;complet&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;detect_signal&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;pair&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;at_index&lt;/span&gt;&lt;span class="o"&gt;=&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;tronque&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;detect_signal&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;iloc&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&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="nf"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;drop&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;pair&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;assert &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complet&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&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;tronque&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;L'absence de témoin.&lt;/strong&gt; Une stratégie positive sur 6 ans n'a rien démontré&lt;br&gt;
tant qu'on ne l'a pas comparée à un tirage aléatoire &lt;em&gt;de même densité&lt;/em&gt; — même&lt;br&gt;
nombre de trades, mêmes durées de détention, mêmes paires. Sans ce témoin, on&lt;br&gt;
mesure le marché, pas la stratégie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le résultat
&lt;/h2&gt;

&lt;p&gt;Entre -24,9 % et +16,9 % par an selon les réglages, majoritairement négatif.&lt;br&gt;
La stratégie n'était pas neutre : c'était la jambe &lt;strong&gt;perdante&lt;/strong&gt; du système.&lt;/p&gt;

&lt;p&gt;Elle a été désactivée. Les dix signaux qu'elle avait déjà émis sont restés en&lt;br&gt;
base, et l'étiquette affichée à leur sujet a été changée en « moteur retiré » —&lt;br&gt;
parce que continuer à afficher « haute confiance » sur les signaux d'un moteur&lt;br&gt;
qu'on vient de désavouer serait un mensonge rétroactif.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que j'en retiens
&lt;/h2&gt;

&lt;p&gt;Un backtest positif est une hypothèse, pas une preuve. La question utile n'est&lt;br&gt;
jamais « est-ce que ça gagne ? » mais « est-ce que ça gagne &lt;strong&gt;plus que le&lt;br&gt;
hasard, à contraintes égales&lt;/strong&gt; ? ». Les stratégies qui survivent à cette&lt;br&gt;
question sont beaucoup moins nombreuses qu'on ne l'espère.&lt;/p&gt;

&lt;p&gt;Le plus dur n'a pas été de coder le test. Ça a été d'accepter son résultat sur&lt;br&gt;
du code que j'avais déjà mis en production.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ce billet documente un projet réel : un bot de signaux crypto entièrement automatisé, dont le code, les backtests et les résultats — gagnants comme perdants — sont publics. Le détail est sur &lt;a href="https://crypto-signals-bot-site.signalytics.workers.dev" rel="noopener noreferrer"&gt;le site&lt;/a&gt;, et les signaux sont publiés en clair sur &lt;a href="https://t.me/ProSignauxPublic" rel="noopener noreferrer"&gt;un canal Telegram ouvert&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>backtesting</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
