<?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: Jack Chen</title>
    <description>The latest articles on DEV Community by Jack Chen (@jacktrader).</description>
    <link>https://dev.to/jacktrader</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%2F3977439%2Fa3ff3f15-83d5-431a-9276-dac37e13a3f8.png</url>
      <title>DEV Community: Jack Chen</title>
      <link>https://dev.to/jacktrader</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jacktrader"/>
    <language>en</language>
    <item>
      <title>The retention treadmill behind volume-based partner tiers: a 20-line cohort model</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Mon, 27 Jul 2026 03:37:13 +0000</pubDate>
      <link>https://dev.to/jacktrader/the-retention-treadmill-behind-volume-based-partner-tiers-a-20-line-cohort-model-5ni</link>
      <guid>https://dev.to/jacktrader/the-retention-treadmill-behind-volume-based-partner-tiers-a-20-line-cohort-model-5ni</guid>
      <description>&lt;p&gt;Most exchange partner programs price your tier on &lt;strong&gt;recent&lt;/strong&gt; referred fee output, not on cumulative history. That single design choice turns a static-looking percentage into a control loop with feedback — and it's the part that surprises people who model the program as "get approved once, then collect a slice."&lt;/p&gt;

&lt;p&gt;Here's the 20-line model I run before deciding whether a channel is worth building.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three inputs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Value used here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;exchange fees one active referred trader generates per month&lt;/td&gt;
&lt;td&gt;$800&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fraction of active traders lost per month&lt;/td&gt;
&lt;td&gt;0.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;monthly referred fee output your tier is priced on&lt;/td&gt;
&lt;td&gt;$30,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;F = $800&lt;/code&gt; is a retail futures trader doing roughly $2M monthly notional at a ~0.04% blended maker/taker rate. &lt;code&gt;T&lt;/code&gt; is your own estimate — exchanges don't publish tier thresholds, which is precisely why you should model the &lt;em&gt;shape&lt;/em&gt; instead of chasing a number.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CHURN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;800.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.12&lt;/span&gt;      &lt;span class="c1"&gt;# fees per active trader per month, monthly churn
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ramp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_per_month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;CHURN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;new_per_month&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fees&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;ramp&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&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;month &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  active &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;5.1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  output $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;month  1  active   5.0  output $    4,000
month  3  active  13.3  output $   10,618
month  6  active  22.3  output $   17,853
month 12  active  32.7  output $   26,144
month 24  active  39.7  output $   31,783
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two results fall out of this, and both are counterintuitive if you've been doing the arithmetic in your head.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steady state is &lt;code&gt;new_per_month / c&lt;/code&gt;, not &lt;code&gt;new_per_month × months&lt;/code&gt;.&lt;/strong&gt; Adding 5 active traders a month at 12% churn doesn't build an ever-growing tree. It converges on ~41.7 active traders and ~$33.3k of monthly output. By month 24 you're at $31.8k — 95% of the ceiling. Everything after that is replacement, not growth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The standing-still cost is &lt;code&gt;T/F × c&lt;/code&gt;.&lt;/strong&gt; Holding $30,000/month of output needs ~37.5 active traders, which means recruiting ~4.5 replacements every month, indefinitely:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;churn / mo&lt;/th&gt;
&lt;th&gt;active traders needed&lt;/th&gt;
&lt;th&gt;new per month to stand still&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;td&gt;37.5&lt;/td&gt;
&lt;td&gt;1.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;37.5&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;td&gt;37.5&lt;/td&gt;
&lt;td&gt;4.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;37.5&lt;/td&gt;
&lt;td&gt;7.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;37.5&lt;/td&gt;
&lt;td&gt;11.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tier isn't an asset you acquire once. It's a subscription you pay in acquisition, and the price is set by your churn rate — a variable most people never measure.&lt;/p&gt;

&lt;p&gt;That's the real reason the fee-share layer behaves like an operating business rather than a link you paste. If you want the application steps, the ongoing volume and headcount gates, and the case where binding into a tree that already cleared those gates beats running the treadmill yourself, I wrote that up at &lt;a href="https://www.jacktrader.xyz/en/blog/how-to-become-okx-affiliate.html" rel="noopener noreferrer"&gt;how to become an OKX affiliate&lt;/a&gt;. The fee tables I use as model inputs live in &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;crypto-exchange-fee-data&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this model is wrong
&lt;/h2&gt;

&lt;p&gt;Three honest failure modes, because a model you can't break isn't a model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Churn isn't a constant.&lt;/strong&gt; It's front-loaded — a trader in month 1 is far likelier to quit than a six-month survivor. A single &lt;code&gt;c&lt;/code&gt; overstates decay in mature cohorts and understates the month-1 bleed. If you have real data, fit per-cohort survival curves instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;F&lt;/code&gt; is a mean over a very long tail.&lt;/strong&gt; One high-volume account can carry the whole number while the median contributor sits near zero. That makes the tree fragile in a way the smooth curve above hides: lose the top account and output drops by more than &lt;code&gt;1/n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;T&lt;/code&gt; is unobservable.&lt;/strong&gt; Tier thresholds are discretionary and mostly undisclosed, and split ranges are advertised as ceilings ("up to"), never guarantees. Treat every dollar figure here as a shape, not a forecast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not financial advice. I run an independent, non-official fee-comparison site, so read my framing as interested rather than neutral.&lt;/p&gt;

</description>
      <category>python</category>
      <category>trading</category>
      <category>crypto</category>
      <category>datascience</category>
    </item>
    <item>
      <title>The crossover taker share: why the cheaper fee table is often the more expensive venue</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Fri, 24 Jul 2026 03:34:44 +0000</pubDate>
      <link>https://dev.to/jacktrader/the-crossover-taker-share-why-the-cheaper-fee-table-is-often-the-more-expensive-venue-44d1</link>
      <guid>https://dev.to/jacktrader/the-crossover-taker-share-why-the-cheaper-fee-table-is-often-the-more-expensive-venue-44d1</guid>
      <description>&lt;p&gt;Every "Exchange A vs Exchange B fees" comparison does the same thing: it puts two maker/taker pairs side by side and declares the smaller maker number the winner. That comparison is only valid for a trader who never sends a market order.&lt;/p&gt;

&lt;p&gt;What you actually pay is one blended number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;effective rate = total fees paid / total notional traded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tier, token discount, fee share — everything else is a lever on that one number. And the blend has a property the fee tables never print: &lt;strong&gt;two schedules cross&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure it, don't estimate it
&lt;/h2&gt;

