pmfees 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pmfees-0.1.0/LICENSE +21 -0
- pmfees-0.1.0/MANIFEST.in +2 -0
- pmfees-0.1.0/PKG-INFO +232 -0
- pmfees-0.1.0/README.md +210 -0
- pmfees-0.1.0/pyproject.toml +52 -0
- pmfees-0.1.0/setup.cfg +4 -0
- pmfees-0.1.0/src/pmfees/__init__.py +26 -0
- pmfees-0.1.0/src/pmfees/__main__.py +3 -0
- pmfees-0.1.0/src/pmfees/cli.py +177 -0
- pmfees-0.1.0/src/pmfees/core.py +373 -0
- pmfees-0.1.0/src/pmfees/data/prediction_market_fees.json +101 -0
- pmfees-0.1.0/src/pmfees/py.typed +0 -0
- pmfees-0.1.0/src/pmfees/rates.py +265 -0
- pmfees-0.1.0/src/pmfees.egg-info/PKG-INFO +232 -0
- pmfees-0.1.0/src/pmfees.egg-info/SOURCES.txt +22 -0
- pmfees-0.1.0/src/pmfees.egg-info/dependency_links.txt +1 -0
- pmfees-0.1.0/src/pmfees.egg-info/entry_points.txt +2 -0
- pmfees-0.1.0/src/pmfees.egg-info/top_level.txt +1 -0
- pmfees-0.1.0/tests/conftest.py +6 -0
- pmfees-0.1.0/tests/fixtures/rates_2026-11-08.json +97 -0
- pmfees-0.1.0/tests/test_cli.py +55 -0
- pmfees-0.1.0/tests/test_formulas.py +279 -0
- pmfees-0.1.0/tests/test_rates.py +121 -0
- pmfees-0.1.0/tests/test_readme.py +80 -0
pmfees-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SwapHunt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pmfees-0.1.0/MANIFEST.in
ADDED
pmfees-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pmfees
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Exact trading fees for Kalshi, Polymarket US and polymarket.com, with a CLI and break-even helper.
|
|
5
|
+
Author-email: SwapHunt <github@swaphunt.dev>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/swaphunt/pmfees
|
|
8
|
+
Project-URL: Source, https://github.com/swaphunt/pmfees
|
|
9
|
+
Project-URL: Issues, https://github.com/swaphunt/pmfees/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/swaphunt/pmfees/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Fee calculator, https://swaphunt.dev/tools/kalshi-vs-polymarket-fee-calculator
|
|
12
|
+
Keywords: kalshi,polymarket,prediction markets,fees,trading
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Classifier: Development Status :: 4 - Beta
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# pmfees
|
|
24
|
+
|
|
25
|
+
Exact trading fees for the prediction market platforms **Kalshi**, **Polymarket US** and
|
|
26
|
+
**polymarket.com** (international), as a small Python library and a command line tool.
|
|
27
|
+
|
|
28
|
+
- The platforms' own formulas and rounding rules: Kalshi rounds up so that fee + position cost
|
|
29
|
+
is a whole centicent ($0.0001), Polymarket US rounds to the cent with banker's rounding,
|
|
30
|
+
polymarket.com rounds to 5 decimals.
|
|
31
|
+
- Exact decimal arithmetic (`decimal.Decimal`), so $1.75 is $1.75 and not $1.7500000000000002.
|
|
32
|
+
- A break-even helper: how far the price has to move before a round trip is in profit after
|
|
33
|
+
the fee on both orders.
|
|
34
|
+
- No dependencies outside the Python standard library. Typed (`py.typed`).
|
|
35
|
+
|
|
36
|
+
Rates current as of: Kalshi 2026-11-10 (fee schedule 7.7.26), Polymarket US 2026-11-09,
|
|
37
|
+
polymarket.com 2026-11-08. Each platform's date and source are in the rates file and in every result.
|
|
38
|
+
|
|
39
|
+
Other ways to get the same numbers, from the same rates file:
|
|
40
|
+
|
|
41
|
+
- In a browser: the [SwapHunt Kalshi vs Polymarket fee calculator](https://swaphunt.dev/tools/kalshi-vs-polymarket-fee-calculator).
|
|
42
|
+
- Over HTTP, for agents: [`GET https://x402.swaphunt.dev/v1/pm/fees`](https://swaphunt.dev/api), paid per call
|
|
43
|
+
with [x402](https://www.x402.org/) in USDC. This package is free; the endpoint exists for agents that
|
|
44
|
+
cannot install a library.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install pmfees
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Python 3.10 or newer.
|
|
53
|
+
|
|
54
|
+
## Command line
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pmfees kalshi --price 0.50 --contracts 100
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Kalshi taker fee: $1.75 (3.50% of trade value at 50¢)
|
|
62
|
+
buy 100 contracts at $0.50 = $50.00 trade value
|
|
63
|
+
base rate: 0.07
|
|
64
|
+
multiplier: 1
|
|
65
|
+
fee schedule version: 7.7.26
|
|
66
|
+
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
|
|
67
|
+
rates as of 2026-11-10 · source: https://kalshi.com/docs/kalshi-fee-schedule.pdf
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
More examples:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Polymarket US, Tier 1 (under $10,000 of 30-day taker volume, the default)
|
|
74
|
+
pmfees polymarket-us --price 0.50 --contracts 100
|
|
75
|
+
# -> Polymarket US taker fee: $2.38 (4.76% of trade value at 50¢) [0.095 × 100 × 0.5 × 0.5 = 2.375]
|
|
76
|
+
|
|
77
|
+
# polymarket.com, Crypto category
|
|
78
|
+
pmfees polymarket --price 0.25 --contracts 100 --category Crypto
|
|
79
|
+
# -> polymarket.com taker fee: $1.3125 (5.25% of trade value at 25¢)
|
|
80
|
+
|
|
81
|
+
# Break-even: buy 100 on Kalshi at 50¢, when is selling in profit?
|
|
82
|
+
pmfees kalshi --price 0.50 --contracts 100 --break-even
|
|
83
|
+
# -> 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
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
|
|
88
|
+
| Option | Platforms | Meaning |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `--price` | all | Price of the contract you trade, in dollars (0 < price < 1) |
|
|
91
|
+
| `--contracts` | all | Number of contracts (shares on polymarket.com) |
|
|
92
|
+
| `--side buy\|sell` | all | Changes the cash flow only; the fee formulas are symmetric |
|
|
93
|
+
| `--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 |
|
|
94
|
+
| `--multiplier` | kalshi | Fee multiplier M (default 1 for takers, 0 for makers) |
|
|
95
|
+
| `--tier 1-4\|new` | polymarket-us | Taker tier, or `new` for the first 7 days of a new account (default 1) |
|
|
96
|
+
| `--volume` | polymarket-us | Trailing 30-day taker volume in USD; picks the tier for you |
|
|
97
|
+
| `--category` | polymarket | Market category, e.g. `Crypto`, `Sports`, `Politics` (required) |
|
|
98
|
+
| `--break-even`, `--tick` | all | Also print the break-even move (price step, default 0.01) |
|
|
99
|
+
| `--json` | all | Machine-readable output |
|
|
100
|
+
| `--rates PATH` | all | Use an updated rates file |
|
|
101
|
+
|
|
102
|
+
`pmfees rates` prints the loaded rates and their date.
|
|
103
|
+
|
|
104
|
+
## Library
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from pmfees import fee, break_even
|
|
108
|
+
|
|
109
|
+
r = fee("kalshi", 0.50, 100)
|
|
110
|
+
r.fee # Decimal('1.7500') what you pay, in USD
|
|
111
|
+
r.raw_fee # Decimal('1.7500') before rounding
|
|
112
|
+
r.fee_pct_of_trade_value # Decimal('3.500')
|
|
113
|
+
r.breakdown() # dict of strings: coefficient, rounding, formula, source_url, rates_as_of, ...
|
|
114
|
+
|
|
115
|
+
fee("polymarket-us", 0.10, 1000, "buy", tier=4).fee # Decimal('6.26')
|
|
116
|
+
fee("polymarket-us", 0.10, 1000, volume_30d=12_500).fee # Tier 2
|
|
117
|
+
fee("polymarket", 0.25, 100, category="Crypto").fee # Decimal('1.31250')
|
|
118
|
+
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') centicent rounding, not $0.02
|
|
119
|
+
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker M defaults to 0
|
|
120
|
+
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375')
|
|
121
|
+
fee("kalshi", 0.50, 100, multiplier=0.5).fee # Decimal('0.8750')
|
|
122
|
+
|
|
123
|
+
b = break_even("polymarket-us", 0.40, 500, tier=2)
|
|
124
|
+
b.exit_price, b.move_cents # (Decimal('0.45'), Decimal('5.00'))
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Signature: `fee(platform, price, contracts, side="buy", tier=None, maker=False, *, category=None,
|
|
128
|
+
multiplier=None, volume_30d=None, rates=None) -> FeeResult`. Platform names: `kalshi`,
|
|
129
|
+
`polymarket-us`, `polymarket` (also `polymarket.com`). Prices and counts can be `str`, `int`,
|
|
130
|
+
`float` or `Decimal`; floats are converted through `str`, so `0.1` means exactly 0.1.
|
|
131
|
+
|
|
132
|
+
`break_even(...)` takes the same arguments plus `tick`. It opens the position at `price`, then
|
|
133
|
+
walks the price in `tick` steps (up for a buy, down for a sell) and returns the first exit price
|
|
134
|
+
where proceeds − cost − entry fee − exit fee > 0, or `exit_price=None` if no price before $1 (or
|
|
135
|
+
$0) works.
|
|
136
|
+
|
|
137
|
+
## Kalshi: centicent rounding and the multiplier
|
|
138
|
+
|
|
139
|
+
Kalshi does not round the fee on its own. It rounds **fee + position cost** (contracts × price) up to
|
|
140
|
+
a whole centicent ($0.0001), per the fee schedule (version 7.7.26, page 2). Most of the time that
|
|
141
|
+
looks like rounding the fee up to four decimals, but the fee alone is what you see change:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from pmfees import fee
|
|
145
|
+
|
|
146
|
+
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') 0.07 × 1 × 0.5 × 0.5 = 0.0175 exactly; not $0.02
|
|
147
|
+
fee("kalshi", 0.33, 7).fee # Decimal('0.1084') raw 0.108339; 2.31 + 0.108339 = 2.418339 -> 2.4184
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Accounts cleared through a broker (FCM) keep balances in whole cents, so there the fee rounds to the
|
|
151
|
+
cent ([Kalshi docs](https://docs.kalshi.com/getting_started/fee_rounding.md)). pmfees models
|
|
152
|
+
kalshi.com accounts (direct members).
|
|
153
|
+
|
|
154
|
+
Each Kalshi series has a fee multiplier M: 1 (standard), 0.5 or 0. Takers default to M = 1, makers
|
|
155
|
+
to M = 0, because Kalshi charges makers only on series listed with maker fees:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
fee("kalshi", 0.25, 100).fee # Decimal('1.3125') M = 1
|
|
159
|
+
fee("kalshi", 0.25, 100, multiplier=0.5).fee # Decimal('0.6563') raw 0.65625, rounded up
|
|
160
|
+
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker, M defaults to 0
|
|
161
|
+
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375') 0.0175 × 100 × 0.25
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pmfees kalshi --price 0.25 --contracts 100 --multiplier 0.5
|
|
166
|
+
# -> Kalshi taker fee: $0.6563 (2.63% of trade value at 25¢)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## The formulas
|
|
170
|
+
|
|
171
|
+
| Platform | Taker fee | Rounding |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| 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) |
|
|
174
|
+
| 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 |
|
|
175
|
+
| 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 |
|
|
176
|
+
|
|
177
|
+
The numbers in this table are for reading only. The code takes every rate, tier, multiplier and
|
|
178
|
+
rounding rule (including Kalshi's fee + position cost basis) from `prediction_market_fees.json`.
|
|
179
|
+
|
|
180
|
+
Not modelled: Polymarket US combo fees and maker rebates, polymarket.com maker and taker rebate
|
|
181
|
+
programs, and per-market exceptions (polymarket.com
|
|
182
|
+
markets carry their own `feeSchedule`, Kalshi series their own multiplier). Check the market when
|
|
183
|
+
it matters.
|
|
184
|
+
|
|
185
|
+
## Sources
|
|
186
|
+
|
|
187
|
+
| Platform | Source | Rates current as of |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| Kalshi | <https://kalshi.com/docs/kalshi-fee-schedule.pdf> (version 7.7.26) | 2026-11-10 |
|
|
190
|
+
| Polymarket US | <https://docs.polymarket.us/fees> | 2026-11-09 |
|
|
191
|
+
| polymarket.com | <https://docs.polymarket.com/trading/fees> | 2026-11-08 |
|
|
192
|
+
|
|
193
|
+
The tests lock the formulas to the worked examples and fee tables on these pages, with a link
|
|
194
|
+
to the source in each test.
|
|
195
|
+
|
|
196
|
+
## Updating the rates
|
|
197
|
+
|
|
198
|
+
All rates live in `src/pmfees/data/prediction_market_fees.json`. Each platform has its own `as_of`
|
|
199
|
+
(the date its rates were last checked against `source_url`). SwapHunt checks the official fee pages
|
|
200
|
+
every week; when a rate changes, the updated file arrives here as a pull request, and a new release
|
|
201
|
+
follows after review. To use newer rates without waiting for a release:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from pmfees import fee, load_rates
|
|
205
|
+
|
|
206
|
+
rates = load_rates("prediction_market_fees.json")
|
|
207
|
+
fee("kalshi", 0.50, 100, rates=rates)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
or set `PMFEES_RATES_FILE=/path/to/prediction_market_fees.json`, or pass `--rates` on the
|
|
211
|
+
command line. A file with a missing field or an unknown rounding mode is rejected with a
|
|
212
|
+
`RatesError` that names the field.
|
|
213
|
+
|
|
214
|
+
## Development
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install -e . pytest ruff mypy
|
|
218
|
+
pytest
|
|
219
|
+
ruff check . && ruff format --check .
|
|
220
|
+
mypy
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Releases go to PyPI from GitHub Actions with trusted publishing: bump `__version__`, add a
|
|
224
|
+
CHANGELOG entry, and push a `v<version>` tag. The publish job waits for approval.
|
|
225
|
+
|
|
226
|
+
## Disclaimer
|
|
227
|
+
|
|
228
|
+
Fee estimates for information only. The platform's own confirmation is what you pay.
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT. See [LICENSE](LICENSE).
|
pmfees-0.1.0/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# pmfees
|
|
2
|
+
|
|
3
|
+
Exact trading fees for the prediction market platforms **Kalshi**, **Polymarket US** and
|
|
4
|
+
**polymarket.com** (international), as a small Python library and a command line tool.
|
|
5
|
+
|
|
6
|
+
- The platforms' own formulas and rounding rules: Kalshi rounds up so that fee + position cost
|
|
7
|
+
is a whole centicent ($0.0001), Polymarket US rounds to the cent with banker's rounding,
|
|
8
|
+
polymarket.com rounds to 5 decimals.
|
|
9
|
+
- Exact decimal arithmetic (`decimal.Decimal`), so $1.75 is $1.75 and not $1.7500000000000002.
|
|
10
|
+
- A break-even helper: how far the price has to move before a round trip is in profit after
|
|
11
|
+
the fee on both orders.
|
|
12
|
+
- No dependencies outside the Python standard library. Typed (`py.typed`).
|
|
13
|
+
|
|
14
|
+
Rates current as of: Kalshi 2026-11-10 (fee schedule 7.7.26), Polymarket US 2026-11-09,
|
|
15
|
+
polymarket.com 2026-11-08. Each platform's date and source are in the rates file and in every result.
|
|
16
|
+
|
|
17
|
+
Other ways to get the same numbers, from the same rates file:
|
|
18
|
+
|
|
19
|
+
- In a browser: the [SwapHunt Kalshi vs Polymarket fee calculator](https://swaphunt.dev/tools/kalshi-vs-polymarket-fee-calculator).
|
|
20
|
+
- Over HTTP, for agents: [`GET https://x402.swaphunt.dev/v1/pm/fees`](https://swaphunt.dev/api), paid per call
|
|
21
|
+
with [x402](https://www.x402.org/) in USDC. This package is free; the endpoint exists for agents that
|
|
22
|
+
cannot install a library.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install pmfees
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Python 3.10 or newer.
|
|
31
|
+
|
|
32
|
+
## Command line
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pmfees kalshi --price 0.50 --contracts 100
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
Kalshi taker fee: $1.75 (3.50% of trade value at 50¢)
|
|
40
|
+
buy 100 contracts at $0.50 = $50.00 trade value
|
|
41
|
+
base rate: 0.07
|
|
42
|
+
multiplier: 1
|
|
43
|
+
fee schedule version: 7.7.26
|
|
44
|
+
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
|
|
45
|
+
rates as of 2026-11-10 · source: https://kalshi.com/docs/kalshi-fee-schedule.pdf
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
More examples:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Polymarket US, Tier 1 (under $10,000 of 30-day taker volume, the default)
|
|
52
|
+
pmfees polymarket-us --price 0.50 --contracts 100
|
|
53
|
+
# -> Polymarket US taker fee: $2.38 (4.76% of trade value at 50¢) [0.095 × 100 × 0.5 × 0.5 = 2.375]
|
|
54
|
+
|
|
55
|
+
# polymarket.com, Crypto category
|
|
56
|
+
pmfees polymarket --price 0.25 --contracts 100 --category Crypto
|
|
57
|
+
# -> polymarket.com taker fee: $1.3125 (5.25% of trade value at 25¢)
|
|
58
|
+
|
|
59
|
+
# Break-even: buy 100 on Kalshi at 50¢, when is selling in profit?
|
|
60
|
+
pmfees kalshi --price 0.50 --contracts 100 --break-even
|
|
61
|
+
# -> 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
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
|
|
66
|
+
| Option | Platforms | Meaning |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `--price` | all | Price of the contract you trade, in dollars (0 < price < 1) |
|
|
69
|
+
| `--contracts` | all | Number of contracts (shares on polymarket.com) |
|
|
70
|
+
| `--side buy\|sell` | all | Changes the cash flow only; the fee formulas are symmetric |
|
|
71
|
+
| `--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 |
|
|
72
|
+
| `--multiplier` | kalshi | Fee multiplier M (default 1 for takers, 0 for makers) |
|
|
73
|
+
| `--tier 1-4\|new` | polymarket-us | Taker tier, or `new` for the first 7 days of a new account (default 1) |
|
|
74
|
+
| `--volume` | polymarket-us | Trailing 30-day taker volume in USD; picks the tier for you |
|
|
75
|
+
| `--category` | polymarket | Market category, e.g. `Crypto`, `Sports`, `Politics` (required) |
|
|
76
|
+
| `--break-even`, `--tick` | all | Also print the break-even move (price step, default 0.01) |
|
|
77
|
+
| `--json` | all | Machine-readable output |
|
|
78
|
+
| `--rates PATH` | all | Use an updated rates file |
|
|
79
|
+
|
|
80
|
+
`pmfees rates` prints the loaded rates and their date.
|
|
81
|
+
|
|
82
|
+
## Library
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from pmfees import fee, break_even
|
|
86
|
+
|
|
87
|
+
r = fee("kalshi", 0.50, 100)
|
|
88
|
+
r.fee # Decimal('1.7500') what you pay, in USD
|
|
89
|
+
r.raw_fee # Decimal('1.7500') before rounding
|
|
90
|
+
r.fee_pct_of_trade_value # Decimal('3.500')
|
|
91
|
+
r.breakdown() # dict of strings: coefficient, rounding, formula, source_url, rates_as_of, ...
|
|
92
|
+
|
|
93
|
+
fee("polymarket-us", 0.10, 1000, "buy", tier=4).fee # Decimal('6.26')
|
|
94
|
+
fee("polymarket-us", 0.10, 1000, volume_30d=12_500).fee # Tier 2
|
|
95
|
+
fee("polymarket", 0.25, 100, category="Crypto").fee # Decimal('1.31250')
|
|
96
|
+
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') centicent rounding, not $0.02
|
|
97
|
+
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker M defaults to 0
|
|
98
|
+
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375')
|
|
99
|
+
fee("kalshi", 0.50, 100, multiplier=0.5).fee # Decimal('0.8750')
|
|
100
|
+
|
|
101
|
+
b = break_even("polymarket-us", 0.40, 500, tier=2)
|
|
102
|
+
b.exit_price, b.move_cents # (Decimal('0.45'), Decimal('5.00'))
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Signature: `fee(platform, price, contracts, side="buy", tier=None, maker=False, *, category=None,
|
|
106
|
+
multiplier=None, volume_30d=None, rates=None) -> FeeResult`. Platform names: `kalshi`,
|
|
107
|
+
`polymarket-us`, `polymarket` (also `polymarket.com`). Prices and counts can be `str`, `int`,
|
|
108
|
+
`float` or `Decimal`; floats are converted through `str`, so `0.1` means exactly 0.1.
|
|
109
|
+
|
|
110
|
+
`break_even(...)` takes the same arguments plus `tick`. It opens the position at `price`, then
|
|
111
|
+
walks the price in `tick` steps (up for a buy, down for a sell) and returns the first exit price
|
|
112
|
+
where proceeds − cost − entry fee − exit fee > 0, or `exit_price=None` if no price before $1 (or
|
|
113
|
+
$0) works.
|
|
114
|
+
|
|
115
|
+
## Kalshi: centicent rounding and the multiplier
|
|
116
|
+
|
|
117
|
+
Kalshi does not round the fee on its own. It rounds **fee + position cost** (contracts × price) up to
|
|
118
|
+
a whole centicent ($0.0001), per the fee schedule (version 7.7.26, page 2). Most of the time that
|
|
119
|
+
looks like rounding the fee up to four decimals, but the fee alone is what you see change:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from pmfees import fee
|
|
123
|
+
|
|
124
|
+
fee("kalshi", 0.50, 1).fee # Decimal('0.0175') 0.07 × 1 × 0.5 × 0.5 = 0.0175 exactly; not $0.02
|
|
125
|
+
fee("kalshi", 0.33, 7).fee # Decimal('0.1084') raw 0.108339; 2.31 + 0.108339 = 2.418339 -> 2.4184
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Accounts cleared through a broker (FCM) keep balances in whole cents, so there the fee rounds to the
|
|
129
|
+
cent ([Kalshi docs](https://docs.kalshi.com/getting_started/fee_rounding.md)). pmfees models
|
|
130
|
+
kalshi.com accounts (direct members).
|
|
131
|
+
|
|
132
|
+
Each Kalshi series has a fee multiplier M: 1 (standard), 0.5 or 0. Takers default to M = 1, makers
|
|
133
|
+
to M = 0, because Kalshi charges makers only on series listed with maker fees:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
fee("kalshi", 0.25, 100).fee # Decimal('1.3125') M = 1
|
|
137
|
+
fee("kalshi", 0.25, 100, multiplier=0.5).fee # Decimal('0.6563') raw 0.65625, rounded up
|
|
138
|
+
fee("kalshi", 0.50, 100, maker=True).fee # Decimal('0.0000') maker, M defaults to 0
|
|
139
|
+
fee("kalshi", 0.50, 100, maker=True, multiplier=1).fee # Decimal('0.4375') 0.0175 × 100 × 0.25
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pmfees kalshi --price 0.25 --contracts 100 --multiplier 0.5
|
|
144
|
+
# -> Kalshi taker fee: $0.6563 (2.63% of trade value at 25¢)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## The formulas
|
|
148
|
+
|
|
149
|
+
| Platform | Taker fee | Rounding |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| 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) |
|
|
152
|
+
| 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 |
|
|
153
|
+
| 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 |
|
|
154
|
+
|
|
155
|
+
The numbers in this table are for reading only. The code takes every rate, tier, multiplier and
|
|
156
|
+
rounding rule (including Kalshi's fee + position cost basis) from `prediction_market_fees.json`.
|
|
157
|
+
|
|
158
|
+
Not modelled: Polymarket US combo fees and maker rebates, polymarket.com maker and taker rebate
|
|
159
|
+
programs, and per-market exceptions (polymarket.com
|
|
160
|
+
markets carry their own `feeSchedule`, Kalshi series their own multiplier). Check the market when
|
|
161
|
+
it matters.
|
|
162
|
+
|
|
163
|
+
## Sources
|
|
164
|
+
|
|
165
|
+
| Platform | Source | Rates current as of |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| Kalshi | <https://kalshi.com/docs/kalshi-fee-schedule.pdf> (version 7.7.26) | 2026-11-10 |
|
|
168
|
+
| Polymarket US | <https://docs.polymarket.us/fees> | 2026-11-09 |
|
|
169
|
+
| polymarket.com | <https://docs.polymarket.com/trading/fees> | 2026-11-08 |
|
|
170
|
+
|
|
171
|
+
The tests lock the formulas to the worked examples and fee tables on these pages, with a link
|
|
172
|
+
to the source in each test.
|
|
173
|
+
|
|
174
|
+
## Updating the rates
|
|
175
|
+
|
|
176
|
+
All rates live in `src/pmfees/data/prediction_market_fees.json`. Each platform has its own `as_of`
|
|
177
|
+
(the date its rates were last checked against `source_url`). SwapHunt checks the official fee pages
|
|
178
|
+
every week; when a rate changes, the updated file arrives here as a pull request, and a new release
|
|
179
|
+
follows after review. To use newer rates without waiting for a release:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from pmfees import fee, load_rates
|
|
183
|
+
|
|
184
|
+
rates = load_rates("prediction_market_fees.json")
|
|
185
|
+
fee("kalshi", 0.50, 100, rates=rates)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
or set `PMFEES_RATES_FILE=/path/to/prediction_market_fees.json`, or pass `--rates` on the
|
|
189
|
+
command line. A file with a missing field or an unknown rounding mode is rejected with a
|
|
190
|
+
`RatesError` that names the field.
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pip install -e . pytest ruff mypy
|
|
196
|
+
pytest
|
|
197
|
+
ruff check . && ruff format --check .
|
|
198
|
+
mypy
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Releases go to PyPI from GitHub Actions with trusted publishing: bump `__version__`, add a
|
|
202
|
+
CHANGELOG entry, and push a `v<version>` tag. The publish job waits for approval.
|
|
203
|
+
|
|
204
|
+
## Disclaimer
|
|
205
|
+
|
|
206
|
+
Fee estimates for information only. The platform's own confirmation is what you pay.
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pmfees"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Exact trading fees for Kalshi, Polymarket US and polymarket.com, with a CLI and break-even helper."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "SwapHunt", email = "github@swaphunt.dev" }]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = []
|
|
15
|
+
keywords = ["kalshi", "polymarket", "prediction markets", "fees", "trading"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Topic :: Office/Business :: Financial",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/swaphunt/pmfees"
|
|
26
|
+
Source = "https://github.com/swaphunt/pmfees"
|
|
27
|
+
Issues = "https://github.com/swaphunt/pmfees/issues"
|
|
28
|
+
Changelog = "https://github.com/swaphunt/pmfees/blob/main/CHANGELOG.md"
|
|
29
|
+
"Fee calculator" = "https://swaphunt.dev/tools/kalshi-vs-polymarket-fee-calculator"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
pmfees = "pmfees.cli:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.package-data]
|
|
38
|
+
pmfees = ["py.typed", "data/prediction_market_fees.json"]
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
line-length = 110
|
|
42
|
+
target-version = "py310"
|
|
43
|
+
|
|
44
|
+
[tool.ruff.lint]
|
|
45
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF"]
|
|
46
|
+
ignore = ["RUF001", "RUF002", "RUF003"] # Θ, × and − are intentional in formulas and docs
|
|
47
|
+
|
|
48
|
+
[tool.mypy]
|
|
49
|
+
strict = true
|
|
50
|
+
python_version = "3.10"
|
|
51
|
+
mypy_path = "src"
|
|
52
|
+
files = ["src", "tests"]
|
pmfees-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""pmfees: exact trading fees for Kalshi, Polymarket US and polymarket.com.
|
|
2
|
+
|
|
3
|
+
All rates, tiers, multipliers and rounding rules come from ``prediction_market_fees.json``
|
|
4
|
+
(bundled, or your own file via ``load_rates(path)`` / ``PMFEES_RATES_FILE``).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
|
|
11
|
+
from .core import PLATFORMS, BreakEven, FeeResult, break_even, fee, platform_key
|
|
12
|
+
from .rates import Rates, RatesError, default_rates, load_rates
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"PLATFORMS",
|
|
16
|
+
"BreakEven",
|
|
17
|
+
"FeeResult",
|
|
18
|
+
"Rates",
|
|
19
|
+
"RatesError",
|
|
20
|
+
"__version__",
|
|
21
|
+
"break_even",
|
|
22
|
+
"default_rates",
|
|
23
|
+
"fee",
|
|
24
|
+
"load_rates",
|
|
25
|
+
"platform_key",
|
|
26
|
+
]
|