simmer-sdk 0.2.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.
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.1
2
+ Name: simmer-sdk
3
+ Version: 0.2.3
4
+ Summary: Python SDK for Simmer prediction markets
5
+ Author-email: Simmer <hello@simmer.markets>
6
+ Project-URL: Homepage, https://simmer.markets
7
+ Project-URL: Documentation, https://github.com/SpartanLabsXyz/simmer-sdk
8
+ Project-URL: Repository, https://github.com/SpartanLabsXyz/simmer-sdk
9
+ Project-URL: Issues, https://github.com/SpartanLabsXyz/simmer-sdk/issues
10
+ Keywords: prediction-markets,polymarket,kalshi,trading,sdk
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Office/Business :: Financial :: Investment
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Simmer SDK
25
+
26
+ Python client for trading on Simmer prediction markets.
27
+
28
+ ## Trading Venues
29
+
30
+ The SDK supports three trading venues via the `venue` parameter:
31
+
32
+ | Venue | Currency | Description |
33
+ |-------|----------|-------------|
34
+ | `sandbox` | $SIM (virtual) | Default. Trade on Simmer's LMSR markets with virtual currency. |
35
+ | `polymarket` | USDC (real) | Execute real trades on Polymarket. Requires wallet linked in dashboard. |
36
+ | `shadow` | $SIM | Paper trading - LMSR execution with P&L tracked against real prices. *(Coming soon)* |
37
+
38
+ ```python
39
+ # Sandbox trading (default) - virtual currency, no risk
40
+ client = SimmerClient(api_key="sk_live_...", venue="sandbox")
41
+
42
+ # Real trading on Polymarket - requires linked wallet
43
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
44
+
45
+ # Override venue for a single trade
46
+ result = client.trade(market_id, "yes", 10.0, venue="polymarket")
47
+ ```
48
+
49
+ ## Trading Modes
50
+
51
+ ### Training Mode (Sandbox)
52
+
53
+ Import markets as **isolated sandboxes** for RL training and development:
54
+
55
+ ```python
56
+ # Import a Polymarket market as sandbox (training mode)
57
+ result = client.import_market("https://polymarket.com/event/btc-updown-15m-...")
58
+
59
+ # Trade in isolation - no other agents, no impact on production
60
+ client.trade(market_id=result['market_id'], side="yes", amount=10)
61
+ ```
62
+
63
+ **Best for:**
64
+ - RL training with thousands of exploration trades
65
+ - Strategy backtesting without affecting real markets
66
+ - Development and debugging
67
+ - Ultra-short-term markets (15-min crypto predictions)
68
+
69
+ ### Production Mode (Shared Markets)
70
+
71
+ Trade on **existing Simmer markets** alongside AI agents and other users:
72
+
73
+ ```python
74
+ # Get active markets where Simmer's AI agents are trading
75
+ markets = client.get_markets(status="active", import_source="polymarket")
76
+
77
+ # Trade alongside GPT-4o, Claude, Llama and other agents
78
+ client.trade(market_id=markets[0].id, side="yes", amount=10)
79
+ ```
80
+
81
+ **Best for:**
82
+ - Benchmarking your bot against Simmer's AI agents
83
+ - Real multi-agent price discovery
84
+ - Production deployment after training
85
+
86
+ ### Real Trading Mode
87
+
88
+ Graduate to real money trading on Polymarket:
89
+
90
+ ```python
91
+ # Initialize with polymarket venue
92
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
93
+
94
+ # Trades execute on Polymarket CLOB with real USDC
95
+ result = client.trade(market_id, side="yes", amount=10.0)
96
+ ```
97
+
98
+ **Requirements:**
99
+ 1. Link your Polymarket wallet in the Simmer dashboard
100
+ 2. Enable "Real Trading" toggle in SDK settings
101
+ 3. Fund your wallet with USDC
102
+
103
+ ### Workflow
104
+
105
+ 1. **Train**: Import markets as sandbox, run RL training loops
106
+ 2. **Evaluate**: Deploy trained model on shared production markets
107
+ 3. **Benchmark**: Compare your bot's P&L against Simmer's native agents
108
+ 4. **Graduate**: Enable real trading to execute on Polymarket
109
+
110
+ ## Installation
111
+
112
+ ```bash
113
+ pip install -e sdk/
114
+ ```
115
+
116
+ ## Quick Start
117
+
118
+ ```python
119
+ from simmer_sdk import SimmerClient
120
+
121
+ # Initialize client
122
+ client = SimmerClient(
123
+ api_key="sk_live_...",
124
+ base_url="http://localhost:8000" # or https://api.simmer.markets
125
+ )
126
+
127
+ # List available markets
128
+ markets = client.get_markets(import_source="polymarket", limit=10)
129
+ for m in markets:
130
+ print(f"{m.question}: {m.current_probability:.1%}")
131
+
132
+ # Execute a trade
133
+ result = client.trade(
134
+ market_id=markets[0].id,
135
+ side="yes",
136
+ amount=10.0 # $10
137
+ )
138
+ print(f"Bought {result.shares_bought:.2f} shares for ${result.cost:.2f}")
139
+
140
+ # Check positions
141
+ positions = client.get_positions()
142
+ for p in positions:
143
+ print(f"{p.question[:50]}: P&L ${p.pnl:.2f}")
144
+
145
+ # Get total P&L
146
+ total_pnl = client.get_total_pnl()
147
+ print(f"Total P&L: ${total_pnl:.2f}")
148
+ ```
149
+
150
+ ## API Reference
151
+
152
+ ### SimmerClient
153
+
154
+ #### `__init__(api_key, base_url, venue)`
155
+ - `api_key`: Your SDK API key (starts with `sk_live_`)
156
+ - `base_url`: API URL (default: `https://api.simmer.markets`)
157
+ - `venue`: Trading venue (default: `sandbox`)
158
+ - `sandbox`: Simmer LMSR with $SIM virtual currency
159
+ - `polymarket`: Real Polymarket CLOB with USDC
160
+ - `shadow`: Paper trading against real prices *(coming soon)*
161
+
162
+ #### `get_markets(status, import_source, limit)`
163
+ List available markets.
164
+ - `status`: Filter by status (`active`, `resolved`)
165
+ - `import_source`: Filter by source (`polymarket`, `kalshi`, or `None` for all)
166
+ - Returns: List of `Market` objects
167
+
168
+ #### `trade(market_id, side, amount, venue)`
169
+ Execute a trade.
170
+ - `market_id`: Market to trade on
171
+ - `side`: `yes` or `no`
172
+ - `amount`: Dollar amount to spend
173
+ - `venue`: Override client's default venue for this trade (optional)
174
+ - Returns: `TradeResult` with execution details
175
+
176
+ #### `get_positions()`
177
+ Get all positions with P&L.
178
+ - Returns: List of `Position` objects
179
+
180
+ #### `get_total_pnl()`
181
+ Get total unrealized P&L.
182
+ - Returns: Float
183
+
184
+ #### `import_market(polymarket_url, sandbox=True)`
185
+ Import a Polymarket market for trading.
186
+ - `polymarket_url`: Full Polymarket event URL
187
+ - `sandbox`: If `True` (default), creates isolated training market. If `False`, would create shared market (not yet supported).
188
+ - Returns: Dict with `market_id`, `question`, and import details
189
+
190
+ ```python
191
+ # Import 15-min BTC market for RL training
192
+ result = client.import_market(
193
+ "https://polymarket.com/event/btc-updown-15m-1767489300",
194
+ sandbox=True # default - isolated training environment
195
+ )
196
+ print(f"Imported: {result['market_id']}")
197
+ ```
198
+
199
+ #### `find_markets(query)`
200
+ Search markets by question text.
201
+ - `query`: Search string
202
+ - Returns: List of matching `Market` objects
203
+
204
+ #### `get_market_by_id(market_id)`
205
+ Get a specific market by ID.
206
+ - `market_id`: Market ID
207
+ - Returns: `Market` object or `None`
208
+
209
+ ## Data Classes
210
+
211
+ ### Market
212
+ - `id`: Market ID
213
+ - `question`: Market question
214
+ - `status`: `active` or `resolved`
215
+ - `current_probability`: Current YES probability (0-1)
216
+ - `import_source`: Source platform (if imported)
217
+ - `external_price_yes`: External market price
218
+ - `divergence`: Simmer vs external price difference
219
+ - `resolves_at`: Resolution timestamp (ISO format)
220
+ - `is_sdk_only`: `True` for sandbox/training markets, `False` for shared markets
221
+
222
+ ### Position
223
+ - `market_id`: Market ID
224
+ - `shares_yes`: YES shares held
225
+ - `shares_no`: NO shares held
226
+ - `current_value`: Current position value
227
+ - `pnl`: Unrealized profit/loss
228
+
229
+ ### TradeResult
230
+ - `success`: Whether trade succeeded
231
+ - `shares_bought`: Shares acquired
232
+ - `cost`: Amount spent
233
+ - `new_price`: New market price after trade
234
+ - `balance`: Remaining balance after trade (sandbox only)
235
+ - `error`: Error message if failed
236
+
237
+ ## Publishing to PyPI
238
+
239
+ ```bash
240
+ # Install build tools
241
+ pip install build twine
242
+
243
+ # Build package
244
+ python -m build
245
+
246
+ # Upload to PyPI
247
+ twine upload dist/*
248
+ ```
249
+
250
+ ## License
251
+
252
+ MIT
@@ -0,0 +1,229 @@
1
+ # Simmer SDK
2
+
3
+ Python client for trading on Simmer prediction markets.
4
+
5
+ ## Trading Venues
6
+
7
+ The SDK supports three trading venues via the `venue` parameter:
8
+
9
+ | Venue | Currency | Description |
10
+ |-------|----------|-------------|
11
+ | `sandbox` | $SIM (virtual) | Default. Trade on Simmer's LMSR markets with virtual currency. |
12
+ | `polymarket` | USDC (real) | Execute real trades on Polymarket. Requires wallet linked in dashboard. |
13
+ | `shadow` | $SIM | Paper trading - LMSR execution with P&L tracked against real prices. *(Coming soon)* |
14
+
15
+ ```python
16
+ # Sandbox trading (default) - virtual currency, no risk
17
+ client = SimmerClient(api_key="sk_live_...", venue="sandbox")
18
+
19
+ # Real trading on Polymarket - requires linked wallet
20
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
21
+
22
+ # Override venue for a single trade
23
+ result = client.trade(market_id, "yes", 10.0, venue="polymarket")
24
+ ```
25
+
26
+ ## Trading Modes
27
+
28
+ ### Training Mode (Sandbox)
29
+
30
+ Import markets as **isolated sandboxes** for RL training and development:
31
+
32
+ ```python
33
+ # Import a Polymarket market as sandbox (training mode)
34
+ result = client.import_market("https://polymarket.com/event/btc-updown-15m-...")
35
+
36
+ # Trade in isolation - no other agents, no impact on production
37
+ client.trade(market_id=result['market_id'], side="yes", amount=10)
38
+ ```
39
+
40
+ **Best for:**
41
+ - RL training with thousands of exploration trades
42
+ - Strategy backtesting without affecting real markets
43
+ - Development and debugging
44
+ - Ultra-short-term markets (15-min crypto predictions)
45
+
46
+ ### Production Mode (Shared Markets)
47
+
48
+ Trade on **existing Simmer markets** alongside AI agents and other users:
49
+
50
+ ```python
51
+ # Get active markets where Simmer's AI agents are trading
52
+ markets = client.get_markets(status="active", import_source="polymarket")
53
+
54
+ # Trade alongside GPT-4o, Claude, Llama and other agents
55
+ client.trade(market_id=markets[0].id, side="yes", amount=10)
56
+ ```
57
+
58
+ **Best for:**
59
+ - Benchmarking your bot against Simmer's AI agents
60
+ - Real multi-agent price discovery
61
+ - Production deployment after training
62
+
63
+ ### Real Trading Mode
64
+
65
+ Graduate to real money trading on Polymarket:
66
+
67
+ ```python
68
+ # Initialize with polymarket venue
69
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
70
+
71
+ # Trades execute on Polymarket CLOB with real USDC
72
+ result = client.trade(market_id, side="yes", amount=10.0)
73
+ ```
74
+
75
+ **Requirements:**
76
+ 1. Link your Polymarket wallet in the Simmer dashboard
77
+ 2. Enable "Real Trading" toggle in SDK settings
78
+ 3. Fund your wallet with USDC
79
+
80
+ ### Workflow
81
+
82
+ 1. **Train**: Import markets as sandbox, run RL training loops
83
+ 2. **Evaluate**: Deploy trained model on shared production markets
84
+ 3. **Benchmark**: Compare your bot's P&L against Simmer's native agents
85
+ 4. **Graduate**: Enable real trading to execute on Polymarket
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ pip install -e sdk/
91
+ ```
92
+
93
+ ## Quick Start
94
+
95
+ ```python
96
+ from simmer_sdk import SimmerClient
97
+
98
+ # Initialize client
99
+ client = SimmerClient(
100
+ api_key="sk_live_...",
101
+ base_url="http://localhost:8000" # or https://api.simmer.markets
102
+ )
103
+
104
+ # List available markets
105
+ markets = client.get_markets(import_source="polymarket", limit=10)
106
+ for m in markets:
107
+ print(f"{m.question}: {m.current_probability:.1%}")
108
+
109
+ # Execute a trade
110
+ result = client.trade(
111
+ market_id=markets[0].id,
112
+ side="yes",
113
+ amount=10.0 # $10
114
+ )
115
+ print(f"Bought {result.shares_bought:.2f} shares for ${result.cost:.2f}")
116
+
117
+ # Check positions
118
+ positions = client.get_positions()
119
+ for p in positions:
120
+ print(f"{p.question[:50]}: P&L ${p.pnl:.2f}")
121
+
122
+ # Get total P&L
123
+ total_pnl = client.get_total_pnl()
124
+ print(f"Total P&L: ${total_pnl:.2f}")
125
+ ```
126
+
127
+ ## API Reference
128
+
129
+ ### SimmerClient
130
+
131
+ #### `__init__(api_key, base_url, venue)`
132
+ - `api_key`: Your SDK API key (starts with `sk_live_`)
133
+ - `base_url`: API URL (default: `https://api.simmer.markets`)
134
+ - `venue`: Trading venue (default: `sandbox`)
135
+ - `sandbox`: Simmer LMSR with $SIM virtual currency
136
+ - `polymarket`: Real Polymarket CLOB with USDC
137
+ - `shadow`: Paper trading against real prices *(coming soon)*
138
+
139
+ #### `get_markets(status, import_source, limit)`
140
+ List available markets.
141
+ - `status`: Filter by status (`active`, `resolved`)
142
+ - `import_source`: Filter by source (`polymarket`, `kalshi`, or `None` for all)
143
+ - Returns: List of `Market` objects
144
+
145
+ #### `trade(market_id, side, amount, venue)`
146
+ Execute a trade.
147
+ - `market_id`: Market to trade on
148
+ - `side`: `yes` or `no`
149
+ - `amount`: Dollar amount to spend
150
+ - `venue`: Override client's default venue for this trade (optional)
151
+ - Returns: `TradeResult` with execution details
152
+
153
+ #### `get_positions()`
154
+ Get all positions with P&L.
155
+ - Returns: List of `Position` objects
156
+
157
+ #### `get_total_pnl()`
158
+ Get total unrealized P&L.
159
+ - Returns: Float
160
+
161
+ #### `import_market(polymarket_url, sandbox=True)`
162
+ Import a Polymarket market for trading.
163
+ - `polymarket_url`: Full Polymarket event URL
164
+ - `sandbox`: If `True` (default), creates isolated training market. If `False`, would create shared market (not yet supported).
165
+ - Returns: Dict with `market_id`, `question`, and import details
166
+
167
+ ```python
168
+ # Import 15-min BTC market for RL training
169
+ result = client.import_market(
170
+ "https://polymarket.com/event/btc-updown-15m-1767489300",
171
+ sandbox=True # default - isolated training environment
172
+ )
173
+ print(f"Imported: {result['market_id']}")
174
+ ```
175
+
176
+ #### `find_markets(query)`
177
+ Search markets by question text.
178
+ - `query`: Search string
179
+ - Returns: List of matching `Market` objects
180
+
181
+ #### `get_market_by_id(market_id)`
182
+ Get a specific market by ID.
183
+ - `market_id`: Market ID
184
+ - Returns: `Market` object or `None`
185
+
186
+ ## Data Classes
187
+
188
+ ### Market
189
+ - `id`: Market ID
190
+ - `question`: Market question
191
+ - `status`: `active` or `resolved`
192
+ - `current_probability`: Current YES probability (0-1)
193
+ - `import_source`: Source platform (if imported)
194
+ - `external_price_yes`: External market price
195
+ - `divergence`: Simmer vs external price difference
196
+ - `resolves_at`: Resolution timestamp (ISO format)
197
+ - `is_sdk_only`: `True` for sandbox/training markets, `False` for shared markets
198
+
199
+ ### Position
200
+ - `market_id`: Market ID
201
+ - `shares_yes`: YES shares held
202
+ - `shares_no`: NO shares held
203
+ - `current_value`: Current position value
204
+ - `pnl`: Unrealized profit/loss
205
+
206
+ ### TradeResult
207
+ - `success`: Whether trade succeeded
208
+ - `shares_bought`: Shares acquired
209
+ - `cost`: Amount spent
210
+ - `new_price`: New market price after trade
211
+ - `balance`: Remaining balance after trade (sandbox only)
212
+ - `error`: Error message if failed
213
+
214
+ ## Publishing to PyPI
215
+
216
+ ```bash
217
+ # Install build tools
218
+ pip install build twine
219
+
220
+ # Build package
221
+ python -m build
222
+
223
+ # Upload to PyPI
224
+ twine upload dist/*
225
+ ```
226
+
227
+ ## License
228
+
229
+ MIT
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "simmer-sdk"
7
+ version = "0.2.3"
8
+ description = "Python SDK for Simmer prediction markets"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Simmer", email = "hello@simmer.markets"}
12
+ ]
13
+ keywords = ["prediction-markets", "polymarket", "kalshi", "trading", "sdk"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.8",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Office/Business :: Financial :: Investment",
25
+ ]
26
+ requires-python = ">=3.8"
27
+ dependencies = [
28
+ "requests>=2.25.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://simmer.markets"
33
+ Documentation = "https://github.com/SpartanLabsXyz/simmer-sdk"
34
+ Repository = "https://github.com/SpartanLabsXyz/simmer-sdk"
35
+ Issues = "https://github.com/SpartanLabsXyz/simmer-sdk/issues"
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["."]
39
+ include = ["simmer_sdk*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,22 @@
1
+ """
2
+ Simmer SDK - Python client for Simmer prediction markets
3
+
4
+ Usage:
5
+ from simmer_sdk import SimmerClient
6
+
7
+ client = SimmerClient(api_key="sk_live_...")
8
+
9
+ # List markets
10
+ markets = client.get_markets(import_source="polymarket")
11
+
12
+ # Execute trade
13
+ result = client.trade(market_id="...", side="yes", amount=10.0)
14
+
15
+ # Get positions
16
+ positions = client.get_positions()
17
+ """
18
+
19
+ from .client import SimmerClient
20
+
21
+ __version__ = "0.2.3"
22
+ __all__ = ["SimmerClient"]
@@ -0,0 +1,436 @@
1
+ """
2
+ Simmer SDK Client
3
+
4
+ Simple Python client for trading on Simmer prediction markets.
5
+ """
6
+
7
+ import requests
8
+ from typing import Optional, List, Dict, Any
9
+ from dataclasses import dataclass
10
+
11
+
12
+ @dataclass
13
+ class Market:
14
+ """Represents a Simmer market."""
15
+ id: str
16
+ question: str
17
+ status: str
18
+ current_probability: float
19
+ import_source: Optional[str] = None
20
+ external_price_yes: Optional[float] = None
21
+ divergence: Optional[float] = None
22
+ resolves_at: Optional[str] = None
23
+ is_sdk_only: bool = False # True for ultra-short-term markets hidden from public UI
24
+
25
+
26
+ @dataclass
27
+ class Position:
28
+ """Represents a position in a market."""
29
+ market_id: str
30
+ question: str
31
+ shares_yes: float
32
+ shares_no: float
33
+ sim_balance: float
34
+ current_value: float
35
+ pnl: float
36
+ status: str
37
+
38
+
39
+ @dataclass
40
+ class TradeResult:
41
+ """Result of a trade execution."""
42
+ success: bool
43
+ trade_id: Optional[str] = None
44
+ market_id: str = ""
45
+ side: str = ""
46
+ shares_bought: float = 0
47
+ cost: float = 0
48
+ new_price: float = 0
49
+ balance: Optional[float] = None # Remaining balance after trade
50
+ error: Optional[str] = None
51
+
52
+
53
+ @dataclass
54
+ class PolymarketOrderParams:
55
+ """Order parameters for Polymarket CLOB execution."""
56
+ token_id: str
57
+ price: float
58
+ size: float
59
+ side: str # "BUY" or "SELL"
60
+ condition_id: str
61
+ neg_risk: bool = False
62
+
63
+
64
+ @dataclass
65
+ class RealTradeResult:
66
+ """Result of prepare_real_trade() - contains order params for CLOB submission."""
67
+ success: bool
68
+ market_id: str = ""
69
+ platform: str = ""
70
+ order_params: Optional[PolymarketOrderParams] = None
71
+ intent_id: Optional[str] = None
72
+ error: Optional[str] = None
73
+
74
+
75
+ class SimmerClient:
76
+ """
77
+ Client for interacting with Simmer SDK API.
78
+
79
+ Example:
80
+ # Sandbox trading (default) - uses $SIM virtual currency
81
+ client = SimmerClient(api_key="sk_live_...")
82
+ markets = client.get_markets(limit=10)
83
+ result = client.trade(market_id=markets[0].id, side="yes", amount=10)
84
+ print(f"Bought {result.shares_bought} shares for ${result.cost}")
85
+
86
+ # Real trading on Polymarket - uses real USDC (requires wallet linked in dashboard)
87
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
88
+ result = client.trade(market_id=markets[0].id, side="yes", amount=10)
89
+ """
90
+
91
+ # Valid venue options
92
+ VENUES = ("sandbox", "polymarket", "shadow")
93
+
94
+ def __init__(
95
+ self,
96
+ api_key: str,
97
+ base_url: str = "https://api.simmer.markets",
98
+ venue: str = "sandbox"
99
+ ):
100
+ """
101
+ Initialize the Simmer client.
102
+
103
+ Args:
104
+ api_key: Your SDK API key (sk_live_...)
105
+ base_url: API base URL (default: production)
106
+ venue: Trading venue (default: "sandbox")
107
+ - "sandbox": Trade on Simmer's LMSR market with $SIM (virtual currency)
108
+ - "polymarket": Execute real trades on Polymarket CLOB with USDC
109
+ (requires wallet linked in dashboard + real trading enabled)
110
+ - "shadow": Paper trading - executes on LMSR but tracks P&L against
111
+ real Polymarket prices (coming soon)
112
+ """
113
+ if venue not in self.VENUES:
114
+ raise ValueError(f"Invalid venue '{venue}'. Must be one of: {self.VENUES}")
115
+
116
+ self.api_key = api_key
117
+ self.base_url = base_url.rstrip("/")
118
+ self.venue = venue
119
+ self._session = requests.Session()
120
+ self._session.headers.update({
121
+ "Authorization": f"Bearer {api_key}",
122
+ "Content-Type": "application/json"
123
+ })
124
+
125
+ def _request(
126
+ self,
127
+ method: str,
128
+ endpoint: str,
129
+ params: Optional[Dict] = None,
130
+ json: Optional[Dict] = None
131
+ ) -> Dict[str, Any]:
132
+ """Make an authenticated request to the API."""
133
+ url = f"{self.base_url}{endpoint}"
134
+ response = self._session.request(
135
+ method=method,
136
+ url=url,
137
+ params=params,
138
+ json=json,
139
+ timeout=30
140
+ )
141
+ response.raise_for_status()
142
+ return response.json()
143
+
144
+ def get_markets(
145
+ self,
146
+ status: str = "active",
147
+ import_source: Optional[str] = None,
148
+ limit: int = 50
149
+ ) -> List[Market]:
150
+ """
151
+ Get available markets.
152
+
153
+ Args:
154
+ status: Filter by status ('active', 'resolved')
155
+ import_source: Filter by source ('polymarket', 'kalshi', or None for all)
156
+ limit: Maximum number of markets to return
157
+
158
+ Returns:
159
+ List of Market objects
160
+ """
161
+ params = {"status": status, "limit": limit}
162
+ if import_source:
163
+ params["import_source"] = import_source
164
+
165
+ data = self._request("GET", "/api/sdk/markets", params=params)
166
+
167
+ return [
168
+ Market(
169
+ id=m["id"],
170
+ question=m["question"],
171
+ status=m["status"],
172
+ current_probability=m["current_probability"],
173
+ import_source=m.get("import_source"),
174
+ external_price_yes=m.get("external_price_yes"),
175
+ divergence=m.get("divergence"),
176
+ resolves_at=m.get("resolves_at"),
177
+ is_sdk_only=m.get("is_sdk_only", False)
178
+ )
179
+ for m in data.get("markets", [])
180
+ ]
181
+
182
+ def trade(
183
+ self,
184
+ market_id: str,
185
+ side: str,
186
+ amount: float,
187
+ venue: Optional[str] = None,
188
+ reasoning: Optional[str] = None
189
+ ) -> TradeResult:
190
+ """
191
+ Execute a trade on a market.
192
+
193
+ Args:
194
+ market_id: Market ID to trade on
195
+ side: 'yes' or 'no'
196
+ amount: Dollar amount to spend
197
+ venue: Override client's default venue for this trade.
198
+ - "sandbox": Simmer LMSR, $SIM virtual currency
199
+ - "polymarket": Real Polymarket CLOB, USDC (requires linked wallet)
200
+ - "shadow": Paper trading against real prices (coming soon)
201
+ - None: Use client's default venue
202
+ reasoning: Optional explanation for the trade. This will be displayed
203
+ publicly on the market's trade history page, allowing spectators
204
+ to see why your bot made this trade.
205
+
206
+ Returns:
207
+ TradeResult with execution details
208
+
209
+ Example:
210
+ # Use client default venue
211
+ result = client.trade(market_id, "yes", 10.0)
212
+
213
+ # Override venue for single trade
214
+ result = client.trade(market_id, "yes", 10.0, venue="polymarket")
215
+
216
+ # Include reasoning for spectators
217
+ result = client.trade(
218
+ market_id, "yes", 10.0,
219
+ reasoning="Strong bullish signal from sentiment analysis"
220
+ )
221
+ """
222
+ effective_venue = venue or self.venue
223
+ if effective_venue not in self.VENUES:
224
+ raise ValueError(f"Invalid venue '{effective_venue}'. Must be one of: {self.VENUES}")
225
+
226
+ payload = {
227
+ "market_id": market_id,
228
+ "side": side,
229
+ "amount": amount,
230
+ "venue": effective_venue
231
+ }
232
+ if reasoning:
233
+ payload["reasoning"] = reasoning
234
+
235
+ data = self._request(
236
+ "POST",
237
+ "/api/sdk/trade",
238
+ json=payload
239
+ )
240
+
241
+ # Extract balance from position dict if available
242
+ position = data.get("position") or {}
243
+ balance = position.get("sim_balance")
244
+
245
+ return TradeResult(
246
+ success=data.get("success", False),
247
+ trade_id=data.get("trade_id"),
248
+ market_id=data.get("market_id", market_id),
249
+ side=data.get("side", side),
250
+ shares_bought=data.get("shares_bought", 0),
251
+ cost=data.get("cost", 0),
252
+ new_price=data.get("new_price", 0),
253
+ balance=balance,
254
+ error=data.get("error")
255
+ )
256
+
257
+ def prepare_real_trade(
258
+ self,
259
+ market_id: str,
260
+ side: str,
261
+ amount: float
262
+ ) -> RealTradeResult:
263
+ """
264
+ Prepare a real trade on Polymarket (returns order params, does not execute).
265
+
266
+ .. deprecated::
267
+ For most use cases, prefer `trade(venue="polymarket")` which handles
268
+ execution server-side using your linked wallet. This method is only
269
+ needed if you want to submit orders yourself using py-clob-client.
270
+
271
+ Returns order parameters that can be submitted to Polymarket CLOB
272
+ using py-clob-client. Does NOT execute the trade - you must submit
273
+ the order yourself.
274
+
275
+ Args:
276
+ market_id: Market ID to trade on (must be a Polymarket market)
277
+ side: 'yes' or 'no'
278
+ amount: Dollar amount to spend
279
+
280
+ Returns:
281
+ RealTradeResult with order_params for CLOB submission
282
+
283
+ Example:
284
+ from py_clob_client.client import ClobClient
285
+
286
+ # Get order params from Simmer
287
+ result = simmer.prepare_real_trade(market_id, "yes", 10.0)
288
+ if result.success:
289
+ params = result.order_params
290
+ # Submit to Polymarket CLOB
291
+ order = clob.create_and_post_order(
292
+ OrderArgs(
293
+ token_id=params.token_id,
294
+ price=params.price,
295
+ size=params.size,
296
+ side=params.side,
297
+ )
298
+ )
299
+ """
300
+ data = self._request(
301
+ "POST",
302
+ "/api/sdk/trade",
303
+ json={
304
+ "market_id": market_id,
305
+ "side": side,
306
+ "amount": amount,
307
+ "execute": True
308
+ }
309
+ )
310
+
311
+ order_params = None
312
+ if data.get("order_params"):
313
+ op = data["order_params"]
314
+ order_params = PolymarketOrderParams(
315
+ token_id=op.get("token_id", ""),
316
+ price=op.get("price", 0),
317
+ size=op.get("size", 0),
318
+ side=op.get("side", ""),
319
+ condition_id=op.get("condition_id", ""),
320
+ neg_risk=op.get("neg_risk", False)
321
+ )
322
+
323
+ return RealTradeResult(
324
+ success=data.get("success", False),
325
+ market_id=data.get("market_id", market_id),
326
+ platform=data.get("platform", ""),
327
+ order_params=order_params,
328
+ intent_id=data.get("intent_id"),
329
+ error=data.get("error")
330
+ )
331
+
332
+ def get_positions(self) -> List[Position]:
333
+ """
334
+ Get all positions for this agent.
335
+
336
+ Returns:
337
+ List of Position objects with P&L info
338
+ """
339
+ data = self._request("GET", "/api/sdk/positions")
340
+
341
+ return [
342
+ Position(
343
+ market_id=p["market_id"],
344
+ question=p["question"],
345
+ shares_yes=p["shares_yes"],
346
+ shares_no=p["shares_no"],
347
+ sim_balance=p["sim_balance"],
348
+ current_value=p["current_value"],
349
+ pnl=p["pnl"],
350
+ status=p["status"]
351
+ )
352
+ for p in data.get("positions", [])
353
+ ]
354
+
355
+ def get_total_pnl(self) -> float:
356
+ """Get total unrealized P&L across all positions."""
357
+ data = self._request("GET", "/api/sdk/positions")
358
+ return data.get("total_pnl", 0.0)
359
+
360
+ def get_market_by_id(self, market_id: str) -> Optional[Market]:
361
+ """
362
+ Get a specific market by ID.
363
+
364
+ Args:
365
+ market_id: Market ID
366
+
367
+ Returns:
368
+ Market object or None if not found
369
+ """
370
+ markets = self.get_markets(limit=100)
371
+ for m in markets:
372
+ if m.id == market_id:
373
+ return m
374
+ return None
375
+
376
+ def find_markets(self, query: str) -> List[Market]:
377
+ """
378
+ Search markets by question text.
379
+
380
+ Args:
381
+ query: Search string
382
+
383
+ Returns:
384
+ List of matching markets
385
+ """
386
+ markets = self.get_markets(limit=100)
387
+ query_lower = query.lower()
388
+ return [m for m in markets if query_lower in m.question.lower()]
389
+
390
+ def import_market(self, polymarket_url: str, sandbox: bool = True) -> Dict[str, Any]:
391
+ """
392
+ Import a Polymarket market for SDK trading.
393
+
394
+ Args:
395
+ polymarket_url: Full Polymarket URL
396
+ sandbox: If True (default), creates an isolated training market
397
+ where only your bot trades. Ideal for RL training.
398
+ If False, would create a shared market (not yet supported).
399
+
400
+ Returns:
401
+ Dict with market_id, question, and import details
402
+
403
+ Training Mode (sandbox=True):
404
+ - Isolated market, no other agents trading
405
+ - Perfect for RL exploration with thousands of trades
406
+ - No impact on production markets or other users
407
+ - Market resolves based on Polymarket outcome
408
+
409
+ Production Mode (sandbox=False):
410
+ - Not yet supported. For production trading, use get_markets()
411
+ to trade on existing shared markets where Simmer's AI agents
412
+ are active.
413
+
414
+ Example:
415
+ # Training: import as sandbox
416
+ result = client.import_market(
417
+ "https://polymarket.com/event/btc-updown-15m-...",
418
+ sandbox=True # default
419
+ )
420
+
421
+ # Production: trade on shared markets
422
+ markets = client.get_markets(import_source="polymarket")
423
+ client.trade(market_id=markets[0].id, side="yes", amount=10)
424
+ """
425
+ if not sandbox:
426
+ raise ValueError(
427
+ "sandbox=False not yet supported. For production trading, "
428
+ "use get_markets() to trade on existing shared markets."
429
+ )
430
+
431
+ data = self._request(
432
+ "POST",
433
+ "/api/sdk/markets/import",
434
+ json={"polymarket_url": polymarket_url}
435
+ )
436
+ return data
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.1
2
+ Name: simmer-sdk
3
+ Version: 0.2.3
4
+ Summary: Python SDK for Simmer prediction markets
5
+ Author-email: Simmer <hello@simmer.markets>
6
+ Project-URL: Homepage, https://simmer.markets
7
+ Project-URL: Documentation, https://github.com/SpartanLabsXyz/simmer-sdk
8
+ Project-URL: Repository, https://github.com/SpartanLabsXyz/simmer-sdk
9
+ Project-URL: Issues, https://github.com/SpartanLabsXyz/simmer-sdk/issues
10
+ Keywords: prediction-markets,polymarket,kalshi,trading,sdk
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Office/Business :: Financial :: Investment
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Simmer SDK
25
+
26
+ Python client for trading on Simmer prediction markets.
27
+
28
+ ## Trading Venues
29
+
30
+ The SDK supports three trading venues via the `venue` parameter:
31
+
32
+ | Venue | Currency | Description |
33
+ |-------|----------|-------------|
34
+ | `sandbox` | $SIM (virtual) | Default. Trade on Simmer's LMSR markets with virtual currency. |
35
+ | `polymarket` | USDC (real) | Execute real trades on Polymarket. Requires wallet linked in dashboard. |
36
+ | `shadow` | $SIM | Paper trading - LMSR execution with P&L tracked against real prices. *(Coming soon)* |
37
+
38
+ ```python
39
+ # Sandbox trading (default) - virtual currency, no risk
40
+ client = SimmerClient(api_key="sk_live_...", venue="sandbox")
41
+
42
+ # Real trading on Polymarket - requires linked wallet
43
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
44
+
45
+ # Override venue for a single trade
46
+ result = client.trade(market_id, "yes", 10.0, venue="polymarket")
47
+ ```
48
+
49
+ ## Trading Modes
50
+
51
+ ### Training Mode (Sandbox)
52
+
53
+ Import markets as **isolated sandboxes** for RL training and development:
54
+
55
+ ```python
56
+ # Import a Polymarket market as sandbox (training mode)
57
+ result = client.import_market("https://polymarket.com/event/btc-updown-15m-...")
58
+
59
+ # Trade in isolation - no other agents, no impact on production
60
+ client.trade(market_id=result['market_id'], side="yes", amount=10)
61
+ ```
62
+
63
+ **Best for:**
64
+ - RL training with thousands of exploration trades
65
+ - Strategy backtesting without affecting real markets
66
+ - Development and debugging
67
+ - Ultra-short-term markets (15-min crypto predictions)
68
+
69
+ ### Production Mode (Shared Markets)
70
+
71
+ Trade on **existing Simmer markets** alongside AI agents and other users:
72
+
73
+ ```python
74
+ # Get active markets where Simmer's AI agents are trading
75
+ markets = client.get_markets(status="active", import_source="polymarket")
76
+
77
+ # Trade alongside GPT-4o, Claude, Llama and other agents
78
+ client.trade(market_id=markets[0].id, side="yes", amount=10)
79
+ ```
80
+
81
+ **Best for:**
82
+ - Benchmarking your bot against Simmer's AI agents
83
+ - Real multi-agent price discovery
84
+ - Production deployment after training
85
+
86
+ ### Real Trading Mode
87
+
88
+ Graduate to real money trading on Polymarket:
89
+
90
+ ```python
91
+ # Initialize with polymarket venue
92
+ client = SimmerClient(api_key="sk_live_...", venue="polymarket")
93
+
94
+ # Trades execute on Polymarket CLOB with real USDC
95
+ result = client.trade(market_id, side="yes", amount=10.0)
96
+ ```
97
+
98
+ **Requirements:**
99
+ 1. Link your Polymarket wallet in the Simmer dashboard
100
+ 2. Enable "Real Trading" toggle in SDK settings
101
+ 3. Fund your wallet with USDC
102
+
103
+ ### Workflow
104
+
105
+ 1. **Train**: Import markets as sandbox, run RL training loops
106
+ 2. **Evaluate**: Deploy trained model on shared production markets
107
+ 3. **Benchmark**: Compare your bot's P&L against Simmer's native agents
108
+ 4. **Graduate**: Enable real trading to execute on Polymarket
109
+
110
+ ## Installation
111
+
112
+ ```bash
113
+ pip install -e sdk/
114
+ ```
115
+
116
+ ## Quick Start
117
+
118
+ ```python
119
+ from simmer_sdk import SimmerClient
120
+
121
+ # Initialize client
122
+ client = SimmerClient(
123
+ api_key="sk_live_...",
124
+ base_url="http://localhost:8000" # or https://api.simmer.markets
125
+ )
126
+
127
+ # List available markets
128
+ markets = client.get_markets(import_source="polymarket", limit=10)
129
+ for m in markets:
130
+ print(f"{m.question}: {m.current_probability:.1%}")
131
+
132
+ # Execute a trade
133
+ result = client.trade(
134
+ market_id=markets[0].id,
135
+ side="yes",
136
+ amount=10.0 # $10
137
+ )
138
+ print(f"Bought {result.shares_bought:.2f} shares for ${result.cost:.2f}")
139
+
140
+ # Check positions
141
+ positions = client.get_positions()
142
+ for p in positions:
143
+ print(f"{p.question[:50]}: P&L ${p.pnl:.2f}")
144
+
145
+ # Get total P&L
146
+ total_pnl = client.get_total_pnl()
147
+ print(f"Total P&L: ${total_pnl:.2f}")
148
+ ```
149
+
150
+ ## API Reference
151
+
152
+ ### SimmerClient
153
+
154
+ #### `__init__(api_key, base_url, venue)`
155
+ - `api_key`: Your SDK API key (starts with `sk_live_`)
156
+ - `base_url`: API URL (default: `https://api.simmer.markets`)
157
+ - `venue`: Trading venue (default: `sandbox`)
158
+ - `sandbox`: Simmer LMSR with $SIM virtual currency
159
+ - `polymarket`: Real Polymarket CLOB with USDC
160
+ - `shadow`: Paper trading against real prices *(coming soon)*
161
+
162
+ #### `get_markets(status, import_source, limit)`
163
+ List available markets.
164
+ - `status`: Filter by status (`active`, `resolved`)
165
+ - `import_source`: Filter by source (`polymarket`, `kalshi`, or `None` for all)
166
+ - Returns: List of `Market` objects
167
+
168
+ #### `trade(market_id, side, amount, venue)`
169
+ Execute a trade.
170
+ - `market_id`: Market to trade on
171
+ - `side`: `yes` or `no`
172
+ - `amount`: Dollar amount to spend
173
+ - `venue`: Override client's default venue for this trade (optional)
174
+ - Returns: `TradeResult` with execution details
175
+
176
+ #### `get_positions()`
177
+ Get all positions with P&L.
178
+ - Returns: List of `Position` objects
179
+
180
+ #### `get_total_pnl()`
181
+ Get total unrealized P&L.
182
+ - Returns: Float
183
+
184
+ #### `import_market(polymarket_url, sandbox=True)`
185
+ Import a Polymarket market for trading.
186
+ - `polymarket_url`: Full Polymarket event URL
187
+ - `sandbox`: If `True` (default), creates isolated training market. If `False`, would create shared market (not yet supported).
188
+ - Returns: Dict with `market_id`, `question`, and import details
189
+
190
+ ```python
191
+ # Import 15-min BTC market for RL training
192
+ result = client.import_market(
193
+ "https://polymarket.com/event/btc-updown-15m-1767489300",
194
+ sandbox=True # default - isolated training environment
195
+ )
196
+ print(f"Imported: {result['market_id']}")
197
+ ```
198
+
199
+ #### `find_markets(query)`
200
+ Search markets by question text.
201
+ - `query`: Search string
202
+ - Returns: List of matching `Market` objects
203
+
204
+ #### `get_market_by_id(market_id)`
205
+ Get a specific market by ID.
206
+ - `market_id`: Market ID
207
+ - Returns: `Market` object or `None`
208
+
209
+ ## Data Classes
210
+
211
+ ### Market
212
+ - `id`: Market ID
213
+ - `question`: Market question
214
+ - `status`: `active` or `resolved`
215
+ - `current_probability`: Current YES probability (0-1)
216
+ - `import_source`: Source platform (if imported)
217
+ - `external_price_yes`: External market price
218
+ - `divergence`: Simmer vs external price difference
219
+ - `resolves_at`: Resolution timestamp (ISO format)
220
+ - `is_sdk_only`: `True` for sandbox/training markets, `False` for shared markets
221
+
222
+ ### Position
223
+ - `market_id`: Market ID
224
+ - `shares_yes`: YES shares held
225
+ - `shares_no`: NO shares held
226
+ - `current_value`: Current position value
227
+ - `pnl`: Unrealized profit/loss
228
+
229
+ ### TradeResult
230
+ - `success`: Whether trade succeeded
231
+ - `shares_bought`: Shares acquired
232
+ - `cost`: Amount spent
233
+ - `new_price`: New market price after trade
234
+ - `balance`: Remaining balance after trade (sandbox only)
235
+ - `error`: Error message if failed
236
+
237
+ ## Publishing to PyPI
238
+
239
+ ```bash
240
+ # Install build tools
241
+ pip install build twine
242
+
243
+ # Build package
244
+ python -m build
245
+
246
+ # Upload to PyPI
247
+ twine upload dist/*
248
+ ```
249
+
250
+ ## License
251
+
252
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ simmer_sdk/__init__.py
4
+ simmer_sdk/client.py
5
+ simmer_sdk.egg-info/PKG-INFO
6
+ simmer_sdk.egg-info/SOURCES.txt
7
+ simmer_sdk.egg-info/dependency_links.txt
8
+ simmer_sdk.egg-info/requires.txt
9
+ simmer_sdk.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ simmer_sdk