&lt;p&gt;If you have your fills, compute it directly instead of trusting the sticker:&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;effective_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;fills: [(notional, is_maker), ...]&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;fees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maker&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;taker&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;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fills&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fills&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;fees&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;

&lt;span class="n"&gt;fills&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;50_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="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="nf"&gt;effective_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0005&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&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;span class="c1"&gt;# 0.0350%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where the schedules cross
&lt;/h2&gt;

&lt;p&gt;Two representative standard-tier schedules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;venue&lt;/th&gt;
&lt;th&gt;maker&lt;/th&gt;
&lt;th&gt;taker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;0.0200%&lt;/td&gt;
&lt;td&gt;0.0500%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0.0160%&lt;/td&gt;
&lt;td&gt;0.0600%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;B has the better maker sticker — 20% lower. Set the two blends equal and solve for taker share &lt;code&gt;t&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="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.000200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.000500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.000160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.000600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;blend&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;s&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="n"&gt;s&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="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;s&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="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;span class="n"&gt;t_star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mA&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mB&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;mA&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mB&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;kB&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;kA&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;t_star&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="o"&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;span class="c1"&gt;# 28.57%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;taker share&lt;/th&gt;
&lt;th&gt;A effective&lt;/th&gt;
&lt;th&gt;B effective&lt;/th&gt;
&lt;th&gt;cheaper&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0.0200%&lt;/td&gt;
&lt;td&gt;0.0160%&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;0.0230%&lt;/td&gt;
&lt;td&gt;0.0204%&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28.6%&lt;/td&gt;
&lt;td&gt;0.0286%&lt;/td&gt;
&lt;td&gt;0.0286%&lt;/td&gt;
&lt;td&gt;tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;55%&lt;/td&gt;
&lt;td&gt;0.0365%&lt;/td&gt;
&lt;td&gt;0.0402%&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;td&gt;0.0440%&lt;/td&gt;
&lt;td&gt;0.0512%&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Below 28.6% taker, B's better maker rate wins. Above it, A wins and the gap widens fast. At 55% taker on $3,000,000/month: A costs $1,095, B costs $1,206 — &lt;strong&gt;$1,332 per year&lt;/strong&gt; handed over for picking the venue with the "cheaper" fee table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this bites
&lt;/h2&gt;

&lt;p&gt;Your taker share is not what you think it is. Count the &lt;code&gt;is_maker&lt;/code&gt; flag in your own fill log rather than your recollection. Stop-markets that trigger, liquidations, and every get-me-filled click are taker fills, and traders who describe themselves as "mostly limit orders" routinely land in the 40–60% band once those are counted. That is on the far side of most crossovers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this breaks
&lt;/h2&gt;

&lt;p&gt;Three honest limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;t*&lt;/code&gt; assumes fixed schedules. Cross a volume tier on either venue and it moves — recompute monthly, not once.&lt;/li&gt;
&lt;li&gt;Funding and slippage are excluded, and both are usually larger than the 0.4bp being argued over. A venue that wins on &lt;code&gt;t*&lt;/code&gt; can still lose on a thinner book.&lt;/li&gt;
&lt;li&gt;If your taker share swings month to month, the cheaper venue swings with it. At that point the fee table isn't the deciding variable at all, and you should optimise order routing instead of venue choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full derivation of the blend, plus the three levers (tier, token discount, fee share) that stack on top of it, is written up at &lt;a href="https://www.jacktrader.xyz/en/blog/effective-fee-rate-explained.html" rel="noopener noreferrer"&gt;effective fee rate explained&lt;/a&gt;. The schedules used above come from a small public repo I keep: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;crypto-exchange-fee-data&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I run an independent site on this topic and am not affiliated with any exchange. Figures are representative standard-tier examples, not guarantees — check your own tier. Not financial advice.&lt;/p&gt;

</description>
      <category>python</category>
      <category>crypto</category>
      <category>trading</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Same partner tier, 8x the payout: the fee base is what you should model</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Mon, 20 Jul 2026 03:33:56 +0000</pubDate>
      <link>https://dev.to/jacktrader/same-partner-tier-8x-the-payout-the-fee-base-is-what-you-should-model-3ofm</link>
      <guid>https://dev.to/jacktrader/same-partner-tier-8x-the-payout-the-fee-base-is-what-you-should-model-3ofm</guid>
      <description>&lt;p&gt;Two operators can sit on the exact same partner tier at an exchange and collect payouts that differ by 8x. The percentage is identical. The base it multiplies is not.&lt;/p&gt;

&lt;p&gt;This trips up a lot of people who evaluate a partner program by reading the headline number and stopping there. The number is a share of &lt;strong&gt;fees actually paid&lt;/strong&gt; by the traders attributed to you — not a share of their volume, and not a function of how many of them there are.&lt;/p&gt;

&lt;h2&gt;
  
  
  The base is fees, not volume
&lt;/h2&gt;

&lt;p&gt;Futures fees on the major venues run roughly 0.02% maker / 0.05% taker at entry tier. Spot is flatter, around 0.10% both sides. So the same notional produces wildly different fee dollars depending on &lt;em&gt;how&lt;/em&gt; it was traded.&lt;/p&gt;

&lt;p&gt;Worked at a 30% futures share:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trader profile&lt;/th&gt;
&lt;th&gt;Monthly notional&lt;/th&gt;
&lt;th&gt;Maker share&lt;/th&gt;
&lt;th&gt;Blended rate&lt;/th&gt;
&lt;th&gt;Fees paid&lt;/th&gt;
&lt;th&gt;Your split&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Spot swing trader&lt;/td&gt;
&lt;td&gt;$250,000&lt;/td&gt;
&lt;td&gt;n/a (0.10%)&lt;/td&gt;
&lt;td&gt;0.1000%&lt;/td&gt;
&lt;td&gt;$250&lt;/td&gt;
&lt;td&gt;$75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Futures scalper&lt;/td&gt;
&lt;td&gt;$2,000,000&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;0.0410%&lt;/td&gt;
&lt;td&gt;$820&lt;/td&gt;
&lt;td&gt;$246&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Futures grid bot&lt;/td&gt;
&lt;td&gt;$8,000,000&lt;/td&gt;
&lt;td&gt;85%&lt;/td&gt;
&lt;td&gt;0.0245%&lt;/td&gt;
&lt;td&gt;$1,960&lt;/td&gt;
&lt;td&gt;$588&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The grid bot operator sends 32x the notional of the spot trader and pays only 7.8x the fees — maker-heavy flow is cheap per dollar moved. But it still pays out nearly 8x more, because volume scales faster than the maker discount shrinks the rate.&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;MAKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TAKER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0005&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;monthly_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maker_share&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;blended&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maker_share&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MAKER&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;maker_share&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;TAKER&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notional&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;blended&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;share&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;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;monthly_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.85&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="c1"&gt;# 588.0
&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;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;monthly_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.30&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="c1"&gt;# 246.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this changes what you optimize
&lt;/h2&gt;

