<?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: Steven Hansen</title>
    <description>The latest articles on DEV Community by Steven Hansen (@steven_hansen_04c7f869e72).</description>
    <link>https://dev.to/steven_hansen_04c7f869e72</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3919588%2F4e0d4919-ad95-4dd0-9fd3-ebb9debaf67b.jpg</url>
      <title>DEV Community: Steven Hansen</title>
      <link>https://dev.to/steven_hansen_04c7f869e72</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/steven_hansen_04c7f869e72"/>
    <language>en</language>
    <item>
      <title>A Developer's Guide to Comparing Crypto Exchange APIs in 2026 published: false</title>
      <dc:creator>Steven Hansen</dc:creator>
      <pubDate>Fri, 08 May 2026 09:11:47 +0000</pubDate>
      <link>https://dev.to/steven_hansen_04c7f869e72/a-developers-guide-to-comparing-crypto-exchange-apis-in-2026published-false-3nn0</link>
      <guid>https://dev.to/steven_hansen_04c7f869e72/a-developers-guide-to-comparing-crypto-exchange-apis-in-2026published-false-3nn0</guid>
      <description>&lt;p&gt;If you've ever tried to build anything that talks to more than one crypto exchange - a portfolio tracker, an arbitrage bot, a price aggregator, a tax tool - you already know the dirty secret: &lt;strong&gt;every exchange's API is its own little universe&lt;/strong&gt;. They all loosely speak REST and WebSocket, but the auth schemes, rate-limit models, error formats, symbol conventions, and pagination styles diverge in ways that turn "just fetch the ticker" into a multi-day yak-shave.&lt;/p&gt;

&lt;p&gt;This guide is a developer-to-developer comparison of the five APIs you're most likely to integrate against - &lt;strong&gt;Binance, Kraken, Coinbase, Bybit, and OKX&lt;/strong&gt; - focused on the things that actually matter when you're writing code: authentication, rate limits, how they want you to handle real-time data, and the specific footguns waiting in production.&lt;/p&gt;

