pmquant 0.4.2__tar.gz → 0.4.3__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.
- pmquant-0.4.3/.github/dependabot.yml +13 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/.github/workflows/canary.yml +8 -4
- {pmquant-0.4.2 → pmquant-0.4.3}/.github/workflows/publish.yml +3 -3
- pmquant-0.4.3/.github/workflows/scorecard.yml +28 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/.github/workflows/test.yml +5 -2
- {pmquant-0.4.2 → pmquant-0.4.3}/.gitignore +1 -0
- pmquant-0.4.3/.hypothesis/.gitignore +9 -0
- pmquant-0.4.3/.hypothesis/constants/07a2a0eac57d1dd0 +4 -0
- pmquant-0.4.3/.hypothesis/constants/1720e64af9235558 +4 -0
- pmquant-0.4.3/.hypothesis/constants/6c9ffb0a1efc27b6 +4 -0
- pmquant-0.4.3/.hypothesis/constants/855d9c2e5b4693f1 +4 -0
- pmquant-0.4.3/.hypothesis/constants/ef909bf87e6ac33f +4 -0
- pmquant-0.4.3/.hypothesis/unicode_data/15.0.0/charmap.json.gz +0 -0
- pmquant-0.4.3/.hypothesis/unicode_data/15.0.0/codec-utf-8.json.gz +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/CHANGELOG.md +33 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/CLAUDE.md +9 -1
- {pmquant-0.4.2 → pmquant-0.4.3}/PKG-INFO +63 -10
- {pmquant-0.4.2 → pmquant-0.4.3}/README.md +61 -9
- {pmquant-0.4.2 → pmquant-0.4.3}/SECURITY.md +15 -4
- pmquant-0.4.3/bot-template/bot.py +354 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/bot-template/dash/bot_dash.py +19 -7
- {pmquant-0.4.2 → pmquant-0.4.3}/llms.txt +6 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/pyproject.toml +2 -2
- {pmquant-0.4.2 → pmquant-0.4.3}/server.json +3 -3
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/__init__.py +1 -1
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/doctor.py +88 -58
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/executor.py +41 -12
- {pmquant-0.4.2 → pmquant-0.4.3}/tests/test_canary_live.py +33 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/tests/test_executor.py +53 -0
- pmquant-0.4.3/tests/test_fill_fuzz.py +118 -0
- pmquant-0.4.3/tests/test_template_engine.py +398 -0
- pmquant-0.4.2/bot-template/bot.py +0 -305
- pmquant-0.4.2/tests/test_template_engine.py +0 -82
- {pmquant-0.4.2 → pmquant-0.4.3}/AGENTS.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/CONTRIBUTING.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/LICENSE +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/bot-template/README.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/bot-template/dash/dash.html +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/bot-template/pmq-bot.service +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/bot-template/strategy.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/docs/assets/pmq-doctor.svg +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/docs/recipes.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/docs/rounding-study.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/docs/war-story.md +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/examples/fak_buy_guarded.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/examples/read_market.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/data.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/exceptions.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/mcp.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/src/pmq/py.typed +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/tests/test_data.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/tests/test_doctor.py +0 -0
- {pmquant-0.4.2 → pmquant-0.4.3}/tests/test_mcp.py +0 -0
|
@@ -12,8 +12,8 @@ jobs:
|
|
|
12
12
|
canary:
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
16
|
-
- uses: actions/setup-python@v6
|
|
15
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
16
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
17
17
|
with:
|
|
18
18
|
python-version: "3.12"
|
|
19
19
|
- run: pip install -e ".[dev]"
|
|
@@ -21,6 +21,10 @@ jobs:
|
|
|
21
21
|
env:
|
|
22
22
|
PMQ_CANARY: "1"
|
|
23
23
|
run: pytest tests/test_canary_live.py -q
|
|
24
|
+
- name: Dependency vulnerability audit
|
|
25
|
+
run: |
|
|
26
|
+
pip install pip-audit
|
|
27
|
+
pip-audit --skip-editable
|
|
24
28
|
- name: Open an issue if Polymarket drifted
|
|
25
29
|
if: failure()
|
|
26
30
|
env:
|
|
@@ -29,6 +33,6 @@ jobs:
|
|
|
29
33
|
existing=$(gh issue list --label canary --state open --json number --jq length)
|
|
30
34
|
if [ "$existing" = "0" ]; then
|
|
31
35
|
gh issue create --label canary \
|
|
32
|
-
--title "Canary:
|
|
33
|
-
--body "The weekly
|
|
36
|
+
--title "Canary failed: endpoint drift or vulnerable dependency ($(date -u +%F))" \
|
|
37
|
+
--body "The weekly canary failed: an endpoint shape or the installed py-clob-client-v2 surface no longer matches what pmq was verified against, the egress allowlist saw a foreign host, or pip-audit found a vulnerable dependency. See the failed run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
34
38
|
fi
|
|
@@ -11,10 +11,10 @@ jobs:
|
|
|
11
11
|
permissions:
|
|
12
12
|
id-token: write
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
15
15
|
|
|
16
16
|
- name: Set up Python
|
|
17
|
-
uses: actions/setup-python@v6
|
|
17
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.12"
|
|
20
20
|
|
|
@@ -41,4 +41,4 @@ jobs:
|
|
|
41
41
|
python -m build
|
|
42
42
|
|
|
43
43
|
- name: Publish to PyPI
|
|
44
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
44
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: scorecard
|
|
2
|
+
on:
|
|
3
|
+
schedule:
|
|
4
|
+
- cron: "23 7 * * 1" # weekly, monday 07:23 UTC
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions: read-all
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
analysis:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
security-events: write # SARIF upload
|
|
16
|
+
id-token: write # signed publication to scorecard.dev
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
- uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
|
22
|
+
with:
|
|
23
|
+
results_file: results.sarif
|
|
24
|
+
results_format: sarif
|
|
25
|
+
publish_results: true
|
|
26
|
+
- uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
|
|
27
|
+
with:
|
|
28
|
+
sarif_file: results.sarif
|
|
@@ -2,6 +2,9 @@ name: tests
|
|
|
2
2
|
on:
|
|
3
3
|
push:
|
|
4
4
|
pull_request:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
5
8
|
jobs:
|
|
6
9
|
test:
|
|
7
10
|
runs-on: ubuntu-latest
|
|
@@ -9,8 +12,8 @@ jobs:
|
|
|
9
12
|
matrix:
|
|
10
13
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
11
14
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
13
|
-
- uses: actions/setup-python@v6
|
|
15
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
16
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
14
17
|
with:
|
|
15
18
|
python-version: ${{ matrix.python-version }}
|
|
16
19
|
- run: pip install -e ".[dev]"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This .gitignore file was automatically created by Hypothesis. Hypothesis gitignores
|
|
2
|
+
# .hypothesis by default, because we generally recommend that .hypothesis not be checked
|
|
3
|
+
# into version control.
|
|
4
|
+
#
|
|
5
|
+
# If you *would* like to check .hypothesis into version control, you should delete this
|
|
6
|
+
# file. Hypothesis will not re-create this .gitignore unless .hypothesis is deleted (and
|
|
7
|
+
# if it does, that's a bug - please report it!)
|
|
8
|
+
|
|
9
|
+
*
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# file: /home/runner/work/pmq/pmq/src/pmq/executor.py
|
|
2
|
+
# hypothesis_version: 6.156.1
|
|
3
|
+
|
|
4
|
+
[0.0, 1000000.0, 137, 300, 400, 500, '0', '0.01', '0x[0-9a-fA-F]{64}', '; ', 'AssetType', 'BUY', 'FAILED', 'FAK', 'MAKER', 'MarketOrderArgs', 'MarketOrderArgsV2', 'OpenOrderParams', 'OrderArgs', 'OrderArgsV2', 'OrderType', 'POLY_BUILDER_CODE', 'POLY_FUNDER', 'POLY_PRIVATE_KEY', 'POLY_SIG_TYPE', 'SELL', 'TradeParams', '_pmq_taker4', 'amount', 'balance', 'builder_code', 'cancel_market_orders', 'crypto', 'error_msg', 'fd', 'get_open_orders', 'get_trades', 'makingAmount', 'off', 'on', 'orderID', 'order_args', 'order_type', 'params', 'payload', 'pmq', 'price', 'r', 'side', 'size', 'status', 'status_code', 'success', 'takingAmount', 'token_id', 'trader_side']
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# file: /home/runner/work/pmq/pmq/src/pmq/__init__.py
|
|
2
|
+
# hypothesis_version: 6.156.1
|
|
3
|
+
|
|
4
|
+
['0.4.3', 'DEFAULT_BUILDER_CODE', 'FEE_RATES', 'Fill', 'OrderUncertain', 'PmqError', 'PolymarketExecutor', '__version__', 'band_ask_depth_usd', 'best_bid_ask', 'book_inferred_winner', 'book_meta', 'event_markets', 'fee', 'get_book', 'get_market', 'get_tape', 'http_get_json', 'parse_market', 'positions', 'resolved_winner']
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# file: /home/runner/work/pmq/pmq/src/pmq/data.py
|
|
2
|
+
# hypothesis_version: 6.156.1
|
|
3
|
+
|
|
4
|
+
[0.0, 0.03, 0.04, 0.05, 0.07, 0.9, 0.99, 1.0, 1.5, 200, '%Y-%m-%dT%H:%M:%SZ', 'Mozilla/5.0', 'User-Agent', 'a', 'asks', 'b', 'bids', 'clobTokenIds', 'conditionId', 'crypto', 'culture', 'economics', 'endDate', 'endDateIso', 'finance', 'geopolitics', 'idx_a', 'last_trade_price', 'markets', 'mentions', 'min_order_size', 'neg_risk', 'outcomePrices', 'outcome_a', 'outcome_b', 'outcome_prices_raw', 'outcomes', 'politics', 'price', 'size', 'slug', 'sports', 'tech', 'tick_size', 'timestamp', 'weather']
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# file: /home/runner/work/pmq/pmq/src/pmq/doctor.py
|
|
2
|
+
# hypothesis_version: 6.156.1
|
|
3
|
+
|
|
4
|
+
[1000000.0, 120, 160, 400, '\nverdict:', ', ', '--market', '0', '0x', '0x70a08231', '0x8da5cb5b', '2.0', 'CLOB auth/collateral', 'Content-Type', 'FAK', 'Mozilla/5.0', 'OrderType.FAK', 'POLY_FUNDER', 'POLY_PRIVATE_KEY', 'POLY_SIG_TYPE', 'User-Agent', '[!!]', '[??]', '[ok]', '__main__', 'application/json', 'data', 'drifted: ', 'error', 'eth_call', 'eth_getCode', 'funder', 'id', 'jsonrpc', 'latest', 'method', 'min_order_size', 'params', 'result', 'to', 'token_a']
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.3 (2026-07-04)
|
|
4
|
+
|
|
5
|
+
* Fix: py-clob-client-v2 1.0.2 reuses its limit-order rounding table for
|
|
6
|
+
MARKET orders, so on markets whose tick size is finer than 0.01 it signs
|
|
7
|
+
taker amounts with 5-6 decimals; the V2 exchange rejects those with
|
|
8
|
+
"invalid amounts ... taker amount a max of 4 decimals" and every FAK on
|
|
9
|
+
such a market fails. The executor now clamps the market-order path to 4
|
|
10
|
+
decimals at client level (round-down: the never-exceed-budget contract is
|
|
11
|
+
intact, the dust given up is under 0.0001 share per order). Found in
|
|
12
|
+
production: a fine-tick market rejected 10 consecutive buys and the
|
|
13
|
+
fail-closed halt fired exactly as designed; nothing was booked, nothing
|
|
14
|
+
was lost. Regression test pins maker 2dp / taker 4dp on both sides for
|
|
15
|
+
ticks 0.01, 0.001 and 0.0001.
|
|
16
|
+
|
|
17
|
+
* Trust batch: executable egress proof in the canary suite (records every
|
|
18
|
+
DNS resolution during a full session incl. a signed zero-fund order;
|
|
19
|
+
fails on any host outside polymarket.com; weekly CI prints the list in
|
|
20
|
+
public logs), a test pinning that the private key never reaches logs,
|
|
21
|
+
OpenSSF Scorecard workflow + badge, GitHub Actions pinned by commit SHA,
|
|
22
|
+
explicit workflow permissions, Dependabot (pip + actions), weekly
|
|
23
|
+
pip-audit wired into the canary alarm, README sections "Verify the
|
|
24
|
+
claims yourself" (egress, PEP 740 provenance, dependency watch) and
|
|
25
|
+
"Stability and maintenance" (pre-1.0 SemVer contract, the stated bar for
|
|
26
|
+
1.0, bus-factor honesty, precisely scoped help-wanted).
|
|
27
|
+
* Quality pass driven by pyscn (CFG complexity, dead code, clones): the
|
|
28
|
+
template engine loop and pmq-doctor were split into single-purpose phase
|
|
29
|
+
functions (worst cyclomatic complexity 36 -> 10 across the repo, zero dead
|
|
30
|
+
code, behavior identical), and the previously untested template main loop
|
|
31
|
+
is now pinned by 17 end-to-end tests (fake clock, stubbed exchange):
|
|
32
|
+
paper fills at the real ask, budget headroom, halts, poisoning,
|
|
33
|
+
consecutive-failure exit, exchange-truth scoring. 113 tests total.
|
|
34
|
+
`pyscn check src/pmq bot-template` passes at default thresholds.
|
|
35
|
+
|
|
3
36
|
## 0.4.2 (2026-07-03)
|
|
4
37
|
|
|
5
38
|
* Fix: `buy_fak`/`sell_fak` cent-rounding used `int(x * 100) / 100`, which
|
|
@@ -32,7 +32,10 @@ agents EDITING it. Read both before changing code.)
|
|
|
32
32
|
|
|
33
33
|
## Working rules
|
|
34
34
|
|
|
35
|
-
* Tests green (`pytest -q`) and `ruff check .` clean before any push;
|
|
35
|
+
* Tests green (`pytest -q`) and `ruff check .` clean before any push;
|
|
36
|
+
`pyscn check src/pmq bot-template` (complexity <= 10, no dead code)
|
|
37
|
+
must stay green too; clone warnings are informational (the template
|
|
38
|
+
dash deliberately duplicates helpers to stay stdlib-standalone). Add
|
|
36
39
|
tests with every behavior change. Network-touching tests go to
|
|
37
40
|
`tests/test_canary_live.py` behind `PMQ_CANARY=1`, never in default CI.
|
|
38
41
|
* Exchange rules (min size, tick, fee rate) are READ from the venue
|
|
@@ -42,6 +45,11 @@ agents EDITING it. Read both before changing code.)
|
|
|
42
45
|
update CHANGELOG.md, push, then `gh release create vX.Y.Z`: PyPI publish
|
|
43
46
|
is automatic via trusted publishing (no tokens anywhere). PyPI name is
|
|
44
47
|
`pmquant`, import name `pmq`: keep the README line explaining it.
|
|
48
|
+
* GitHub Actions stay pinned by commit SHA (dependabot bumps them); new
|
|
49
|
+
workflows get an explicit least-privilege permissions block. The egress
|
|
50
|
+
test and pip-audit ride the weekly canary: never move them to default CI
|
|
51
|
+
(they need network) and never widen the egress allowlist beyond
|
|
52
|
+
polymarket.com without updating SECURITY.md and the README section.
|
|
45
53
|
* The weekly canary workflow is the drift alarm: if it opens an issue, the
|
|
46
54
|
fix starts by re-running the introspection against the new surface, not
|
|
47
55
|
by loosening the checks.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pmquant
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Fail-closed execution and market-data layer for Polymarket CLOB V2: local signing, confirmed fills only, fee-correct math, working deposit-wallet (POLY_1271) support.
|
|
5
5
|
Project-URL: Homepage, https://github.com/crp4222/pmq
|
|
6
6
|
Project-URL: Issues, https://github.com/crp4222/pmq/issues
|
|
@@ -23,6 +23,7 @@ Classifier: Typing :: Typed
|
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: py-clob-client-v2<2,>=1.0.2
|
|
25
25
|
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
26
27
|
Requires-Dist: mcp>=1.2; extra == 'dev'
|
|
27
28
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
28
29
|
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
@@ -41,6 +42,7 @@ Description-Content-Type: text/markdown
|
|
|
41
42
|
[](https://github.com/crp4222/pmq/actions/workflows/canary.yml)
|
|
42
43
|
[](.github/workflows/test.yml)
|
|
43
44
|
[](pyproject.toml)
|
|
45
|
+
[](https://scorecard.dev/viewer/?uri=github.com/crp4222/pmq)
|
|
44
46
|
[](LICENSE)
|
|
45
47
|
|
|
46
48
|
Fail-closed execution and market data for **Polymarket CLOB V2**, in Python.
|
|
@@ -81,13 +83,15 @@ a real error in live trading:
|
|
|
81
83
|
|
|
82
84
|
The full write-up with reproduction details: [docs/war-story.md](docs/war-story.md).
|
|
83
85
|
|
|
84
|
-
## Runs in production
|
|
86
|
+
## Runs in production: my own money, daily
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
I built pmq for my own trading. It executes real volume with my funds every
|
|
89
|
+
day, and it has never booked a fill the exchange did not confirm. If you
|
|
90
|
+
want to see it on-chain, here is a settlement from one of my wallets
|
|
91
|
+
(2026-07-03):
|
|
88
92
|
[`0x387f5f09...100d88a8`](https://polygonscan.com/tx/0x387f5f09c031bb36a71c54adc978b1ed4d50c67f6dd3f0c2c8068391100d88a8)
|
|
89
93
|
on the CTF Exchange V2: a FAK market buy built by this library, matched and
|
|
90
|
-
settled, with the builder code visible in the calldata.
|
|
94
|
+
settled, with the builder code visible in the calldata. A weekly
|
|
91
95
|
[canary workflow](.github/workflows/canary.yml) exercises the real endpoints
|
|
92
96
|
and the installed client surface, and opens an issue by itself if Polymarket
|
|
93
97
|
drifts.
|
|
@@ -160,9 +164,10 @@ else:
|
|
|
160
164
|
print(fill.matched_shares, "shares at", fill.price, "order", fill.order_id)
|
|
161
165
|
```
|
|
162
166
|
|
|
163
|
-
`sell_fak` and `limit_gtc` follow the same contract.
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
`sell_fak` and `limit_gtc` follow the same contract. Both FAK paths have
|
|
168
|
+
carried real volume: a production round trip (buy 5.149 @ 0.94, sell back
|
|
169
|
+
5.14 @ 0.94, cross-checked via `get_trades`) confirmed the mirrored
|
|
170
|
+
`makingAmount`/`takingAmount` semantics on 2026-07-03.
|
|
166
171
|
|
|
167
172
|
## The signature_type table nobody gives you
|
|
168
173
|
|
|
@@ -247,12 +252,60 @@ shipped demo strategy is an API illustration meant to be replaced.
|
|
|
247
252
|
* Keys are read from the environment, used to instantiate the signer, and
|
|
248
253
|
never logged. No custody, no backend, no telemetry, zero network calls
|
|
249
254
|
besides Polymarket endpoints.
|
|
250
|
-
*
|
|
251
|
-
|
|
255
|
+
* A documented wave of fake "polymarket bot" repositories steals private
|
|
256
|
+
keys; pmq is deliberately small so the entire execution path stays
|
|
257
|
+
readable in minutes by anyone who wants to look.
|
|
252
258
|
* Fund the trading wallet with what you can afford to lose. Nothing here is
|
|
253
259
|
financial advice; prediction-market access is restricted in some
|
|
254
260
|
jurisdictions and compliance is on you.
|
|
255
261
|
|
|
262
|
+
## If you feel like checking any of it
|
|
263
|
+
|
|
264
|
+
None of the claims above require taking my word; each one comes with a
|
|
265
|
+
handle you can pull, whenever you care to:
|
|
266
|
+
|
|
267
|
+
* **Egress.** `PMQ_CANARY=1 pytest tests/test_canary_live.py -k egress -s`
|
|
268
|
+
records every DNS resolution during a full session (market data, auth
|
|
269
|
+
derivation, one signed order) and fails on any host outside
|
|
270
|
+
`polymarket.com`. Last observed list: `clob.polymarket.com`,
|
|
271
|
+
`gamma-api.polymarket.com`, nothing else. The weekly
|
|
272
|
+
[canary](../../actions/workflows/canary.yml) prints that list in public
|
|
273
|
+
CI logs. One designed exception: `pmq-doctor`'s optional on-chain checks
|
|
274
|
+
use the public Polygon RPCs named in its source.
|
|
275
|
+
* **Provenance.** Releases carry a signed PEP 740 attestation (Sigstore,
|
|
276
|
+
via PyPI trusted publishing): click "provenance" next to any file on the
|
|
277
|
+
[PyPI files page](https://pypi.org/project/pmquant/#files), or fetch it
|
|
278
|
+
raw from PyPI's integrity API. The signing identity is this repository's
|
|
279
|
+
`publish.yml` workflow.
|
|
280
|
+
* **Dependencies.** Dependabot files weekly bump PRs (Python and
|
|
281
|
+
SHA-pinned GitHub Actions), and the weekly canary runs `pip-audit`; a
|
|
282
|
+
hit opens an issue by itself.
|
|
283
|
+
* **The source.** Five small modules; the whole execution path reads in
|
|
284
|
+
minutes. The grep targets that answer the important questions fastest
|
|
285
|
+
are listed in [SECURITY.md](SECURITY.md).
|
|
286
|
+
|
|
287
|
+
## Stability and maintenance
|
|
288
|
+
|
|
289
|
+
* Pre-1.0 SemVer: PATCH releases only fix, MINOR releases may change the
|
|
290
|
+
public API with the migration named in [CHANGELOG.md](CHANGELOG.md).
|
|
291
|
+
Nothing changes silently.
|
|
292
|
+
* Deprecated APIs keep working and warn for at least one MINOR release
|
|
293
|
+
before removal.
|
|
294
|
+
* The bar for 1.0, stated in advance: months of green weekly canaries, the
|
|
295
|
+
maker path (`limit_gtc`) production-proven with real volume the way the
|
|
296
|
+
FAK paths already are, and external production users.
|
|
297
|
+
* Bus-factor honesty: one maintainer, who trades real money through this
|
|
298
|
+
exact code daily (strongest available incentive to keep it correct). The
|
|
299
|
+
mitigations are structural, not promises: five small modules, the
|
|
300
|
+
executable fill-contract test table, a weekly canary that opens issues by
|
|
301
|
+
itself, SHA-pinned CI. Operational rule: if the canary badge goes red and
|
|
302
|
+
stays red, treat the project as unmaintained and pin your last known-good
|
|
303
|
+
version.
|
|
304
|
+
* Help wanted, precisely scoped: production receipts for `signature_type`
|
|
305
|
+
1 and 2 accounts (legacy Magic/email and browser-wallet proxies). Both
|
|
306
|
+
paths are introspection-tested but have never carried real money through
|
|
307
|
+
this library; the maintainer's own accounts are all types 0 and 3.
|
|
308
|
+
|
|
256
309
|
## License
|
|
257
310
|
|
|
258
311
|
MIT
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
[](https://github.com/crp4222/pmq/actions/workflows/canary.yml)
|
|
8
8
|
[](.github/workflows/test.yml)
|
|
9
9
|
[](pyproject.toml)
|
|
10
|
+
[](https://scorecard.dev/viewer/?uri=github.com/crp4222/pmq)
|
|
10
11
|
[](LICENSE)
|
|
11
12
|
|
|
12
13
|
Fail-closed execution and market data for **Polymarket CLOB V2**, in Python.
|
|
@@ -47,13 +48,15 @@ a real error in live trading:
|
|
|
47
48
|
|
|
48
49
|
The full write-up with reproduction details: [docs/war-story.md](docs/war-story.md).
|
|
49
50
|
|
|
50
|
-
## Runs in production
|
|
51
|
+
## Runs in production: my own money, daily
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
I built pmq for my own trading. It executes real volume with my funds every
|
|
54
|
+
day, and it has never booked a fill the exchange did not confirm. If you
|
|
55
|
+
want to see it on-chain, here is a settlement from one of my wallets
|
|
56
|
+
(2026-07-03):
|
|
54
57
|
[`0x387f5f09...100d88a8`](https://polygonscan.com/tx/0x387f5f09c031bb36a71c54adc978b1ed4d50c67f6dd3f0c2c8068391100d88a8)
|
|
55
58
|
on the CTF Exchange V2: a FAK market buy built by this library, matched and
|
|
56
|
-
settled, with the builder code visible in the calldata.
|
|
59
|
+
settled, with the builder code visible in the calldata. A weekly
|
|
57
60
|
[canary workflow](.github/workflows/canary.yml) exercises the real endpoints
|
|
58
61
|
and the installed client surface, and opens an issue by itself if Polymarket
|
|
59
62
|
drifts.
|
|
@@ -126,9 +129,10 @@ else:
|
|
|
126
129
|
print(fill.matched_shares, "shares at", fill.price, "order", fill.order_id)
|
|
127
130
|
```
|
|
128
131
|
|
|
129
|
-
`sell_fak` and `limit_gtc` follow the same contract.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
`sell_fak` and `limit_gtc` follow the same contract. Both FAK paths have
|
|
133
|
+
carried real volume: a production round trip (buy 5.149 @ 0.94, sell back
|
|
134
|
+
5.14 @ 0.94, cross-checked via `get_trades`) confirmed the mirrored
|
|
135
|
+
`makingAmount`/`takingAmount` semantics on 2026-07-03.
|
|
132
136
|
|
|
133
137
|
## The signature_type table nobody gives you
|
|
134
138
|
|
|
@@ -213,12 +217,60 @@ shipped demo strategy is an API illustration meant to be replaced.
|
|
|
213
217
|
* Keys are read from the environment, used to instantiate the signer, and
|
|
214
218
|
never logged. No custody, no backend, no telemetry, zero network calls
|
|
215
219
|
besides Polymarket endpoints.
|
|
216
|
-
*
|
|
217
|
-
|
|
220
|
+
* A documented wave of fake "polymarket bot" repositories steals private
|
|
221
|
+
keys; pmq is deliberately small so the entire execution path stays
|
|
222
|
+
readable in minutes by anyone who wants to look.
|
|
218
223
|
* Fund the trading wallet with what you can afford to lose. Nothing here is
|
|
219
224
|
financial advice; prediction-market access is restricted in some
|
|
220
225
|
jurisdictions and compliance is on you.
|
|
221
226
|
|
|
227
|
+
## If you feel like checking any of it
|
|
228
|
+
|
|
229
|
+
None of the claims above require taking my word; each one comes with a
|
|
230
|
+
handle you can pull, whenever you care to:
|
|
231
|
+
|
|
232
|
+
* **Egress.** `PMQ_CANARY=1 pytest tests/test_canary_live.py -k egress -s`
|
|
233
|
+
records every DNS resolution during a full session (market data, auth
|
|
234
|
+
derivation, one signed order) and fails on any host outside
|
|
235
|
+
`polymarket.com`. Last observed list: `clob.polymarket.com`,
|
|
236
|
+
`gamma-api.polymarket.com`, nothing else. The weekly
|
|
237
|
+
[canary](../../actions/workflows/canary.yml) prints that list in public
|
|
238
|
+
CI logs. One designed exception: `pmq-doctor`'s optional on-chain checks
|
|
239
|
+
use the public Polygon RPCs named in its source.
|
|
240
|
+
* **Provenance.** Releases carry a signed PEP 740 attestation (Sigstore,
|
|
241
|
+
via PyPI trusted publishing): click "provenance" next to any file on the
|
|
242
|
+
[PyPI files page](https://pypi.org/project/pmquant/#files), or fetch it
|
|
243
|
+
raw from PyPI's integrity API. The signing identity is this repository's
|
|
244
|
+
`publish.yml` workflow.
|
|
245
|
+
* **Dependencies.** Dependabot files weekly bump PRs (Python and
|
|
246
|
+
SHA-pinned GitHub Actions), and the weekly canary runs `pip-audit`; a
|
|
247
|
+
hit opens an issue by itself.
|
|
248
|
+
* **The source.** Five small modules; the whole execution path reads in
|
|
249
|
+
minutes. The grep targets that answer the important questions fastest
|
|
250
|
+
are listed in [SECURITY.md](SECURITY.md).
|
|
251
|
+
|
|
252
|
+
## Stability and maintenance
|
|
253
|
+
|
|
254
|
+
* Pre-1.0 SemVer: PATCH releases only fix, MINOR releases may change the
|
|
255
|
+
public API with the migration named in [CHANGELOG.md](CHANGELOG.md).
|
|
256
|
+
Nothing changes silently.
|
|
257
|
+
* Deprecated APIs keep working and warn for at least one MINOR release
|
|
258
|
+
before removal.
|
|
259
|
+
* The bar for 1.0, stated in advance: months of green weekly canaries, the
|
|
260
|
+
maker path (`limit_gtc`) production-proven with real volume the way the
|
|
261
|
+
FAK paths already are, and external production users.
|
|
262
|
+
* Bus-factor honesty: one maintainer, who trades real money through this
|
|
263
|
+
exact code daily (strongest available incentive to keep it correct). The
|
|
264
|
+
mitigations are structural, not promises: five small modules, the
|
|
265
|
+
executable fill-contract test table, a weekly canary that opens issues by
|
|
266
|
+
itself, SHA-pinned CI. Operational rule: if the canary badge goes red and
|
|
267
|
+
stays red, treat the project as unmaintained and pin your last known-good
|
|
268
|
+
version.
|
|
269
|
+
* Help wanted, precisely scoped: production receipts for `signature_type`
|
|
270
|
+
1 and 2 accounts (legacy Magic/email and browser-wallet proxies). Both
|
|
271
|
+
paths are introspection-tested but have never carried real money through
|
|
272
|
+
this library; the maintainer's own accounts are all types 0 and 3.
|
|
273
|
+
|
|
222
274
|
## License
|
|
223
275
|
|
|
224
276
|
MIT
|
|
@@ -14,14 +14,25 @@
|
|
|
14
14
|
matches the API surface pmq was verified against (introspection at startup),
|
|
15
15
|
rather than signing through changed semantics.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Small enough to read
|
|
18
18
|
|
|
19
|
-
A documented wave of fake "polymarket bot" repositories steals private keys
|
|
20
|
-
pmq is deliberately small (five modules) so
|
|
21
|
-
|
|
19
|
+
A documented wave of fake "polymarket bot" repositories steals private keys;
|
|
20
|
+
pmq is deliberately small (five modules) so the entire execution path reads
|
|
21
|
+
in minutes. For whoever wants the fast route, the grep targets that settle
|
|
22
|
+
the important questions:
|
|
22
23
|
`POLY_PRIVATE_KEY` (read once, passed to the official client), `builder_code`
|
|
23
24
|
(the disclosure and the opt-out), `http` (every host contacted).
|
|
24
25
|
|
|
26
|
+
## Automated watch
|
|
27
|
+
|
|
28
|
+
* Weekly canary CI runs the egress test (every DNS resolution during a full
|
|
29
|
+
session must stay inside polymarket.com) and `pip-audit` over the
|
|
30
|
+
dependency tree; any failure opens a labeled issue automatically.
|
|
31
|
+
* Dependabot files weekly update PRs for Python dependencies and for the
|
|
32
|
+
GitHub Actions, which are pinned by commit SHA.
|
|
33
|
+
* PyPI releases carry signed PEP 740 attestations (see "Verify the claims
|
|
34
|
+
yourself" in the README).
|
|
35
|
+
|
|
25
36
|
## Reporting a vulnerability
|
|
26
37
|
|
|
27
38
|
Open a GitHub security advisory on this repository (Security tab, "Report a
|