<?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: Oliver Zehentleitner</title>
    <description>The latest articles on DEV Community by Oliver Zehentleitner (@oliverzehentleitner).</description>
    <link>https://dev.to/oliverzehentleitner</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%2F2124155%2F0d79bc59-db7b-4879-bd1a-36dc2f79d1c2.png</url>
      <title>DEV Community: Oliver Zehentleitner</title>
      <link>https://dev.to/oliverzehentleitner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oliverzehentleitner"/>
    <language>en</language>
    <item>
      <title>The Complete Binance Python API Guide (2026)</title>
      <dc:creator>Oliver Zehentleitner</dc:creator>
      <pubDate>Mon, 20 Jul 2026 11:53:29 +0000</pubDate>
      <link>https://dev.to/oliverzehentleitner/the-complete-binance-python-api-guide-2026-35hf</link>
      <guid>https://dev.to/oliverzehentleitner/the-complete-binance-python-api-guide-2026-35hf</guid>
      <description>&lt;h2&gt;
  
  
  REST, WebSocket, order books, trailing stops, and cluster-scale infrastructure — the production-grade Python stack for Binance.
&lt;/h2&gt;

&lt;p&gt;If you Google &lt;strong&gt;"python binance"&lt;/strong&gt; in 2026, the first hits are &lt;code&gt;python-binance&lt;/code&gt;, &lt;code&gt;binance-connector-python&lt;/code&gt;, and &lt;code&gt;CCXT&lt;/code&gt;. Useful tools, all of them. But once a Binance bot moves from &lt;em&gt;script&lt;/em&gt; to &lt;em&gt;service&lt;/em&gt;, the interesting question changes: not only &lt;em&gt;can this library call the endpoint?&lt;/em&gt;, but &lt;em&gt;does it give me the operational model to keep REST, WebSocket streams, WebSocket API trading requests, order state, reconnects, depth caches, and failure handling under control?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One library with a more operational focus still barely shows up in search results: the &lt;a href="https://blog.technopathy.club/page/unicorn-binance-suite" rel="noopener noreferrer"&gt;&lt;strong&gt;UNICORN Binance Suite&lt;/strong&gt;&lt;/a&gt; (UBS). 3.3M+ downloads. 390+ public dependent projects. Several interlocking packages, all MIT, all maintained by one developer with a public name, public GitHub repos, and a Telegram you can actually message.&lt;/p&gt;

&lt;p&gt;This guide is the cornerstone reference: what each tool does, why it matters, when to use which, and how the pieces fit together. With &lt;strong&gt;verified, live code&lt;/strong&gt; — every output you see in this article was captured from a real call to &lt;code&gt;api.binance.com&lt;/code&gt; while writing it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're already sold and just want to read code, skip to Your First Binance REST Call in Python.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Python-on-Binance Landscape in 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Honest strength&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;python-binance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Widely known Python package with broad REST coverage, WebSocket managers, many examples, tutorials, and existing bots&lt;/td&gt;
&lt;td&gt;Familiar does not automatically mean operationally simpler: stream lifecycle, trust state, and order-book correctness are less explicit than in UBS, so production behavior often has to be handled in application code&lt;/td&gt;
&lt;td&gt;Existing projects, users already invested in that ecosystem, quick experiments where operational state is not the main concern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;binance-connector-python / official SDKs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Official Binance direction, close to the published API surface, strong REST endpoint coverage, lightweight clients, modern authentication support&lt;/td&gt;
&lt;td&gt;Intentionally low-level: good building blocks, but reconnect policy, queues, depth-cache trust, strategy state, and operational glue are mostly your responsibility&lt;/td&gt;
&lt;td&gt;Teams that want the official API surface and prefer to build their own runtime around it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CCXT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent multi-exchange abstraction across multiple languages and many exchanges; great when one codebase must talk to more than Binance&lt;/td&gt;
&lt;td&gt;The abstraction is the value, but it naturally trades away some Binance-specific controls, lifecycle detail, and exchange-specific ergonomics&lt;/td&gt;
&lt;td&gt;Multi-exchange systems, portfolio tooling, arbitrage research, backtesting, and teams that do not want to be Binance-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UNICORN Binance Suite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Binance-native operational stack: simple REST calls, WebSocket streams, stream lifecycle signals, WebSocket API requests, reconnects, sequence validation, out-of-sync handling, multi-account routing, asyncio queues, and cluster-scale DepthCache infrastructure&lt;/td&gt;
&lt;td&gt;Binance-only by design; explicit manager model instead of loose helper functions; strongest when REST, WebSockets, order books, and failure states need to work together&lt;/td&gt;
&lt;td&gt;Beginners who want sane defaults, Binance-specific bots, 24/7 services, local order books, and systems where failure states must be visible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;This guide is about the fourth row.&lt;/strong&gt; Not because the others are bad. They are strong in different ways: &lt;code&gt;python-binance&lt;/code&gt; is widely known and has many examples, the official Binance SDKs closely track Binance's published API surface, and &lt;code&gt;CCXT&lt;/code&gt; is excellent when exchange abstraction matters more than Binance-specific depth. UBS is built for a narrower problem: Binance-specific systems where WebSocket lifecycle, order-book correctness, reconnect behavior, request routing, and failure states should be explicit instead of hidden in application glue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A friendly maintainer's note: I am the author of UBS. I'll cite community sources where I can, show you working code, and let you decide. If you spot anything that looks unfair, the comments and &lt;a href="https://t.me/unicorndevs" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; are open.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What UBS Actually Is
&lt;/h2&gt;

&lt;p&gt;UBS is &lt;strong&gt;not a single library&lt;/strong&gt; — it's a coordinated suite of six packages plus an optional Kubernetes-scale service. Each piece is its own PyPI package, its own GitHub repo, its own release cadence — but the interfaces line up so they compose without glue code.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;unicorn-binance-rest-api&lt;/strong&gt; (UBRA)&lt;/td&gt;
&lt;td&gt;REST client for public and private Binance endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;unicorn-binance-websocket-api&lt;/strong&gt; (UBWA)&lt;/td&gt;
&lt;td&gt;WebSocket streams, WebSocket API requests, user-data streams, reconnects, lifecycle signals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;unicorn-binance-local-depth-cache&lt;/strong&gt; (UBLDC)&lt;/td&gt;
&lt;td&gt;Local synchronized order books with sequence validation, pruning, resync, and &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;unicorn-binance-trailing-stop-loss&lt;/strong&gt; (UBTSL)&lt;/td&gt;
&lt;td&gt;Trailing stop engine and CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;unicorn-fy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Raw Binance payloads → normalized Python dictionaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;ubdcc&lt;/strong&gt; (UBDCC)&lt;/td&gt;
&lt;td&gt;Shared DepthCache service for local or Kubernetes-scale infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;unicorn-binance-suite&lt;/strong&gt; (meta)&lt;/td&gt;
&lt;td&gt;Installs the suite components together&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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




&lt;h2&gt;
  
  
  Install in One Line
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-binance-suite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you the core UNICORN Binance Suite packages — UBRA, UBWA, UBLDC, UBTSL, and UnicornFy — in one install. UBDCC is different: it is the cluster service built on top of UBLDC, not a client library inside the suite. Want a single piece? Install just that one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-binance-websocket-api
pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-binance-rest-api
pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-binance-local-depth-cache
pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-binance-trailing-stop-loss
pip &lt;span class="nb"&gt;install &lt;/span&gt;unicorn-fy
pip &lt;span class="nb"&gt;install &lt;/span&gt;ubdcc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A note on a myth that still floats around: &lt;em&gt;"UBS is hard to install because it needs C build tools."&lt;/em&gt; Not since multi-arch wheels (x86_64, aarch64, arm64) were added. Where UBS uses native/Cython components, &lt;code&gt;pip install&lt;/code&gt; resolves to a pre-built binary on common platforms. Cython where it pays off, plain Python where it doesn't.&lt;/p&gt;

&lt;p&gt;You &lt;strong&gt;do not need API keys&lt;/strong&gt; for anything in the &lt;em&gt;Market Data&lt;/em&gt; sections below (REST tickers, WebSocket public streams, depth caches). For account operations and trailing stops, see &lt;a href="https://blog.technopathy.club/how-to-create-a-binance-api-key-and-api-secret" rel="noopener noreferrer"&gt;How to create a Binance API Key and API Secret&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your First Binance REST Call in Python
&lt;/h2&gt;

&lt;p&gt;The most common starting question: &lt;strong&gt;"How do I get the current price of BTC in Python?"&lt;/strong&gt; With UBRA:&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_rest_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceRestApiManager&lt;/span&gt;

&lt;span class="n"&gt;ubra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceRestApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ticker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_symbol_ticker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&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="n"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ubra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop_manager&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;Live output&lt;/strong&gt; (captured from &lt;code&gt;api.binance.com&lt;/code&gt; while writing this):&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;symbol&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;BTCUSDC&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;price&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;81250.60000000&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;24h statistics in one call:&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;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ticker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&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="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lastPrice&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;priceChangePercent&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;highPrice&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;lowPrice&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;volume&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;quoteVolume&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&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;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;stats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  lastPrice: 81250.60000000
  priceChangePercent: 0.394
  highPrice: 82137.26000000
  lowPrice: 80462.97000000
  volume: 11772.94006000
  quoteVolume: 957215665.33209680
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Historical candles for backtesting or charts:&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;klines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_klines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;klines&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;  open=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  high=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  low=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  close=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  volume=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&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="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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  open=81249.93000000  high=81294.42000000  low=81024.41000000  close=81058.80000000  volume=187.87319000
  open=81058.79000000  high=81303.99000000  low=81000.00000000  close=81240.01000000  volume=398.28206000
  open=81240.01000000  high=81283.80000000  low=81203.81000000  close=81250.60000000  volume=157.79464000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authentication for account/trading endpoints&lt;/strong&gt; is one extra constructor argument:&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;ubra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceRestApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&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;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_account&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# private endpoint, requires signed request
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UBRA supports &lt;strong&gt;com, com-margin, com-isolated-margin, com-futures, us, and tr&lt;/strong&gt;, plus all matching testnets — switch with the &lt;code&gt;exchange&lt;/code&gt; argument. A signed-order example for an OCO take-profit/stop-loss pattern lives in &lt;a href="https://blog.technopathy.club/buy-an-asset-and-instantly-create-a-take-profit-and-stop-loss-oco-sell-order-using-python-in-binance-isolated-margin" rel="noopener noreferrer"&gt;Buy an Asset and Instantly Create a Take-Profit + Stop-Loss OCO Sell Order&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your First WebSocket Stream in Python
&lt;/h2&gt;

&lt;p&gt;REST polling is fine for one-off queries. For real-time price feeds you want WebSockets. UBWA's model is simple: &lt;strong&gt;one Manager, many streams&lt;/strong&gt;. The receiving side can be as small as a few lines, or as explicit as a dedicated asyncio queue per stream.&lt;/p&gt;