&lt;p&gt;If you publish content, your growth lever is headcount — more readers, more clicks, more sign-ups. Each one is a small, mostly-spot, high-churn base.&lt;/p&gt;

&lt;p&gt;If you run a bot community or a signals group, headcount is almost irrelevant. One member running a grid strategy at $8M monthly notional is worth roughly eight casual spot traders, and they don't churn the same way — an automated strategy keeps trading while its operator is asleep or bored.&lt;/p&gt;

&lt;p&gt;So the fee table isn't a marketing detail. It's the thing that tells you which audience to go get. A creator reads the table to estimate income. An operator reads it to decide what kind of member to recruit, and the answer is usually "fewer, with API keys."&lt;/p&gt;

&lt;p&gt;Full breakdown of the tier structure and what it resolves to: &lt;a href="https://www.jacktrader.xyz/en/blog/binance-affiliate-program-commission.html" rel="noopener noreferrer"&gt;Binance affiliate commission table&lt;/a&gt;. Raw fee schedules I keep versioned here: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;crypto-exchange-fee-data&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three caveats worth stating plainly
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Headline rates are ceilings, not entitlements.&lt;/strong&gt; Published tiers are "up to" figures gated on volume and account tests. Assume the entry tier until a backend says otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribution windows are the silent failure mode.&lt;/strong&gt; A trader who registers through one path and funds weeks later may not bind to you at all. Check the binding rule before you model anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fee tiers move underneath you.&lt;/strong&gt; As a member climbs VIP levels their own fees drop, which shrinks the base your split multiplies. Growth in member sophistication can flatten your payout curve.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Model the base, not the percentage. The percentage is the easy part and it's the part everyone quotes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Independent write-up, not affiliated with or endorsed by any exchange. Rates and tier rules change — verify current terms at the source. Not financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>trading</category>
      <category>python</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Modeling the pass-through gap: what an exchange's headline partner rate actually resolves to</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Sat, 18 Jul 2026 03:34:20 +0000</pubDate>
      <link>https://dev.to/jacktrader/modeling-the-pass-through-gap-what-an-exchanges-headline-partner-rate-actually-resolves-to-2o91</link>
      <guid>https://dev.to/jacktrader/modeling-the-pass-through-gap-what-an-exchanges-headline-partner-rate-actually-resolves-to-2o91</guid>
      <description>&lt;p&gt;If you run a trading community, exchanges court you with one number — a headline "up to X%" of the fees your community's users generate. On paper it reads like a flat cut. In practice, the amount you keep is the output of a small pipeline, and most people never model the stages between the sticker rate and their actual payout.&lt;/p&gt;

&lt;p&gt;Here are the three stages that decide your take-home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1 — the ceiling is conditional
&lt;/h2&gt;

&lt;p&gt;"Up to 40%" is a maximum, not a rate. It resolves upward only when your team's monthly volume clears higher bands. A partner tree doing $2M notional a month usually sits two bands below the top.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;30d team volume (USDT)&lt;/th&gt;
&lt;th&gt;Applied fee share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; 5,000,000&lt;/td&gt;
&lt;td&gt;~20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5M – 20M&lt;/td&gt;
&lt;td&gt;~30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20M+&lt;/td&gt;
&lt;td&gt;up to the ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Stage 2 — the base the % applies to
&lt;/h2&gt;

&lt;p&gt;The share is taken on &lt;em&gt;net trading fees&lt;/em&gt;, after the venue's own maker/taker discounts and any VIP reductions your users already earn. A user on a 0.02% maker tier produces a far smaller fee base than the 0.10% sticker implies. A high headline % on a thin base often pays less than a modest % on a full one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 3 — timing and clawbacks
&lt;/h2&gt;

&lt;p&gt;Payout lands on the venue's official backend, typically on a daily or rolling settlement, and reverses if a trade is later voided. None of the headline math is contractual — it's a model, not a promise.&lt;/p&gt;

&lt;p&gt;A back-of-envelope calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;take_home = team_net_fees * applied_share
          = (volume * effective_fee_rate) * band_share

# 10M USDT volume, 0.04% blended net fee, 30% band
= 10_000_000 * 0.0004 * 0.30
= 1,200 USDT / month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap in your own numbers and the headline usually lands 30–50% below what a naive reader assumes, because both the band and the fee base pull it down at the same time.&lt;/p&gt;

&lt;p&gt;I keep the raw venue fee schedules I use for these models in a public repo — maker/taker tables by tier, updated as exchanges change them: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;https://github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full split modeling for OKX's partner-tree structure, and how the bands actually apply, is written up here: &lt;a href="https://www.jacktrader.xyz/en/blog/okx-sub-broker-affiliate-program.html" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/blog/okx-sub-broker-affiliate-program.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Model your own base before you pick a venue on its headline. Not financial advice.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Modeling the blended fee rate of a mixed-tier trading community</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Mon, 13 Jul 2026 03:34:27 +0000</pubDate>
      <link>https://dev.to/jacktrader/modeling-the-blended-fee-rate-of-a-mixed-tier-trading-community-2kno</link>
      <guid>https://dev.to/jacktrader/modeling-the-blended-fee-rate-of-a-mixed-tier-trading-community-2kno</guid>
      <description>&lt;p&gt;If you run a trading community — a Discord of grid-bot operators, a signal group, a small prop pod — every member sits at a different exchange fee tier. A few clear enough monthly volume to hit VIP 2 or 3; most sit at Regular. When you try to reason about "what does our group actually pay," a single headline number is useless. What you want is the &lt;strong&gt;blended rate&lt;/strong&gt;: the volume-weighted average fee across everyone.&lt;/p&gt;

&lt;p&gt;Here's how I model it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The inputs
&lt;/h2&gt;

