pykalshi 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. pykalshi-0.1.0/LICENSE +21 -0
  2. pykalshi-0.1.0/PKG-INFO +182 -0
  3. pykalshi-0.1.0/README.md +138 -0
  4. pykalshi-0.1.0/kalshi_api/__init__.py +144 -0
  5. pykalshi-0.1.0/kalshi_api/api_keys.py +59 -0
  6. pykalshi-0.1.0/kalshi_api/client.py +526 -0
  7. pykalshi-0.1.0/kalshi_api/enums.py +54 -0
  8. pykalshi-0.1.0/kalshi_api/events.py +87 -0
  9. pykalshi-0.1.0/kalshi_api/exceptions.py +115 -0
  10. pykalshi-0.1.0/kalshi_api/exchange.py +37 -0
  11. pykalshi-0.1.0/kalshi_api/feed.py +592 -0
  12. pykalshi-0.1.0/kalshi_api/markets.py +234 -0
  13. pykalshi-0.1.0/kalshi_api/models.py +552 -0
  14. pykalshi-0.1.0/kalshi_api/orderbook.py +146 -0
  15. pykalshi-0.1.0/kalshi_api/orders.py +144 -0
  16. pykalshi-0.1.0/kalshi_api/portfolio.py +542 -0
  17. pykalshi-0.1.0/kalshi_api/py.typed +0 -0
  18. pykalshi-0.1.0/kalshi_api/rate_limiter.py +171 -0
  19. pykalshi-0.1.0/pykalshi.egg-info/PKG-INFO +182 -0
  20. pykalshi-0.1.0/pykalshi.egg-info/SOURCES.txt +33 -0
  21. pykalshi-0.1.0/pykalshi.egg-info/dependency_links.txt +1 -0
  22. pykalshi-0.1.0/pykalshi.egg-info/requires.txt +18 -0
  23. pykalshi-0.1.0/pykalshi.egg-info/top_level.txt +1 -0
  24. pykalshi-0.1.0/pyproject.toml +80 -0
  25. pykalshi-0.1.0/setup.cfg +4 -0
  26. pykalshi-0.1.0/tests/test_api_keys.py +211 -0
  27. pykalshi-0.1.0/tests/test_client.py +153 -0
  28. pykalshi-0.1.0/tests/test_exchange.py +173 -0
  29. pykalshi-0.1.0/tests/test_feed.py +687 -0
  30. pykalshi-0.1.0/tests/test_integration.py +102 -0
  31. pykalshi-0.1.0/tests/test_markets.py +519 -0
  32. pykalshi-0.1.0/tests/test_models.py +285 -0
  33. pykalshi-0.1.0/tests/test_portfolio.py +364 -0
  34. pykalshi-0.1.0/tests/test_series.py +360 -0
  35. pykalshi-0.1.0/tests/test_workflow.py +102 -0