&lt;p&gt;The examples below intentionally follow the UBWA README style. Start simple, then choose the processing model that fits your bot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1 — Pull from the stream buffer
&lt;/h3&gt;

&lt;p&gt;The shortest possible pattern. No callbacks, no asyncio in your code. UBWA receives frames in the background; you pull the oldest item from the stream buffer when you are ready.&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;

&lt;span class="n"&gt;ubwa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;channels&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;trade&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;kline_1m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;markets&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;btcusdc&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;bnbbtc&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;ethbtc&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="k"&gt;while&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;oldest_data_from_stream_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop_stream_data_from_stream_buffer&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;oldest_data_from_stream_buffer&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;oldest_data_from_stream_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the easiest way to understand the flow: Binance pushes data asynchronously, UBWA stores it, and your code consumes it.&lt;/p&gt;

&lt;p&gt;For normalized Python dictionaries instead of raw Binance payloads, request UnicornFy output on the stream:&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;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;channels&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;trade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;markets&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;btcusdc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UnicornFy&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When to use it: scripts, demos, notebooks, quick collectors. For long-running services, avoid a tight empty polling loop. Use a callback or an asyncio queue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2 — Callback per received frame
&lt;/h3&gt;

&lt;p&gt;You hand UBWA a normal function. Every received frame is passed to it.&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_new_receives&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_data&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="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;ubwa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;channels&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;trade&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;kline_1m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;markets&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;btcusdc&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;bnbbtc&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;ethbtc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;process_stream_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_new_receives&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;There is also an async callback variant:&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;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_new_receives&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_data&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;stream_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&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;ubwa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;channels&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;trade&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;kline_1m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;markets&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;btcusdc&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;bnbbtc&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;ethbtc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;process_stream_data_async&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_new_receives&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;When to use it: clean event-style processing where each message can be handled independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3 — Await the stream data in an asyncio coroutine
&lt;/h3&gt;

&lt;p&gt;This is the README-recommended pattern for processing stream data when you want explicit async handling. UBWA creates the stream and feeds an asyncio queue; your coroutine awaits data from that queue.&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;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_asyncio_queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;Start processing data from stream &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_stream_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&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="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_stop_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_stream_data_from_asyncio_queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&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;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncio_queue_task_done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;channels&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;trade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;markets&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;ethbtc&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;btcusdc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;stream_label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;process_asyncio_queue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_asyncio_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_manager_stopping&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&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="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&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;Gracefully stopping ...&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;What this gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;one explicit coroutine for the stream,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a real &lt;code&gt;await&lt;/code&gt; on incoming data,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;clean backpressure via &lt;code&gt;asyncio_queue_task_done()&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a manager lifecycle that exits cleanly when used with &lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Subscribe and unsubscribe without rebuilding the stream
&lt;/h3&gt;

&lt;p&gt;UBWA can add or remove markets and channels at runtime:&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;markets&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;engbtc&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;zileth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;channels&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;kline_5m&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;kline_15m&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;depth5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe_to_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe_from_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe_from_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That matters in real bots. You do not want to tear down and recreate a socket every time your market universe changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's true for all receiving patterns
&lt;/h3&gt;

&lt;p&gt;Regardless of which option you pick:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSocket receiving is asynchronous by nature.&lt;/strong&gt; You subscribe once; Binance pushes frames when they exist. Your job is to route and process them correctly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UBWA owns the socket lifecycle.&lt;/strong&gt; Reconnects, listenKey renewal for user-data streams, ping/pong, and stream health happen below your strategy code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UnicornFy is optional but useful.&lt;/strong&gt; Use &lt;code&gt;output="UnicornFy"&lt;/code&gt; when you want readable dict keys instead of raw Binance event fields.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Receiving data is not the same as knowing the stream is healthy.&lt;/strong&gt; That is what &lt;code&gt;stream_signals&lt;/code&gt; are for.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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




&lt;h2&gt;
  
  
  Stream Signals: Know When Your Bot Is Blind
&lt;/h2&gt;

&lt;p&gt;Receiving data is only half of a WebSocket client. The other half is knowing whether the stream itself is currently trustworthy.&lt;/p&gt;

&lt;p&gt;A WebSocket is asynchronous by nature. Data arrives when Binance pushes it. Silence can mean "no trade happened", but it can also mean "your connection is gone", "the stream is reconnecting", "the first data frame has not arrived yet", or "this stream cannot be restored". For a trading bot, those states are not cosmetic. They decide whether indicators are still valid, whether a strategy should pause, whether missing data must be reloaded via REST, or whether open positions should be handled defensively.&lt;/p&gt;

&lt;p&gt;UBWA exposes this through &lt;code&gt;stream_signals&lt;/code&gt;. They tell your code about lifecycle changes in real time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONNECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The stream connection was established.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FIRST_RECEIVED_DATA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The first data record arrived. This is the point where the stream is no longer just connected, but actually feeding data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DISCONNECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The stream disconnected. UBWA includes the last received data record if available, so your code has a recovery anchor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;STOP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The stream was stopped.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;STREAM_UNREPAIRABLE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UBWA cannot restore the stream, for example because of invalid credentials or an exception in your own processing coroutine.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last distinction matters: &lt;strong&gt;connected is not the same as usable&lt;/strong&gt;. A bot that subscribes to &lt;code&gt;btcusdc@depth&lt;/code&gt; and immediately starts trading before the first data frame arrived is guessing. A bot that keeps calculating indicators after a disconnect is blind. &lt;code&gt;stream_signals&lt;/code&gt; make those states explicit.&lt;/p&gt;

&lt;p&gt;The callback version is usually the cleanest production pattern:&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_stream_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_record&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error_msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;Received stream_signal for stream &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_stream_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&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;signal_type&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;stream_id&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;data_record&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;error_msg&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="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process_stream_signals&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_stream_signals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;btcusdc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream_label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simpler scripts you can also enable the signal buffer and poll it, similar to normal stream data:&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;ubwa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enable_stream_signal_buffer&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;btcusdc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream_label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC_TRADES&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&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;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop_stream_signal_from_stream_signal_buffer&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;signal&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;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a small feature with huge operational impact. It turns WebSocket reliability from log-reading into code-level state. Your own application can know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"I am connected, but not live yet."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"I received the first usable market-data frame."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"I just lost the stream and must stop trusting derived indicators."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"This stream is unrecoverable and needs human or strategy-level intervention."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also why UBWA fits so well underneath UBLDC and UBDCC. A depth cache does not only need bids and asks. It needs lifecycle truth. &lt;code&gt;CONNECT&lt;/code&gt;, &lt;code&gt;FIRST_RECEIVED_DATA&lt;/code&gt;, &lt;code&gt;DISCONNECT&lt;/code&gt;, and &lt;code&gt;STREAM_UNREPAIRABLE&lt;/code&gt; are the vocabulary that lets the next layer decide whether data is authoritative, stale, recovering, or unusable.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Trading Over WebSocket: Create and Cancel Orders Without REST
&lt;/h2&gt;

&lt;p&gt;There is one Binance feature many Python guides still treat as an afterthought: the &lt;strong&gt;Binance WebSocket API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is not the same thing as a market-data WebSocket stream.&lt;/p&gt;

&lt;p&gt;A market-data stream pushes events to you: trades, klines, depth updates, user-data events. The &lt;strong&gt;WebSocket API&lt;/strong&gt; is a request/response API over a persistent WebSocket connection: place an order, cancel an order, query account state, and receive a correlated response later — without opening a new HTTP request for every action.&lt;/p&gt;

&lt;p&gt;That last word matters: &lt;strong&gt;later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;WebSocket is asynchronous by nature. You send a request into an already-open connection and move on. At some later point Binance pushes a response frame back. Your code should not pretend that this is just REST with a different transport. The clean design is not "call function, block forever, hope the socket behaves." The clean design is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;send a request with an ID,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;receive frames asynchronously,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;route the matching response to the right handler,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;keep the connection lifecycle independent from the strategy logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For slow scripts, REST is fine. For systems that already live on WebSockets, jumping back to REST for trading actions creates an awkward split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;market data arrives over WebSocket,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the strategy reacts in memory,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;order placement jumps back to REST,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;response handling follows a different path,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;request IDs, retries, state reconciliation, and failure handling become your problem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UBWA supports Binance WebSocket API requests directly through the same manager model used for streams.&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_websocket_api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceWebSocketApiManager&lt;/span&gt;

&lt;span class="n"&gt;ubwa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceWebSocketApiManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dict&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;api_stream_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api&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;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&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="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LIMIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_in_force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GTC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50000&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="c1"&gt;# The response is pushed back by Binance and handled asynchronously.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the natural WebSocket way: send the request, keep the socket alive, process the response when it arrives.&lt;/p&gt;

&lt;p&gt;For scripts, demos, tests, or migration from REST-style code, UBWA can also wait for the matching response and return it directly:&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&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="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LIMIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_in_force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GTC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;return_response&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="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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Canceling an order follows the same model:&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;ubwa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;stream_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_stream_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;123456789&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;The important part is not only that order placement and cancellation work over WebSocket. The important part is &lt;strong&gt;how responses can be processed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;UBWA lets you handle WebSocket API responses in several ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;global callback,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;stream-specific callback,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;request-specific callback,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;async handler,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;blocking &lt;code&gt;return_response=True&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or the normal stream buffer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the same feature usable in a notebook, a CLI tool, a long-running bot, or a service with dedicated request routing.&lt;/p&gt;

&lt;p&gt;A small but useful detail: &lt;code&gt;stream_id=api_stream_id&lt;/code&gt; is only required when more than one WebSocket API stream is active. If there is exactly one WebSocket API stream, UBWA can use that stream automatically. In simple examples I still pass the &lt;code&gt;stream_id&lt;/code&gt; explicitly because it makes the routing visible.&lt;/p&gt;

&lt;p&gt;The real advantage shows up in multi-account or multi-key setups: you can run several WebSocket API streams with different &lt;code&gt;api_key&lt;/code&gt; / &lt;code&gt;api_secret&lt;/code&gt; pairs and then explicitly route a request to the stream that belongs to the right account.&lt;/p&gt;

&lt;p&gt;To stay fair: this is no longer a UBS-only checkbox. &lt;code&gt;python-binance&lt;/code&gt; documents &lt;a href="https://python-binance.readthedocs.io/en/latest/websockets.html" rel="noopener noreferrer"&gt;API requests via WebSockets&lt;/a&gt;, Binance's official &lt;code&gt;binance-sdk-spot&lt;/code&gt; describes itself as supporting REST API, WebSocket API, and WebSocket Streams, and CCXT/CCXT Pro has exchange-dependent WebSocket support. The difference is the operational model: in UBWA, WebSocket streams, WebSocket API requests, reconnect handling, callbacks, stream buffers, async queues, and request routing all live inside one Binance-native manager.&lt;/p&gt;