&lt;p&gt;I'll keep the marketing out of it. Where I do reference rankings or scores, they're from the comparison work &lt;a href="https://exchange-rank.com/" rel="noopener noreferrer"&gt;ExchangeRank&lt;/a&gt; has already done so I don't have to re-derive trust scores from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR - the comparison table you came for
&lt;/h2&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;Binance&lt;/th&gt;
&lt;th&gt;Kraken&lt;/th&gt;
&lt;th&gt;Coinbase Advanced&lt;/th&gt;
&lt;th&gt;Bybit&lt;/th&gt;
&lt;th&gt;OKX&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;REST base&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.binance.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.kraken.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.coinbase.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.bybit.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;www.okx.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Public market data auth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Private auth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HMAC SHA256 / RSA / Ed25519&lt;/td&gt;
&lt;td&gt;HMAC SHA512 + nonce&lt;/td&gt;
&lt;td&gt;Ed25519 / HMAC + JWT&lt;/td&gt;
&lt;td&gt;HMAC SHA256 + timestamp&lt;/td&gt;
&lt;td&gt;HMAC SHA256 + passphrase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rate limit model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Weight-per-endpoint, IP-based&lt;/td&gt;
&lt;td&gt;Counter that decays per tier&lt;/td&gt;
&lt;td&gt;Sliding window&lt;/td&gt;
&lt;td&gt;Per-endpoint per-UID&lt;/td&gt;
&lt;td&gt;Per-endpoint per-UID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Symbol format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BTCUSDT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;XBT/USD&lt;/code&gt; (and &lt;code&gt;XXBTZUSD&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BTC-USD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BTCUSDT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BTC-USDT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Timestamp&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ms&lt;/td&gt;
&lt;td&gt;ns since epoch (nonce)&lt;/td&gt;
&lt;td&gt;s (ISO 8601)&lt;/td&gt;
&lt;td&gt;ms&lt;/td&gt;
&lt;td&gt;ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pagination&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;startTime&lt;/code&gt;/&lt;code&gt;endTime&lt;/code&gt; + limit&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;since&lt;/code&gt; cursor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cursor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cursor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;before&lt;/code&gt;/&lt;code&gt;after&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sandbox/testnet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (futures)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WS public&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wss://stream.binance.com:9443&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wss://ws.kraken.com/v2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wss://advanced-trade-ws.coinbase.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wss://stream.bybit.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wss://ws.okx.com:8443&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now let's get into the parts that hurt.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Authentication: nobody agrees on anything
&lt;/h2&gt;

&lt;p&gt;If you only ever hit public market data, you can skip this section - none of these exchanges require auth for tickers, order books, or trades. The moment you need account data or trading, prepare for five totally different rituals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Binance
&lt;/h3&gt;

&lt;p&gt;Binance signs requests with HMAC-SHA256 over the query string, and now also supports RSA and Ed25519 keys. The signature goes in the &lt;code&gt;signature&lt;/code&gt; query param, and your API key goes in the &lt;code&gt;X-MBX-APIKEY&lt;/code&gt; header.&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;hmac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&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="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&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;...&lt;/span&gt;&lt;span class="sh"&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;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;params&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;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;BTCUSDT&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;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recvWindow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;API_SECRET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.binance.com/api/v3/account?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;signature=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signature&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="n"&gt;headers&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;X-MBX-APIKEY&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="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 &lt;code&gt;recvWindow&lt;/code&gt; (default 5000ms, max 60000ms) is your tolerance for clock skew. If your server clock drifts, you'll get cryptic &lt;code&gt;-1021&lt;/code&gt; errors. Sync NTP and stop debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kraken
&lt;/h3&gt;

&lt;p&gt;Kraken uses HMAC-SHA512, but the signature input is weirder: it's &lt;code&gt;URI path + SHA256(nonce + POST data)&lt;/code&gt;, and the whole thing is base64-encoded with a base64-decoded secret.&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;base64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hmac&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="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;secret&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;postdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencode&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;encoded&lt;/span&gt; &lt;span class="o"&gt;=&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;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nonce&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;postdata&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;data&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;nonce&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;path&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/private/Balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;headers&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;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_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API-Sign&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;API_SECRET&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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;https://api.kraken.com&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&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="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&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="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nonce &lt;strong&gt;must increase monotonically per key&lt;/strong&gt;. Run two processes in parallel with the same key and you'll start eating &lt;code&gt;EAPI:Invalid nonce&lt;/code&gt; errors. Solution: one key per process, or a shared nonce server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Advanced Trade
&lt;/h3&gt;

&lt;p&gt;Coinbase recently moved to Ed25519-based JWTs (their older HMAC scheme still works for legacy API keys). You generate a short-lived JWT signed with your private key, valid for ~2 minutes, and pass it as a Bearer token. Library support varies - for serious work, use their official &lt;code&gt;coinbase-advanced-py&lt;/code&gt; SDK rather than rolling your own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bybit and OKX
&lt;/h3&gt;

&lt;p&gt;Both use HMAC-SHA256 with timestamp-in-header schemes. OKX additionally requires a passphrase header (&lt;code&gt;OK-ACCESS-PASSPHRASE&lt;/code&gt;) that you set when creating the key - lose it and you regenerate the key. Bybit's signature input is &lt;code&gt;timestamp + apiKey + recvWindow + queryString&lt;/code&gt;, OKX's is &lt;code&gt;timestamp + method + requestPath + body&lt;/code&gt;. Trivially different. Annoyingly different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; if you're integrating more than two exchanges, use &lt;a href="https://github.com/ccxt/ccxt" rel="noopener noreferrer"&gt;CCXT&lt;/a&gt;. It papers over all of this for ~120 exchanges and is genuinely well-maintained. The only reason to roll your own is if you need a feature CCXT doesn't expose yet, or you're optimizing for sub-millisecond latency.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Rate limits: the part that kills your bot at 3am
&lt;/h2&gt;

&lt;p&gt;This is where the abstractions leak the most, and where naive code dies first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Binance: weighted requests
&lt;/h3&gt;

&lt;p&gt;Binance assigns each endpoint a &lt;strong&gt;weight&lt;/strong&gt; (1 to 250 depending on how expensive it is) and you have a budget - currently 6000 weight per minute per IP for the spot API. Every response includes an &lt;code&gt;X-MBX-USED-WEIGHT-1M&lt;/code&gt; header telling you exactly how much of the budget you've burned.&lt;/p&gt;

&lt;p&gt;The crucial thing most tutorials skip: when you hit 429, &lt;strong&gt;back off&lt;/strong&gt;. If you keep hammering, you graduate to a 418 ban that scales from 2 minutes to &lt;strong&gt;3 days&lt;/strong&gt; for repeat offenders. The response includes a &lt;code&gt;Retry-After&lt;/code&gt; header - respect 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;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_with_retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&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;max_retries&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&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;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;retry_after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retry-After&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="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="n"&gt;retry_after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-MBX-USED-WEIGHT-1M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;used&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# 83% of budget
&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;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# preemptive throttle
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate limited beyond retries&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;Notice the preemptive throttle. The 429 → backoff loop is reactive; the headers let you be proactive, which is the difference between a bot that survives and one that gets IP-banned during a market move.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kraken: tiered counter that decays
&lt;/h3&gt;

&lt;p&gt;Kraken's REST counter starts at 0 and increments per call (most calls = 1, ledger/trade history = 4). It decays based on your verification tier - Starter accounts decay slowly, Pro accounts decay much faster. The max counter value before you get rate limited is also tier-dependent.&lt;/p&gt;

&lt;p&gt;This is friendlier than Binance's burst-then-ban model: a steady stream of calls at 1/sec is fine on most tiers. The trap is that &lt;strong&gt;public endpoints share IP-based limits&lt;/strong&gt;, and Kraken explicitly recommends ≤1 request/sec on the public side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bybit and OKX
&lt;/h3&gt;

&lt;p&gt;Both use simpler &lt;strong&gt;per-endpoint per-UID&lt;/strong&gt; limits - typically X requests per second on a given endpoint, returned in response headers. Easy to reason about, easy to throttle with a token bucket per endpoint. This is, frankly, the model the others should adopt.&lt;/p&gt;

&lt;h3&gt;
  
  
  The one rule that applies everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use WebSockets for anything you'd otherwise poll.&lt;/strong&gt; Every single exchange's docs explicitly say this. Polling &lt;code&gt;/ticker&lt;/code&gt; once per second across 100 symbols will eat your rate budget in seconds; subscribing to a ticker stream costs effectively zero ongoing weight and gives you push updates faster than you could poll anyway. If your "real-time" code path uses REST, rewrite it.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. WebSockets: less standardized than you'd hope
&lt;/h2&gt;

&lt;p&gt;Every exchange has a WebSocket API. None of them work the same way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binance&lt;/strong&gt; uses a stream-name-in-URL pattern: connect to &lt;code&gt;wss://stream.binance.com:9443/ws/btcusdt@ticker&lt;/code&gt; and you're subscribed. Multiple streams via &lt;code&gt;/stream?streams=btcusdt@ticker/ethusdt@ticker&lt;/code&gt;. Messages are auto-pushed; no subscription handshake needed for combined streams. Connections last 24 hours then get cycled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kraken&lt;/strong&gt; uses a JSON subscription model - you connect to &lt;code&gt;wss://ws.kraken.com/v2&lt;/code&gt; and send &lt;code&gt;{"method": "subscribe", "params": {"channel": "ticker", "symbol": ["BTC/USD"]}}&lt;/code&gt;. Cleaner mental model, more code to write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coinbase Advanced Trade&lt;/strong&gt; is also subscription-based (&lt;code&gt;{"type": "subscribe", "product_ids": ["BTC-USD"], "channel": "ticker"}&lt;/code&gt;), and the auth flow for private channels uses the same JWT scheme as REST.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bybit and OKX&lt;/strong&gt; are subscription-based with their own JSON shapes.&lt;/p&gt;

&lt;p&gt;The real lesson here: don't write five WebSocket clients. Either use CCXT Pro (paid), or use one of the per-exchange official SDKs. Hand-rolled WS clients become a graveyard of reconnection bugs, missed heartbeats, and stale subscriptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heartbeats and reconnection
&lt;/h3&gt;

&lt;p&gt;Every WS API will silently kill your connection if you don't ping/pong on schedule. The intervals vary (Binance: server pings every 3 minutes, you have 10 minutes to pong; Kraken: client-initiated heartbeats, etc.). Get this wrong and your "real-time" feed is actually a 10-minute-stale feed. Always log disconnects with timestamps and set up an external watchdog - not just an in-process one.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The footguns nobody warns you about
&lt;/h2&gt;

&lt;p&gt;These are the things I've seen burn real production systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symbol format hell.&lt;/strong&gt; &lt;code&gt;BTC-USD&lt;/code&gt;, &lt;code&gt;BTCUSD&lt;/code&gt;, &lt;code&gt;BTCUSDT&lt;/code&gt;, &lt;code&gt;XBTUSD&lt;/code&gt;, &lt;code&gt;XXBTZUSD&lt;/code&gt;, &lt;code&gt;BTC/USD&lt;/code&gt;, &lt;code&gt;tBTCUSD&lt;/code&gt; (Bitfinex) - they're all the same pair. Build a normalization layer on day one. Don't sprinkle string concatenation throughout your codebase or you will pay for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timestamps in different units.&lt;/strong&gt; Binance: milliseconds. Coinbase: seconds (or ISO 8601 strings). Kraken: nanoseconds for nonces, seconds for trade timestamps. Convert to a single canonical format (I prefer ms-since-epoch) at the boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asset code mismatches.&lt;/strong&gt; Kraken uses &lt;code&gt;XBT&lt;/code&gt; for Bitcoin in some contexts, &lt;code&gt;BTC&lt;/code&gt; in others, and &lt;code&gt;XXBT&lt;/code&gt; in legacy responses. They'll also use &lt;code&gt;ZUSD&lt;/code&gt; instead of &lt;code&gt;USD&lt;/code&gt;. Their docs explain it; the explanation does not make it less annoying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decimal precision.&lt;/strong&gt; Always parse prices/quantities as strings and use &lt;code&gt;Decimal&lt;/code&gt; (Python) or a big-decimal library (JS). Floats will silently round and you'll be off by satoshis on big trades. This isn't theoretical - exchanges will reject orders that don't match their tick size or step size, and float math is how that happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pagination is inconsistent.&lt;/strong&gt; Some use cursors, some use timestamps, some use both. Time-based pagination breaks when two trades have the same timestamp (yes, this happens). Cursor-based is safer. Always page until you get an empty response, never trust a &lt;code&gt;total&lt;/code&gt; field - they lie or omit it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Maintenance mode" returns 200.&lt;/strong&gt; Several exchanges return HTTP 200 with an error in the JSON body during maintenance. If you only check status codes, you'll happily process garbage. Always check the body's error field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Withdrawal endpoints have separate, harsher rate limits.&lt;/strong&gt; This isn't documented as prominently as it should be on most exchanges. Don't loop your "process all pending withdrawals" job without a delay - you can get IP-banned from a perfectly normal cron task.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Choosing one to start with
&lt;/h2&gt;

&lt;p&gt;If you're picking a single exchange to integrate first - for a portfolio tool, a tax tracker, a hobby bot - the answer depends on what you value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cleanest auth and docs:&lt;/strong&gt; Coinbase Advanced. The Ed25519 JWT scheme is the most modern and least error-prone of the bunch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deepest liquidity for backtesting/data:&lt;/strong&gt; Binance. The historical data endpoints alone justify it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most predictable rate limits:&lt;/strong&gt; Bybit or OKX. The per-endpoint model is the easiest to reason about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best regulatory standing if you're shipping a product:&lt;/strong&gt; Kraken or Coinbase. Both have unhacked operating histories and clear US/EU compliance posture - Kraken sits at the top of &lt;a href="https://exchange-rank.com/best-crypto-exchange" rel="noopener noreferrer"&gt;ExchangeRank's composite score&lt;/a&gt; at 4.4/5 mostly on the strength of that record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For anything beyond a single exchange, just use CCXT. The 30 lines you save per integration compound fast across five exchanges.&lt;/p&gt;




&lt;h2&gt;
  
  
  A small bench: pulling BTC mid-price from all five
&lt;/h2&gt;

&lt;p&gt;Here's a runnable example that fetches the mid-price from each exchange's public ticker endpoint. No auth, no SDK, just &lt;code&gt;aiohttp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;

&lt;span class="n"&gt;ENDPOINTS&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;binance&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;https://api.binance.com/api/v3/ticker/bookTicker?symbol=BTCUSDT&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;kraken&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;https://api.kraken.com/0/public/Ticker?pair=XBTUSD&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;coinbase&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;https://api.coinbase.com/api/v3/brokerage/market/products/BTC-USD&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;bybit&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;https://api.bybit.com/v5/market/tickers?category=spot&amp;amp;symbol=BTCUSDT&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;okx&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;https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT&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;def&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &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;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bidPrice&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="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;askPrice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kraken&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="nf"&gt;return &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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&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="o"&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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coinbase&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="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bybit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&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;list&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;return &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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bid1Price&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="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ask1Price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;okx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;return &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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bidPx&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="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;askPx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&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;with&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&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;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;j&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;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClientSession&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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;gather&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&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;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ENDPOINTS&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="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="ow"&gt;in&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;results&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;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;s&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;price&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that and you'll see live spreads of typically $5–$30 between the cheapest and most expensive venue at any given moment. That's the raw material for everything from arbitrage to "show users where they'd get the best fill" features - and it's a useful sanity check that all five APIs are alive and returning sensible data before you build anything fancier on top.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The crypto exchange API landscape is fragmented in ways that will not improve any time soon. Each exchange has commercial reasons to keep its API distinctive, and there's no analog to FIX-for-equities forcing convergence. Your job as a developer is to wrap that fragmentation behind a sane internal interface - symbols normalized, timestamps in one unit, errors mapped to your own taxonomy - and never let the per-exchange weirdness leak into your business logic.&lt;/p&gt;

&lt;p&gt;If you're evaluating exchanges for end users rather than for code (which is a different question with different criteria - fees, security, custody, support quality), &lt;a href="https://exchange-rank.com/" rel="noopener noreferrer"&gt;ExchangeRank&lt;/a&gt; maintains a methodology-driven comparison across 16 exchanges. It's a useful sanity check on the consumer-facing side of platforms you're already integrating against.&lt;/p&gt;

&lt;p&gt;What did I miss? Particularly interested in war stories about pagination edge cases or weird WS reconnection behaviors - drop them in the comments.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>api</category>
      <category>javascript</category>
      <category>python</category>
    </item>
  </channel>
</rss>
