kellyiq 0.0.1__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.
kellyiq-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KellyIQ LLC
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.
kellyiq-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: kellyiq
3
+ Version: 0.0.1
4
+ Summary: Size a whole sports betting slate as one portfolio: a client for the KellyIQ API.
5
+ Author-email: KellyIQ <opensource@kellyiq.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://www.kellyiq.com/developers
8
+ Project-URL: Documentation, https://www.kellyiq.com/developers/quickstart
9
+ Project-URL: Source, https://github.com/kellyiq/kellyiq-python
10
+ Keywords: kelly criterion,bet sizing,sports betting,portfolio optimization,bankroll
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # kellyiq
22
+
23
+ Size a whole sports betting slate as one portfolio, from Python.
24
+
25
+ A small client for the [KellyIQ API](https://www.kellyiq.com/developers): send your bankroll and the
26
+ bets you have chosen, with your view of each, and get back a stake for every bet, sized across the
27
+ slate together under per-bet and total-exposure limits. No dependencies.
28
+
29
+ ```bash
30
+ pip install kellyiq
31
+ ```
32
+
33
+ ```python
34
+ from kellyiq import KellyIQ
35
+
36
+ client = KellyIQ() # reads KELLYIQ_API_KEY
37
+
38
+ result = client.optimize({
39
+ "bankroll": 1000,
40
+ "picks": [
41
+ {"sport": "baseball_mlb", "team": "Dodgers", "opponent": "Padres",
42
+ "odds": -145, "opponentOdds": 125, "confidence": "STRONG_EDGE"},
43
+ {"sport": "baseball_mlb", "team": "Cubs", "opponent": "Cardinals",
44
+ "odds": 120, "opponentOdds": -140, "confidence": "MODERATE_EDGE"},
45
+ ],
46
+ })
47
+
48
+ for stake in result["allocation"]["stakes"]:
49
+ print(f'{stake["team"]}: ${stake["stake"]}')
50
+ ```
51
+
52
+ Create an API key in the KellyIQ app under **Settings → API**. Every plan includes API access, Free
53
+ included, each with its own daily allowance.
54
+
55
+ ## What's in it
56
+
57
+ | Method | Endpoint | Counts against the allowance |
58
+ |---|---|---|
59
+ | `optimize(slate)` | `POST /v1/optimize` | Yes |
60
+ | `sports()` | `GET /v1/sports` | No |
61
+ | `me()` | `GET /v1/me` | No |
62
+ | `devig(markets)` | `POST /v1/devig` | No |
63
+ | `implied_probability(odds)` | `POST /v1/implied-probability` | No |
64
+ | `kelly(bets, bankroll=None, fraction=None)` | `POST /v1/kelly` | No |
65
+
66
+ Responses are the API's JSON as Python dicts; the [API reference](https://www.kellyiq.com/developers/reference/optimize)
67
+ describes every field. Errors raise `KellyIQError` with `status`, `code`, `violations`, `request_id`
68
+ and `retry_after`.
69
+
70
+ This is an early release. A fuller SDK (typed results, automatic retries) is on the way; the
71
+ methods above will keep working.
72
+
73
+ ## More
74
+
75
+ - [Quickstart](https://www.kellyiq.com/developers/quickstart) and [docs](https://www.kellyiq.com/developers)
76
+ - [Examples and AI-assistant (MCP) configs](https://github.com/kellyiq/kellyiq-examples)
77
+ - Support: support@kellyiq.com
78
+
79
+ KellyIQ sizes the bets you choose; it does not choose bets or predict outcomes. Results are
80
+ calculations, not betting advice. 21+, where legal.
81
+
82
+ MIT licensed.
@@ -0,0 +1,62 @@
1
+ # kellyiq
2
+
3
+ Size a whole sports betting slate as one portfolio, from Python.
4
+
5
+ A small client for the [KellyIQ API](https://www.kellyiq.com/developers): send your bankroll and the
6
+ bets you have chosen, with your view of each, and get back a stake for every bet, sized across the
7
+ slate together under per-bet and total-exposure limits. No dependencies.
8
+
9
+ ```bash
10
+ pip install kellyiq
11
+ ```
12
+
13
+ ```python
14
+ from kellyiq import KellyIQ
15
+
16
+ client = KellyIQ() # reads KELLYIQ_API_KEY
17
+
18
+ result = client.optimize({
19
+ "bankroll": 1000,
20
+ "picks": [
21
+ {"sport": "baseball_mlb", "team": "Dodgers", "opponent": "Padres",
22
+ "odds": -145, "opponentOdds": 125, "confidence": "STRONG_EDGE"},
23
+ {"sport": "baseball_mlb", "team": "Cubs", "opponent": "Cardinals",
24
+ "odds": 120, "opponentOdds": -140, "confidence": "MODERATE_EDGE"},
25
+ ],
26
+ })
27
+
28
+ for stake in result["allocation"]["stakes"]:
29
+ print(f'{stake["team"]}: ${stake["stake"]}')
30
+ ```
31
+
32
+ Create an API key in the KellyIQ app under **Settings → API**. Every plan includes API access, Free
33
+ included, each with its own daily allowance.
34
+
35
+ ## What's in it
36
+
37
+ | Method | Endpoint | Counts against the allowance |
38
+ |---|---|---|
39
+ | `optimize(slate)` | `POST /v1/optimize` | Yes |
40
+ | `sports()` | `GET /v1/sports` | No |
41
+ | `me()` | `GET /v1/me` | No |
42
+ | `devig(markets)` | `POST /v1/devig` | No |
43
+ | `implied_probability(odds)` | `POST /v1/implied-probability` | No |
44
+ | `kelly(bets, bankroll=None, fraction=None)` | `POST /v1/kelly` | No |
45
+
46
+ Responses are the API's JSON as Python dicts; the [API reference](https://www.kellyiq.com/developers/reference/optimize)
47
+ describes every field. Errors raise `KellyIQError` with `status`, `code`, `violations`, `request_id`
48
+ and `retry_after`.
49
+
50
+ This is an early release. A fuller SDK (typed results, automatic retries) is on the way; the
51
+ methods above will keep working.
52
+
53
+ ## More
54
+
55
+ - [Quickstart](https://www.kellyiq.com/developers/quickstart) and [docs](https://www.kellyiq.com/developers)
56
+ - [Examples and AI-assistant (MCP) configs](https://github.com/kellyiq/kellyiq-examples)
57
+ - Support: support@kellyiq.com
58
+
59
+ KellyIQ sizes the bets you choose; it does not choose bets or predict outcomes. Results are
60
+ calculations, not betting advice. 21+, where legal.
61
+
62
+ MIT licensed.
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "kellyiq"
7
+ version = "0.0.1"
8
+ description = "Size a whole sports betting slate as one portfolio: a client for the KellyIQ API."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ authors = [{ name = "KellyIQ", email = "opensource@kellyiq.com" }]
13
+ keywords = ["kelly criterion", "bet sizing", "sports betting", "portfolio optimization", "bankroll"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Operating System :: OS Independent",
19
+ "Topic :: Scientific/Engineering :: Mathematics",
20
+ ]
21
+ dependencies = []
22
+
23
+ [project.urls]
24
+ Homepage = "https://www.kellyiq.com/developers"
25
+ Documentation = "https://www.kellyiq.com/developers/quickstart"
26
+ Source = "https://github.com/kellyiq/kellyiq-python"
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ """KellyIQ: size a whole sports betting slate as one portfolio.
2
+
3
+ A small client for the KellyIQ API (https://www.kellyiq.com/developers). No dependencies.
4
+
5
+ from kellyiq import KellyIQ
6
+
7
+ client = KellyIQ() # reads KELLYIQ_API_KEY
8
+ result = client.optimize({
9
+ "bankroll": 1000,
10
+ "picks": [
11
+ {"sport": "baseball_mlb", "team": "Dodgers", "opponent": "Padres",
12
+ "odds": -145, "opponentOdds": 125, "confidence": "STRONG_EDGE"},
13
+ ],
14
+ })
15
+ for stake in result["allocation"]["stakes"]:
16
+ print(stake["team"], stake["stake"])
17
+
18
+ KellyIQ sizes the bets you choose; it does not choose bets or predict outcomes. Results are
19
+ calculations, not betting advice.
20
+ """
21
+
22
+ from ._client import KellyIQ, KellyIQError
23
+
24
+ __all__ = ["KellyIQ", "KellyIQError", "__version__"]
25
+ __version__ = "0.0.1"
@@ -0,0 +1,117 @@
1
+ import json
2
+ import os
3
+ import urllib.error
4
+ import urllib.request
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ DEFAULT_BASE_URL = "https://api.kellyiq.com"
8
+ _VERSION = "0.0.1"
9
+
10
+
11
+ class KellyIQError(Exception):
12
+ """An error response from the KellyIQ API.
13
+
14
+ Attributes mirror the API's error body: ``status`` (HTTP status), ``code`` (for example
15
+ ``VALIDATION_ERROR`` or ``DAILY_LIMIT_EXCEEDED``), ``violations`` (which field was wrong, for
16
+ validation errors), ``request_id`` (quote it to support@kellyiq.com) and ``retry_after``
17
+ (seconds, when the API asks you to wait).
18
+ """
19
+
20
+ def __init__(self, status: int, code: str, message: str, violations: Optional[List[str]] = None,
21
+ request_id: Optional[str] = None, retry_after: Optional[int] = None,
22
+ body: Optional[Dict[str, Any]] = None) -> None:
23
+ detail = f"{code}: {message}" + (f" ({'; '.join(violations)})" if violations else "")
24
+ super().__init__(f"HTTP {status} {detail}")
25
+ self.status = status
26
+ self.code = code
27
+ self.message = message
28
+ self.violations = violations or []
29
+ self.request_id = request_id
30
+ self.retry_after = retry_after
31
+ self.body = body or {}
32
+
33
+
34
+ class KellyIQ:
35
+ """Client for the KellyIQ API.
36
+
37
+ :param api_key: your API key (``kiqa_...``); defaults to the ``KELLYIQ_API_KEY`` environment variable.
38
+ Create one in the KellyIQ app under Settings, API. Every plan includes API access.
39
+ :param base_url: defaults to ``KELLYIQ_API_BASE`` or https://api.kellyiq.com.
40
+ :param timeout: seconds to wait for a response (an optimize can take several seconds).
41
+ """
42
+
43
+ def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None,
44
+ timeout: float = 60.0) -> None:
45
+ key = api_key or os.environ.get("KELLYIQ_API_KEY")
46
+ if not key:
47
+ raise ValueError("Pass api_key or set the KELLYIQ_API_KEY environment variable.")
48
+ self._key = key
49
+ self._base = (base_url or os.environ.get("KELLYIQ_API_BASE") or DEFAULT_BASE_URL).rstrip("/")
50
+ self._timeout = timeout
51
+
52
+ def __repr__(self) -> str: # never show the key
53
+ return f"KellyIQ(base_url={self._base!r})"
54
+
55
+ # ---- endpoints -------------------------------------------------------------------------
56
+
57
+ def optimize(self, slate: Dict[str, Any]) -> Dict[str, Any]:
58
+ """Size a slate (POST /v1/optimize). Returns the API response; stakes are in
59
+ ``result["allocation"]["stakes"]``. Counts against your daily optimize allowance."""
60
+ return self._request("POST", "/v1/optimize", slate)
61
+
62
+ def sports(self) -> List[Dict[str, Any]]:
63
+ """The sports you can size right now, with the key to send as each pick's ``sport``. Free."""
64
+ return self._request("GET", "/v1/sports")["sports"]
65
+
66
+ def me(self) -> Dict[str, Any]:
67
+ """Your plan, today's allowance and the settings optimize applies by default. Free."""
68
+ return self._request("GET", "/v1/me")
69
+
70
+ def devig(self, markets: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
71
+ """Fair probabilities with the bookmaker's margin removed. Each market: ``{"odds": [-145, 125]}``."""
72
+ return self._request("POST", "/v1/devig", {"markets": markets})["results"]
73
+
74
+ def implied_probability(self, odds: List[int]) -> List[Dict[str, Any]]:
75
+ """The probability each American price implies, margin included."""
76
+ return self._request("POST", "/v1/implied-probability", {"odds": odds})["results"]
77
+
78
+ def kelly(self, bets: List[Dict[str, Any]], bankroll: Optional[float] = None,
79
+ fraction: Optional[float] = None) -> List[Dict[str, Any]]:
80
+ """Kelly stake for each bet on its own. For two or more bets placed together, use optimize()."""
81
+ body: Dict[str, Any] = {"bets": bets}
82
+ if bankroll is not None:
83
+ body["bankroll"] = bankroll
84
+ if fraction is not None:
85
+ body["fraction"] = fraction
86
+ return self._request("POST", "/v1/kelly", body)["results"]
87
+
88
+ # ---- transport -------------------------------------------------------------------------
89
+
90
+ def _request(self, method: str, path: str, body: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
91
+ data = json.dumps(body).encode("utf-8") if body is not None else None
92
+ req = urllib.request.Request(self._base + path, data=data, method=method)
93
+ req.add_header("Authorization", f"Bearer {self._key}")
94
+ req.add_header("Accept", "application/json")
95
+ # Identifies SDK traffic, so KellyIQ can tell how many calls come through this package.
96
+ req.add_header("User-Agent", f"kellyiq-python/{_VERSION}")
97
+ if data is not None:
98
+ req.add_header("Content-Type", "application/json")
99
+ try:
100
+ with urllib.request.urlopen(req, timeout=self._timeout) as resp:
101
+ return json.loads(resp.read().decode("utf-8"))
102
+ except urllib.error.HTTPError as e:
103
+ raw = e.read().decode("utf-8", "replace")
104
+ try:
105
+ err = json.loads(raw)
106
+ except ValueError:
107
+ err = {}
108
+ retry = e.headers.get("Retry-After")
109
+ raise KellyIQError(
110
+ status=e.code,
111
+ code=err.get("error", f"HTTP_{e.code}"),
112
+ message=err.get("message", raw[:200] or e.reason),
113
+ violations=err.get("violations"),
114
+ request_id=err.get("requestId") or e.headers.get("X-Request-Id"),
115
+ retry_after=int(retry) if retry and retry.isdigit() else None,
116
+ body=err,
117
+ ) from None
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: kellyiq
3
+ Version: 0.0.1
4
+ Summary: Size a whole sports betting slate as one portfolio: a client for the KellyIQ API.
5
+ Author-email: KellyIQ <opensource@kellyiq.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://www.kellyiq.com/developers
8
+ Project-URL: Documentation, https://www.kellyiq.com/developers/quickstart
9
+ Project-URL: Source, https://github.com/kellyiq/kellyiq-python
10
+ Keywords: kelly criterion,bet sizing,sports betting,portfolio optimization,bankroll
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # kellyiq
22
+
23
+ Size a whole sports betting slate as one portfolio, from Python.
24
+
25
+ A small client for the [KellyIQ API](https://www.kellyiq.com/developers): send your bankroll and the
26
+ bets you have chosen, with your view of each, and get back a stake for every bet, sized across the
27
+ slate together under per-bet and total-exposure limits. No dependencies.
28
+
29
+ ```bash
30
+ pip install kellyiq
31
+ ```
32
+
33
+ ```python
34
+ from kellyiq import KellyIQ
35
+
36
+ client = KellyIQ() # reads KELLYIQ_API_KEY
37
+
38
+ result = client.optimize({
39
+ "bankroll": 1000,
40
+ "picks": [
41
+ {"sport": "baseball_mlb", "team": "Dodgers", "opponent": "Padres",
42
+ "odds": -145, "opponentOdds": 125, "confidence": "STRONG_EDGE"},
43
+ {"sport": "baseball_mlb", "team": "Cubs", "opponent": "Cardinals",
44
+ "odds": 120, "opponentOdds": -140, "confidence": "MODERATE_EDGE"},
45
+ ],
46
+ })
47
+
48
+ for stake in result["allocation"]["stakes"]:
49
+ print(f'{stake["team"]}: ${stake["stake"]}')
50
+ ```
51
+
52
+ Create an API key in the KellyIQ app under **Settings → API**. Every plan includes API access, Free
53
+ included, each with its own daily allowance.
54
+
55
+ ## What's in it
56
+
57
+ | Method | Endpoint | Counts against the allowance |
58
+ |---|---|---|
59
+ | `optimize(slate)` | `POST /v1/optimize` | Yes |
60
+ | `sports()` | `GET /v1/sports` | No |
61
+ | `me()` | `GET /v1/me` | No |
62
+ | `devig(markets)` | `POST /v1/devig` | No |
63
+ | `implied_probability(odds)` | `POST /v1/implied-probability` | No |
64
+ | `kelly(bets, bankroll=None, fraction=None)` | `POST /v1/kelly` | No |
65
+
66
+ Responses are the API's JSON as Python dicts; the [API reference](https://www.kellyiq.com/developers/reference/optimize)
67
+ describes every field. Errors raise `KellyIQError` with `status`, `code`, `violations`, `request_id`
68
+ and `retry_after`.
69
+
70
+ This is an early release. A fuller SDK (typed results, automatic retries) is on the way; the
71
+ methods above will keep working.
72
+
73
+ ## More
74
+
75
+ - [Quickstart](https://www.kellyiq.com/developers/quickstart) and [docs](https://www.kellyiq.com/developers)
76
+ - [Examples and AI-assistant (MCP) configs](https://github.com/kellyiq/kellyiq-examples)
77
+ - Support: support@kellyiq.com
78
+
79
+ KellyIQ sizes the bets you choose; it does not choose bets or predict outcomes. Results are
80
+ calculations, not betting advice. 21+, where legal.
81
+
82
+ MIT licensed.
@@ -0,0 +1,9 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/kellyiq/__init__.py
5
+ src/kellyiq/_client.py
6
+ src/kellyiq.egg-info/PKG-INFO
7
+ src/kellyiq.egg-info/SOURCES.txt
8
+ src/kellyiq.egg-info/dependency_links.txt
9
+ src/kellyiq.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ kellyiq