&lt;p&gt;A full walkthrough lives here: &lt;a href="https://blog.technopathy.club/create-and-cancel-orders-via-websocket-on-binance" rel="noopener noreferrer"&gt;Create and Cancel Orders via WebSocket on Binance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is where UBS becomes more than "REST client plus WebSocket client". REST, market streams, user-data streams, WebSocket API trading requests, response routing, and reconnect handling fit into one mental model.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Local Order Book Without the Pain (UBLDC)
&lt;/h2&gt;

&lt;p&gt;If your strategy reads the order book more than a few times per second, REST polling is a dead end: every call is a round trip across the internet, you will hit rate limits, and the data is stale by the time you parse it. The right answer is a &lt;strong&gt;local depth cache&lt;/strong&gt; — Binance pushes diffs over WebSocket, you keep a synchronized copy in memory.&lt;/p&gt;

&lt;p&gt;The naive way to do this is on the third page of Binance's docs. The right way is what UBLDC does: create the cache, read asks and bids, and let the manager handle synchronization, pruning, and resync logic.&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;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_local_depth_cache&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceLocalDepthCacheManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DepthCacheOutOfSync&lt;/span&gt;

&lt;span class="n"&gt;ubldc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinanceLocalDepthCacheManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth_cache_update_interval&lt;/span&gt;&lt;span class="o"&gt;=&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;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_depthcache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Wait for the initial REST snapshot + WebSocket diff synchronization.
&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_depth_cache_synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&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;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_asks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&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;Top 5 asks:&lt;/span&gt;&lt;span class="sh"&gt;"&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;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;asks&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;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  qty=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qty&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="s"&gt;Top 5 bids:&lt;/span&gt;&lt;span class="sh"&gt;"&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;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bids&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;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  qty=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qty&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="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;DepthCacheOutOfSync&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;BTCUSDC depth cache is currently out of sync — skip this decision cycle.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop_manager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That exception is the important contract.&lt;/p&gt;

&lt;p&gt;A local order book can temporarily be unusable: initial snapshot still loading, sequence gap detected, reconnect in progress, resync running. UBLDC does &lt;strong&gt;not&lt;/strong&gt; silently pretend that stale memory is still authoritative. If you access the book while it is out of sync, it can raise &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt;. Your strategy can then pause, skip this tick, reduce risk, or wait for the cache to recover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading the book the way strategies actually need it
&lt;/h3&gt;

&lt;p&gt;Most strategies don't want "the full book." They want &lt;strong&gt;the first N levels&lt;/strong&gt; or &lt;strong&gt;enough depth to fill X quote-units of volume&lt;/strong&gt;. UBLDC's &lt;code&gt;get_asks&lt;/code&gt; / &lt;code&gt;get_bids&lt;/code&gt; accept both forms:&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;# First 10 levels on each side
&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_asks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# All levels until cumulative volume crosses 300 000, e.g. USDT for a USDT pair
&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_asks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold_volume&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold_volume&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;limit_count=N&lt;/code&gt; trims the result to the top N levels by price. &lt;code&gt;threshold_volume=X&lt;/code&gt; walks the book outward until the cumulative quote volume crosses X and stops there — exactly what you need to estimate "how far would I move the price if I market-bought X USDT of BTC right now?" without slicing the full book yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt; is the production boundary
&lt;/h3&gt;

&lt;p&gt;You do &lt;strong&gt;not&lt;/strong&gt; have to call &lt;code&gt;is_depth_cache_synchronized()&lt;/code&gt; before every read. That is useful for dashboards, readiness checks, or explicit control flow. The stronger production pattern is to treat reads as authoritative only if they succeed, and to handle &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt; where your strategy consumes the book:&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_local_depth_cache&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DepthCacheOutOfSync&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_asks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit_count&lt;/span&gt;&lt;span class="o"&gt;=&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;except&lt;/span&gt; &lt;span class="n"&gt;DepthCacheOutOfSync&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC depth cache out of sync — skipping decision cycle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="c1"&gt;# If execution reaches this point, the strategy has a usable book snapshot.
&lt;/span&gt;&lt;span class="nf"&gt;run_strategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction matters. A boolean pre-check can be stale by the time you act on it. The exception is raised at the access boundary, exactly where trust is needed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_depth_cache_synchronized("BTCUSDC")&lt;/code&gt; still has a place:&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;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ubldc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_depth_cache_synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC still initializing or resyncing&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;Use it for observability and readiness. Use &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt; for correctness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidebar — Binance's docs are incomplete about depth caches
&lt;/h3&gt;

&lt;p&gt;This is the part most libraries get subtly wrong, and most users never notice until their P&amp;amp;L starts drifting.&lt;/p&gt;

&lt;p&gt;Binance's published depth-cache algorithm is &lt;strong&gt;incomplete&lt;/strong&gt; in one specific way: when a price level falls out of the top-1000, Binance stops sending updates for it — but &lt;strong&gt;never sends a "delete" event&lt;/strong&gt; for it either. A library that follows the documentation blindly will accumulate orphaned levels forever. Your "order book" turns into a museum of orders that no longer exist. Strategies that key off the depth profile slowly start trading against ghosts.&lt;/p&gt;

&lt;p&gt;UBLDC actively prunes out-of-scope levels. I ran a 25-hour side-by-side experiment to quantify the rot: a naive cache built strictly to spec versus the UBLDC-style pruned cache, fed by the same WebSocket stream. After 9 hours the naive cache was at &lt;strong&gt;~34% bid-match / ~45% ask-match&lt;/strong&gt; against a fresh REST snapshot, with 22 000 stale levels still in memory. The pruned cache held a steady ~1050 levels at 90–97% match for the full run.&lt;/p&gt;

&lt;p&gt;Full write-up with charts and raw data: &lt;a href="https://blog.technopathy.club/your-binance-depthcache-is-rotting-here-s-the-proof-in-25-hours" rel="noopener noreferrer"&gt;&lt;strong&gt;Your Binance DepthCache Is Rotting — Here's the Proof in 25 Hours&lt;/strong&gt;&lt;/a&gt;. If you build your own depth cache or use a library that doesn't handle this, please at least read the comparison chart.&lt;/p&gt;

&lt;p&gt;UBLDC additionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;validates &lt;code&gt;U&lt;/code&gt; / &lt;code&gt;u&lt;/code&gt; sequence numbers on every update and resynchronizes on gap detection,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;raises &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt; instead of silently serving stale data while a cache is unusable,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;buffers WebSocket events during the initial REST snapshot load,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;removes orphaned out-of-scope levels beyond the top-1000 corridor,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;runs many caches in one Manager.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://oliver-zehentleitner.github.io/binance-depthcache-forensics/comparison.html" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fli4nr6fkoj8eftsz3gtb.png" alt="Chart" width="799" height="423"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Trailing Stop Loss from the CLI or Python (UBTSL)
&lt;/h2&gt;

&lt;p&gt;Risk management is the second-most-asked Binance-Python topic after "how do I get the price?"&lt;/p&gt;

&lt;p&gt;A trailing stop looks simple from the outside: follow the market while it moves in your favor, keep moving the stop behind it, and exit when the market reverses far enough. In practice, the annoying parts are all operational:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;where to store API keys,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;how to test connectivity before risking a live order,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;how to run the trailing engine from a terminal,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;how to reuse predefined profiles,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and how to integrate the same logic into Python code when the CLI is not enough.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what &lt;strong&gt;UNICORN Binance Trailing Stop Loss&lt;/strong&gt; (UBTSL) is for.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI workflow
&lt;/h3&gt;

&lt;p&gt;The CLI is the fastest way to use UBTSL directly from a terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# add Binance API key and secret&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--createconfigini&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--openconfigini&lt;/span&gt;

&lt;span class="c"&gt;# test connectivity&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--test&lt;/span&gt; binance-connectivity

&lt;span class="c"&gt;# start trailing&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;-m&lt;/span&gt; BTCUSDC &lt;span class="nt"&gt;-n&lt;/span&gt; trail &lt;span class="nt"&gt;--stoplosslimit&lt;/span&gt; 1% &lt;span class="nt"&gt;-e&lt;/span&gt; binance.com

&lt;span class="c"&gt;# use a profile&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--createprofilesini&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--openprofilesini&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--profile&lt;/span&gt; BTCUSDC_SELL &lt;span class="nt"&gt;--stoplosslimit&lt;/span&gt; 1.5%

&lt;span class="c"&gt;# cancel all open orders on the configured account/exchange&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;--profile&lt;/span&gt; BTCUSDC_SELL &lt;span class="nt"&gt;--cancelopenorders&lt;/span&gt;

&lt;span class="c"&gt;# help&lt;/span&gt;
ubtsl &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The normal flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;create the config file,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;add your Binance API key and secret,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;test connectivity,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;start a trailing stop directly or through a named profile.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Profiles are useful once you repeatedly trade the same market or strategy pattern. Instead of passing every detail on the command line each time, you define the profile once and then override only the values you want to change, such as &lt;code&gt;--stoplosslimit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The example above starts a trailing stop on &lt;code&gt;BTCUSDC&lt;/code&gt; with a 1% stop-loss limit on &lt;code&gt;binance.com&lt;/code&gt;. The profile example starts the predefined &lt;code&gt;BTCUSDC_SELL&lt;/code&gt; setup and overrides the stop-loss limit to 1.5%.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--cancelopenorders&lt;/code&gt; is a practical cleanup command when you intentionally want to cancel all currently open orders on the configured account/exchange before starting fresh. Use it deliberately — it does exactly what the name says.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python integration
&lt;/h3&gt;

&lt;p&gt;UBTSL can also be used from Python when the trailing stop should be part of a larger bot or service. The exact parameters depend on the trade direction, market, profile, and execution mode you want to use, so the official example should be treated as the reference implementation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-trailing-stop-loss/blob/master/example_binance_trailing_stop_loss.py" rel="noopener noreferrer"&gt;example_binance_trailing_stop_loss.py&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The important architectural point is this: UBTSL is not just a small formula that calculates a moving stop price. It is an engine around Binance execution state. It tracks the market, updates the stop logic, reacts to partial fills and finished orders, and gives you callbacks for operational handling.&lt;/p&gt;

&lt;p&gt;A minimal SDK integration usually follows this shape:&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;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_binance_trailing_stop_loss.manager&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinanceTrailingStopLossManager&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;callback_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;ERROR: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error_msg&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;callback_finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;FINISHED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;callback_partially_filled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;PARTIALLY FILLED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;BinanceTrailingStopLossManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTCUSDC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stop_loss_limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.5%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;callback_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;callback_error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;callback_finished&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;callback_finished&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;callback_partially_filled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;callback_partially_filled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ubtsl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ubtsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_manager_stopping&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&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;Gracefully stopping ...&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;For a production bot, I would not paste this blindly and call it done. I would start from the official example, wire the callbacks into your own logging/alerting, and make sure the account, market, order side, and stop-loss behavior match your intended execution model.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Stop Parsing Raw Binance JSON by Hand (UnicornFy)
&lt;/h2&gt;