&lt;p&gt;OKX USDT-perp taker fees by tier (published schedule, current after the April 2026 update):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;30-day volume gate&lt;/th&gt;
&lt;th&gt;Maker&lt;/th&gt;
&lt;th&gt;Taker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Regular&lt;/td&gt;
&lt;td&gt;&amp;lt; $5M&lt;/td&gt;
&lt;td&gt;0.0200%&lt;/td&gt;
&lt;td&gt;0.0500%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIP 1&lt;/td&gt;
&lt;td&gt;≥ $5M&lt;/td&gt;
&lt;td&gt;0.0160%&lt;/td&gt;
&lt;td&gt;0.0450%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIP 2&lt;/td&gt;
&lt;td&gt;≥ $10M&lt;/td&gt;
&lt;td&gt;0.0150%&lt;/td&gt;
&lt;td&gt;0.0360%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIP 3&lt;/td&gt;
&lt;td&gt;≥ $50M&lt;/td&gt;
&lt;td&gt;0.0100%&lt;/td&gt;
&lt;td&gt;0.0280%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most retail communities are a long tail: a handful of high-volume members and a large base at Regular. The blended rate is dominated by &lt;em&gt;where the volume sits&lt;/em&gt;, not by headcount.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# members: (monthly_notional_usd, taker_rate)
&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.0500&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="c1"&gt;# Regular
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2_500_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.0500&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="c1"&gt;# Regular
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.0450&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="c1"&gt;# VIP 1
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0360&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="c1"&gt;# VIP 2
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;55_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0280&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="c1"&gt;# VIP 3
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;total_vol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# volume-weighted blended rate
&lt;/span&gt;&lt;span class="n"&gt;blended&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_vol&lt;/span&gt;
&lt;span class="c1"&gt;# naive headcount average (the wrong way)
&lt;/span&gt;&lt;span class="n"&gt;naive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;members&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;total monthly volume: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_vol&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&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="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;blended (volume-weighted): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;blended&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="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;naive (headcount avg):     &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;naive&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total monthly volume: $77,500,000
blended (volume-weighted): 0.0329%
naive (headcount avg):     0.0418%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The naive average says 0.0418%. The real blended rate is 0.0329% — about 21% lower — because the single VIP 3 member carries most of the volume at the cheapest rate. If you price a group fee split or a community payout off the headcount average, you misjudge the pool by a fifth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two levers that move the blend
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Migration up the tiers.&lt;/strong&gt; Moving your Regular base to VIP 1 barely dents the blend — they're small volume. Moving a mid-tier member from VIP 2 to VIP 3 moves it a lot. Effort should follow volume, not headcount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A flat fee share on paid fees.&lt;/strong&gt; A partner-tier split applies the same fraction to everyone's paid fee regardless of tier, so it lowers the blended &lt;em&gt;net&lt;/em&gt; rate uniformly — often a bigger, more predictable lever for the low-volume majority than chasing a tier they'll never reach.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I keep the underlying tier tables and a few community fee models in a public repo: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;https://github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt; — pull requests with other venues' schedules are welcome. The full OKX VIP tier breakdown (spot + futures, and the asset-vs-volume qualification rule) is here: &lt;a href="https://www.jacktrader.xyz/en/blog/okx-vip-fee-tiers-2026.html" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/blog/okx-vip-fee-tiers-2026.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Model your community off the volume-weighted number, not the member count. The distribution is almost always more lopsided than it feels.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not financial advice — educational modeling only. Fee schedules reflect published rates at time of writing and can change.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>trading</category>
      <category>crypto</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Default fee configs in Hummingbot, Freqtrade, and OctoBot are all wrong — differently</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Sat, 11 Jul 2026 03:33:18 +0000</pubDate>
      <link>https://dev.to/jacktrader/default-fee-configs-in-hummingbot-freqtrade-and-octobot-are-all-wrong-differently-44h1</link>
      <guid>https://dev.to/jacktrader/default-fee-configs-in-hummingbot-freqtrade-and-octobot-are-all-wrong-differently-44h1</guid>
      <description>&lt;p&gt;If you run a market-making or grid bot, the single number that decides whether your backtest survives contact with a live account is the fee assumption baked into your config. I pulled the default fee settings out of three popular open-source frameworks and compared them against what the venues actually charge in mid-2026. All three are wrong — but they're wrong in different directions, and that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The defaults, side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Default maker&lt;/th&gt;
