odds-api-io 1.0.0__py3-none-any.whl
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.
- odds_api/__init__.py +27 -0
- odds_api/async_client.py +502 -0
- odds_api/client.py +495 -0
- odds_api/constants.py +42 -0
- odds_api/exceptions.py +31 -0
- odds_api/py.typed +2 -0
- odds_api_io-1.0.0.dist-info/METADATA +313 -0
- odds_api_io-1.0.0.dist-info/RECORD +11 -0
- odds_api_io-1.0.0.dist-info/WHEEL +5 -0
- odds_api_io-1.0.0.dist-info/licenses/LICENSE +21 -0
- odds_api_io-1.0.0.dist-info/top_level.txt +1 -0
odds_api/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Odds-API.io Python SDK
|
|
3
|
+
Official Python client for the Odds-API.io sports betting odds API.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
|
|
8
|
+
from .client import OddsAPIClient
|
|
9
|
+
from .async_client import AsyncOddsAPIClient
|
|
10
|
+
from .exceptions import (
|
|
11
|
+
OddsAPIError,
|
|
12
|
+
InvalidAPIKeyError,
|
|
13
|
+
RateLimitExceededError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
ValidationError,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"OddsAPIClient",
|
|
20
|
+
"AsyncOddsAPIClient",
|
|
21
|
+
"OddsAPIError",
|
|
22
|
+
"InvalidAPIKeyError",
|
|
23
|
+
"RateLimitExceededError",
|
|
24
|
+
"NotFoundError",
|
|
25
|
+
"ValidationError",
|
|
26
|
+
"__version__",
|
|
27
|
+
]
|
odds_api/async_client.py
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
"""Asynchronous client for the Odds-API.io API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional, List
|
|
4
|
+
import aiohttp
|
|
5
|
+
|
|
6
|
+
from .constants import BASE_API_URL, DEFAULT_TIMEOUT, Endpoints
|
|
7
|
+
from .exceptions import (
|
|
8
|
+
InvalidAPIKeyError,
|
|
9
|
+
NotFoundError,
|
|
10
|
+
OddsAPIError,
|
|
11
|
+
RateLimitExceededError,
|
|
12
|
+
ValidationError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AsyncOddsAPIClient:
|
|
17
|
+
"""
|
|
18
|
+
Asynchronous client for the Odds-API.io API.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
api_key: Your Odds-API.io API key
|
|
22
|
+
timeout: Request timeout in seconds (default: 10)
|
|
23
|
+
base_url: Base API URL (default: https://api2.odds-api.io/v3)
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> async with AsyncOddsAPIClient(api_key="your_api_key") as client:
|
|
27
|
+
... sports = await client.get_sports()
|
|
28
|
+
... events = await client.get_events(sport="basketball", league="usa-nba")
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
api_key: str,
|
|
34
|
+
timeout: int = DEFAULT_TIMEOUT,
|
|
35
|
+
base_url: str = BASE_API_URL,
|
|
36
|
+
):
|
|
37
|
+
"""Initialize the async Odds API client."""
|
|
38
|
+
if not api_key:
|
|
39
|
+
raise ValueError("API key is required")
|
|
40
|
+
|
|
41
|
+
self.api_key = api_key
|
|
42
|
+
self.timeout = aiohttp.ClientTimeout(total=timeout)
|
|
43
|
+
self.base_url = base_url
|
|
44
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def session(self) -> aiohttp.ClientSession:
|
|
48
|
+
"""Get or create the aiohttp session."""
|
|
49
|
+
if self._session is None or self._session.closed:
|
|
50
|
+
self._session = aiohttp.ClientSession(timeout=self.timeout)
|
|
51
|
+
return self._session
|
|
52
|
+
|
|
53
|
+
async def _handle_response(self, response: aiohttp.ClientResponse) -> Any:
|
|
54
|
+
"""Handle API response and raise appropriate exceptions."""
|
|
55
|
+
if response.status == 200:
|
|
56
|
+
return await response.json()
|
|
57
|
+
|
|
58
|
+
text = await response.text()
|
|
59
|
+
status = response.status
|
|
60
|
+
|
|
61
|
+
if status == 400:
|
|
62
|
+
raise ValidationError(f"Invalid request: {text}")
|
|
63
|
+
elif status == 401:
|
|
64
|
+
raise InvalidAPIKeyError("Invalid API key")
|
|
65
|
+
elif status == 404:
|
|
66
|
+
raise NotFoundError("Resource not found")
|
|
67
|
+
elif status == 429:
|
|
68
|
+
raise RateLimitExceededError(
|
|
69
|
+
"Rate limit exceeded - please wait before retrying"
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
raise OddsAPIError(f"API error {status}: {text}")
|
|
73
|
+
|
|
74
|
+
async def _get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
75
|
+
"""Make a GET request to the API."""
|
|
76
|
+
url = f"{self.base_url}/{path}"
|
|
77
|
+
params = params or {}
|
|
78
|
+
params["apiKey"] = self.api_key
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
async with self.session.get(url, params=params) as response:
|
|
82
|
+
return await self._handle_response(response)
|
|
83
|
+
except aiohttp.ClientError as e:
|
|
84
|
+
raise OddsAPIError(f"Request failed: {e}") from e
|
|
85
|
+
|
|
86
|
+
async def _put(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
87
|
+
"""Make a PUT request to the API."""
|
|
88
|
+
url = f"{self.base_url}/{path}"
|
|
89
|
+
params = params or {}
|
|
90
|
+
params["apiKey"] = self.api_key
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
async with self.session.put(url, params=params) as response:
|
|
94
|
+
return await self._handle_response(response)
|
|
95
|
+
except aiohttp.ClientError as e:
|
|
96
|
+
raise OddsAPIError(f"Request failed: {e}") from e
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def _build_params(**kwargs) -> Dict[str, Any]:
|
|
100
|
+
"""Build parameter dictionary, excluding None values."""
|
|
101
|
+
return {k: v for k, v in kwargs.items() if v is not None}
|
|
102
|
+
|
|
103
|
+
# Sports & Leagues
|
|
104
|
+
|
|
105
|
+
async def get_sports(self) -> List[Dict[str, Any]]:
|
|
106
|
+
"""
|
|
107
|
+
Get all available sports.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
List of sports with their details
|
|
111
|
+
|
|
112
|
+
Example:
|
|
113
|
+
>>> sports = await client.get_sports()
|
|
114
|
+
>>> for sport in sports:
|
|
115
|
+
... print(sport['name'])
|
|
116
|
+
"""
|
|
117
|
+
return await self._get(Endpoints.GET_SPORTS)
|
|
118
|
+
|
|
119
|
+
async def get_leagues(self, sport: str) -> List[Dict[str, Any]]:
|
|
120
|
+
"""
|
|
121
|
+
Get all leagues for a specific sport.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
sport: Sport identifier (e.g., "basketball", "football")
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
List of leagues for the specified sport
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
>>> leagues = await client.get_leagues(sport="basketball")
|
|
131
|
+
"""
|
|
132
|
+
params = self._build_params(sport=sport)
|
|
133
|
+
return await self._get(Endpoints.GET_LEAGUES, params)
|
|
134
|
+
|
|
135
|
+
# Events
|
|
136
|
+
|
|
137
|
+
async def get_events(
|
|
138
|
+
self,
|
|
139
|
+
sport: str,
|
|
140
|
+
league: Optional[str] = None,
|
|
141
|
+
participant_id: Optional[int] = None,
|
|
142
|
+
status: Optional[str] = None,
|
|
143
|
+
start: Optional[str] = None,
|
|
144
|
+
end: Optional[str] = None,
|
|
145
|
+
bookmaker: Optional[str] = None,
|
|
146
|
+
) -> List[Dict[str, Any]]:
|
|
147
|
+
"""
|
|
148
|
+
Get events with optional filters.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
sport: Sport identifier (required)
|
|
152
|
+
league: League identifier
|
|
153
|
+
participant_id: Filter by participant ID
|
|
154
|
+
status: Event status (e.g., "upcoming", "live", "finished")
|
|
155
|
+
start: Start date/time filter (ISO 8601 format)
|
|
156
|
+
end: End date/time filter (ISO 8601 format)
|
|
157
|
+
bookmaker: Filter by bookmaker
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
List of events matching the filters
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> events = await client.get_events(
|
|
164
|
+
... sport="basketball",
|
|
165
|
+
... league="usa-nba",
|
|
166
|
+
... status="upcoming"
|
|
167
|
+
... )
|
|
168
|
+
"""
|
|
169
|
+
params = self._build_params(
|
|
170
|
+
sport=sport,
|
|
171
|
+
league=league,
|
|
172
|
+
participantId=participant_id,
|
|
173
|
+
status=status,
|
|
174
|
+
bookmaker=bookmaker,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Map start/end to from/to
|
|
178
|
+
if start:
|
|
179
|
+
params["from"] = start
|
|
180
|
+
if end:
|
|
181
|
+
params["to"] = end
|
|
182
|
+
|
|
183
|
+
return await self._get(Endpoints.GET_EVENTS, params)
|
|
184
|
+
|
|
185
|
+
async def get_event_by_id(self, event_id: int) -> Dict[str, Any]:
|
|
186
|
+
"""
|
|
187
|
+
Get a specific event by ID.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
event_id: The event ID
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Event details
|
|
194
|
+
|
|
195
|
+
Example:
|
|
196
|
+
>>> event = await client.get_event_by_id(event_id=12345)
|
|
197
|
+
"""
|
|
198
|
+
path = Endpoints.GET_EVENT_BY_ID.format(id=event_id)
|
|
199
|
+
return await self._get(path)
|
|
200
|
+
|
|
201
|
+
async def get_live_events(self, sport: str) -> List[Dict[str, Any]]:
|
|
202
|
+
"""
|
|
203
|
+
Get currently live events for a sport.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
sport: Sport identifier
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
List of live events
|
|
210
|
+
|
|
211
|
+
Example:
|
|
212
|
+
>>> live_events = await client.get_live_events(sport="basketball")
|
|
213
|
+
"""
|
|
214
|
+
params = self._build_params(sport=sport)
|
|
215
|
+
return await self._get(Endpoints.GET_LIVE_EVENTS, params)
|
|
216
|
+
|
|
217
|
+
async def search_events(self, query: str) -> List[Dict[str, Any]]:
|
|
218
|
+
"""
|
|
219
|
+
Search for events by keyword.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
query: Search query
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
List of matching events
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> events = await client.search_events(query="Lakers")
|
|
229
|
+
"""
|
|
230
|
+
params = self._build_params(query=query)
|
|
231
|
+
return await self._get(Endpoints.SEARCH_EVENTS, params)
|
|
232
|
+
|
|
233
|
+
# Odds
|
|
234
|
+
|
|
235
|
+
async def get_event_odds(
|
|
236
|
+
self, event_id: str, bookmakers: str
|
|
237
|
+
) -> Dict[str, Any]:
|
|
238
|
+
"""
|
|
239
|
+
Get odds for a specific event.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
event_id: Event ID
|
|
243
|
+
bookmakers: Comma-separated bookmaker slugs
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Odds data for the event
|
|
247
|
+
|
|
248
|
+
Example:
|
|
249
|
+
>>> odds = await client.get_event_odds(
|
|
250
|
+
... event_id="12345",
|
|
251
|
+
... bookmakers="pinnacle,bet365"
|
|
252
|
+
... )
|
|
253
|
+
"""
|
|
254
|
+
params = self._build_params(eventId=event_id, bookmakers=bookmakers)
|
|
255
|
+
return await self._get(Endpoints.GET_EVENT_ODDS, params)
|
|
256
|
+
|
|
257
|
+
async def get_odds_movement(
|
|
258
|
+
self,
|
|
259
|
+
event_id: str,
|
|
260
|
+
bookmaker: str,
|
|
261
|
+
market: str,
|
|
262
|
+
market_line: Optional[str] = None,
|
|
263
|
+
) -> List[Dict[str, Any]]:
|
|
264
|
+
"""
|
|
265
|
+
Track odds changes over time for an event.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
event_id: Event ID
|
|
269
|
+
bookmaker: Bookmaker slug
|
|
270
|
+
market: Market type (e.g., "moneyline", "spread")
|
|
271
|
+
market_line: Market line (optional, for handicap markets)
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
List of odds movements
|
|
275
|
+
|
|
276
|
+
Example:
|
|
277
|
+
>>> movements = await client.get_odds_movement(
|
|
278
|
+
... event_id="12345",
|
|
279
|
+
... bookmaker="pinnacle",
|
|
280
|
+
... market="moneyline"
|
|
281
|
+
... )
|
|
282
|
+
"""
|
|
283
|
+
params = self._build_params(
|
|
284
|
+
eventId=event_id,
|
|
285
|
+
bookmaker=bookmaker,
|
|
286
|
+
market=market,
|
|
287
|
+
marketLine=market_line,
|
|
288
|
+
)
|
|
289
|
+
return await self._get(Endpoints.GET_ODDS_MOVEMENT, params)
|
|
290
|
+
|
|
291
|
+
async def get_odds_for_multiple_events(
|
|
292
|
+
self, event_ids: str, bookmakers: str
|
|
293
|
+
) -> List[Dict[str, Any]]:
|
|
294
|
+
"""
|
|
295
|
+
Get odds for multiple events at once.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
event_ids: Comma-separated event IDs
|
|
299
|
+
bookmakers: Comma-separated bookmaker slugs
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Odds data for multiple events
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
>>> odds = await client.get_odds_for_multiple_events(
|
|
306
|
+
... event_ids="12345,67890",
|
|
307
|
+
... bookmakers="pinnacle,bet365"
|
|
308
|
+
... )
|
|
309
|
+
"""
|
|
310
|
+
params = self._build_params(eventIds=event_ids, bookmakers=bookmakers)
|
|
311
|
+
return await self._get(Endpoints.GET_ODDS_FOR_MULTIPLE_EVENTS, params)
|
|
312
|
+
|
|
313
|
+
async def get_updated_odds_since_timestamp(
|
|
314
|
+
self, since: int, bookmaker: str, sport: str
|
|
315
|
+
) -> List[Dict[str, Any]]:
|
|
316
|
+
"""
|
|
317
|
+
Get odds updated since a given timestamp.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
since: Unix timestamp
|
|
321
|
+
bookmaker: Bookmaker slug
|
|
322
|
+
sport: Sport identifier
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
List of updated odds
|
|
326
|
+
|
|
327
|
+
Example:
|
|
328
|
+
>>> updated = await client.get_updated_odds_since_timestamp(
|
|
329
|
+
... since=1640000000,
|
|
330
|
+
... bookmaker="pinnacle",
|
|
331
|
+
... sport="basketball"
|
|
332
|
+
... )
|
|
333
|
+
"""
|
|
334
|
+
params = self._build_params(since=since, bookmaker=bookmaker, sport=sport)
|
|
335
|
+
return await self._get(Endpoints.GET_UPDATED_ODDS_SINCE_TIMESTAMP, params)
|
|
336
|
+
|
|
337
|
+
# Participants
|
|
338
|
+
|
|
339
|
+
async def get_participants(
|
|
340
|
+
self, sport: str, search: Optional[str] = None
|
|
341
|
+
) -> List[Dict[str, Any]]:
|
|
342
|
+
"""
|
|
343
|
+
Get participants (teams/players) for a sport.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
sport: Sport identifier
|
|
347
|
+
search: Optional search query
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
List of participants
|
|
351
|
+
|
|
352
|
+
Example:
|
|
353
|
+
>>> participants = await client.get_participants(
|
|
354
|
+
... sport="basketball",
|
|
355
|
+
... search="Warriors"
|
|
356
|
+
... )
|
|
357
|
+
"""
|
|
358
|
+
params = self._build_params(sport=sport, search=search)
|
|
359
|
+
return await self._get(Endpoints.GET_PARTICIPANTS, params)
|
|
360
|
+
|
|
361
|
+
async def get_participant_by_id(self, participant_id: int) -> Dict[str, Any]:
|
|
362
|
+
"""
|
|
363
|
+
Get a specific participant by ID.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
participant_id: Participant ID
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Participant details
|
|
370
|
+
|
|
371
|
+
Example:
|
|
372
|
+
>>> participant = await client.get_participant_by_id(participant_id=3428)
|
|
373
|
+
"""
|
|
374
|
+
path = Endpoints.GET_PARTICIPANT_BY_ID.format(id=participant_id)
|
|
375
|
+
return await self._get(path)
|
|
376
|
+
|
|
377
|
+
# Bookmakers
|
|
378
|
+
|
|
379
|
+
async def get_bookmakers(self) -> List[Dict[str, Any]]:
|
|
380
|
+
"""
|
|
381
|
+
Get all available bookmakers.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
List of bookmakers with their details
|
|
385
|
+
|
|
386
|
+
Example:
|
|
387
|
+
>>> bookmakers = await client.get_bookmakers()
|
|
388
|
+
"""
|
|
389
|
+
return await self._get(Endpoints.GET_BOOKMAKERS)
|
|
390
|
+
|
|
391
|
+
async def get_selected_bookmakers(self) -> Dict[str, Any]:
|
|
392
|
+
"""
|
|
393
|
+
Get bookmakers currently selected for your account.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
Selected bookmakers configuration
|
|
397
|
+
|
|
398
|
+
Example:
|
|
399
|
+
>>> selected = await client.get_selected_bookmakers()
|
|
400
|
+
"""
|
|
401
|
+
return await self._get(Endpoints.GET_SELECTED_BOOKMAKERS)
|
|
402
|
+
|
|
403
|
+
async def select_bookmakers(self, bookmakers: str) -> Dict[str, Any]:
|
|
404
|
+
"""
|
|
405
|
+
Select bookmakers for your account.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
bookmakers: Comma-separated bookmaker slugs
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Updated bookmaker selection
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
>>> await client.select_bookmakers(bookmakers="pinnacle,bet365")
|
|
415
|
+
"""
|
|
416
|
+
params = self._build_params(bookmakers=bookmakers)
|
|
417
|
+
return await self._put(Endpoints.SELECT_BOOKMAKERS, params)
|
|
418
|
+
|
|
419
|
+
async def clear_selected_bookmakers(self) -> Dict[str, Any]:
|
|
420
|
+
"""
|
|
421
|
+
Clear all selected bookmakers.
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
Confirmation response
|
|
425
|
+
|
|
426
|
+
Example:
|
|
427
|
+
>>> await client.clear_selected_bookmakers()
|
|
428
|
+
"""
|
|
429
|
+
return await self._put(Endpoints.CLEAR_SELECTED_BOOKMAKERS)
|
|
430
|
+
|
|
431
|
+
# Betting Analysis
|
|
432
|
+
|
|
433
|
+
async def get_arbitrage_bets(
|
|
434
|
+
self,
|
|
435
|
+
bookmakers: str,
|
|
436
|
+
limit: Optional[int] = None,
|
|
437
|
+
include_event_details: Optional[bool] = None,
|
|
438
|
+
) -> List[Dict[str, Any]]:
|
|
439
|
+
"""
|
|
440
|
+
Find arbitrage betting opportunities.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
bookmakers: Comma-separated bookmaker slugs
|
|
444
|
+
limit: Maximum number of results
|
|
445
|
+
include_event_details: Include full event details
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
List of arbitrage opportunities
|
|
449
|
+
|
|
450
|
+
Example:
|
|
451
|
+
>>> arb_bets = await client.get_arbitrage_bets(
|
|
452
|
+
... bookmakers="pinnacle,bet365",
|
|
453
|
+
... limit=10,
|
|
454
|
+
... include_event_details=True
|
|
455
|
+
... )
|
|
456
|
+
"""
|
|
457
|
+
params = self._build_params(
|
|
458
|
+
bookmakers=bookmakers,
|
|
459
|
+
limit=limit,
|
|
460
|
+
includeEventDetails=include_event_details,
|
|
461
|
+
)
|
|
462
|
+
return await self._get(Endpoints.GET_ARBITRAGE_BETS, params)
|
|
463
|
+
|
|
464
|
+
async def get_value_bets(
|
|
465
|
+
self,
|
|
466
|
+
bookmaker: str,
|
|
467
|
+
include_event_details: Optional[bool] = None,
|
|
468
|
+
) -> List[Dict[str, Any]]:
|
|
469
|
+
"""
|
|
470
|
+
Find value betting opportunities.
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
bookmaker: Bookmaker slug
|
|
474
|
+
include_event_details: Include full event details
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
List of value bets
|
|
478
|
+
|
|
479
|
+
Example:
|
|
480
|
+
>>> value_bets = await client.get_value_bets(
|
|
481
|
+
... bookmaker="pinnacle",
|
|
482
|
+
... include_event_details=True
|
|
483
|
+
... )
|
|
484
|
+
"""
|
|
485
|
+
params = self._build_params(
|
|
486
|
+
bookmaker=bookmaker,
|
|
487
|
+
includeEventDetails=include_event_details,
|
|
488
|
+
)
|
|
489
|
+
return await self._get(Endpoints.GET_VALUE_BETS, params)
|
|
490
|
+
|
|
491
|
+
async def close(self) -> None:
|
|
492
|
+
"""Close the HTTP session."""
|
|
493
|
+
if self._session and not self._session.closed:
|
|
494
|
+
await self._session.close()
|
|
495
|
+
|
|
496
|
+
async def __aenter__(self):
|
|
497
|
+
"""Async context manager entry."""
|
|
498
|
+
return self
|
|
499
|
+
|
|
500
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
501
|
+
"""Async context manager exit."""
|
|
502
|
+
await self.close()
|