&lt;p&gt;Binance's raw WebSocket frames are compact and cryptic. Here's a kline update straight off the wire:&lt;br&gt;
&lt;/p&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="nl"&gt;"stream"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"btcusdc@kline_1m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"kline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"E"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1778563770000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"BTCUSDC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"k"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"t"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1778563740000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"T"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1778563799999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"BTCUSDC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"i"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"o"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"81251.35"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"81292.61"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"81293.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"81250.61"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"v"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1.42442"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"n"&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="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"115789.12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"V"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"0.81"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"Q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"65872.55"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"0"&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;p&gt;Single-letter keys. Nested envelopes. Easy to mis-parse, hard to read at a glance. UnicornFy turns that into:&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;from&lt;/span&gt; &lt;span class="n"&gt;unicorn_fy.unicorn_fy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UnicornFy&lt;/span&gt;
&lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UnicornFy&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;binance_com_websocket&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream_type&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;btcusdc@kline_1m&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;event_type&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;kline&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;event_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1778563770000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;symbol&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;BTCUSDC&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;kline&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kline_start_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1778563740000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kline_close_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1778563799999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;symbol&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;BTCUSDC&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;interval&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;1m&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;open_price&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;81251.35&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;close_price&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;81292.61&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;high_price&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;81293.00&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;low_price&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;81250.61&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;base_volume&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;1.42442&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;number_of_trades&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_closed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&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;quote&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;115789.12&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;taker_by_base_asset_volume&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;0.81&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;taker_by_quote_asset_volume&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;65872.55&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You usually don't call UnicornFy directly — pass &lt;code&gt;output_default="UnicornFy"&lt;/code&gt; to UBWA and every frame that lands in your buffer is already normalized.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scaling Beyond a Single Process: UBDCC
&lt;/h2&gt;

&lt;p&gt;A single UBLDC process can handle many markets. The moment you need &lt;strong&gt;redundancy&lt;/strong&gt; or &lt;strong&gt;multiple consumers&lt;/strong&gt;, the order book should stop living inside one bot process.&lt;/p&gt;

&lt;p&gt;UBDCC turns UBLDC into a shared service. You run the cluster once, create DepthCaches there, and every bot, dashboard, or service reads the same synchronized order-book source over HTTP. Locally, the REST API listens on port &lt;code&gt;42081&lt;/code&gt;; in Kubernetes, it is exposed through the &lt;code&gt;ubdcc-restapi&lt;/code&gt; service, usually on port &lt;code&gt;80&lt;/code&gt; behind a LoadBalancer.&lt;/p&gt;

&lt;p&gt;Quick local start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ubdcc
ubdcc start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create redundant DepthCaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'http://127.0.0.1:42081/create_depthcaches'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"exchange": "binance.com", "markets": ["BTCUSDC", "ETHUSDT", "BNBUSDC"], "desired_quantity": 2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Query the order book via REST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'http://127.0.0.1:42081/get_asks?exchange=binance.com&amp;amp;market=BTCUSDC&amp;amp;limit_count=5'&lt;/span&gt;
curl &lt;span class="s1"&gt;'http://127.0.0.1:42081/get_bids?exchange=binance.com&amp;amp;market=BTCUSDC&amp;amp;limit_count=5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important point is the URL shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/get_asks?exchange=binance.com&amp;amp;market=BTCUSDC&amp;amp;limit_count=5
/get_bids?exchange=binance.com&amp;amp;market=BTCUSDC&amp;amp;threshold_volume=100000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UBDCC exposes synchronized order-book data through explicit REST endpoints such as &lt;code&gt;/get_asks&lt;/code&gt; and &lt;code&gt;/get_bids&lt;/code&gt;. For normal consumers, the response stays focused on the requested book side. When you need operational details, &lt;code&gt;debug=true&lt;/code&gt; adds routing and timing metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'http://127.0.0.1:42081/get_asks?exchange=binance.com&amp;amp;market=BTCUSDC&amp;amp;limit_count=2&amp;amp;debug=true'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UBDCC consists of three component types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;mgmt&lt;/strong&gt; on &lt;code&gt;42080&lt;/code&gt;: cluster state and DepthCache distribution,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;restapi&lt;/strong&gt; on &lt;code&gt;42081&lt;/code&gt; locally / &lt;code&gt;80&lt;/code&gt; in Kubernetes: the endpoint your clients call,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DCN&lt;/strong&gt; processes from &lt;code&gt;42082&lt;/code&gt; upward: the workers running the actual UBLDC DepthCaches.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your client calls &lt;code&gt;restapi&lt;/code&gt;. It routes reads to the responsible DCN and management operations to &lt;code&gt;mgmt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two posts dive into UBDCC in detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.technopathy.club/ubdcc-deep-dive-building-a-trust-layer-for-binance-order-books" rel="noopener noreferrer"&gt;UBDCC Deep-Dive: Building a Trust Layer for Binance Order Books&lt;/a&gt; — architecture, why it exists, what problem it solves.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.technopathy.club/from-pip-install-to-a-redundant-binance-order-book-cluster-ubdcc-dashboard-quickstart" rel="noopener noreferrer"&gt;From &lt;code&gt;pip install&lt;/code&gt; to a Redundant Binance Order Book Cluster — UBDCC + Dashboard Quickstart&lt;/a&gt; — a working cluster in minutes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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




&lt;h2&gt;
  
  
  What "Production-Grade" Actually Means
&lt;/h2&gt;

