hermes-pmxt 0.3.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.
- hermes_pmxt-0.3.0/.github/workflows/workflow.yml +95 -0
- hermes_pmxt-0.3.0/.gitignore +8 -0
- hermes_pmxt-0.3.0/LEARNINGS.md +111 -0
- hermes_pmxt-0.3.0/LICENSE +21 -0
- hermes_pmxt-0.3.0/PKG-INFO +269 -0
- hermes_pmxt-0.3.0/README.md +255 -0
- hermes_pmxt-0.3.0/examples/demo.py +130 -0
- hermes_pmxt-0.3.0/hermes_pmxt/__init__.py +101 -0
- hermes_pmxt-0.3.0/hermes_pmxt/config.py +145 -0
- hermes_pmxt-0.3.0/hermes_pmxt/exchanges.py +187 -0
- hermes_pmxt-0.3.0/hermes_pmxt/registry.py +251 -0
- hermes_pmxt-0.3.0/hermes_pmxt/shaper.py +255 -0
- hermes_pmxt-0.3.0/hermes_pmxt/tools.py +1463 -0
- hermes_pmxt-0.3.0/pyproject.toml +34 -0
- hermes_pmxt-0.3.0/skill/SKILL.md +169 -0
- hermes_pmxt-0.3.0/tests/conftest.py +10 -0
- hermes_pmxt-0.3.0/tests/test_exchanges.py +116 -0
- hermes_pmxt-0.3.0/tests/test_tools.py +614 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Build and Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Test Python ${{ matrix.python-version }}
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
cache: pip
|
|
31
|
+
|
|
32
|
+
- name: Install package with dev dependencies
|
|
33
|
+
run: |
|
|
34
|
+
python -m pip install --upgrade pip
|
|
35
|
+
python -m pip install -e ".[dev]"
|
|
36
|
+
|
|
37
|
+
- name: Lint
|
|
38
|
+
run: python -m ruff check hermes_pmxt/ tests/
|
|
39
|
+
|
|
40
|
+
- name: Run unit tests
|
|
41
|
+
run: python -m pytest -q -m unit --tb=short
|
|
42
|
+
|
|
43
|
+
- name: Verify import
|
|
44
|
+
run: python -c "import hermes_pmxt; print('OK v' + hermes_pmxt.__version__)"
|
|
45
|
+
|
|
46
|
+
build:
|
|
47
|
+
name: Build package
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
needs: test
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
- name: Checkout
|
|
53
|
+
uses: actions/checkout@v4
|
|
54
|
+
|
|
55
|
+
- name: Set up Python
|
|
56
|
+
uses: actions/setup-python@v5
|
|
57
|
+
with:
|
|
58
|
+
python-version: "3.12"
|
|
59
|
+
cache: pip
|
|
60
|
+
|
|
61
|
+
- name: Install build tools
|
|
62
|
+
run: |
|
|
63
|
+
python -m pip install --upgrade pip
|
|
64
|
+
python -m pip install build twine
|
|
65
|
+
|
|
66
|
+
- name: Build distributions
|
|
67
|
+
run: python -m build
|
|
68
|
+
|
|
69
|
+
- name: Check distributions
|
|
70
|
+
run: python -m twine check dist/*
|
|
71
|
+
|
|
72
|
+
- name: Upload distributions
|
|
73
|
+
uses: actions/upload-artifact@v4
|
|
74
|
+
with:
|
|
75
|
+
name: python-package-distributions
|
|
76
|
+
path: dist/
|
|
77
|
+
|
|
78
|
+
publish:
|
|
79
|
+
name: Publish to PyPI
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
needs: build
|
|
82
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
83
|
+
permissions:
|
|
84
|
+
id-token: write
|
|
85
|
+
contents: read
|
|
86
|
+
|
|
87
|
+
steps:
|
|
88
|
+
- name: Download distributions
|
|
89
|
+
uses: actions/download-artifact@v4
|
|
90
|
+
with:
|
|
91
|
+
name: python-package-distributions
|
|
92
|
+
path: dist/
|
|
93
|
+
|
|
94
|
+
- name: Publish distributions to PyPI
|
|
95
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Learnings -- Building hermes-pmxt v0.3.0
|
|
2
|
+
|
|
3
|
+
Things discovered during upgrade that differ from docs/research.
|
|
4
|
+
|
|
5
|
+
## pmxt SDK Realities (v2.50.x)
|
|
6
|
+
|
|
7
|
+
### Version metadata is inconsistent across sources
|
|
8
|
+
- PyPI: `pmxt 2.50.16`
|
|
9
|
+
- Raw Python pyproject.toml in monorepo: `2.18.0`
|
|
10
|
+
- monorepo package.json: `pmxtjs ^2.17.1`
|
|
11
|
+
- Generated pmxt-mcp tools.ts: `2.50.16` (2026-06-18)
|
|
12
|
+
- **Lesson**: Rely on runtime capability detection, not version strings.
|
|
13
|
+
|
|
14
|
+
### Dual API hosts
|
|
15
|
+
- `api.pmxt.dev` - reads, Router, MCP, venue passthrough
|
|
16
|
+
- `trade.pmxt.dev` - hosted writes + hosted account state
|
|
17
|
+
- Both authenticate with the same `pmxt_api_key`.
|
|
18
|
+
|
|
19
|
+
### Python SDK has hosted mode built-in
|
|
20
|
+
- `Exchange.__init__()` accepts `pmxt_api_key`, `wallet_address`, `base_url`
|
|
21
|
+
- Auto-resolves base URL: `PMXT_BASE_URL` → `pmxt_api_key` presence → localhost
|
|
22
|
+
- `build_order` + `submit_order` exist natively in Python SDK >= 2.50
|
|
23
|
+
- `call_api(operation_id, params)` exposes raw OpenAPI endpoints
|
|
24
|
+
|
|
25
|
+
### Router is NOT a separate Python class
|
|
26
|
+
- Router appears as `exchange="router"` target
|
|
27
|
+
- Router methods: `compareMarketPrices`, `fetchMarketMatches`, `fetchArbitrage`, etc.
|
|
28
|
+
- Available via `pmxt_call("methodName", "router", params={...})`
|
|
29
|
+
|
|
30
|
+
### server.status() returns a dict, not an object
|
|
31
|
+
- Keys: `running`, `pid`, `port`, `version`, `uptime_seconds`, `lock_file`
|
|
32
|
+
- Must use `.get()` not attribute access.
|
|
33
|
+
|
|
34
|
+
### fetch_market() (singular) doesn't work by ID
|
|
35
|
+
- `exchange.fetch_market(market_id="701486")` throws `PmxtError: Unknown error`
|
|
36
|
+
- **Workaround**: Use `fetch_markets(query=keyword, limit=N)`.
|
|
37
|
+
|
|
38
|
+
### outcome_id is Very Long
|
|
39
|
+
- Polymarket outcome_ids are 70+ character token IDs
|
|
40
|
+
- Use labels for display, pass IDs as-is for API calls
|
|
41
|
+
|
|
42
|
+
## pmxt-mcp Design Patterns Worth Adopting
|
|
43
|
+
|
|
44
|
+
### Auto-generated tool surface
|
|
45
|
+
- PMXT-MCP generates `src/generated/tools.ts` from OpenAPI + method-verbs.json
|
|
46
|
+
- Auto-runs on every PMXT release via GitHub Actions `sync-mcp.yml`
|
|
47
|
+
- hermes-pmxt should adopt: `scripts/sync_pmxt_registry.py`
|
|
48
|
+
|
|
49
|
+
### Flat agent-friendly schemas
|
|
50
|
+
- Complex params flattened to top-level MCP tool inputs
|
|
51
|
+
- `ArgSpec` metadata for runtime positional reconstruction
|
|
52
|
+
- `flatten: true` flags merged params for cleaner agent UX
|
|
53
|
+
|
|
54
|
+
### Safety annotations built into tools
|
|
55
|
+
- `readOnlyHint: true` - safe for repeated calls
|
|
56
|
+
- `destructiveHint: true` - requires confirmation
|
|
57
|
+
- `idempotentHint: true` - safe to retry
|
|
58
|
+
- hermes-pmxt mirrors this in registry.py
|
|
59
|
+
|
|
60
|
+
### Three config modes: hosted / local / custom
|
|
61
|
+
- `PMXT_API_URL` overrides everything
|
|
62
|
+
- `PMXT_API_KEY` → hosted `api.pmxt.dev`
|
|
63
|
+
- Neither → local `http://localhost:3847`
|
|
64
|
+
- hermes-pmxt mirrors this in config.py
|
|
65
|
+
|
|
66
|
+
### Compact result shaping
|
|
67
|
+
- `verbose=false` (default): compact agent-friendly output
|
|
68
|
+
- `verbose=true`: raw uncompacted
|
|
69
|
+
- Strips market status when active, truncates descriptions
|
|
70
|
+
- hermes-pmxt mirrors this in shaper.py
|
|
71
|
+
|
|
72
|
+
### Instructions favor events first
|
|
73
|
+
- pmxt-mcp tells agents: "users say 'market', they mean 'event'"
|
|
74
|
+
- Discovery: fetchEvents → drill to markets → outcomes
|
|
75
|
+
|
|
76
|
+
## Price Scale
|
|
77
|
+
All prices confirmed as 0.0-1.0 (probabilities). Kalshi internally uses 0-100
|
|
78
|
+
but pmxt normalizes to 0-1 in the Python SDK.
|
|
79
|
+
|
|
80
|
+
## Trade Timestamps
|
|
81
|
+
All timestamps are Unix milliseconds. Divide by 1000 for Python datetime.
|
|
82
|
+
|
|
83
|
+
## Kalshi Behavior
|
|
84
|
+
- Returns markets with `before`/`not before` label style
|
|
85
|
+
- Read-only without API keys (local sidecar mode)
|
|
86
|
+
- Search is slower than Polymarket
|
|
87
|
+
|
|
88
|
+
## hermes-pmxt Architecture Decisions (v0.3.0)
|
|
89
|
+
|
|
90
|
+
### Lazy import over eager import
|
|
91
|
+
- `exchanges.py` uses `_get_pmxt()` lazy getter
|
|
92
|
+
- Package imports cleanly without pmxt installed
|
|
93
|
+
- Only raises ImportError when pmxt functionality is used
|
|
94
|
+
|
|
95
|
+
### Generated registry over manual wrappers
|
|
96
|
+
- `registry.py` has ~33 tool definitions with safety annotations
|
|
97
|
+
- `pmxt_call()` dispatches to SDK methods with guard rails
|
|
98
|
+
- Handwritten wrappers for common flows only
|
|
99
|
+
|
|
100
|
+
### confirmed=True gate for destructive ops
|
|
101
|
+
- `createOrder`, `submitOrder`, `cancelOrder` require `confirmed=True`
|
|
102
|
+
- `_require_confirmed()` returns human-readable error when not confirmed
|
|
103
|
+
|
|
104
|
+
### Runtime status as first troubleshooting step
|
|
105
|
+
- `pmxt_runtime_status()` shows mode, URL, version, sidecar health
|
|
106
|
+
- Works without pmxt installed
|
|
107
|
+
|
|
108
|
+
### Exchange list with capability detection
|
|
109
|
+
- 17 known exchanges in registry
|
|
110
|
+
- `pmxt_list_exchanges()` reports which are available in installed build
|
|
111
|
+
- Aliases for common naming variants
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HERMES-PMXT
|
|
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.
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-pmxt
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Prediction market integration for Hermes Agent -- search, compare, and trade across prediction market exchanges via pmxt
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: pmxt>=2.50.0
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
12
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# hermes-pmxt
|
|
16
|
+
|
|
17
|
+
Prediction market integration for [Hermes Agent](https://github.com/NousResearch/hermes-agent).
|
|
18
|
+
Search markets, compare prices, detect arbitrage, and trade across prediction market
|
|
19
|
+
exchanges via [pmxt](https://github.com/pmxt-dev/pmxt) (>= 2.50.0).
|
|
20
|
+
|
|
21
|
+
## What This Is
|
|
22
|
+
|
|
23
|
+
A Hermes skill + Python toolset that gives any Hermes agent real-time access to prediction
|
|
24
|
+
markets. Instead of hallucinating probabilities, the agent checks actual market prices.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
User: "Will Trump win 2028?"
|
|
28
|
+
Agent: *calls pmxt_search + pmxt_quote*
|
|
29
|
+
Agent: "The market implies a 1.9% chance (No: 98.1%). Polymarket is pricing this very low."
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
Install directly with `pip`, matching the one-command style used by Hermes plugins such
|
|
35
|
+
as Mnemosyne. You do not need to clone this repository unless you are developing it.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install "git+https://github.com/0xharryriddle/hermes-pmxt.git"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For local development from a checkout:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python3 -m venv .venv
|
|
45
|
+
source .venv/bin/activate
|
|
46
|
+
pip install -e ".[dev]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Hermes Skill Setup
|
|
50
|
+
|
|
51
|
+
After installing the package, copy or symlink `skill/SKILL.md` into your Hermes skills
|
|
52
|
+
directory so agents know when and how to use the tools. Example:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
mkdir -p ~/.hermes/skills/pmxt
|
|
56
|
+
cp skill/SKILL.md ~/.hermes/skills/pmxt/SKILL.md
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If your Hermes install supports GitHub-backed skill/plugin installation, point it at
|
|
60
|
+
`https://github.com/0xharryriddle/hermes-pmxt` and enable the `pmxt` skill.
|
|
61
|
+
|
|
62
|
+
## Modes
|
|
63
|
+
|
|
64
|
+
hermes-pmxt supports three runtime modes:
|
|
65
|
+
|
|
66
|
+
| Mode | Config | Behavior |
|
|
67
|
+
|------|--------|----------|
|
|
68
|
+
| **Hosted** | Set `PMXT_API_KEY` | Talks to `https://api.pmxt.dev`. Handles exchange connections, caching, and rate limits automatically. Recommended for most users. |
|
|
69
|
+
| **Custom** | Set `PMXT_API_URL` or `PMXT_BASE_URL` | Points to any PMXT-compatible server. |
|
|
70
|
+
| **Local Sidecar** | No API key/URL set | Assumes PMXT core is running at `http://localhost:3847`. For self-hosting / development. |
|
|
71
|
+
|
|
72
|
+
Check your current mode:
|
|
73
|
+
```python
|
|
74
|
+
from hermes_pmxt import pmxt_runtime_status
|
|
75
|
+
print(pmxt_runtime_status())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from hermes_pmxt import pmxt_search, pmxt_quote, pmxt_runtime_status
|
|
82
|
+
|
|
83
|
+
# Check status
|
|
84
|
+
print(pmxt_runtime_status())
|
|
85
|
+
|
|
86
|
+
# Search
|
|
87
|
+
result = pmxt_search("bitcoin", exchange="polymarket", limit=5)
|
|
88
|
+
for m in result["data"]:
|
|
89
|
+
prices = m.get("outcomes", [])
|
|
90
|
+
if prices:
|
|
91
|
+
print(f"{m['title'][:60]}: YES={prices[0]['price']*100:.1f}%")
|
|
92
|
+
|
|
93
|
+
# Quote
|
|
94
|
+
quote = pmxt_quote("bitcoin reach", exchange="polymarket")
|
|
95
|
+
print(f"YES: {quote['data']['yes_pct']} NO: {quote['data']['no_pct']}")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Data Model
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Event (broad topic)
|
|
102
|
+
└── Market (tradeable question)
|
|
103
|
+
├── Outcome "Yes"
|
|
104
|
+
└── Outcome "No"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
When users ask about a topic, start with events (`pmxt_events`), then drill down to
|
|
108
|
+
markets and outcomes.
|
|
109
|
+
|
|
110
|
+
## Tools
|
|
111
|
+
|
|
112
|
+
### Discovery & Research
|
|
113
|
+
|
|
114
|
+
| Function | Auth | Description |
|
|
115
|
+
|----------|------|-------------|
|
|
116
|
+
| `pmxt_search(query, exchange?, limit?, sort?, search_in?, slug?)` | No* | Search markets by keyword |
|
|
117
|
+
| `pmxt_events(query, exchange?, limit?, sort?, search_in?, slug?)` | No* | Search event groups |
|
|
118
|
+
| `pmxt_quote(identifier, exchange)` | No* | Get YES/NO probabilities |
|
|
119
|
+
| `pmxt_order_book(outcome_id, exchange, limit?)` | No* | Order book depth |
|
|
120
|
+
| `pmxt_ohlcv(outcome_id, exchange, resolution?, limit?)` | No* | Price candles |
|
|
121
|
+
| `pmxt_trades(outcome_id, exchange, limit?)` | No* | Recent trades |
|
|
122
|
+
| `pmxt_execution_price(outcome_id, exchange, side, amount)` | No* | Slippage estimate |
|
|
123
|
+
|
|
124
|
+
### Cross-Venue & Arbitrage
|
|
125
|
+
|
|
126
|
+
| Function | Auth | Description |
|
|
127
|
+
|----------|------|-------------|
|
|
128
|
+
| `pmxt_compare_market(query, exchanges?, limit?)` | No* | Compare prices across exchanges |
|
|
129
|
+
| `pmxt_arbitrage_scan(query, exchanges?, threshold?)` | No* | Detect arbitrage opportunities |
|
|
130
|
+
| `pmxt_call("compareMarketPrices", "router", ...)` | No* | Native router comparison |
|
|
131
|
+
| `pmxt_call("fetchArbitrage", "router", ...)` | No* | Native arbitrage search |
|
|
132
|
+
| `pmxt_call("fetchHedges", "router", ...)` | No* | Hedging opportunities |
|
|
133
|
+
|
|
134
|
+
### Portfolio & Account
|
|
135
|
+
|
|
136
|
+
| Function | Auth | Description |
|
|
137
|
+
|----------|------|-------------|
|
|
138
|
+
| `pmxt_balance(exchange)` | Yes | Account balance |
|
|
139
|
+
| `pmxt_positions(exchange)` | Yes | Open positions |
|
|
140
|
+
| `pmxt_portfolio(exchanges?)` | Yes | Cross-exchange portfolio |
|
|
141
|
+
|
|
142
|
+
### Trading (All Destructive -- Require Explicit Confirmation)
|
|
143
|
+
|
|
144
|
+
| Function | Auth | Description |
|
|
145
|
+
|----------|------|-------------|
|
|
146
|
+
| `pmxt_build_order(...)` | Yes | Build/sign order without submitting (SAFE) |
|
|
147
|
+
| `pmxt_submit_order(built, exchange, confirmed=True)` | Yes | Submit a pre-built order |
|
|
148
|
+
| `pmxt_cancel_order(order_id, exchange, confirmed=True)` | Yes | Cancel an open order |
|
|
149
|
+
| `pmxt_order(...)` | Yes | Legacy one-step order (prefer build+submit) |
|
|
150
|
+
|
|
151
|
+
### Generic API Call
|
|
152
|
+
|
|
153
|
+
| Function | Auth | Description |
|
|
154
|
+
|----------|------|-------------|
|
|
155
|
+
| `pmxt_call(method, exchange, ...)` | Varies | Generic PMXT API call with safety checks |
|
|
156
|
+
|
|
157
|
+
### Server & Diagnostics
|
|
158
|
+
|
|
159
|
+
| Function | Auth | Description |
|
|
160
|
+
|----------|------|-------------|
|
|
161
|
+
| `pmxt_runtime_status()` | No | Full runtime status |
|
|
162
|
+
| `pmxt_list_exchanges()` | No | Known/available exchanges |
|
|
163
|
+
| `pmxt_server_status()` | No | Sidecar diagnostics |
|
|
164
|
+
| `pmxt_server_start()` | No | Start sidecar |
|
|
165
|
+
| `pmxt_server_stop()` | No | Stop sidecar |
|
|
166
|
+
|
|
167
|
+
\* Read-only tools work without credentials in local sidecar mode. Hosted mode requires `PMXT_API_KEY` for all operations.
|
|
168
|
+
|
|
169
|
+
## Trading Safety
|
|
170
|
+
|
|
171
|
+
**Destructive operations (create, submit, cancel orders) require explicit user confirmation.**
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# SAFE: Build order for preview (does NOT place any order)
|
|
175
|
+
built = pmxt_build_order(
|
|
176
|
+
market_id="market-uuid",
|
|
177
|
+
outcome="yes",
|
|
178
|
+
side="buy",
|
|
179
|
+
order_type="limit",
|
|
180
|
+
amount=10,
|
|
181
|
+
price=0.55,
|
|
182
|
+
exchange="polymarket",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# DESTRUCTIVE: Submit requires confirmed=True
|
|
186
|
+
result = pmxt_submit_order(built, "polymarket", confirmed=True)
|
|
187
|
+
|
|
188
|
+
# Without confirmed=True:
|
|
189
|
+
result = pmxt_submit_order(built, "polymarket")
|
|
190
|
+
# => {"success": False, "error": "Operation 'submit_order' is destructive..."}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Supported Exchanges
|
|
194
|
+
|
|
195
|
+
hermes-pmxt knows about 17 venues including:
|
|
196
|
+
|
|
197
|
+
- `polymarket` / `polymarket_us`
|
|
198
|
+
- `kalshi` / `kalshi-demo`
|
|
199
|
+
- `limitless`
|
|
200
|
+
- `probable` / `baozi` / `myriad` / `opinion`
|
|
201
|
+
- `metaculus` / `smarkets`
|
|
202
|
+
- `gemini-titan` / `hyperliquid` / `suibets` / `rain`
|
|
203
|
+
- `mock` / `router`
|
|
204
|
+
|
|
205
|
+
Actual availability depends on the installed `pmxt` build. Run `pmxt_list_exchanges()` to check.
|
|
206
|
+
|
|
207
|
+
## Environment Variables
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Hosted mode (recommended)
|
|
211
|
+
export PMXT_API_KEY="pmxt_live_..."
|
|
212
|
+
export PMXT_WALLET_ADDRESS="0x..."
|
|
213
|
+
export PMXT_PRIVATE_KEY="0x..."
|
|
214
|
+
|
|
215
|
+
# Custom server
|
|
216
|
+
export PMXT_API_URL="https://your-server.com"
|
|
217
|
+
# or
|
|
218
|
+
export PMXT_BASE_URL="https://your-server.com"
|
|
219
|
+
|
|
220
|
+
# Venue-specific (self-hosted mode)
|
|
221
|
+
export POLYMARKET_PRIVATE_KEY="0x..."
|
|
222
|
+
export POLYMARKET_PROXY_ADDRESS="0x..." # Optional
|
|
223
|
+
export KALSHI_API_KEY="..."
|
|
224
|
+
export KALSHI_PRIVATE_KEY="..."
|
|
225
|
+
export LIMITLESS_API_KEY="..."
|
|
226
|
+
export LIMITLESS_PRIVATE_KEY="..."
|
|
227
|
+
export POLYMARKET_US_API_KEY="..."
|
|
228
|
+
export POLYMARKET_US_PRIVATE_KEY="..."
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Project Structure
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
hermes-pmxt/
|
|
235
|
+
├── hermes_pmxt/
|
|
236
|
+
│ ├── __init__.py # Public API exports
|
|
237
|
+
│ ├── config.py # Runtime config and mode detection
|
|
238
|
+
│ ├── exchanges.py # Exchange initialization + normalization
|
|
239
|
+
│ ├── registry.py # Tool registry with safety annotations
|
|
240
|
+
│ ├── shaper.py # Result shaping for LLM context
|
|
241
|
+
│ └── tools.py # Core tool functions
|
|
242
|
+
├── skill/
|
|
243
|
+
│ └── SKILL.md # Hermes agent skill instructions
|
|
244
|
+
├── examples/
|
|
245
|
+
│ └── demo.py # Interactive demo
|
|
246
|
+
├── tests/
|
|
247
|
+
│ ├── conftest.py # Test path setup
|
|
248
|
+
│ ├── test_exchanges.py # Exchange wiring unit tests
|
|
249
|
+
│ └── test_tools.py # Unit + integration tests
|
|
250
|
+
├── pyproject.toml
|
|
251
|
+
└── README.md
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Testing
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Unit tests (no pmxt required)
|
|
258
|
+
python3 -m pytest -q -m unit
|
|
259
|
+
|
|
260
|
+
# All non-destructive tests
|
|
261
|
+
python3 -m pytest -q -m "not trading"
|
|
262
|
+
|
|
263
|
+
# Integration tests (need pmxt + sidecar/API)
|
|
264
|
+
python3 -m pytest -q -m integration
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT
|