Zero-Commission Trading: Really Free, or Did the Cost Just Move?
Instrument: US stocks (retail brokers); relevance to forex/CFDs discussed separately · 11 October 2026
Almost every trading app now sells the same line: “zero commission”. This paper asks what its users rarely ask: if brokers no longer charge commissions, where does their money come from, and has the cost simply moved somewhere that never shows on the trade confirmation?
The moment studied is clear-cut. In October 2019, five large US retail brokers (Charles Schwab, TD Ameritrade, E*Trade, Ally Invest and Fidelity) dropped stock commissions almost at once. Retail commissions had typically been about $5 per trade.
Regulators’ worry made sense. US retail brokers usually route customer orders not to exchanges but to wholesalers that pay the broker per share: payment for order flow (PFOF). SEC Chairman Gary Gensler warned that zero commission doesn’t mean free, and doesn’t guarantee best execution.
Finding one: brokers’ Rule 606 filings and financial statements show payment for order flow barely changed after commissions were dropped. Brokers did not make up the lost commissions by squeezing customer orders harder; they absorbed the cost, because competition forced them to. The stock market noticed: on the announcement day Schwab fell about 10%, TD Ameritrade almost 26% and E*Trade about 16%.
Finding two: retail execution costs (effective spreads) barely changed after zero commissions. Retail orders were in fact filled slightly cheaper than similar exchange trades: about 4% cheaper for small orders and 15% cheaper for medium ones (for example 1.4 out of 9.3 basis points).
But zero commission is still not free. The paper’s example: buying 200 shares of a $30 stock still costs about $2.37 in execution cost through the spread. When commissions were $5, this hidden cost was already about a third of the total; with commissions gone, the whole cost sits in the spread, which never appears on a statement.
Finding three, the most important: aggregate retail trading costs fell sharply, even under the worst-case counterfactual in which every order goes to an exchange with no price improvement at all. That held even though people traded more: daily retail dollar volume rose from $7.84 billion to $8.94 billion, and trades per day from 752 thousand to over two million during the pandemic.
Here is the lesson seldom spoken: the cost per trade fell, but the temptation to trade often rose. Older research on retail investor behaviour shows that the more people trade, the worse their average results tend to be. Zero commission removed the brake that used to be felt every time the buy button was pressed.
What about Indonesia? Be careful carrying the conclusion over. This paper is about US stocks under PFOF rules and a best-execution duty overseen by the SEC. In forex and CFDs, “zero commission” usually means the broker earns from a widened spread, and some brokers act as the counterparty to their own clients. That is a different mechanism, not tested here. The most honest way to judge costs is to compute them yourself: spread times position size times number of trades.
The code below is not a strategy. It is a small MQL5 script that computes the spread cost of one round trip at the lot size you plan to use, then multiplies it by 100 trades a month. That number is the “commission” that never gets printed.
Inspect the MQL5 illustration
//+------------------------------------------------------------------+
//| BUKAN STRATEGI: kalkulator biaya transaksi yang tidak tertulis |
//| Paper ini mengingatkan bahwa "nol komisi" tidak sama dengan gratis: |
//| biaya eksekusi (spread) tetap dibayar walau tidak muncul di nota. |
//| Skrip ini menghitung berapa rupiah/dolar yang hilang ke spread |
//| untuk satu transaksi pulang-pergi pada lot tertentu. |
//+------------------------------------------------------------------+
#property script_show_inputs
input double Lot = 0.10; // ukuran posisi yang direncanakan
input double KomisiPerLot = 0.0; // komisi broker per lot pulang-pergi (isi 0 bila "nol komisi")
void OnStart()
{
string sym = _Symbol;
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
double tickVal = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
if(tickSize <= 0 || bid <= 0)
{
Print("Data simbol belum lengkap, coba lagi saat pasar buka.");
return;
}
double spread = ask - bid; // dalam harga
double biayaSpread = spread / tickSize * tickVal * Lot; // mata uang akun
double biayaKomisi = KomisiPerLot * Lot;
double total = biayaSpread + biayaKomisi;
double persen = 100.0 * spread / ((ask + bid) / 2.0);
PrintFormat("%s | spread %.1f poin (%.4f%% dari harga tengah)", sym, spread / _Point, persen);
PrintFormat("Lot %.2f: biaya spread %.2f %s + komisi %.2f = %.2f %s per transaksi pulang-pergi",
Lot, biayaSpread, AccountInfoString(ACCOUNT_CURRENCY), biayaKomisi, total,
AccountInfoString(ACCOUNT_CURRENCY));
PrintFormat("100 transaksi seperti ini per bulan = %.2f %s yang tidak tertulis sebagai 'komisi'",
100.0 * total, AccountInfoString(ACCOUNT_CURRENCY));
}