&lt;p&gt;Most articles compare libraries on &lt;strong&gt;what they do&lt;/strong&gt;. The ones that decide whether your bot survives a year compare on &lt;strong&gt;what they handle when things go wrong&lt;/strong&gt;. Here's the practical checklist that separates a weekend project from a service:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;python-binance&lt;/th&gt;
&lt;th&gt;binance-connector / official SDKs&lt;/th&gt;
&lt;th&gt;CCXT&lt;/th&gt;
&lt;th&gt;UBS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Automatic WebSocket reconnect&lt;/td&gt;
&lt;td&gt;Partial / manager-dependent&lt;/td&gt;
&lt;td&gt;Low-level / DIY&lt;/td&gt;
&lt;td&gt;Available in CCXT Pro / exchange-dependent&lt;/td&gt;
&lt;td&gt;Yes, managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket API trading requests&lt;/td&gt;
&lt;td&gt;Recent support&lt;/td&gt;
&lt;td&gt;Yes, official SDK direction&lt;/td&gt;
&lt;td&gt;Exchange-dependent / Pro&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes — integrated into UBWA manager&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request-specific WS API callbacks&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;SDK-style / DIY routing&lt;/td&gt;
&lt;td&gt;Abstraction-dependent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple WS API streams&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;Abstraction-dependent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes — via stream IDs / labels&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket sequence-gap detection (depth)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (validates &lt;code&gt;U&lt;/code&gt;/&lt;code&gt;u&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Explicit out-of-sync error surface&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes —&lt;/strong&gt; &lt;code&gt;DepthCacheOutOfSync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orphaned depth-level pruning&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-data listenKey auto-renew&lt;/td&gt;
&lt;td&gt;Yes (less robust)&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Yes, robust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subscribe at runtime without reconnect&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native asyncio &lt;code&gt;await&lt;/code&gt; queue&lt;/td&gt;
&lt;td&gt;No decoupled backpressure-aware queue&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Mixed&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-account routing&lt;/td&gt;
&lt;td&gt;Separate clients / application routing&lt;/td&gt;
&lt;td&gt;Separate clients / application routing&lt;/td&gt;
&lt;td&gt;Separate clients / abstraction-dependent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Integrated routing via stream IDs / labels&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native/Cython components with multi-arch wheels&lt;/td&gt;
&lt;td&gt;N/A / mostly pure Python&lt;/td&gt;
&lt;td&gt;N/A / mostly pure Python&lt;/td&gt;
&lt;td&gt;N/A / pure Python&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes — x86_64, aarch64, arm64&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection-state observability&lt;/td&gt;
&lt;td&gt;Limited / application-level&lt;/td&gt;
&lt;td&gt;Low-level / application-level&lt;/td&gt;
&lt;td&gt;Exchange-dependent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Built-in: stream lifecycle signals, per-stream labels, reconnect visibility, and stream-scoped log context&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster-scale option&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;UBDCC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not only for large desks. Beginners benefit from stable defaults too. A small bot is not better because its WebSocket handling is fragile, and &lt;code&gt;python-binance&lt;/code&gt; is not automatically simpler just because it ranks first. The practical reason to look at UBS is that it makes many failure modes explicit before they become your problem.&lt;/p&gt;




&lt;h3&gt;
  
  
  Trust and installation notes
&lt;/h3&gt;

&lt;p&gt;UNICORN Binance Suite is MIT-licensed open source. Install from PyPI or the official GitHub repositories under &lt;code&gt;oliver-zehentleitner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There have been fraudulent repositories impersonating UBWA with malware payloads, so avoid random forks, ZIP downloads, or similarly named projects. The official package names are listed above.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Go from Here
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build something:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Stream market data → Kafka, ready for downstream processing: &lt;a href="https://blog.technopathy.club/passing-binance-market-data-to-apache-kafka-in-python-with-aiokafka" rel="noopener noreferrer"&gt;Passing Binance Market Data to Apache Kafka in Python with aiokafka&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Atomic OCO take-profit + stop-loss: &lt;a href="https://blog.technopathy.club/buy-an-asset-and-instantly-create-a-take-profit-and-stop-loss-oco-sell-order-using-python-in-binance-isolated-margin" rel="noopener noreferrer"&gt;Buy an Asset and Instantly Create a Take-Profit + Stop-Loss OCO Sell Order&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run a redundant order-book cluster: &lt;a href="https://blog.technopathy.club/from-pip-install-to-a-redundant-binance-order-book-cluster-ubdcc-dashboard-quickstart" rel="noopener noreferrer"&gt;UBDCC + Dashboard Quickstart&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Understand the internals:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why a "correct" depth cache rots if you follow the spec: &lt;a href="https://blog.technopathy.club/your-binance-depthcache-is-rotting-here-s-the-proof-in-25-hours" rel="noopener noreferrer"&gt;Your Binance DepthCache Is Rotting&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What UBDCC actually does, architecturally: &lt;a href="https://blog.technopathy.club/ubdcc-deep-dive-building-a-trust-layer-for-binance-order-books" rel="noopener noreferrer"&gt;UBDCC Deep-Dive&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Binance API security model and where it leaks: &lt;a href="https://blog.technopathy.club/binance-fixed-the-ip-whitelist-gap-the-disclosure-process-is-still-broken" rel="noopener noreferrer"&gt;Binance Fixed the IP Whitelist Gap. The Disclosure Process Is Still Broken&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Docs and source:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;UBWA: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UBRA: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-rest-api" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-rest-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UBLDC: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-local-depth-cache" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-local-depth-cache" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UBTSL: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-trailing-stop-loss" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-trailing-stop-loss" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UnicornFy: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-fy" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-fy" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UBDCC: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-depth-cache-cluster/" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-depth-cache-cluster" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suite meta-package: &lt;a href="https://oliver-zehentleitner.github.io/unicorn-binance-suite" rel="noopener noreferrer"&gt;docs&lt;/a&gt; · &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-suite" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Talk to humans:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Telegram: &lt;a href="https://t.me/unicorndevs" rel="noopener noreferrer"&gt;&lt;strong&gt;t.me/unicorndevs&lt;/strong&gt;&lt;/a&gt; — the answer to most questions is one message away.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub Discussions on any of the repos above.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;python-binance&lt;/code&gt;, the official Binance SDKs, and &lt;code&gt;CCXT&lt;/code&gt; are useful tools. They exist for real reasons. But UBS is built around a different premise: a Binance bot should not only be able to call endpoints — it should understand stream lifecycle, reconnects, order-book trust, out-of-sync states, WebSocket API routing, and failure surfaces from the beginning.&lt;/p&gt;

&lt;p&gt;That is useful for production systems, but it is also useful for beginners. Starting small does not mean starting fragile. A stable library is not overkill just because your first script has 50 lines.&lt;/p&gt;

&lt;p&gt;If you are building anything Binance-specific in Python, try the suite once. The install is one line. The list of things you no longer have to reinvent is the rest of this article.&lt;/p&gt;

&lt;p&gt;Either way: name the failure modes before you ship. The libraries that make those states visible are the ones you want under your code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This guide will be expanded into a series of deep-dives — WebSocket API request routing, WebSocket reconnect internals,&lt;/em&gt; &lt;code&gt;stream_signals&lt;/code&gt;&lt;em&gt;, the&lt;/em&gt; &lt;code&gt;high_performance&lt;/code&gt; &lt;em&gt;flag, OCO order patterns, UBDCC cluster architecture, and more. Subscribe to the&lt;/em&gt; &lt;a href="https://blog.technopathy.club/series/unicorn-binance-suite" rel="noopener noreferrer"&gt;&lt;em&gt;UNICORN Binance Suite&lt;/em&gt;&lt;/a&gt; &lt;em&gt;series to catch each one as it lands.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I hope you found this informative and useful.&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://www.binance.com/en/square/profile/oliver-zehentleitner" rel="noopener noreferrer"&gt;Binance Square&lt;/a&gt;, &lt;a href="https://github.com/oliver-zehentleitner" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://burningboard.net/@oliverzehentleitner" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, &lt;a href="https://x.com/unicorn_oz" rel="noopener noreferrer"&gt;X&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/oliver-zehentleitner/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, or join &lt;a href="https://t.me/unicorndevs" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; for updates on my latest publications. Constructive feedback is always appreciated.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and happy coding! ¯\_(ツ)_/¯&lt;/p&gt;

</description>
      <category>python</category>
      <category>cryptocurrency</category>
      <category>api</category>
    </item>
    <item>
      <title>Keep the Why: Code Becomes Legacy When Nobody Remembers Why</title>
      <dc:creator>Oliver Zehentleitner</dc:creator>
      <pubDate>Sat, 11 Jul 2026 06:47:39 +0000</pubDate>
      <link>https://dev.to/oliverzehentleitner/keep-the-why-code-becomes-legacy-when-nobody-remembers-why-47jp</link>
      <guid>https://dev.to/oliverzehentleitner/keep-the-why-code-becomes-legacy-when-nobody-remembers-why-47jp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep a Changelog records what changed. Keep the Why preserves why it changed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;I turned four months of working with AI coding agents into an open-source skill for preserving the reasoning behind a codebase.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've been maintaining the &lt;a href="https://blog.technopathy.club/page/unicorn-binance-suite" rel="noopener noreferrer"&gt;UNICORN Binance Suite&lt;/a&gt; since 2019. It is a set of open-source Python packages for building automated trading systems on Binance, and parts of it have been running in production for years.&lt;/p&gt;

&lt;p&gt;For the last few months, I have also been working with an AI coding agent on these projects every day.&lt;/p&gt;

&lt;p&gt;Early on, I invested quite a bit of time into the harness around it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;conventions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;project structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;persistent context&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;documentation the agent could actually use&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rules for how it should work inside a mature codebase&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That effort paid off.&lt;/p&gt;

&lt;p&gt;Today I can point the agent at a piece of code and ask why something looks the way it does. In many cases, it can answer correctly without guessing.&lt;/p&gt;

&lt;p&gt;Not because the model somehow remembers seven years of development history. It does not.&lt;/p&gt;

&lt;p&gt;It can answer because the reasoning is still present in the repository.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;The more I worked with this setup, the more obvious something became:&lt;/p&gt;

&lt;p&gt;If structured context makes an AI agent useful in a codebase it did not grow up with, the same context should also help a human developer entering that project later.&lt;/p&gt;

&lt;p&gt;A new developer should not have to reverse-engineer every strange retry loop, compatibility workaround or architectural boundary from the code alone. They should be able to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why is this retry logic so defensive?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why are we not using the obvious library?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why does this component wait for a snapshot before processing buffered events?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What broke the last time somebody simplified this?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And ideally, the answer should already live with the project.&lt;/p&gt;

&lt;p&gt;That is the idea behind &lt;strong&gt;Keep the Why&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Tests preserve expected behaviour.&lt;/p&gt;

&lt;p&gt;Git preserves changes.&lt;/p&gt;

&lt;p&gt;Issue trackers preserve discussions, sometimes.&lt;/p&gt;

&lt;p&gt;What often disappears is the reasoning behind the final implementation.&lt;/p&gt;

&lt;p&gt;That creates a few very familiar problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-debate
&lt;/h3&gt;

&lt;p&gt;A team discusses the same architecture question again because nobody remembers that it was already settled eighteen months ago.&lt;/p&gt;

&lt;p&gt;The previous decision may still be correct. The reasons are simply gone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Silent regression
&lt;/h3&gt;

&lt;p&gt;Somebody finds a workaround that looks unnecessary and cleans it up.&lt;/p&gt;

&lt;p&gt;Unfortunately, it was not unnecessary. It was the fix for a bug nobody documented properly.&lt;/p&gt;

&lt;p&gt;The code looked ugly because reality was ugly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onboarding stall
&lt;/h3&gt;

&lt;p&gt;A new developer sees code they do not understand and avoids touching it.&lt;/p&gt;

&lt;p&gt;That is usually a reasonable decision. Changing unfamiliar code without context is how repeat incidents are born.&lt;/p&gt;

&lt;p&gt;AI coding agents have the same problem, only faster. A fresh session starts with little or no project history. Without preserved rationale, the agent either spends time reconstructing it or confidently proposes the exact approach that already failed once.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not a new problem
&lt;/h2&gt;

&lt;p&gt;Architecture Decision Records have existed for years, and they are useful.&lt;/p&gt;

&lt;p&gt;But they require somebody to notice that a decision deserves an ADR, stop the current work and document it deliberately. Large architectural choices may get that treatment. Smaller constraints often do not.&lt;/p&gt;

&lt;p&gt;Those smaller decisions are frequently the ones that become dangerous later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a defensive timeout&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;an odd startup sequence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a compatibility branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a strange cache invalidation rule&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a library that was evaluated and rejected&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a workaround linked to a production incident&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are too small for ceremony and too important to forget.&lt;/p&gt;

&lt;p&gt;The important change is not that reasoning suddenly became valuable.&lt;/p&gt;

&lt;p&gt;The change is that an AI agent already participates in many of the conversations where that reasoning appears. Capturing it no longer has to be a completely separate documentation task.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Keep the Why is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://keepthewhy.com/" rel="noopener noreferrer"&gt;Keep the Why&lt;/a&gt; is an open-source agent skill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fuploads%2Fcovers%2F69d4b99a5da14bc70e00d4f6%2F066f1c95-1ec4-48ab-bd8a-96b39d3ca8c6.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fuploads%2Fcovers%2F69d4b99a5da14bc70e00d4f6%2F066f1c95-1ec4-48ab-bd8a-96b39d3ca8c6.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is a &lt;code&gt;SKILL.md&lt;/code&gt; file with supporting references and examples, based on the open Agent Skills format. There is no service, database, account or MCP server behind it.&lt;/p&gt;

&lt;p&gt;It teaches a coding agent four related workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Continuous capture
&lt;/h3&gt;

&lt;p&gt;During normal development, the agent notices when a conversation contains useful rationale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;an architectural choice&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a rejected alternative&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a production constraint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;an incident finding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;an intentional workaround&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a behaviour that looks strange but is deliberate&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It then updates the relevant project context at a natural checkpoint.&lt;/p&gt;

&lt;p&gt;The goal is not to document every line of code. That would just create a second codebase, only written in Markdown.&lt;/p&gt;

&lt;p&gt;The goal is to preserve the parts that are not obvious from the implementation itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Retrospective recovery
&lt;/h3&gt;

&lt;p&gt;The skill can also be applied to an existing repository.&lt;/p&gt;

&lt;p&gt;The agent inspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;git history&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;issues&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;pull requests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;existing documentation&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It reconstructs what the available evidence supports and clearly marks what remains uncertain.&lt;/p&gt;

&lt;p&gt;It should not invent a clean historical narrative just because that would look nice in a document.&lt;/p&gt;

&lt;p&gt;Sometimes the honest result is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We know what this does. We do not yet know why it was designed this way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is useful information too.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Knowledge-transfer interviews
&lt;/h3&gt;

&lt;p&gt;This is the part I find especially interesting.&lt;/p&gt;

&lt;p&gt;Before a long-term maintainer changes teams, leaves or retires, the agent can first analyse the repository and identify areas where the reasoning is missing.&lt;/p&gt;

&lt;p&gt;It can then prepare focused questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does this synchronization process wait for the snapshot before applying buffered updates?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please explain the synchronization system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first question has a chance of recovering useful knowledge. The second usually produces a meeting nobody wants to attend.&lt;/p&gt;

&lt;p&gt;For broad, mostly tacit knowledge, the process can also work the other way around: let the maintainer explain the history in their own words, then extract decisions, constraints and open questions from the conversation.&lt;/p&gt;

&lt;p&gt;The important part is that the result becomes project knowledge, not another recording nobody will ever watch again.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Maintenance
&lt;/h3&gt;

&lt;p&gt;Documentation can become legacy too.&lt;/p&gt;

&lt;p&gt;So the skill also defines how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;update existing topic files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;resolve contradictions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;mark old decisions as superseded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;split files before they become too large&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;keep indexes lean enough for humans and agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;avoid creating five documents for one small decision&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is living documentation, not an archive of frozen decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The structure
&lt;/h2&gt;

&lt;p&gt;Keep the Why deliberately separates two kinds of project knowledge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
context/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;docs/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I use, operate, test, deploy or troubleshoot this project?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;installation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;configuration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API usage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;deployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;troubleshooting&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;context/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is the project built this way?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;architectural rationale&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rejected alternatives&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;historical constraints&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;incident learnings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;compatibility decisions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;deliberate workarounds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;superseded approaches&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both layers are plain Markdown and versioned with the repository.&lt;/p&gt;

&lt;p&gt;There is no separate AI-only knowledge store waiting to drift away from the human documentation.&lt;/p&gt;

&lt;p&gt;The context is organised by topic, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;context/
├── index.md
├── architecture.md
├── synchronization.md
├── compatibility.md
└── incidents.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer this over a file-by-file shadow tree because decisions often span several files and survive refactors.&lt;/p&gt;

&lt;p&gt;I also prefer it over one file per decision for smaller, evolving topics. Formal ADRs still make sense where they fit. Keep the Why is not trying to ban them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like in practice
&lt;/h2&gt;

&lt;p&gt;Imagine a normal implementation discussion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: The simpler retry mechanism caused duplicate orders during
     reconnects. Keep the stateful version even though it looks
     more complicated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not just an implementation detail.&lt;/p&gt;

&lt;p&gt;It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the rejected alternative&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the reason it was rejected&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the failure mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the constraint future maintainers must preserve&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent should recognise that and update the relevant topic in &lt;code&gt;context/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Six months later, somebody finds the code and thinks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This looks over-engineered. I can simplify it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Chesterton's Fence, except this time the fence has a sign on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that matters most
&lt;/h2&gt;

&lt;p&gt;The core rule of Keep the Why is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never invent rationale.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Plausible-sounding historical explanations are worse than missing documentation. A blank page creates caution. A confident false explanation creates bad decisions.&lt;/p&gt;

&lt;p&gt;Each relevant rationale entry should make clear whether its evidence is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;confirmed&lt;/strong&gt; — supported by a maintainer or authoritative project evidence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;inferred&lt;/strong&gt; — reasonably derived, but not confirmed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;unknown&lt;/strong&gt; — the available evidence is insufficient&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separately, an entry can be marked as &lt;strong&gt;superseded&lt;/strong&gt; when it was once valid but has since been replaced.&lt;/p&gt;

&lt;p&gt;This distinction matters: evidence confidence and temporal status are two different things.&lt;/p&gt;

&lt;p&gt;This is not decoration.&lt;/p&gt;

&lt;p&gt;It is the difference between useful project knowledge and hallucination wearing documentation's clothes.&lt;/p&gt;

&lt;p&gt;The second important rule is proportionality.&lt;/p&gt;

&lt;p&gt;A self-explanatory decision may need one sentence.&lt;/p&gt;

&lt;p&gt;A surprising architecture boundary may need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;context&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;decision&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;alternatives&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;consequences&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;evidence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;conditions under which it should be revisited&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every decision deserves a ceremony. Not every strange-looking line deserves to be forgotten either.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it relates to existing approaches
&lt;/h2&gt;

&lt;p&gt;Keep the Why is not a replacement for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;README files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CONTRIBUTING.md&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ADRs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;issue trackers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://keepachangelog.com/" rel="noopener noreferrer"&gt;Keep a Changelog&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The name is deliberately related to Keep a Changelog.&lt;/p&gt;

&lt;p&gt;Keep a Changelog records &lt;strong&gt;what changed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep the Why preserves &lt;strong&gt;why it changed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There is also prior work in this space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Architecture Decision Records&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/hexapode/git-why" rel="noopener noreferrer"&gt;git-why&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/addyosmani/agent-skills/blob/main/skills/documentation-and-adrs/SKILL.md" rel="noopener noreferrer"&gt;Addy Osmani's &lt;code&gt;documentation-and-adrs&lt;/code&gt; skill&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/me2resh/agent-decision-record" rel="noopener noreferrer"&gt;Agent Decision Records (AgDR)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;repository-memory and agent-context tools&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not invent the idea that software decisions should be documented.&lt;/p&gt;

&lt;p&gt;What I wanted was a practical combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;continuous capture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;retrospective recovery&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;code-guided knowledge-transfer interviews&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;topic-based living documentation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;repository-native storage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no required external platform&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination grew out of how I was already working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the project stands
&lt;/h2&gt;

&lt;p&gt;The underlying practice is not completely new to me.&lt;/p&gt;

&lt;p&gt;I have been testing variations of this approach in my own AI-assisted development workflow for roughly four months.&lt;/p&gt;

&lt;p&gt;But the public project is not a copy of that private setup.&lt;/p&gt;

&lt;p&gt;It is a new incarnation of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;cleaned up&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;generalised&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;made cross-agent&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;turned into an explicit method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;separated from my own repository conventions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;packaged as an open-source skill&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means it now has to prove itself in real use — and mature through it.&lt;/p&gt;

&lt;p&gt;The initial structure looks reasonable to me. The real test is what happens across different repositories, teams and agents.&lt;/p&gt;

&lt;p&gt;I expect some parts to change.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When does the agent capture too much?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When does it ask too little?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which structure works for a small library and which one works for a large multi-repository system?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How much classification is useful before it becomes bureaucracy?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When should a topic be split?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we keep old rationale from becoming trusted but stale?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a small but relevant body of supporting research. &lt;a href="https://arxiv.org/abs/2601.21116" rel="noopener noreferrer"&gt;A 2026 position paper&lt;/a&gt; audited 62 architectural decisions across two internal projects and found that roughly 23% had stale supporting evidence within two months. The sample is small and the result is not a universal law, but it supports something maintainers already know: documentation does not stay correct by existing. It has to be maintained.&lt;/p&gt;

&lt;p&gt;I do not yet have automated cross-agent eval results or a published before-and-after study.&lt;/p&gt;

&lt;p&gt;The eval cases exist. The public evidence does not, yet.&lt;/p&gt;

&lt;p&gt;That is the honest state of the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add oliver-zehentleitner/keep-the-why
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or inspect and install it through GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh skill preview oliver-zehentleitner/keep-the-why keep-the-why
gh skill &lt;span class="nb"&gt;install &lt;/span&gt;oliver-zehentleitner/keep-the-why keep-the-why
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is instructions only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;no scripts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no network calls of its own&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no external service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no database&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Documentation and manual installation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keepthewhy.com/" rel="noopener noreferrer"&gt;keepthewhy.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source, license and the actual skill:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/oliver-zehentleitner/keep-the-why" rel="noopener noreferrer"&gt;github.com/oliver-zehentleitner/keep-the-why&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback is welcome
&lt;/h2&gt;

&lt;p&gt;Keep the Why is young.&lt;/p&gt;

&lt;p&gt;The base is there, but the method now needs real use outside my own projects.&lt;/p&gt;

&lt;p&gt;I am especially interested in feedback from people working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;mature codebases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;long-running production systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AI coding agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;developer onboarding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;knowledge transfer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;maintainers who have inherited code nobody wants to touch&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bug reports are useful.&lt;/p&gt;

&lt;p&gt;Conceptual criticism is even more useful.&lt;/p&gt;

&lt;p&gt;If the structure is wrong for your project, I want to know why. If an important workflow is missing, propose it. If another project already solves part of this better, point me to it.&lt;/p&gt;

&lt;p&gt;The project is open source because I do not think this should become another private knowledge silo.&lt;/p&gt;

&lt;p&gt;The whole point is to keep the reasoning with the code.&lt;/p&gt;

&lt;p&gt;Because “ask Bob” is not documentation.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>documentation</category>
      <category>agents</category>
      <category>legacy</category>
    </item>
    <item>
      <title>Your Binance L2 Order Book Can Be Gap-Free and Still Be Wrong</title>
      <dc:creator>Oliver Zehentleitner</dc:creator>
      <pubDate>Thu, 11 Jun 2026 11:51:41 +0000</pubDate>
      <link>https://dev.to/oliverzehentleitner/your-binance-l2-order-book-can-be-gap-free-and-still-be-wrong-1kk8</link>
      <guid>https://dev.to/oliverzehentleitner/your-binance-l2-order-book-can-be-gap-free-and-still-be-wrong-1kk8</guid>
      <description>&lt;p&gt;A Binance order book looks simple until you try to keep one correct for hours, days, or weeks.&lt;/p&gt;

&lt;p&gt;At first, the task appears straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;subscribe to Binance depth updates over WebSocket,&lt;/li&gt;
&lt;li&gt;fetch an order book snapshot over REST,&lt;/li&gt;
&lt;li&gt;apply every update in sequence,&lt;/li&gt;
&lt;li&gt;expose the resulting bids and asks to your strategy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is enough to produce something that &lt;em&gt;looks&lt;/em&gt; like a live Binance L2 order book.&lt;/p&gt;

&lt;p&gt;It is not enough to prove that the book is correct.&lt;/p&gt;

&lt;p&gt;A local order book can have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no detected sequence gap,&lt;/li&gt;
&lt;li&gt;a healthy WebSocket connection,&lt;/li&gt;
&lt;li&gt;plausible best bids and asks,&lt;/li&gt;
&lt;li&gt;valid-looking quantities,&lt;/li&gt;
&lt;li&gt;and thousands of price levels that no longer exist on Binance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article covers the full lifecycle of a trustworthy Binance order book: initialization, gap detection, retention, resynchronization, observability, redundancy, and the point where an in-process cache should become shared infrastructure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A wrong order book is worse than no order book. No data stops you. Bad data lies to you.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h2&gt;
  
  
  What is a Binance L2 order book?
&lt;/h2&gt;

&lt;p&gt;A Level 2, or L2, order book represents aggregated liquidity at individual price levels.&lt;/p&gt;

&lt;p&gt;For each side of the market, it contains pairs such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;price, quantity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&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;"bids"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"104250.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.842"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"104250.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.307"&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="nl"&gt;"asks"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"104250.20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.514"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"104250.30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.191"&lt;/span&gt;&lt;span class="p"&gt;]&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;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;p&gt;The highest bid and lowest ask form the top of book.&lt;/p&gt;