pykalshi-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
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,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: pykalshi
3
+ Version: 0.1.0
4
+ Summary: A typed Python client for the Kalshi prediction markets API with WebSocket streaming, automatic retries, and ergonomic interfaces
5
+ Author-email: Arsh Koneru <arshkon@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ArshKA/kalshi-api
8
+ Project-URL: Repository, https://github.com/ArshKA/kalshi-api
9
+ Project-URL: Documentation, https://github.com/ArshKA/kalshi-api#readme
10
+ Project-URL: Issues, https://github.com/ArshKA/kalshi-api/issues
11
+ Keywords: kalshi,prediction-markets,trading,api-client,websocket,finance,betting,forecasting,elections,event-contracts,binary-options,real-time,async,pydantic,orderbook,market-data
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Office/Business :: Financial :: Investment
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: requests>=2.31.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Requires-Dist: cryptography>=41.0.0
30
+ Requires-Dist: python-dotenv>=1.0.0
31
+ Requires-Dist: websockets>=11.0
32
+ Provides-Extra: web
33
+ Requires-Dist: fastapi>=0.100.0; extra == "web"
34
+ Requires-Dist: uvicorn>=0.23.0; extra == "web"
35
+ Requires-Dist: aiofiles>=23.0.0; extra == "web"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest>=7.0; extra == "dev"
38
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
39
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
40
+ Requires-Dist: pytest-mock>=3.0.0; extra == "dev"
41
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
42
+ Requires-Dist: types-requests>=2.31.0; extra == "dev"
43
+ Dynamic: license-file
44
+
45
+ # kalshi-api
46
+
47
+ A typed Python client for the [Kalshi](https://kalshi.com) prediction markets API with WebSocket streaming, automatic retries, and ergonomic interfaces.
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install kalshi-api
53
+ ```
54
+
55
+ Create a `.env` file with your credentials from [kalshi.com](https://kalshi.com) → Account & Security → API Keys:
56
+
57
+ ```
58
+ KALSHI_API_KEY_ID=your-key-id
59
+ KALSHI_PRIVATE_KEY_PATH=/path/to/private-key.key
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ```python
65
+ from kalshi_api import KalshiClient, Action, Side
66
+
67
+ client = KalshiClient()
68
+ user = client.get_user()
69
+
70
+ # Browse markets
71
+ markets = client.get_markets(status="open", limit=5)
72
+ market = client.get_market("KXBTC-25JAN15-B100000")
73
+
74
+ # Place an order
75
+ order = user.place_order(
76
+ market,
77
+ action=Action.BUY,
78
+ side=Side.YES,
79
+ count=10,
80
+ price=45 # cents
81
+ )
82
+
83
+ order.cancel() # if needed
84
+ ```
85
+
86
+ ## Usage
87
+
88
+ ### Portfolio
89
+
90
+ `KalshiClient` handles authentication. Call `get_user()` to access your portfolio:
91
+
92
+ ```python
93
+ client = KalshiClient() # Uses .env credentials
94
+ client = KalshiClient(demo=True) # Use demo environment
95
+
96
+ user = client.get_user()
97
+ user.get_balance() # BalanceModel with balance, portfolio_value
98
+ user.get_positions() # Your current positions
99
+ user.get_fills() # Your trade history
100
+ user.get_orders(status="resting") # Your open orders
101
+ ```
102
+
103
+ ### Markets
104
+
105
+ ```python
106
+ # Search markets
107
+ markets = client.get_markets(series_ticker="KXBTC", status="open")
108
+
109
+ # Get a specific market
110
+ market = client.get_market("KXBTC-25JAN15-B100000")
111
+ print(market.title, market.yes_bid, market.yes_ask)
112
+
113
+ # Market data
114
+ orderbook = market.get_orderbook()
115
+ trades = market.get_trades()
116
+ ```
117
+
118
+ ### Orders
119
+
120
+ ```python
121
+ from kalshi_api import Action, Side, OrderType
122
+
123
+ # Limit order (default)
124
+ order = user.place_order(market, Action.BUY, Side.YES, count=10, price=50)
125
+
126
+ # Market order
127
+ order = user.place_order(market, Action.BUY, Side.YES, count=10, order_type=OrderType.MARKET)
128
+
129
+ order.cancel()
130
+ ```
131
+
132
+ ### Real-time Streaming
133
+
134
+ Subscribe to live market data via WebSocket:
135
+
136
+ ```python
137
+ from kalshi_api import Feed
138
+
139
+ async def main():
140
+ async with Feed(client) as feed:
141
+ await feed.subscribe_ticker("KXBTC-25JAN15-B100000")
142
+ await feed.subscribe_orderbook("KXBTC-25JAN15-B100000")
143
+
144
+ async for msg in feed:
145
+ print(msg) # TickerMessage, OrderbookSnapshotMessage, etc.
146
+ ```
147
+
148
+ ### Error Handling
149
+
150
+ ```python
151
+ from kalshi_api import InsufficientFundsError, RateLimitError, KalshiAPIError
152
+
153
+ try:
154
+ user.place_order(...)
155
+ except InsufficientFundsError:
156
+ print("Not enough balance")
157
+ except RateLimitError:
158
+ pass # Client auto-retries with backoff
159
+ except KalshiAPIError as e:
160
+ print(f"{e.status_code}: {e.error_code}")
161
+ ```
162
+
163
+ ## Comparison with Official SDK
164
+
165
+ | Feature | kalshi-api | kalshi-python (official) |
166
+ |---------|------------|--------------------------|
167
+ | WebSocket streaming | ✓ | — |
168
+ | Automatic retry with backoff | ✓ | — |
169
+ | Rate limit handling | ✓ | — |
170
+ | Domain objects (`Market`, `Order`) | ✓ | — |
171
+ | Typed exceptions | ✓ | — |
172
+ | Local orderbook management | ✓ | — |
173
+ | Pydantic models | ✓ | — |
174
+ | Core trading API coverage | ✓ | ✓ |
175
+ | Full API coverage | — | ✓ |
176
+
177
+ The official SDK is auto-generated from the OpenAPI spec. This library adds the infrastructure needed for production trading: real-time data, error recovery, and ergonomic interfaces.
178
+
179
+ ## Links
180
+
181
+ - [Kalshi API Reference](https://trading-api.readme.io/reference)
182
+ - [kalshi-python (official SDK)](https://github.com/Kalshi/kalshi-python)
@@ -0,0 +1,138 @@
1
+ # kalshi-api
2
+
3
+ A typed Python client for the [Kalshi](https://kalshi.com) prediction markets API with WebSocket streaming, automatic retries, and ergonomic interfaces.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install kalshi-api
9
+ ```
10
+
11
+ Create a `.env` file with your credentials from [kalshi.com](https://kalshi.com) → Account & Security → API Keys:
12
+
13
+ ```
14
+ KALSHI_API_KEY_ID=your-key-id
15
+ KALSHI_PRIVATE_KEY_PATH=/path/to/private-key.key
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```python
21
+ from kalshi_api import KalshiClient, Action, Side
22
+
23
+ client = KalshiClient()
24
+ user = client.get_user()
25
+
26
+ # Browse markets
27
+ markets = client.get_markets(status="open", limit=5)
28
+ market = client.get_market("KXBTC-25JAN15-B100000")
29
+
30
+ # Place an order
31
+ order = user.place_order(
32
+ market,
33
+ action=Action.BUY,
34
+ side=Side.YES,
35
+ count=10,
36
+ price=45 # cents
37
+ )
38
+
39
+ order.cancel() # if needed
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ### Portfolio
45
+
46
+ `KalshiClient` handles authentication. Call `get_user()` to access your portfolio:
47
+
48
+ ```python
49
+ client = KalshiClient() # Uses .env credentials
50
+ client = KalshiClient(demo=True) # Use demo environment
51
+
52
+ user = client.get_user()
53
+ user.get_balance() # BalanceModel with balance, portfolio_value
54
+ user.get_positions() # Your current positions
55
+ user.get_fills() # Your trade history
56
+ user.get_orders(status="resting") # Your open orders
57
+ ```
58
+
59
+ ### Markets
60
+
61
+ ```python
62
+ # Search markets
63
+ markets = client.get_markets(series_ticker="KXBTC", status="open")
64
+
65
+ # Get a specific market
66
+ market = client.get_market("KXBTC-25JAN15-B100000")
67
+ print(market.title, market.yes_bid, market.yes_ask)
68
+
69
+ # Market data
70
+ orderbook = market.get_orderbook()
71
+ trades = market.get_trades()
72
+ ```
73
+
74
+ ### Orders
75
+
76
+ ```python
77
+ from kalshi_api import Action, Side, OrderType
78
+
79
+ # Limit order (default)
80
+ order = user.place_order(market, Action.BUY, Side.YES, count=10, price=50)
81
+
82
+ # Market order
83
+ order = user.place_order(market, Action.BUY, Side.YES, count=10, order_type=OrderType.MARKET)
84
+
85
+ order.cancel()
86
+ ```
87
+
88
+ ### Real-time Streaming
89
+
90
+ Subscribe to live market data via WebSocket:
91
+
92
+ ```python
93
+ from kalshi_api import Feed
94
+
95
+ async def main():
96
+ async with Feed(client) as feed:
97
+ await feed.subscribe_ticker("KXBTC-25JAN15-B100000")
98
+ await feed.subscribe_orderbook("KXBTC-25JAN15-B100000")
99
+
100
+ async for msg in feed:
101
+ print(msg) # TickerMessage, OrderbookSnapshotMessage, etc.
102
+ ```
103
+
104
+ ### Error Handling
105
+
106
+ ```python
107
+ from kalshi_api import InsufficientFundsError, RateLimitError, KalshiAPIError
108
+
109
+ try:
110
+ user.place_order(...)
111
+ except InsufficientFundsError:
112
+ print("Not enough balance")
113
+ except RateLimitError:
114
+ pass # Client auto-retries with backoff
115
+ except KalshiAPIError as e:
116
+ print(f"{e.status_code}: {e.error_code}")
117
+ ```
118
+
119
+ ## Comparison with Official SDK
120
+
121
+ | Feature | kalshi-api | kalshi-python (official) |
122
+ |---------|------------|--------------------------|
123
+ | WebSocket streaming | ✓ | — |
124
+ | Automatic retry with backoff | ✓ | — |
125
+ | Rate limit handling | ✓ | — |
126
+ | Domain objects (`Market`, `Order`) | ✓ | — |
127
+ | Typed exceptions | ✓ | — |
128
+ | Local orderbook management | ✓ | — |
129
+ | Pydantic models | ✓ | — |
130
+ | Core trading API coverage | ✓ | ✓ |
131
+ | Full API coverage | — | ✓ |
132
+
133
+ The official SDK is auto-generated from the OpenAPI spec. This library adds the infrastructure needed for production trading: real-time data, error recovery, and ergonomic interfaces.
134
+
135
+ ## Links
136
+
137
+ - [Kalshi API Reference](https://trading-api.readme.io/reference)
138
+ - [kalshi-python (official SDK)](https://github.com/Kalshi/kalshi-python)
@@ -0,0 +1,144 @@
1
+ """
2
+ Kalshi API Client Library
3
+
4
+ A clean, modular interface for the Kalshi trading API.
5
+ """
6
+
7
+ import logging
8
+
9
+ from .client import KalshiClient
10
+ from .events import Event
11
+ from .markets import Market, Series
12
+ from .orders import Order
13
+ from .portfolio import Portfolio
14
+ from .exchange import Exchange
15
+ from .api_keys import APIKeys
16
+ from .feed import (
17
+ Feed,
18
+ TickerMessage,
19
+ OrderbookSnapshotMessage,
20
+ OrderbookDeltaMessage,
21
+ OrderbookMessage,
22
+ TradeMessage,
23
+ FillMessage,
24
+ PositionMessage,
25
+ MarketLifecycleMessage,
26
+ OrderGroupUpdateMessage,
27
+ )
28
+ from .enums import (
29
+ Side,
30
+ Action,
31
+ OrderType,
32
+ OrderStatus,
33
+ MarketStatus,
34
+ CandlestickPeriod,
35
+ TimeInForce,
36
+ SelfTradePrevention,
37
+ )
38
+ from .models import (
39
+ PositionModel,
40
+ FillModel,
41
+ OrderModel,
42
+ BalanceModel,
43
+ MarketModel,
44
+ EventModel,
45
+ OrderbookResponse,
46
+ CandlestickResponse,
47
+ ExchangeStatus,
48
+ Announcement,
49
+ APILimits,
50
+ APIKey,
51
+ GeneratedAPIKey,
52
+ SeriesModel,
53
+ TradeModel,
54
+ SettlementModel,
55
+ QueuePositionModel,
56
+ OrderGroupModel,
57
+ SubaccountModel,
58
+ SubaccountBalanceModel,
59
+ SubaccountTransferModel,
60
+ ForecastPercentileHistory,
61
+ )
62
+ from .orderbook import OrderbookManager
63
+ from .rate_limiter import RateLimiter, NoOpRateLimiter
64
+ from .exceptions import (
65
+ KalshiError,
66
+ KalshiAPIError,
67
+ AuthenticationError,
68
+ InsufficientFundsError,
69
+ ResourceNotFoundError,
70
+ RateLimitError,
71
+ OrderRejectedError,
72
+ )
73
+
74
+ # Set up logging to NullHandler by default to avoid "No handler found" warnings.
75
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
76
+
77
+ __all__ = [
78
+ # Client
79
+ "KalshiClient",
80
+ # Domain objects
81
+ "Event",
82
+ "Market",
83
+ "Series",
84
+ "Order",
85
+ "Portfolio",
86
+ "Exchange",
87
+ "APIKeys",
88
+ # Feed (WebSocket)
89
+ "Feed",
90
+ "TickerMessage",
91
+ "OrderbookSnapshotMessage",
92
+ "OrderbookDeltaMessage",
93
+ "OrderbookMessage",
94
+ "TradeMessage",
95
+ "FillMessage",
96
+ "PositionMessage",
97
+ "MarketLifecycleMessage",
98
+ "OrderGroupUpdateMessage",
99
+ # Enums
100
+ "Side",
101
+ "Action",
102
+ "OrderType",
103
+ "OrderStatus",
104
+ "MarketStatus",
105
+ "CandlestickPeriod",
106
+ "TimeInForce",
107
+ "SelfTradePrevention",
108
+ # Models
109
+ "PositionModel",
110
+ "FillModel",
111
+ "OrderModel",
112
+ "BalanceModel",
113
+ "MarketModel",
114
+ "EventModel",
115
+ "OrderbookResponse",
116
+ "CandlestickResponse",
117
+ "ExchangeStatus",
118
+ "Announcement",
119
+ "APILimits",
120
+ "APIKey",
121
+ "GeneratedAPIKey",
122
+ "SeriesModel",
123
+ "TradeModel",
124
+ "SettlementModel",
125
+ "QueuePositionModel",
126
+ "OrderGroupModel",
127
+ "ForecastPercentileHistory",
128
+ # Utilities
129
+ "OrderbookManager",
130
+ "RateLimiter",
131
+ "NoOpRateLimiter",
132
+ # Subaccount Models
133
+ "SubaccountModel",
134
+ "SubaccountBalanceModel",
135
+ "SubaccountTransferModel",
136
+ # Exceptions
137
+ "KalshiError",
138
+ "KalshiAPIError",
139
+ "AuthenticationError",
140
+ "InsufficientFundsError",
141
+ "ResourceNotFoundError",
142
+ "RateLimitError",
143
+ "OrderRejectedError",
144
+ ]
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+ from .models import APIKey, GeneratedAPIKey, APILimits
4
+
5
+ if TYPE_CHECKING:
6
+ from .client import KalshiClient
7
+
8
+
9
+ class APIKeys:
10
+ """API key management and account limits."""
11
+
12
+ def __init__(self, client: KalshiClient) -> None:
13
+ self._client = client
14
+
15
+ def list(self) -> list[APIKey]:
16
+ """List all API keys for this account."""
17
+ data = self._client.get("/api_keys")
18
+ return [APIKey.model_validate(k) for k in data.get("api_keys", [])]
19
+
20
+ def create(self, public_key: str, name: str | None = None) -> APIKey:
21
+ """Create an API key with a provided RSA public key.
22
+
23
+ Args:
24
+ public_key: PEM-encoded RSA public key.
25
+ name: Optional name for the key.
26
+ """
27
+ body: dict = {"public_key": public_key}
28
+ if name:
29
+ body["name"] = name
30
+ data = self._client.post("/api_keys", body)
31
+ return APIKey.model_validate(data["api_key"])
32
+
33
+ def generate(self, name: str | None = None) -> GeneratedAPIKey:
34
+ """Generate a new API key pair (Kalshi creates both keys).
35
+
36
+ Returns a GeneratedAPIKey with the private_key field populated.
37
+ The private key is only returned ONCE - store it securely.
38
+
39
+ Args:
40
+ name: Optional name for the key.
41
+ """
42
+ body: dict = {}
43
+ if name:
44
+ body["name"] = name
45
+ data = self._client.post("/api_keys/generate", body)
46
+ return GeneratedAPIKey.model_validate(data)
47
+
48
+ def delete(self, key_id: str) -> None:
49
+ """Delete an API key.
50
+
51
+ Args:
52
+ key_id: The API key ID to delete.
53
+ """
54
+ self._client.delete(f"/api_keys/{key_id}")
55
+
56
+ def get_limits(self) -> APILimits:
57
+ """Get API rate limits for this account."""
58
+ data = self._client.get("/account/limits")
59
+ return APILimits.model_validate(data)