pmfees
Exact trading fees for the prediction market platforms Kalshi, Polymarket US and polymarket.com (international), as a small Python library and a command line tool.
- The platforms' own formulas and rounding rules: Kalshi rounds up so that fee + position cost is a whole centicent ($0.0001), Polymarket US rounds to the cent with banker's rounding, polymarket.com rounds to 5 decimals.
- Exact decimal arithmetic (
decimal.Decimal), so $1.75 is $1.75 and not $1.7500000000000002. - A break-even helper: how far the price has to move before a round trip is in profit after the fee on both orders.
- No dependencies outside the Python standard library. Typed (
py.typed).
Rates current as of: Kalshi 2026-11-10 (fee schedule 7.7.26), Polymarket US 2026-11-09, polymarket.com 2026-11-08. Each platform's date and source are in the rates file and in every result.
Other ways to get the same numbers, from the same rates file:
- In a browser: the SwapHunt Kalshi vs Polymarket fee calculator.
- Over HTTP, for agents:
GET https://x402.swaphunt.dev/v1/pm/fees, paid per call with x402 in USDC. This package is free; the endpoint exists for agents that cannot install a library.
Install
pip install pmfees
Python 3.10 or newer.
Command line
pmfees kalshi --price 0.50 --contracts 100
Kalshi taker fee: $1.75 (3.50% of trade value at 50¢)
buy 100 contracts at $0.50 = $50.00 trade value
base rate: 0.07
multiplier: 1
fee schedule version: 7.7.26
0.07 × 100 × 0.5 × (1 − 0.5) = 1.75, rounded up so that fee + position cost is a whole centicent ($0.0001): $1.75
rates as of 2026-11-10 · source: https://kalshi.com/docs/kalshi-fee-schedule.pdf
More examples:
# Polymarket US, Tier 1 (under $10,000 of 30-day taker volume, the default)
pmfees polymarket-us --price 0.50 --contracts 100
# -> Polymarket US taker fee: $2.38 (4.76% of trade value at 50¢) [0.095 × 100 × 0.5 × 0.5 = 2.375]
# polymarket.com, Crypto category
pmfees polymarket --price 0.25 --contracts 100 --category Crypto
# -> polymarket.com taker fee: $1.3125 (5.25% of trade value at 25¢)
# Break-even: buy 100 on Kalshi at 50¢, when is selling in profit?
pmfees kalshi --price 0.50 --contracts 100 --break-even
# -> Break-even: the price must rise 4¢ to 54¢ (tick 1¢); entry fee $1.75 + exit fee $1.7388, profit at that price $0.5112
Options:
| Option | Platforms | Meaning |
|---|---|---|
--price |
all | Price of the contract you trade, in dollars (0 < price < 1) |
--contracts |
all | Number of contracts (shares on polymarket.com): whole contracts on Kalshi, steps of 0.01 on Polymarket US, up to 6 decimals on polymarket.com |
--side buy|sell |
all | Changes the cash flow only; the fee formulas are symmetric |
--maker |
all | Maker order. Kalshi: maker rate 0.0175 with M default 0, so pass --multiplier 1 on markets with maker fees. Polymarket US and polymarket.com: makers pay no fee |
--multiplier |
kalshi | Fee multiplier M (default 1 for takers, 0 for makers) |
--tier 1-4|new |
polymarket-us | Taker tier, or new for the first 7 days of a new account (default 1) |
--volume |
polymarket-us | Trailing 30-day taker volume in USD; picks the tier for you |
--category |
polymarket | Market category, e.g. Crypto, Sports, Politics (required) |
--break-even, --tick |
all | Also print the break-even move (price step, default 0.01) |
--json |
all | Machine-readable output |
--rates PATH |
all | Use an updated rates file |
pmfees rates prints the loaded rates and their date.
Library
from pmfees import fee, break_even
r = fee("kalshi", 0.50, 100)
r.fee # Decimal('1.7500') what you pay, in USD
r.raw_fee # Decimal('1.7500') before rounding
r.fee_pct_of_trade_value # Decimal('3.500')
r.breakdown() # dict of strings: coefficient, rounding, formula, source_url, rates_as_of, ...
fee("polymarket-us", 0.10, 1000, "buy", tier=4).fee # Decimal('6.26')
fee("polymarket-us", 0.10, 1000, volume_30d=12_500).fee # Tier 2
fee("polymarket", 0.25, 100, category="Crypto").fee # Decimal('1.31250')
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') centicent rounding, not $0.02
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker M defaults to 0
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375')
fee("kalshi", 0.50, 100, multiplier=0.5).fee # Decimal('0.8750')
b = break_even("polymarket-us", 0.40, 500, tier=2)
b.exit_price, b.move_cents # (Decimal('0.45'), Decimal('5.00'))
Signature: fee(platform, price, contracts, side="buy", tier=None, maker=False, *, category=None, multiplier=None, volume_30d=None, rates=None) -> FeeResult. Platform names: kalshi,
polymarket-us, polymarket (also polymarket.com). Prices and counts can be str, int,
float or Decimal; floats are converted through str, so 0.1 means exactly 0.1.
break_even(...) takes the same arguments plus tick. It opens the position at price, then
walks the price in tick steps (up for a buy, down for a sell) and returns the first exit price
where proceeds − cost − entry fee − exit fee > 0, or exit_price=None if no price before $1 (or
$0) works.
Kalshi: centicent rounding and the multiplier
Kalshi does not round the fee on its own. It rounds fee + position cost (contracts × price) up to a whole centicent ($0.0001), per the fee schedule (version 7.7.26, page 2). Most of the time that looks like rounding the fee up to four decimals, but the fee alone is what you see change:
from pmfees import fee
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') 0.07 × 1 × 0.5 × 0.5 = 0.0175 exactly; not $0.02
fee("kalshi", 0.33, 7).fee # Decimal('0.1084') raw 0.108339; 2.31 + 0.108339 = 2.418339 -> 2.4184
Accounts cleared through a broker (FCM) keep balances in whole cents, so there the fee rounds to the cent (Kalshi docs). pmfees models kalshi.com accounts (direct members).
Each Kalshi series has a fee multiplier M: 1 (standard), 0.5 or 0. Takers default to M = 1, makers to M = 0, because Kalshi charges makers only on series listed with maker fees:
fee("kalshi", 0.25, 100).fee # Decimal('1.3125') M = 1
fee("kalshi", 0.25, 100, multiplier=0.5).fee # Decimal('0.6563') raw 0.65625, rounded up
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker, M defaults to 0
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375') 0.0175 × 100 × 0.25
pmfees kalshi --price 0.25 --contracts 100 --multiplier 0.5
# -> Kalshi taker fee: $0.6563 (2.63% of trade value at 25¢)
The formulas
| Platform | Taker fee | Rounding |
|---|---|---|
| Kalshi | M × 0.07 × C × P × (1 − P), M default 1; maker M × 0.0175 × C × P × (1 − P), M default 0 | Up, so that fee + position cost is a whole centicent ($0.0001) |
| Polymarket US | Θ × C × p × (1 − p), Θ by 30-day taker volume: 0.095 (< $10K), 0.085 (< $50K), 0.075 (< $250K), 0.0695 ($250K+); new accounts 0.0695 for the first 7 days | Nearest cent, half to even |
| polymarket.com | C × rate × p × (1 − p), rate by category (Crypto 0.07; Sports, Economics, Culture, Weather, Other, Combos 0.05; Finance, Politics, Mentions, Tech 0.04; Geopolitics 0) | 5 decimals |
The numbers in this table are for reading only. The code takes every rate, tier, multiplier and
rounding rule (including Kalshi's fee + position cost basis) from prediction_market_fees.json.
Not modelled: Polymarket US combo fees and maker rebates, polymarket.com maker and taker rebate
programs, and per-market exceptions (polymarket.com
markets carry their own feeSchedule, Kalshi series their own multiplier). Check the market when
it matters.
Sources
| Platform | Source | Rates current as of |
|---|---|---|
| Kalshi | https://kalshi.com/docs/kalshi-fee-schedule.pdf (version 7.7.26) | 2026-11-10 |
| Polymarket US | https://docs.polymarket.us/fees | 2026-11-09 |
| polymarket.com | https://docs.polymarket.com/trading/fees | 2026-11-08 |
The tests lock the formulas to the worked examples and fee tables on these pages, with a link to the source in each test.
Updating the rates
All rates live in src/pmfees/data/prediction_market_fees.json. Each platform has its own as_of
(the date its rates were last checked against source_url). SwapHunt checks the official fee pages
every week; when a rate changes, the updated file arrives here as a pull request, and a new release
follows after review. To use newer rates without waiting for a release:
from pmfees import fee, load_rates
rates = load_rates("prediction_market_fees.json")
fee("kalshi", 0.50, 100, rates=rates)
or set PMFEES_RATES_FILE=/path/to/prediction_market_fees.json, or pass --rates on the
command line. A file with a missing field or an unknown rounding mode is rejected with a
RatesError that names the field.
Development
pip install -e . pytest ruff mypy
pytest
ruff check . && ruff format --check .
mypy
Releases go to PyPI from GitHub Actions with trusted publishing: bump __version__, add a
CHANGELOG entry, and push a v<version> tag. The publish job waits for approval.
Limitations
- pmfees checks
contractsagainst each platform's general order size step, not the step of a single market. Most Polymarket US markets trade in steps of 0.01 contracts, but a few, mostly futures, trade whole contracts only (Fractional Contracts). pmfees cannot see which market an order is for, so it accepts 0.01 steps on those markets too. Check the market's step yourself for Polymarket US futures.
Disclaimer
Fee estimates for information only. The platform's own confirmation is what you pay.
License
MIT. See LICENSE.
Metadata
Release files for pmfees 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pmfees-0.1.1.tar.gz | 28.5 kB | Without provenance | Details for pmfees-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pmfees-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for pmfees-0.1.1-py3-none-any.whl |
Total release size: 47.6 kB
Release files / pmfees-0.1.1.tar.gz
| Download URL | pmfees-0.1.1.tar.gz |
|---|---|
| Size | 28.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
73b7f1f625b7efa0fc838398e911bc4f060138310f40a611110de7eb0f280157
|
|
BLAKE2b-256 checksum How to use checksums |
143c41feb4422c3aa01f8fbb0b4ccabf6fc3be050b3046f3d8f494cd587e71c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pmfees-0.1.1-py3-none-any.whl
| Download URL | pmfees-0.1.1-py3-none-any.whl |
|---|---|
| Size | 19.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4831993650c6909d7e055724e21db6a3f34afa58cc5d9d785bb565cf3da41054
|
|
BLAKE2b-256 checksum How to use checksums |
a649a4a3513552acf0676d80ba0991baeb18eaacc0ec00886fa84dc9b84bebbe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for pmfees 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.