&lt;p&gt;The full price ladder is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;spread and slippage calculations,&lt;/li&gt;
&lt;li&gt;market-depth analysis,&lt;/li&gt;
&lt;li&gt;liquidity monitoring,&lt;/li&gt;
&lt;li&gt;order-flow research,&lt;/li&gt;
&lt;li&gt;market making,&lt;/li&gt;
&lt;li&gt;arbitrage,&lt;/li&gt;
&lt;li&gt;execution planning,&lt;/li&gt;
&lt;li&gt;and trading-system risk controls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Binance does not continuously send a complete order book to every client. It gives you separate pieces that your application must combine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Binance actually gives you
&lt;/h2&gt;

&lt;p&gt;To construct a local Binance order book, you normally use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a REST depth snapshot,&lt;/li&gt;
&lt;li&gt;a WebSocket diff-depth stream.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The REST response gives you a bounded view of the order book at a specific &lt;code&gt;lastUpdateId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The WebSocket stream then sends incremental changes containing fields such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U  first update ID in the event
u  final update ID in the event
pu previous event's final update ID on relevant futures streams
b  bid updates
a  ask updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code is responsible for turning those two independent data sources into one coherent state.&lt;/p&gt;

&lt;p&gt;That requires more than applying JSON messages to a dictionary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first trap: the snapshot race condition
&lt;/h2&gt;

