<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ReturnFee]]></title><description><![CDATA[ReturnFee]]></description><link>https://returnfee.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 13 Nov 2026 18:55:34 GMT</lastBuildDate><atom:link href="https://returnfee.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How much a trading bot loses to fees (and a 40-line script to measure yours)]]></title><description><![CDATA[Most bot backtests I see print a win rate and a P&L curve. Fewer print the one line that decides whether the bot makes money in production: what it paid in…]]></description><link>https://returnfee.hashnode.dev/how-much-a-trading-bot-loses-to-fees-and-a-40-line-script-to-measure-yours</link><guid isPermaLink="true">https://returnfee.hashnode.dev/how-much-a-trading-bot-loses-to-fees-and-a-40-line-script-to-measure-yours</guid><category><![CDATA[Python]]></category><category><![CDATA[trading, ]]></category><category><![CDATA[Cryptocurrency]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[ReturnFee]]></dc:creator><pubDate>Thu, 12 Nov 2026 14:04:27 GMT</pubDate><content:encoded><![CDATA[<p>Most bot backtests I see print a win rate and a P&amp;L curve. Fewer print the one line that decides whether the bot makes money in production: what it paid in fees.</p>
<p>Fees are charged on <strong>volume</strong>, not on profit. A bot that trades often can have a real edge and still lose, because every fill pays the exchange whether the trade worked or not.</p>
<h2>The math, with one example</h2>
<p>Exchanges charge a fee proportional to each fill's notional value (price x quantity), at one of two rates:</p>
<ul>
<li><strong>Maker</strong> rate: your order rested on the book and someone filled it (limit orders that don't cross).</li>
<li><strong>Taker</strong> rate: your order filled immediately against the book (market orders, crossing limits).</li>
</ul>
<p>A round trip (open + close) pays the fee twice:</p>
<pre><code>fee per round trip = fee on the entry fill + fee on the exit fill
</code></pre>
<p>Take a small bot. The fee below is a made-up round number, written as dollars per $1,000 traded; check your own exchange's schedule.</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Position size</td>
<td>$1,000</td>
</tr>
<tr>
<td>Round trips per day</td>
<td>20</td>
</tr>
<tr>
<td>Example taker fee</td>
<td>$0.50 per $1,000 traded, per side</td>
</tr>
</tbody></table>
<pre><code>per round trip: $0.50 entry + $0.50 exit = $1.00
per day:        20 x $1.00              = $20
per 30 days:    30 x $20                = $600
</code></pre>
<p>That bot has to make more than <strong>$1.00 per round trip</strong> before it earns a cent. If its average gross edge is $0.80 per trade, it books a profit on paper and loses $0.20 on every round trip after fees, about $120 a month.</p>
<p>Now change one thing: post limit orders and get filled as maker, at a made-up $0.20 per $1,000 per side.</p>
<pre><code>per round trip: $0.20 + $0.20    = $0.40
per 30 days:    20 x 30 x $0.40  = $240
</code></pre>
<p>Same strategy, same edge, and the monthly fee bill drops from $600 to $240. The $0.80 edge is now +$0.40 net per trade instead of -$0.20. Nothing about the signal changed; only how the orders hit the book.</p>
<p>Three things move this number more than strategy tweaks usually do:</p>
<ol>
<li><strong>Maker vs taker share.</strong> Market orders are convenient and, on most schedules, the more expensive side. (Some spot schedules charge the same rate for both at the base tier; check yours.)</li>
<li><strong>Trade frequency.</strong> Fee drag scales linearly with round trips.</li>
<li><strong>Your fee tier.</strong> Most exchanges lower rates with 30-day volume, and some also require a token balance. Check which tier you are actually on, not the headline rate.</li>
</ol>
<h2>Measure your own fee drag</h2>
<p>Most major exchanges let you export trade history as CSV. Column names differ, so rename yours to <code>time,side,price,qty,fee,realized_pnl</code> (fee in quote currency, realized P&amp;L before fees, 0 on opening fills) and run this:</p>
<pre><code class="language-python">"""fee_drag.py - how much of your trading P&amp;L went to fees.

Usage: python fee_drag.py trades.csv
CSV columns (rename yours to match): time,side,price,qty,fee,realized_pnl
  fee          = fee paid on that fill, in quote currency (positive number)
  realized_pnl = P&amp;L booked on that fill before fees (0 for opening fills)
"""
import csv, sys
from collections import defaultdict

def load(path):
    with open(path, newline="") as f:
        return [{k: (v if k in ("time", "side") else float(v)) for k, v in row.items()}
                for row in csv.DictReader(f)]

def report(rows):
    volume = sum(r["price"] * r["qty"] for r in rows)
    fees = sum(r["fee"] for r in rows)
    gross = sum(r["realized_pnl"] for r in rows)
    by_month = defaultdict(float)
    for r in rows:
        by_month[r["time"][:7]] += r["fee"]
    print(f"fills:              {len(rows)}")
    print(f"traded volume:      {volume:,.2f}")
    print(f"fees paid:          {fees:,.2f}")
    print(f"fees per $1,000:    {1000 * fees / volume:,.2f}")
    print(f"gross P&amp;L:          {gross:,.2f}")
    print(f"net P&amp;L:            {gross - fees:,.2f}")
    if gross &gt; 0:
        print(f"fees ate:           {fees / gross:.1%} of gross profit")
    for month, fee in sorted(by_month.items()):
        print(f"  {month}: {fee:,.2f} in fees")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        sys.exit(__doc__)
    report(load(sys.argv[1]))
</code></pre>
<p>Output on a synthetic file of 400 fills (made-up data, about 70% taker fills):</p>
<pre><code>fills:              400
traded volume:      479,999.82
fees paid:          197.88
fees per $1,000:    0.41
gross P&amp;L:          1,254.50
net P&amp;L:            1,056.62
fees ate:           15.8% of gross profit
  2026-09: 96.24 in fees
  2026-10: 101.64 in fees
</code></pre>
<p>The line to watch is <strong>fees ate X% of gross profit</strong>. If that number is high, a better entry signal is not your cheapest fix. Moving fills to maker, trading less often, or reaching a lower tier usually is.</p>
<p>A few gotchas when you export:</p>
<ul>
<li>Some exchanges report fees in the asset you received (or in a fee token), not the quote currency. Convert before summing.</li>
<li>Futures exports often split realized P&amp;L and fees into separate rows or files. Join them on order id.</li>
<li>Funding payments on perpetuals are a separate cost. This script doesn't count them; add them as another column if your bot holds positions across funding times.</li>
</ul>
<hr />
<p>I work on ReturnFee, a fee-cashback site. More plain explainers on how trading fees work: <a href="https://returnfee.com/learn/?utm_source=hashnode&amp;utm_medium=post">https://returnfee.com/learn/?utm_source=hashnode&amp;utm_medium=post</a></p>
]]></content:encoded></item><item><title><![CDATA[How to read an exchange fee schedule (maker, taker, tiers)]]></title><description><![CDATA[Every crypto exchange publishes a fee page, and most of them look the same: a table of tiers, two columns of percentages, and footnotes that matter more…]]></description><link>https://returnfee.hashnode.dev/how-to-read-an-exchange-fee-schedule-maker-taker-tiers</link><guid isPermaLink="true">https://returnfee.hashnode.dev/how-to-read-an-exchange-fee-schedule-maker-taker-tiers</guid><category><![CDATA[crypto]]></category><category><![CDATA[trading, ]]></category><category><![CDATA[fees ]]></category><dc:creator><![CDATA[ReturnFee]]></dc:creator><pubDate>Tue, 10 Nov 2026 13:31:32 GMT</pubDate><content:encoded><![CDATA[<p>Every crypto exchange publishes a fee page, and most of them look the same: a table of tiers, two columns of percentages, and footnotes that matter more than the table. This is a checklist for reading one in about five minutes and coming out with the number you will actually pay.</p>
<h2>1. Find the right table</h2>
<p>Most exchanges have several schedules on the same page. Before you read any number, confirm which one applies to you:</p>
<ul>
<li><strong>Spot or derivatives.</strong> Spot and futures/perpetuals almost always have separate tables, and futures rates are usually lower per side.</li>
<li><strong>Which futures.</strong> USDT-margined and coin-margined contracts can have different tables.</li>
<li><strong>Region or entity.</strong> Some exchanges run different legal entities per region with different fee pages. The page you land on from a search engine may not be the one your account uses.</li>
<li><strong>Account type.</strong> Regular, VIP, market-maker programme and sub-account rates can differ.</li>
</ul>
<p>If in doubt, your account's own fee page (usually under account settings or "My fee rate") shows your live rate. Trust that over the public table.</p>
<h2>2. Maker vs taker</h2>
<p>Each tier lists two rates:</p>
<ul>
<li><strong>Maker:</strong> you added liquidity. Your limit order sat on the book and someone else's order filled it.</li>
<li><strong>Taker:</strong> you removed liquidity. Your order filled immediately: a market order, or a limit order priced to cross the spread.</li>
</ul>
<p>What decides it is whether your order rested on the book, not whether you clicked "limit". A limit buy above the best ask fills instantly and pays taker.</p>
<p>Most exchanges offer a <strong>post-only</strong> flag on limit orders. It cancels the order instead of letting it fill as taker, which is the simplest way to ensure the maker rate.</p>
<h2>3. Read the tier table</h2>
<p>A typical table looks like this. The numbers are made up for illustration; use your exchange's own.</p>
<table>
<thead>
<tr>
<th>Tier</th>
<th>30-day volume</th>
<th>or asset balance</th>
<th>Maker</th>
<th>Taker</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>&lt; $1M</td>
<td>&lt; $10k</td>
<td>0.020%</td>
<td>0.050%</td>
</tr>
<tr>
<td>1</td>
<td>&gt;= $1M</td>
<td>&gt;= $10k</td>
<td>0.016%</td>
<td>0.045%</td>
</tr>
<tr>
<td>2</td>
<td>&gt;= $5M</td>
<td>&gt;= $50k</td>
<td>0.014%</td>
<td>0.040%</td>
</tr>
<tr>
<td>3</td>
<td>&gt;= $25M</td>
<td>&gt;= $250k</td>
<td>0.012%</td>
<td>0.035%</td>
</tr>
</tbody></table>
<p>Questions to answer from the footnotes:</p>
<ul>
<li><strong>What counts as volume?</strong> Spot and futures volume are often counted separately. Some exchanges count only one side, some include sub-accounts.</li>
<li><strong>"Or" vs "and".</strong> Many tables let you qualify by volume <em>or</em> by a held balance. Some require both.</li>
<li><strong>When is your tier recalculated?</strong> Usually once a day on a rolling 30-day window, so a big trading week moves your tier the next day, not instantly.</li>
<li><strong>Is the tier per account or per user?</strong> Sub-accounts may or may not pool.</li>
</ul>
<p>Most retail traders sit on the lowest tier, so tier 0 is usually the line to read.</p>
<h2>4. Discounts that change the real rate</h2>
<p>The table is rarely the final number. Look for:</p>
<ul>
<li><strong>Fee-token discounts.</strong> Paying fees in the exchange's own token often cuts the rate by a fixed share. Check whether it applies to futures as well as spot, and whether it needs a toggle in settings.</li>
<li><strong>Promotional zero-fee pairs.</strong> Some pairs run at zero maker or zero taker for a period. Check the end date.</li>
<li><strong>Negative maker fees (rebates).</strong> Some higher tiers pay makers. You will rarely see this below the top tiers.</li>
</ul>
<h2>5. Things the fee table does not show</h2>
<ul>
<li><strong>Funding on perpetuals.</strong> Paid or received between longs and shorts every few hours. It is not an exchange fee, but it is a cost of holding a position.</li>
<li><strong>Spread and slippage.</strong> A market order on a thin pair can cost more in slippage than in fees.</li>
<li><strong>Withdrawal and network fees.</strong> Separate page, flat per withdrawal.</li>
<li><strong>Conversion fees.</strong> "Convert" or "quick buy" screens often price the fee into the quote instead of listing it.</li>
</ul>
<h2>6. Turn it into one number</h2>
<p>Once you know your table, tier and discounts, your monthly fee bill is:</p>
<pre><code class="language-plaintext">monthly fees = volume x (maker share x maker rate + taker share x taker rate)
</code></pre>
<p>Worked example with the made-up tier 0 above, $200,000 of monthly volume, 70% taker:</p>
<pre><code class="language-plaintext">200,000 x (0.30 x 0.020% + 0.70 x 0.050%)
= 200,000 x (0.0060% + 0.0350%)
= 200,000 x 0.0410%
= $82 a month
</code></pre>
<p>Shift the split to 70% maker and the same volume costs:</p>
<pre><code class="language-plaintext">200,000 x (0.70 x 0.020% + 0.30 x 0.050%) = 200,000 x 0.0290% = $58
</code></pre>
<p>Same trades, same tier, $24 a month apart, only because of how the orders hit the book.</p>
<h2>Checklist</h2>
<ul>
<li><input disabled type="checkbox" /> Right product (spot / USDT futures / coin futures)</li>
<li><input disabled type="checkbox" /> Right entity / region</li>
<li><input disabled type="checkbox" /> My current tier, from the account page</li>
<li><input disabled type="checkbox" /> Maker and taker rate at that tier</li>
<li><input disabled type="checkbox" /> What counts toward the next tier, and when it updates</li>
<li><input disabled type="checkbox" /> Fee-token or other discounts, and whether they are switched on</li>
<li><input disabled type="checkbox" /> Funding, spread and withdrawal costs noted separately</li>
<li><input disabled type="checkbox" /> Monthly fee estimate = volume x blended rate</li>
</ul>
<hr />
<p>I work on ReturnFee, a fee-cashback site. More plain explainers on trading fees are at <a href="https://returnfee.com/learn/?utm_source=hashnode&amp;utm_medium=post">https://returnfee.com/learn/?utm_source=hashnode&amp;utm_medium=post</a>.</p>
]]></content:encoded></item></channel></rss>