&lt;th&gt;Default taker&lt;/th&gt;
&lt;th&gt;What it assumes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hummingbot&lt;/td&gt;
&lt;td&gt;0.10%&lt;/td&gt;
&lt;td&gt;0.10%&lt;/td&gt;
&lt;td&gt;Flat symmetric fee, no tier logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freqtrade&lt;/td&gt;
&lt;td&gt;0.10% (single &lt;code&gt;fee&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;0.10%&lt;/td&gt;
&lt;td&gt;One value applied to both sides&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OctoBot&lt;/td&gt;
&lt;td&gt;0.10% / 0.10%&lt;/td&gt;
&lt;td&gt;reads from ccxt&lt;/td&gt;
&lt;td&gt;Pulls venue defaults, ignores your tier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The common failure is symmetry. Every one of these treats maker and taker as equal by default, but a post-only grid on a major venue in 2026 is paying maker rates that can be &lt;strong&gt;negative to +0.02%&lt;/strong&gt;, while taker is closer to 0.04–0.05%. If your bot fills 80% maker, a flat 0.10% assumption overstates cost by roughly 3–5x on the side that dominates your fills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why each one bites you differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hummingbot&lt;/strong&gt; hardcodes the symmetric 0.10% in the connector config. It's honest that it's a placeholder, but most people never edit it. Your PnL curve looks conservative — which feels safe until the strategy that "worked" in sim was only profitable &lt;em&gt;because&lt;/em&gt; the fake fee drag hid overtrading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freqtrade&lt;/strong&gt; collapses both sides into one &lt;code&gt;fee&lt;/code&gt; field. There is no maker/taker split at all, so a maker-heavy strategy is systematically punished and a taker-heavy one flattered. Same number, opposite bias.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OctoBot&lt;/strong&gt; does the smart thing and reads fees from ccxt — but ccxt returns the &lt;em&gt;public default&lt;/em&gt; tier, not your account's actual schedule. If you're on a higher volume tier or a partner-linked account, the real number your account settles at can be materially lower than what the sim used.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A quick sanity check
&lt;/h2&gt;

&lt;p&gt;Before trusting any of them, print the effective rate your bot is actually using per side:&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;mkt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;market&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BTC/USDT&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;maker:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mkt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maker&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:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mkt&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# then reconcile against a real settled fill:
# fee_paid / notional  ==  effective_rate
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that ratio doesn't match your config, every equity curve you've drawn is fiction on the fee axis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did about it
&lt;/h2&gt;

&lt;p&gt;I keep a small dataset of the fee schedules I actually settle at per venue and per tier, so the number in the config is the number the account pays, not a framework placeholder. The raw tables are here: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;https://github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt; — and I wrote up how the maker/taker split and tier attribution actually flow through a bot's PnL here: &lt;a href="https://www.jacktrader.xyz/en/blog/hummingbot-fee-rebate.html" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/blog/hummingbot-fee-rebate.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tools aren't wrong to ship a placeholder — they just can't know your tier. That's your job to fill in.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;None of this is financial advice; verify current schedules against your own account before trading.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>trading</category>
      <category>python</category>
      <category>crypto</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Maker-taker economics for grid bots: when post-only actually pays</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Fri, 10 Jul 2026 03:36:14 +0000</pubDate>
      <link>https://dev.to/jacktrader/maker-taker-economics-for-grid-bots-when-post-only-actually-pays-4ihm</link>
      <guid>https://dev.to/jacktrader/maker-taker-economics-for-grid-bots-when-post-only-actually-pays-4ihm</guid>
      <description>&lt;p&gt;Grid bots don't win by predicting direction — they win on fee bps. Every rung you fill is one leg of a round trip, and a grid that trades 400 times a day turns a 1 bps fee gap into real money. The question isn't "maker or taker" in the abstract; it's whether forcing post-only actually earns its keep once you count the fills you &lt;em&gt;miss&lt;/em&gt; by insisting on being a maker.&lt;/p&gt;

&lt;p&gt;Here's the trade-off in one line: post-only guarantees the maker rate but rejects any order that would cross the book, so in fast markets some rungs never fill and you lose that grid step. A taker order fills every time but pays the higher rate.&lt;/p&gt;

&lt;p&gt;The break-even is easy to model. Let:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m&lt;/code&gt; = maker fee (bps)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt; = taker fee (bps)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p&lt;/code&gt; = probability a post-only rung actually fills before price walks away&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g&lt;/code&gt; = grid step captured per successful round trip (bps)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A post-only rung's expected value per attempt is &lt;code&gt;p * (g - 2m)&lt;/code&gt;. A taker rung's is &lt;code&gt;g - 2t&lt;/code&gt; (it always fills). Post-only wins when:&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;post_only_wins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&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="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ev_maker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# fills with prob p, pays maker both legs
&lt;/span&gt;    &lt;span class="n"&gt;ev_taker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# always fills, pays taker both legs
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ev_maker&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ev_taker&lt;/span&gt;

&lt;span class="c1"&gt;# 5 bps grid step, maker 2 bps, taker 5 bps
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;post_only_wins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# 0.60 False
# 0.72 True (right at the edge)
# 0.90 True
# 1.00 True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a 5 bps step and a 2/5 maker-taker split, post-only stops paying off once your fill probability drops below ~0.72. On a tight, liquid pair where post-only fills 90%+ of the time, maker-only is clearly correct. On a thin pair during a move, where half your post-only rungs get rejected, you're better off just taking.&lt;/p&gt;

&lt;p&gt;Net cost per round trip (both legs) at a few fee tiers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;maker/taker (bps)&lt;/th&gt;
&lt;th&gt;maker round trip&lt;/th&gt;
&lt;th&gt;taker round trip&lt;/th&gt;
&lt;th&gt;crossover fill-prob (g=5)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2 / 5&lt;/td&gt;
&lt;td&gt;4 bps&lt;/td&gt;
&lt;td&gt;10 bps&lt;/td&gt;
&lt;td&gt;0.72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 / 4&lt;/td&gt;
&lt;td&gt;2 bps&lt;/td&gt;
&lt;td&gt;8 bps&lt;/td&gt;
&lt;td&gt;0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 / 5&lt;/td&gt;
&lt;td&gt;0 bps&lt;/td&gt;
&lt;td&gt;10 bps&lt;/td&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical takeaway: measure your &lt;em&gt;actual&lt;/em&gt; post-only fill rate per pair — most bot frameworks log rejected orders, so count them — plug it in, and stop assuming maker-only is free. It isn't; the hidden cost is the fills you never got.&lt;/p&gt;

&lt;p&gt;I keep the raw per-exchange fee tiers I use for this in a public dataset: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;https://github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A longer write-up on grid fee optimization with worked examples is here: &lt;a href="https://www.jacktrader.xyz/en/blog/grid-bot-fee-optimization.html" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/blog/grid-bot-fee-optimization.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not financial advice — just the arithmetic. Your fill rates and fee tiers are yours to measure.&lt;/p&gt;

</description>
      <category>python</category>
      <category>crypto</category>
      <category>trading</category>
      <category>datascience</category>
    </item>
    <item>
      <title>The payout math of running a trading community (a 3-variable model)</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Tue, 07 Jul 2026 00:52:19 +0000</pubDate>
      <link>https://dev.to/jacktrader/the-payout-math-of-running-a-trading-community-a-3-variable-model-1hfi</link>
      <guid>https://dev.to/jacktrader/the-payout-math-of-running-a-trading-community-a-3-variable-model-1hfi</guid>
      <description>&lt;p&gt;Most people who run a trading group, a signals channel, or a bot community have never modeled what that audience is worth in &lt;em&gt;fee flow&lt;/em&gt;. Not token-hype worth — boring, recurring, fee-flow worth. It's a three-variable problem, so let's model it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three numbers that matter
&lt;/h2&gt;

&lt;p&gt;Every major exchange pays partners out of the same pool: the trading fees their introduced users generate. Which means your channel's monthly value is just:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Active traders&lt;/strong&gt; you actually send (not subscribers — people who trade)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume per trader per month&lt;/strong&gt;, in USD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effective fee rate&lt;/strong&gt;, in basis points (perps taker is the workhorse here)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Multiply, then apply whatever &lt;strong&gt;split&lt;/strong&gt; the program gives you.&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;monthly_payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;traders&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="n"&gt;vol_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fee_bps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traders&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;vol_usd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fee_bps&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10_000&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fees&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;

&lt;span class="c1"&gt;# a 50-person bot community, $200k/mo each, 2 bps taker, 35% split
&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;monthly_payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# -&amp;gt; 700.0 USD / month
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why the naive estimate is usually wrong
&lt;/h2&gt;

&lt;p&gt;Three corrections that move the answer by 2–5x in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bots trade more than humans.&lt;/strong&gt; A grid or DCA bot at $200k/mo is a &lt;em&gt;small&lt;/em&gt; bot. Communities built around automated strategies routinely average 5–10x the volume of discretionary-trader communities of the same size. If your 50 people run bots, the example above is closer to $3,500–$7,000/mo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fee tiers cut both ways.&lt;/strong&gt; High-volume users climb VIP tiers, and their taker fee drops (say 5 bps → 2 bps). Your payout pool shrinks with it. Model the &lt;em&gt;blended&lt;/em&gt; rate of your actual audience, not the headline rate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The split itself is tiered.&lt;/strong&gt; This is the part almost nobody prices in: the public self-serve rate and the negotiated partner tiers can differ by 10–20 percentage points for exactly the same audience. On a $10k/yr fee pool, that difference is rent money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity, quick and dirty
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traders&lt;/th&gt;
&lt;th&gt;Vol/mo each&lt;/th&gt;
&lt;th&gt;Blended bps&lt;/th&gt;
&lt;th&gt;Split 20%&lt;/th&gt;
&lt;th&gt;Split 35%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$100k&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;$175&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;$200k&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;$400&lt;/td&gt;
&lt;td&gt;$700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;$1M (bots)&lt;/td&gt;
&lt;td&gt;1.8&lt;/td&gt;
&lt;td&gt;$1,800&lt;/td&gt;
&lt;td&gt;$3,150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;$500k&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;$4,000&lt;/td&gt;
&lt;td&gt;$7,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The lesson from the table: &lt;strong&gt;the split tier you land matters more than adding 30% more users.&lt;/strong&gt; Negotiating (or qualifying into) a higher tier is the highest-leverage move available to a channel owner, and it costs nothing.&lt;/p&gt;

&lt;p&gt;I wrote up a tier-by-tier breakdown of one major exchange's partner program — thresholds, what's negotiable, and the exact payout mechanics — here: &lt;a href="https://www.jacktrader.xyz/en/blog/okx-sub-broker-affiliate-program.html" rel="noopener noreferrer"&gt;OKX partner-tier breakdown, with numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And the raw fee schedules I used (maker/taker per VIP tier, per exchange, as JSON) are open-sourced in this repo: &lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;crypto-exchange-fee-data&lt;/a&gt; — PRs welcome if a schedule drifts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not financial advice. Numbers current as of July 2026 — always check the exchange's live schedule before modeling anything on top of it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>crypto</category>
      <category>finance</category>
      <category>datascience</category>
    </item>
    <item>
      <title>I open-sourced every Binance and OKX 2026 fee tier as JSON (+ a calculator)</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Wed, 17 Jun 2026 07:36:15 +0000</pubDate>
      <link>https://dev.to/jacktrader/i-open-sourced-every-binance-and-okx-2026-fee-tier-as-json-a-calculator-fnj</link>
      <guid>https://dev.to/jacktrader/i-open-sourced-every-binance-and-okx-2026-fee-tier-as-json-a-calculator-fnj</guid>
      <description>&lt;p&gt;If you've ever written a backtest or a fee-aware order router for Binance or OKX, you've hit this wall: the exchanges publish their fee schedules as HTML tables that change without notice, and there's no clean machine-readable source. So you end up hardcoding &lt;code&gt;0.0004&lt;/code&gt; somewhere and forgetting about it until your live PnL doesn't match your sim.&lt;/p&gt;

&lt;p&gt;I got tired of that, so I open-sourced the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt;&lt;/strong&gt; (MIT)&lt;/p&gt;

&lt;p&gt;Every VIP tier for Binance (spot + USD-M futures) and OKX (futures), maker/taker, as JSON — plus the qualification rules and a small CLI calculator. No dependencies, stdlib only.&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;"tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VIP 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"futures_vol_min_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0140&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"taker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0350&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;Rates are in &lt;strong&gt;percent&lt;/strong&gt; (so &lt;code&gt;0.0140&lt;/code&gt; means 0.014%, i.e. 1.4 bps), which is the unit the exchanges themselves print. Pick whichever convention you want, just be consistent — mixing percent and fraction is the #1 fee bug I see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part most people get wrong
&lt;/h2&gt;

&lt;p&gt;Your real per-trade cost isn't one number. It's a stack:&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;effective_fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;base_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VIP&lt;/span&gt; &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;token_discount&lt;/span&gt; &lt;span class="nf"&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rebate_share&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three independent levers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;VIP tier&lt;/strong&gt; sets the base rate. On Binance it's gated on 30-day volume &lt;strong&gt;plus&lt;/strong&gt; a BNB-balance floor, recalculated daily at 00:00 UTC on a rolling window — so your tier can silently drop overnight. On OKX it's the &lt;em&gt;better of&lt;/em&gt; 30-day volume &lt;strong&gt;or&lt;/strong&gt; assets held, which means a high-balance/low-frequency account can sit at a tier it would never reach on volume alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token discount&lt;/strong&gt; — paying fees in BNB knocks 25% off spot / 10% off futures. OKB is woven into OKX's tier qualification instead of a flat toggle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebate&lt;/strong&gt; — an affiliate/sub-broker partner can pass back a slice of the fee. This one is multiplicative on top of the other two and most people leave it on the table.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The calculator models all three:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 calculator.py &lt;span class="nt"&gt;--exchange&lt;/span&gt; binance &lt;span class="nt"&gt;--market&lt;/span&gt; futures &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--volume&lt;/span&gt; 10_000_000 &lt;span class="nt"&gt;--maker-share&lt;/span&gt; 0.7 &lt;span class="nt"&gt;--rebate&lt;/span&gt; 0.4
&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;Binance futures — tier Regular (maker 0.02% / taker 0.05%)
Blended rate: 0.0290%
Gross monthly fee on $10,000,000: $2,900.00
After 40% rebate: $1,740.00  (rebate back: $1,160.00)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A worked detail that surprises people: at $10M/month futures, Binance is still &lt;strong&gt;Regular&lt;/strong&gt; tier (its futures gate is $15M) while OKX already auto-qualifies &lt;strong&gt;VIP 2&lt;/strong&gt; ($10M gate). Same volume, different base rate — your fee model has to branch per-exchange, not share one tier table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I care about this number
&lt;/h2&gt;

&lt;p&gt;I run &lt;a href="https://www.jacktrader.xyz/en/" rel="noopener noreferrer"&gt;JackTrader&lt;/a&gt;, an independent fee-rebate channel for Binance and OKX (not affiliated with either — I'm a sub-broker partner). The repo is the same data I use to reconcile rebate statements, so it's in my interest to keep it accurate. If you want the deep-dive write-ups, the tier mechanics are here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.jacktrader.xyz/en/blog/binance-vip-fee-tiers-2026.html" rel="noopener noreferrer"&gt;Binance VIP fee tiers 2026 — the full breakdown&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jacktrader.xyz/en/blog/okx-vip-fee-tiers-2026.html" rel="noopener noreferrer"&gt;OKX VIP fee tiers 2026 — the assets-OR-volume rule&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jacktrader.xyz/en/blog/crypto-fee-rebate-explained.html" rel="noopener noreferrer"&gt;How a sub-broker rebate actually works (no keys, no custody)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contributions welcome
&lt;/h2&gt;

&lt;p&gt;If you spot a stale rate — exchanges revise these a few times a year — open a PR against the JSON and I'll merge it. The whole point is one source of truth the community can keep current instead of everyone hardcoding their own.&lt;/p&gt;

&lt;p&gt;Star the repo if it saves you a fee bug: &lt;strong&gt;&lt;a href="https://github.com/jack0752168/crypto-exchange-fee-data" rel="noopener noreferrer"&gt;github.com/jack0752168/crypto-exchange-fee-data&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclaimer: fee schedules change; always confirm against the exchange's own page before trading. "Up to 40%" rebate is a maximum reference, not a guarantee, and depends on platform policy and account status. Nothing here is investment advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>crypto</category>
      <category>api</category>
    </item>
    <item>
      <title>The Fee Assumption Quietly Wrong in Most Backtests</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Mon, 15 Jun 2026 04:02:57 +0000</pubDate>
      <link>https://dev.to/jacktrader/the-fee-assumption-quietly-wrong-in-most-backtests-1jpa</link>
      <guid>https://dev.to/jacktrader/the-fee-assumption-quietly-wrong-in-most-backtests-1jpa</guid>
      <description>&lt;p&gt;If you've written a crypto backtester, there's a decent chance one line in it is quietly wrong. It's not the slippage model, not the funding rate, not the fill logic. It's the fee.&lt;/p&gt;

&lt;p&gt;I've reviewed a lot of grid-bot and market-making backtests over the past couple of years, and the fee handling falls into three buckets, roughly in order of how common they are:&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;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;              &lt;span class="c1"&gt;# "I'll add fees later" (you won't)
&lt;/span&gt;&lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;            &lt;span class="c1"&gt;# 0.1%, the spot default everyone copies
&lt;/span&gt;&lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taker_rate&lt;/span&gt;       &lt;span class="c1"&gt;# better, but still missing two layers
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a low-frequency swing strategy, getting the fee wrong by a few basis points is noise. For anything that churns — grids, scalpers, MM, anything with a high turnover ratio — the fee assumption is one of the largest single error terms in the whole backtest. And it's wrong in a direction that flatters your results, which is the worst kind of wrong.&lt;/p&gt;

&lt;p&gt;Let me break down the four things a realistic fee model needs, then show what happens to net PnL when you actually wire them in.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Maker/taker asymmetry is not a rounding error
&lt;/h2&gt;

&lt;p&gt;The 0.1% default comes from Binance &lt;strong&gt;spot&lt;/strong&gt;, where maker and taker are symmetric at the Regular tier. But most bot volume lives in USDT-M perpetual futures, where the schedule is asymmetric. Per Binance's official fee schedule, USDT-M futures at the Regular tier are roughly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maker: &lt;strong&gt;0.02%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Taker: &lt;strong&gt;0.05%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a 2.5x difference between the two. If your grid uses post-only limit orders for entries and exits (as most well-built grids do), you're paying the maker rate on the bulk of your fills — which means a backtest hardcoded at 0.1% is overcharging you by 5x, and a backtest hardcoded at the taker rate is overcharging you by 2.5x.&lt;/p&gt;

&lt;p&gt;Either way, the point stands: a single &lt;code&gt;fee&lt;/code&gt; constant cannot represent reality. You need to model your &lt;strong&gt;maker share&lt;/strong&gt; — the fraction of fills that rest on the book versus cross the spread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;blended_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maker_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taker_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maker_share&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;maker_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;maker_share&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;taker_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;maker_share&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# A tight grid running post-only exits, ~90% maker:
&lt;/span&gt;&lt;span class="nf"&gt;blended_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0005&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# -&amp;gt; 0.000230  (2.3 bps)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your maker share is a real, measurable property of your strategy. Pull it from your fill logs. Don't guess it, and definitely don't assume 100% — even post-only grids eat taker fills when the market gaps through a level.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The BNB / token discount
&lt;/h2&gt;

&lt;p&gt;If you pay fees in BNB on Binance, futures fees drop by a further 10% (spot gets 25%), per the exchange's official schedule. OKX has an equivalent mechanic. This is a flat multiplier on the blended rate:&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;after_token_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.10&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;rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small, but it stacks, and stacking is the whole game here.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. VIP tiers — model the tier you're actually in
&lt;/h2&gt;

&lt;p&gt;Exchange fee schedules step down as 30-day volume climbs. The trap in backtesting is assuming the VIP-9 maker rate while testing a strategy that will never do VIP-9 volume. Model the tier your live volume actually qualifies for. If you're a $20M/month desk, that's roughly VIP 1 territory on Binance futures — meaningful, but not the rebate-on-fills fantasy of the top tiers. Be honest about where you sit.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The rebate layer almost nobody models
&lt;/h2&gt;

&lt;p&gt;This is the one that's genuinely absent from most backtests, because most devs don't know it exists. A meaningful slice of the fee you pay can come back to you as a rebate.&lt;/p&gt;

&lt;p&gt;Exchanges run affiliate / sub-broker programs that pay a share of the fees your account generates. If your account is bound to such a channel, you get a slice back — single-level referral, paid on your own trading volume, typically settled weekly. The headline figure is &lt;strong&gt;up to 40%&lt;/strong&gt; of the affiliate's fee share (the exact number depends on the exchange's official schedule, your account status, review, and your jurisdiction — it's a maximum reference, not a guaranteed return).&lt;/p&gt;

&lt;p&gt;The key insight for a quant: this is not a marketing perk, it's a term in your cost function. It applies &lt;em&gt;after&lt;/em&gt; the discount, on the fees you've already paid:&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;effective_fee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blended&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token_discount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rebate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;gross&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notional&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;blended&lt;/span&gt;
    &lt;span class="n"&gt;after_discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gross&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;token_discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;after_discount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rebate&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;net&lt;/span&gt;

&lt;span class="c1"&gt;# $20M monthly notional, 90% maker, BNB discount, up to 40% rebate
&lt;/span&gt;&lt;span class="nf"&gt;effective_fee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.000230&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# -&amp;gt; $2,484
# vs the naive 0.1% model on the same notional:
&lt;/span&gt;&lt;span class="mi"&gt;20_000_000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;                                &lt;span class="c1"&gt;# -&amp;gt; $20,000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The naive model says you'll pay $20k/month in fees. The realistic model says ~$2.5k. That's not a tweak — it's an &lt;strong&gt;8x&lt;/strong&gt; difference in your single largest controllable cost. A strategy that looks marginal at 0.1% can be solidly profitable once you model the fee correctly; conversely, a strategy that looks great at 0-fee can be dead on arrival.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: a 5-bot grid desk
&lt;/h2&gt;

&lt;p&gt;Take a desk running five grid bots at $20M combined monthly notional, split $16M maker / $4M taker. Working it through the official Binance futures schedule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Monthly cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gross fees (0.02% / 0.05% blended)&lt;/td&gt;
&lt;td&gt;~$5,200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After BNB discount (−10% futures)&lt;/td&gt;
&lt;td&gt;~$4,680&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After rebate (up to 40% back, weekly)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$2,808 net&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Roughly &lt;strong&gt;$1,872/month recovered&lt;/strong&gt; that a naive backtest would have silently expensed — about $22k/year. On a strategy whose edge might be a few hundred bps annually on deployed capital, that rebate layer can be the difference between green and red. The full grid-specific breakdown, including how maker-share optimization interacts with VIP tiers, is laid out here: &lt;a href="https://www.jacktrader.xyz/en/blog/grid-bot-fee-optimization.html" rel="noopener noreferrer"&gt;grid-bot fee optimization&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical takeaway
&lt;/h2&gt;

&lt;p&gt;Replace your &lt;code&gt;fee&lt;/code&gt; constant with an effective-fee function:&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;effective&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;blended_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&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="n"&gt;maker_share&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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;token_discount&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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rebate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then sanity-check it against your real account: pull a month of fills, sum what you actually paid net of any rebate, and reconcile it against what your model predicts. If they don't match, your backtest's PnL is fiction at the margin — and for a high-turnover strategy, the margin is the whole business.&lt;/p&gt;

&lt;p&gt;Two honest caveats. First, rebate eligibility and exact rates depend on the exchange's official program, account review, and your local regulations and KYC — model it as "up to," never as a guaranteed number. Worth noting the channels are single-level referral on your own volume, not anything multi-tier. Second, none of this is investment advice; it's cost modeling. A correctly modeled fee can turn a losing strategy profitable on paper, but it doesn't change the strategy's actual edge — it just stops you from lying to yourself about your costs. If you want the mechanics of how the rebate is structured and settled, the reference I used is here: &lt;a href="https://www.jacktrader.xyz/en/okx-rebate.html" rel="noopener noreferrer"&gt;OKX rebate / sub-broker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Model your real effective fee. It's the cheapest alpha in your stack — you're already paying for it.&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>trading</category>
      <category>algotrading</category>
    </item>
    <item>
      <title>Grid Bot Fees Are Quietly Eating Your Returns: The Quant Fee Checklist</title>
      <dc:creator>Jack Chen</dc:creator>
      <pubDate>Wed, 10 Jun 2026 10:20:34 +0000</pubDate>
      <link>https://dev.to/jacktrader/grid-bot-fees-are-quietly-eating-your-returns-the-quant-fee-checklist-2cbc</link>
      <guid>https://dev.to/jacktrader/grid-bot-fees-are-quietly-eating-your-returns-the-quant-fee-checklist-2cbc</guid>
      <description>&lt;p&gt;If you run a grid bot or any automated strategy, you've optimized the spacing, the range, the rebalance logic. But the fee side often goes unexamined — and on a high-churn bot it can quietly eat 20-30% of your gross returns. Here's the checklist I use.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Know your &lt;em&gt;effective&lt;/em&gt; fee, not the headline
&lt;/h2&gt;

&lt;p&gt;The exchange shows 0.02% maker / 0.05% taker on futures. Your real cost is the blend:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;effective_fee = maker_share * maker_fee + (1 - maker_share) * taker_fee&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Most bot operators assume they're mostly maker. Verify it. If your grid uses post-only orders you should be 90%+ maker. If you cross the spread to guarantee fills, you're paying taker on those, and it adds up fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Three levers that cut the effective fee
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maker share&lt;/strong&gt; — switch limit orders to post-only (rejected if it would take, so you never accidentally pay taker).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VIP tier&lt;/strong&gt; — your 30-day volume already discounts your base fee; concentrate volume on one venue to climb faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fee rebate&lt;/strong&gt; — a referral / sub-broker channel passes back a percentage of the fee you pay. It stacks on top of the VIP tier and token discount (BNB / OKB); it does not replace them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. The rebate is the most-overlooked lever
&lt;/h2&gt;

&lt;p&gt;The standard referral code caps the rebate at ~20%. A sub-broker channel pushes it toward 40%. For a bot doing $5M/month that's a few hundred dollars a month back — pure margin, no strategy change.&lt;/p&gt;

&lt;p&gt;Full grid-bot fee math (worked examples for $5M / $20M / $50M desks, Binance vs OKX vs perp DEX): &lt;a href="https://www.jacktrader.xyz/en/blog/grid-bot-fee-optimization.html" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/blog/grid-bot-fee-optimization.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free calculator for the effective-fee math on both exchanges: &lt;a href="https://www.jacktrader.xyz/en/" rel="noopener noreferrer"&gt;https://www.jacktrader.xyz/en/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Up to 40% is a maximum, not guaranteed. Independent referral / sub-broker partner, not affiliated with Binance or OKX. Not financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>trading</category>
      <category>python</category>
    </item>
  </channel>
</rss>