&lt;p&gt;A common implementation does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch snapshot
connect WebSocket
apply updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That ordering is unsafe.&lt;/p&gt;

&lt;p&gt;Updates can occur after the snapshot was created but before the WebSocket subscription becomes active. Those updates are lost, and the local Binance order book starts with a silent gap.&lt;/p&gt;

&lt;p&gt;The safer sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connect WebSocket
buffer depth events
fetch REST snapshot
discard obsolete buffered events
find the first event that continues from the snapshot
replay the remaining buffer
continue with live updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually:&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="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="nf"&gt;start_depth_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;on_event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_depth_snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;last_update_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lastUpdateId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;buffer&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u&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="n"&gt;last_update_id&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;first_event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_first_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;U&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="n"&gt;last_update_id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u&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="nf"&gt;apply_snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snapshot&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;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_event&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
    &lt;span class="nf"&gt;apply_depth_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact protocol differs slightly between Binance Spot and Futures, so do not blindly reuse a Spot implementation for Futures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequence continuity is a trust boundary
&lt;/h2&gt;

&lt;p&gt;Once the Binance order book is synchronized, every event must continue the sequence you already processed.&lt;/p&gt;

&lt;p&gt;For Spot, the steady-state check is commonly based on the next expected update ID:&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;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;U&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;last_update_id&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;request_full_resync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For relevant Futures streams, Binance provides &lt;code&gt;pu&lt;/code&gt;, which references the previous event:&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;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pu&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;last_update_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;request_full_resync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After validation:&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="nf"&gt;apply_updates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;last_update_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u&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;A broken sequence is not merely a warning.&lt;/p&gt;

&lt;p&gt;It means your local order book no longer has a proven relationship to the exchange state.&lt;/p&gt;

&lt;p&gt;Do not log the problem and keep serving the same book. Mark it as out of sync, stop trusting it, and initialize it again from a fresh snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying bid and ask updates
&lt;/h2&gt;

&lt;p&gt;Each depth event contains price-level changes.&lt;/p&gt;

&lt;p&gt;The basic rule is:&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;apply_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&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;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;price&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;quantity&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&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;quantity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&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;book&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part is easy.&lt;/p&gt;

&lt;p&gt;The dangerous assumption is that correct update application plus correct sequence validation guarantees a correct long-running Binance order book.&lt;/p&gt;

&lt;p&gt;It does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second trap: a gap-free order book can still rot
&lt;/h2&gt;

&lt;p&gt;While maintaining the UNICORN Binance Local Depth Cache, I investigated a &lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-local-depth-cache/issues/45" rel="noopener noreferrer"&gt;report that bids and asks kept growing beyond their expected size&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;started from a valid snapshot,&lt;/li&gt;
&lt;li&gt;processed updates in order,&lt;/li&gt;
&lt;li&gt;removed levels when Binance sent quantity &lt;code&gt;0&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and detected broken update continuity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It still accumulated stale price levels.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;A bounded REST snapshot defines the initial view your cache can validate. The diff stream can later introduce price levels outside the active region that your application intends to maintain.&lt;/p&gt;

&lt;p&gt;A naive implementation inserts every streamed level and removes it only when a future update explicitly sets its quantity to zero.&lt;/p&gt;

&lt;p&gt;But a reliable cleanup event does not necessarily arrive for every price level your cache has collected. Levels can move outside the bounded region you are validating and remain in local memory indefinitely.&lt;/p&gt;

&lt;p&gt;The result is a growing archive of plausible-looking historical price levels.&lt;/p&gt;

&lt;p&gt;I call them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;orphaned levels,&lt;/li&gt;
&lt;li&gt;ghost levels,&lt;/li&gt;
&lt;li&gt;or ghost orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are especially dangerous because they do not look corrupted.&lt;/p&gt;

&lt;p&gt;A stale level such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;104000.00 BTCUSDT bid quantity 0.73
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;looks completely reasonable.&lt;/p&gt;

&lt;p&gt;Your best bid and best ask may still be correct while deeper liquidity, cumulative volume, order-book shape, and slippage estimates are increasingly wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a 25-hour Binance order book test showed
&lt;/h2&gt;

&lt;p&gt;To isolate this behavior, I ran two BTCUSDT depth caches side by side for 25.10 hours.&lt;/p&gt;

&lt;p&gt;Both received the same WebSocket data and were audited against REST snapshots at the same times.&lt;/p&gt;

&lt;p&gt;The only relevant difference was retention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;naive cache&lt;/strong&gt;: apply updates and delete only on &lt;code&gt;quantity == 0&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fixed cache&lt;/strong&gt;: apply the same updates but actively prune the maintained book back to its intended top-1000 corridor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BTC moved only 1.88% during the test window. This was a calm market, not a flash crash or extreme volatility event.&lt;/p&gt;

&lt;p&gt;At the final audit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Local bids&lt;/th&gt;
&lt;th&gt;Local asks&lt;/th&gt;
&lt;th&gt;Bid levels matching REST&lt;/th&gt;
&lt;th&gt;Ask levels matching REST&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Naive&lt;/td&gt;
&lt;td&gt;20,758&lt;/td&gt;
&lt;td&gt;9,116&lt;/td&gt;
&lt;td&gt;24.09%&lt;/td&gt;
&lt;td&gt;39.82%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pruned&lt;/td&gt;
&lt;td&gt;1,011&lt;/td&gt;
&lt;td&gt;1,078&lt;/td&gt;
&lt;td&gt;87.83%&lt;/td&gt;
&lt;td&gt;91.74%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The naive Binance order book started almost perfectly aligned.&lt;/p&gt;

&lt;p&gt;Then it rotted.&lt;br&gt;
&lt;a href="https://oliver-zehentleitner.github.io/binance-depthcache-forensics/report_naive.html" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz88ak5kfokxsphu2c64.png" alt=" " width="799" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open interactive 3D chart: &lt;a href="https://oliver-zehentleitner.github.io/binance-depthcache-forensics/report_naive.html" rel="noopener noreferrer"&gt;report_naive.html&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Warning: large Plotly file, about 78 MB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://oliver-zehentleitner.github.io/binance-depthcache-forensics/report_fixed.html" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx1raw2nzctgxj6uueza.png" alt=" " width="799" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open interactive 3D chart: &lt;a href="https://oliver-zehentleitner.github.io/binance-depthcache-forensics/report_fixed.html" rel="noopener noreferrer"&gt;report_fixed.html&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Warning: large Plotly file, about 41 MB.&lt;/p&gt;

&lt;p&gt;The important lesson is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Gap-free does not mean correct forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sequence checks answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did I miss a depth event?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A retention policy answers a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which price levels am I still able and willing to claim as part of my maintained L2 order book?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A production implementation needs both.&lt;/p&gt;
&lt;h2&gt;
  
  
  Add an explicit retention policy
&lt;/h2&gt;

&lt;p&gt;If your application claims to maintain a bounded top-&lt;em&gt;N&lt;/em&gt; Binance order book, enforce that boundary.&lt;/p&gt;

&lt;p&gt;A simplified pruning function could look like this:&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;prune_side&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&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;str&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;descending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&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="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ordered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;side&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="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;item&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="n"&gt;item&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;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;descending&lt;/span&gt;&lt;span class="p"&gt;,&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;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_quantity&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ordered&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applied to both sides:&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="nf"&gt;prune_side&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;descending&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;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;prune_side&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;descending&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;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For bids, higher prices are better.&lt;/p&gt;

&lt;p&gt;For asks, lower prices are better.&lt;/p&gt;

&lt;p&gt;The exact retention strategy depends on your use case, market, performance requirements, and the depth corridor you promise to consumers. The critical part is that the policy must exist.&lt;/p&gt;

&lt;p&gt;An initial snapshot size alone is not a retention policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resync must be normal behavior
&lt;/h2&gt;

&lt;p&gt;Many trading systems treat resynchronization as an exceptional failure.&lt;/p&gt;

&lt;p&gt;It should be treated as part of normal order book lifecycle management.&lt;/p&gt;

&lt;p&gt;A resync may be required after:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a missing update ID,&lt;/li&gt;
&lt;li&gt;an invalid first buffered event,&lt;/li&gt;
&lt;li&gt;a WebSocket reconnect,&lt;/li&gt;
&lt;li&gt;a buffer overflow,&lt;/li&gt;
&lt;li&gt;an internal processing delay,&lt;/li&gt;
&lt;li&gt;an invariant violation,&lt;/li&gt;
&lt;li&gt;a crossed local book,&lt;/li&gt;
&lt;li&gt;or an operator-requested refresh.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A robust state machine should expose states such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INITIALIZING
SYNCHRONIZED
OUT_OF_SYNC
RESYNCING
STOPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consumers should never have to infer those states from stale timestamps or log files.&lt;/p&gt;

&lt;p&gt;Before returning bids or asks, the service should know whether the Binance order book is currently trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not silently serve stale order book data
&lt;/h2&gt;

&lt;p&gt;Imagine an API consumer requests BTCUSDT asks while the cache is resynchronizing.&lt;/p&gt;

&lt;p&gt;The convenient behavior is to return the last known data with HTTP 200.&lt;/p&gt;

&lt;p&gt;The honest behavior is to return an explicit trust-state error.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&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;"error_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#6000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DepthCache 'BTCUSDT' for 'binance.com' is out of sync!"&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;p&gt;The consumer can then choose to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry,&lt;/li&gt;
&lt;li&gt;temporarily reduce confidence,&lt;/li&gt;
&lt;li&gt;use a redundant replica,&lt;/li&gt;
&lt;li&gt;disable a strategy,&lt;/li&gt;
&lt;li&gt;or stop trading that market.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That decision belongs to the consumer.&lt;/p&gt;

&lt;p&gt;The order book layer's responsibility is to preserve the truth about its own state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate more than update IDs
&lt;/h2&gt;

&lt;p&gt;Sequence validation is essential, but useful runtime invariants go further.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Invariant&lt;/th&gt;
&lt;th&gt;Possible meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;best_bid &amp;gt;= best_ask&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;crossed or corrupted local order book&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unexpected update-ID transition&lt;/td&gt;
&lt;td&gt;missing, duplicated, or reordered event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;event buffer exceeds capacity&lt;/td&gt;
&lt;td&gt;consumer cannot keep up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stream silence exceeds threshold&lt;/td&gt;
&lt;td&gt;dead or stalled connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;maintained depth grows beyond policy&lt;/td&gt;
&lt;td&gt;missing or ineffective pruning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cache age exceeds threshold&lt;/td&gt;
&lt;td&gt;stale data path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;replica states disagree for too long&lt;/td&gt;
&lt;td&gt;one cache may be unhealthy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A crossed book should be handled carefully because fast-moving markets and independently timed observations can complicate comparisons. But inside one consistently applied local state, impossible relationships are valuable warning signals.&lt;/p&gt;

