<?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: vladik1314</title>
    <description>The latest articles on DEV Community by vladik1314 (@vladik1314).</description>
    <link>https://dev.to/vladik1314</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3965071%2Fdd82e97a-3fd9-4307-97db-f12bea7ea6e7.png</url>
      <title>DEV Community: vladik1314</title>
      <link>https://dev.to/vladik1314</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vladik1314"/>
    <language>en</language>
    <item>
      <title>I Built an ML Bitcoin Trading Bot — Then Proved It Had No Edge.</title>
      <dc:creator>vladik1314</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:21:21 +0000</pubDate>
      <link>https://dev.to/vladik1314/i-built-an-ml-bitcoin-trading-bot-then-proved-it-had-no-edge-pjh</link>
      <guid>https://dev.to/vladik1314/i-built-an-ml-bitcoin-trading-bot-then-proved-it-had-no-edge-pjh</guid>
      <description>&lt;p&gt;&lt;strong&gt;A case study in building crypto trading infrastructure and, more importantly, testing it honestly — including when the honest answer is "no edge."&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A clean, modular system (one responsibility per file) for trading BTC on Bybit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signal layer&lt;/strong&gt; — a Random Forest over 20 engineered features (EMA gaps, RSI, MACD, Bollinger position, ATR, volume, momentum, time-of-day).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regime detection&lt;/strong&gt; — classifies the market into BULL / BEAR / NEUTRAL / CRASH / EUPHORIA and swaps strategy parameters accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt; — multi-position management, trailing stops, 50% scale-out at TP1, 4h position aging, daily-loss and trade-rate risk limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry timing&lt;/strong&gt; — Optimal Trade Entry using Fibonacci retracement zones, plus higher-timeframe and session filters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engineering is solid. The architecture is something I'd happily put in production. But good engineering and a profitable strategy are two completely different things — and conflating them is how people lose money.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap almost everyone falls into
&lt;/h2&gt;

&lt;p&gt;The original model reported &lt;strong&gt;52.9% accuracy&lt;/strong&gt; and felt promising. But it was predicting the wrong thing: &lt;em&gt;"will the next 15-minute candle close higher?"&lt;/em&gt; That target is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Near-random&lt;/strong&gt; — next-bar direction is dominated by microstructure noise; the theoretical ceiling is barely above 50%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disconnected from P&amp;amp;L&lt;/strong&gt; — a +0.01% tick and a +2% rip are both labeled "up," but only one makes money after a 0.4% stop and fees.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A model can be "accurate" on a meaningless target and still lose every dollar. So I rebuilt the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing it properly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Triple-barrier labeling.&lt;/strong&gt; Instead of "next candle up?", I labeled each sample by what a &lt;em&gt;real trade&lt;/em&gt; does: does price hit +0.5% before −0.5% within the next 8 bars? Indecisive samples (no real move) are dropped. Now the model predicts tradeable outcomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eliminated train/serve skew.&lt;/strong&gt; I found the features were computed by &lt;em&gt;two separate code paths&lt;/em&gt; (training vs live) — a classic silent bug where the model scores on slightly different inputs than it trained on. I refactored both to call one shared function. (There was even a third, broken copy that hardcoded constants for two features.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Walk-forward validation.&lt;/strong&gt; Chronological folds — train on the past, test on the future — so the model never sees data from its own future. No lookahead bias.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-driven backtest.&lt;/strong&gt; I wrote a backtester that replays the &lt;em&gt;actual&lt;/em&gt; trade mechanics — stop-loss, scale-out, trailing stop, timeout — including fees and slippage, with pessimistic intrabar fill assumptions. Then I ran it strictly out-of-sample.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;15m next-candle direction (the illusion)&lt;/td&gt;
&lt;td&gt;52.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15m triple-barrier, walk-forward&lt;/td&gt;
&lt;td&gt;51.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1h ATR triple-barrier, &lt;strong&gt;out-of-sample&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;50.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full backtest, real mechanics, 12 months&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Win rate 32%, profit factor 0.37&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three independent tests, two timeframes, two labeling schemes — all converging on the same answer: &lt;strong&gt;a coin flip.&lt;/strong&gt; The 32% live-mechanics win rate was even worse than the raw accuracy, because a 0.4% stop sits &lt;em&gt;inside&lt;/em&gt; Bitcoin's 15-minute noise band, so 86% of trades got stopped out before the thesis could play out.&lt;/p&gt;

&lt;p&gt;The feature importances told the story too: the model leaned almost entirely on &lt;strong&gt;volatility&lt;/strong&gt; features (ATR, Bollinger width) and essentially ignored the &lt;strong&gt;directional&lt;/strong&gt; ones. It had learned to predict &lt;em&gt;how big&lt;/em&gt; the next move would be — but not &lt;em&gt;which way&lt;/em&gt;. Which is exactly the part that matters, and exactly the part that isn't predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why — and why that's not surprising
&lt;/h2&gt;

&lt;p&gt;This is market efficiency in action. Technical indicators are public information; any directional signal in them gets arbitraged away by faster participants almost instantly. The conclusion isn't "tune more parameters" (that's just overfitting noise until something looks good by chance) — it's that &lt;strong&gt;TA-derived features don't predict BTC direction at retail timeframes.&lt;/strong&gt; A well-documented result I confirmed on my own data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did next
&lt;/h2&gt;

&lt;p&gt;If prediction doesn't work, the answer is to stop predicting and look for &lt;em&gt;structural&lt;/em&gt; edges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Funding-rate capture&lt;/strong&gt; — a delta-neutral (long spot / short perp) strategy that harvests the perpetual funding premium regardless of direction. I built a monitor for it — and found that at current rates it pays &lt;em&gt;less than the risk-free rate after fees&lt;/em&gt;, so the disciplined move is to wait for the regime where it's actually profitable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prediction-market arbitrage&lt;/strong&gt; — I built a scanner for "underround" mispricings on Polymarket. It found that liquid markets are priced &lt;em&gt;to the tick&lt;/em&gt; (every binary summed to exactly 1.001), with no accessible arbitrage — efficiency again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each negative result is itself a finding: it tells you precisely where &lt;em&gt;not&lt;/em&gt; to put your money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this project actually demonstrates
&lt;/h2&gt;

&lt;p&gt;Anyone can wire up an exchange API and curve-fit a backtest. The harder, rarer skill is &lt;strong&gt;knowing whether what you built is real&lt;/strong&gt; — and being honest when it isn't. This project shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End-to-end ML pipeline design (feature engineering, labeling, validation, serving)&lt;/li&gt;
&lt;li&gt;Awareness of the failure modes that fool most people (lookahead bias, train/serve skew, meaningless targets, overfitting)&lt;/li&gt;
&lt;li&gt;Realistic backtesting with costs and conservative assumptions&lt;/li&gt;
&lt;li&gt;The judgment to kill a strategy that doesn't work instead of shipping it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In trading, &lt;em&gt;not losing money on a bad strategy&lt;/em&gt; is worth as much as finding a good one. This is the discipline behind that.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code and full architecture on &lt;a href="https://github.com/vladik1314/btc-trading-bot" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Built with Python, scikit-learn, NumPy, and the Bybit v5 API.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>datascience</category>
      <category>playwright</category>
    </item>
  </channel>
</rss>