&lt;p&gt;The broader rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make corruption observable before it reaches the strategy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why one correct local order book is still not enough
&lt;/h2&gt;

&lt;p&gt;For one bot and one market, an in-process Binance L2 order book can be a reasonable design.&lt;/p&gt;

&lt;p&gt;Then the system grows.&lt;/p&gt;

&lt;p&gt;You add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;another strategy,&lt;/li&gt;
&lt;li&gt;a dashboard,&lt;/li&gt;
&lt;li&gt;a monitoring service,&lt;/li&gt;
&lt;li&gt;an alerting process,&lt;/li&gt;
&lt;li&gt;a backtesting or research consumer,&lt;/li&gt;
&lt;li&gt;a Node.js application,&lt;/li&gt;
&lt;li&gt;a Go execution service,&lt;/li&gt;
&lt;li&gt;or a script that only needs the top five asks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If each application reconstructs the same Binance order book independently, each one now owns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket lifecycle handling,&lt;/li&gt;
&lt;li&gt;REST snapshot initialization,&lt;/li&gt;
&lt;li&gt;buffering,&lt;/li&gt;
&lt;li&gt;sequence validation,&lt;/li&gt;
&lt;li&gt;pruning,&lt;/li&gt;
&lt;li&gt;resync,&lt;/li&gt;
&lt;li&gt;memory management,&lt;/li&gt;
&lt;li&gt;and exchange rate-limit consumption.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A reconnect storm duplicates the same initialization work.&lt;/p&gt;

&lt;p&gt;Two processes can temporarily hold different views of the same market.&lt;/p&gt;

&lt;p&gt;Restarting application logic also destroys and rebuilds market-data state that did not need to be coupled to that application.&lt;/p&gt;

&lt;p&gt;At this point, the order book is no longer an implementation detail of the bot.&lt;/p&gt;

&lt;p&gt;It is infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat the Binance order book as a shared service
&lt;/h2&gt;

&lt;p&gt;The architectural shift is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one synchronized order book layer
many independent consumers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bot A -&amp;gt; Binance -&amp;gt; local BTCUSDT cache
bot B -&amp;gt; Binance -&amp;gt; local BTCUSDT cache
dashboard -&amp;gt; Binance -&amp;gt; local BTCUSDT cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Binance
   |
shared synchronized depth-cache layer
   |          |          |
 bot A      bot B     dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides a single place to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;snapshot and WebSocket synchronization,&lt;/li&gt;
&lt;li&gt;sequence validation,&lt;/li&gt;
&lt;li&gt;retention,&lt;/li&gt;
&lt;li&gt;resync,&lt;/li&gt;
&lt;li&gt;cache-state reporting,&lt;/li&gt;
&lt;li&gt;replicas,&lt;/li&gt;
&lt;li&gt;failover,&lt;/li&gt;
&lt;li&gt;monitoring,&lt;/li&gt;
&lt;li&gt;and client access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The consuming application can remain focused on strategy or analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical implementation with UBDCC
&lt;/h2&gt;

&lt;p&gt;I built the open-source UNICORN Binance DepthCache Cluster, or UBDCC, for this architecture.&lt;/p&gt;

&lt;p&gt;UBDCC runs synchronized Binance DepthCaches as a standalone service and exposes them over HTTP/JSON.&lt;/p&gt;

&lt;p&gt;It is written in Python, but clients do not need to be Python applications.&lt;/p&gt;

&lt;p&gt;Anything that can call an HTTP endpoint can consume the same Binance order book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python,&lt;/li&gt;
&lt;li&gt;JavaScript,&lt;/li&gt;
&lt;li&gt;Go,&lt;/li&gt;
&lt;li&gt;Rust,&lt;/li&gt;
&lt;li&gt;Java,&lt;/li&gt;
&lt;li&gt;C#,&lt;/li&gt;
&lt;li&gt;PHP,&lt;/li&gt;
&lt;li&gt;Bash,&lt;/li&gt;
&lt;li&gt;dashboards,&lt;/li&gt;
&lt;li&gt;spreadsheets,&lt;/li&gt;
&lt;li&gt;or internal services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A local test setup starts with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;ubdcc
ubdcc start &lt;span class="nt"&gt;--dcn&lt;/span&gt; 4
ubdcc-dashboard start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a BTCUSDT DepthCache with two replicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'http://127.0.0.1:42081/create_depthcaches'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "exchange": "binance.com",
    "markets": ["BTCUSDT"],
    "desired_quantity": 2
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Query the first five asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'http://127.0.0.1:42081/get_asks?exchange=binance.com&amp;amp;market=BTCUSDT&amp;amp;limit_count=5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Query the first five bids:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'http://127.0.0.1:42081/get_bids?exchange=binance.com&amp;amp;market=BTCUSDT&amp;amp;limit_count=5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With two replicas, the same market exists on separate DepthCache nodes. If one node fails, another synchronized replica can serve the request.&lt;/p&gt;

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

&lt;p&gt;UBDCC is not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a trading strategy,&lt;/li&gt;
&lt;li&gt;an execution engine,&lt;/li&gt;
&lt;li&gt;a backtesting framework,&lt;/li&gt;
&lt;li&gt;or a promise of profitable trading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a market-data layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local library, service, or cluster?
&lt;/h2&gt;

&lt;p&gt;Not every project needs distributed infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use a local in-process Binance order book when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;you have one process,&lt;/li&gt;
&lt;li&gt;only one consumer needs the data,&lt;/li&gt;
&lt;li&gt;temporary loss during restart is acceptable,&lt;/li&gt;
&lt;li&gt;and you are prepared to own synchronization and retention logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use a standalone shared service when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;several applications need the same markets,&lt;/li&gt;
&lt;li&gt;applications use different programming languages,&lt;/li&gt;
&lt;li&gt;rebuilding caches during every deployment is wasteful,&lt;/li&gt;
&lt;li&gt;or you want one observable trust state.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use replicas or a cluster when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;order book availability matters,&lt;/li&gt;
&lt;li&gt;one process must not be a single point of failure,&lt;/li&gt;
&lt;li&gt;you maintain many markets,&lt;/li&gt;
&lt;li&gt;initialization pressure must be distributed,&lt;/li&gt;
&lt;li&gt;or consumers require explicit failover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture should follow the reliability contract you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  A checklist for a trustworthy Binance L2 order book
&lt;/h2&gt;

&lt;p&gt;Before trusting a local or remote Binance order book, verify that the implementation can answer all of these:&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Does it subscribe before fetching the snapshot?&lt;/li&gt;
&lt;li&gt;Does it buffer WebSocket events while the snapshot is in flight?&lt;/li&gt;
&lt;li&gt;Does it discard stale events correctly?&lt;/li&gt;
&lt;li&gt;Does it find the correct first applicable update?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Continuity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Does it validate Spot and Futures sequences using the correct fields?&lt;/li&gt;
&lt;li&gt;Does any continuity failure trigger a full resync?&lt;/li&gt;
&lt;li&gt;Can the event buffer overflow silently?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  State management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Is synchronization state explicit and queryable?&lt;/li&gt;
&lt;li&gt;Are reads rejected or marked while the cache is out of sync?&lt;/li&gt;
&lt;li&gt;Are reconnect and resync events observable?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Long-running correctness
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Is there an explicit retention boundary?&lt;/li&gt;
&lt;li&gt;Are old levels pruned?&lt;/li&gt;
&lt;li&gt;Does maintained depth remain bounded?&lt;/li&gt;
&lt;li&gt;Is the complete book audited periodically, not only best bid and ask?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Can the cache recover without restarting the strategy?&lt;/li&gt;
&lt;li&gt;Are metrics and health states exposed?&lt;/li&gt;
&lt;li&gt;Can replicas fail independently?&lt;/li&gt;
&lt;li&gt;Can consumers distinguish fresh data from stale data?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any answer is “I do not know,” that is where to investigate next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Most Binance order book tutorials stop after they have combined one REST snapshot with one WebSocket stream.&lt;/p&gt;

&lt;p&gt;That is the beginning, not the end.&lt;/p&gt;

&lt;p&gt;A production-grade Binance L2 order book needs at least four separate guarantees:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Correct bootstrap&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The snapshot and buffered events form one continuous initial state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Continuous sequence validation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Missing or reordered updates cause a loud resync.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicit retention&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The cache does not silently become a museum of historical price levels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observable trust state&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Consumers know whether the book is synchronized before using it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And once several applications need the same data, there is a fifth:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shared, redundant infrastructure&lt;/strong&gt;
Order book reconstruction should not be duplicated inside every bot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The difficult part is not receiving Binance depth data.&lt;/p&gt;

&lt;p&gt;The difficult part is knowing when that data still deserves to be called an order book.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code and related research
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-depth-cache-cluster" rel="noopener noreferrer"&gt;UNICORN Binance DepthCache Cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oliver-zehentleitner/unicorn-binance-local-depth-cache" rel="noopener noreferrer"&gt;UNICORN Binance Local Depth Cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.technopathy.club/your-binance-order-book-is-wrong-here-s-why" rel="noopener noreferrer"&gt;Your Binance Order Book Is Wrong — Here's Why&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.technopathy.club/your-binance-depthcache-is-rotting-here-s-the-proof-in-25-hours" rel="noopener noreferrer"&gt;Your Binance DepthCache is rotting — here's the proof in 25 hours&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.technopathy.club/ubdcc-deep-dive-building-a-trust-layer-for-binance-order-books" rel="noopener noreferrer"&gt;UBDCC Deep-Dive: Building a Trust Layer for Binance Order Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.technopathy.club/from-pip-install-to-a-redundant-binance-order-book-cluster-ubdcc-dashboard-quickstart" rel="noopener noreferrer"&gt;UBDCC local quickstart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions, corrections, failed test cases, and contradictory results are welcome in the comments.&lt;/p&gt;




&lt;p&gt;I hope you found this informative and useful.&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://www.binance.com/en/square/profile/oliver-zehentleitner" rel="noopener noreferrer"&gt;Binance Square&lt;/a&gt;, &lt;a href="https://github.com/oliver-zehentleitner" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://x.com/unicorn_oz" rel="noopener noreferrer"&gt;X&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/oliver-zehentleitner/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, or join &lt;a href="https://t.me/unicorndevs" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; for updates on my latest publications. Constructive feedback is always appreciated.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and happy coding! ¯\_(ツ)_/¯&lt;/p&gt;

</description>
      <category>python</category>
      <category>cryptocurrency</category>
      <category>opensource</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
