Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 29 additions & 93 deletions betconnect/endpoints/betting.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def bet_request_get(
"""
Gets a bet request for the given filter.

This is other users bet requests (please use get_active_bet_requests / my_bets ) to get your own.
This is other users bet requests (please use my_bets to get your own).

:param request_filter: A bet request filter, either enter a bet request id or other filter values
:return: A bet BetRequest resource or an BaseRequestException when BetConnect detects an issue.
Expand Down Expand Up @@ -365,39 +365,6 @@ def bet_request_stop(
elapsed_time=elapsed_time,
)

def get_active_bet_requests(
self, limit: int = None, page: int = None
) -> Union[resources.ActiveBetRequests, resources.BaseRequestException]:
"""
Gets active bet requests, taking into account pagination
:param limit: Limit the number of active bets returned
:param page: The page starting number
:return: A ActiveBetRequests resource or an BaseRequestException when BetConnect detects an issue.
"""
if (page is not None) or (limit is not None):
limit = (
max(limit, self.client.minimum_limit_value)
if limit
else self.client.minimum_limit_value
)
page = (
max(page, self.client.page_start_value)
if page
else self.client.page_start_value
)

(response, response_json, elapsed_time) = self._request(
method_uri=f"{self.api_version}/get_active_bet_requests{f'/{limit}/{page}' if page is not None else ''}",
authenticated=True,
)

return self.process_response(
response=response,
response_json=response_json,
resource=resources.ActiveBetRequests,
elapsed_time=elapsed_time,
)

def prices(
self,
fixture_id: int,
Expand Down Expand Up @@ -512,53 +479,40 @@ def my_bets(
:param customer_strategy_ref: The customer strategy ref which has been attached to any bet requests
:return: A MyBetsBetRequests resource or an BaseRequestException when BetConnect detects an issue.
"""

if user_id is None:
if self.client.user_id:
user_id = self.client.user_id
else:
logger.debug(
f"Trying to get your user preferences as no user_id was supplied!"
)
self.client.account.get_user_preferences()
if self.client.user_id:
user_id = self.client.user_id
else:
raise exceptions.MissingUserPerferences()

uri_extension = ""

if (
(page is not None)
or (limit is not None)
or (get_all is not None)
or (customer_strategy_ref is not None)
):

if (page is not None) or (limit is not None):
limit = (
max(limit, self.client.minimum_limit_value)
if limit is not None
if limit
else self.client.minimum_limit_value
)
page = (
max(page, self.client.page_start_value)
if page is not None
if page
else self.client.page_start_value
)
get_all = "get_all"

uri_extension += f"/{limit}/{page}/{get_all}"
if not user_id:
if self.client.user_preferences:
user_id = self.client.user_preferences.user_id

uri_extension += (
f"/{customer_strategy_ref}" if customer_strategy_ref else ""
if get_all:
(response, response_json, elapsed_time) = self._request(
method_uri=f"{self.api_version}/my_bets/{str(side.value)}/{user_id}/{str(status.value)}{f'/{limit}/{page}'if page is not None else ''}/{get_all}{f'/{customer_strategy_ref}'if customer_strategy_ref is not None else ''}",
authenticated=True,
)
else:
if customer_strategy_ref:
(response, response_json, elapsed_time) = self._request(
method_uri=f"{self.api_version}/my_bets/{str(side.value)}/{user_id}/{str(status.value)}{f'/{limit}/{page}'if page is not None else ''}/get_only/{customer_strategy_ref}",
authenticated=True,
)
else:
(response, response_json, elapsed_time) = self._request(
method_uri=f"{self.api_version}/my_bets/{str(side.value)}/{user_id}/{str(status.value)}{f'/{limit}/{page}'if page is not None else ''}",
authenticated=True,
)

(response, response_json, elapsed_time) = self._request(
method_uri=f"{self.api_version}/my_bets/{side.value}/{user_id}/{str(status.value)}{uri_extension}",
authenticated=True,
)

if side.value == "back":
if str(side.value).upper() == "BACK":
return self.process_response(
response=response,
response_json=response_json,
Expand All @@ -573,30 +527,12 @@ def my_bets(
elapsed_time=elapsed_time,
)

def lock_bet(
self, bet_request_id: UUID, bet_status_id: int, allocated_stake: int
) -> Union[resources.LockBet, resources.BaseRequestException]:
def lock_bet(self, bet_request_id: UUID, amount: int, seconds: int):
"""
Matched betting premium product only. Premuim subscription required.
client.account_preferences.is_premium_subscriber ==1.
Not Yet Implemented: Locks a bet for a set amount of seconds for a set amount
:param bet_request_id: The bet request ID
:param bet_status_id: The status ID of the bet
:param allocated_stake:
:return: LockBet
:param amount: the amount
:param seconds: the seconds to lock the bet
:return: A Lock bet resource
"""
raise NotImplementedError

(response, response_json, elapsed_time) = self._put(
method_uri=f"{self.api_version}/lock_bet",
data={
"bet_request_id": str(bet_request_id),
"bet_status_id": bet_status_id,
"allocated_stake": allocated_stake,
},
)
return self.process_response(
response=response,
response_json=response_json,
resource=resources.LockBet,
elapsed_time=elapsed_time,
)
raise NotImplementedError()
2 changes: 0 additions & 2 deletions betconnect/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
BetHistory,
BetHistoryRequest,
SelectionsForMarket,
ActiveBet,
ActiveBetRequests,
Viewed,
BetRequestMatchMore,
PricesBookmaker,
Expand Down
136 changes: 49 additions & 87 deletions betconnect/resources/betting.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,90 +575,68 @@ def __repr__(self) -> str:
return f"Bets Active: {self.bets_active}"


class ActiveBet(BaseResource):
class BetRequestMatchMore(BaseResource):
accepted: bool
amount_matched: Optional[float] = Field(default=None)
available: bool
bet_id: Optional[str] = Field(default=None)
bet_request_id: UUID
bet_type_name: Optional[str] = Field(default=None)
competition_name: str
created_at: datetime
customer_order_ref: Optional[CustomerOrderRef] = Field(default=None)
customer_strategy_ref: Optional[CustomerStrategyRef] = Field(default=None)
each_way_factor: Optional[float] = Field(default=None)
fill_percentage: float
fixture_id: Optional[int] = Field(default=None)
fixture_name: str
fixture_start_date: datetime = Field(alias="fixture_startdate")
handicap: Optional[float] = Field(default=None)
market_name: str
matched_stake: float
price: float
price_denominator: int
price_numerator: int
selection_name: str
sport_name: str
stake: float
status_name: str

# noinspection PyMethodParameters
@field_validator("customer_order_ref", mode="before")
def parse_customer_order_ref(cls, v) -> Optional[CustomerOrderRef]:
if v:
return CustomerOrderRef(customer_order_ref=v)

# noinspection PyMethodParameters
@field_validator("customer_strategy_ref", mode="before")
def parse_customer_strategy_ref(cls, v) -> Optional[CustomerStrategyRef]:
if v:
return CustomerStrategyRef(customer_strategy_ref=v)

# noinspection PyMethodParameters
@field_validator("created_at", "fixture_start_date", mode="before")
def date_parser(cls, v) -> datetime:
if isinstance(v, str):
return datetime.fromisoformat(v)
elif isinstance(v, datetime):
return v
else:
raise TypeError(f"Expected value of type str or datetime")
bet_status: Optional[str] = Field(default=None)
liability_increase: float
matched: bool
potential_bet_request_id: Optional[str] = Field(default=None)
request_matches: List[dict] = Field(default=[])

def __repr__(self) -> str:
return f"Bet: {str(self.bet_request_id)}, Competition: {self.competition_name}, Selection: {self.selection_name}, Price: {self.price}, Stake: {self.stake}"
return f"Matched: {self.matched}, Available: {self.available}"


class ActiveBetRequests(BaseResource):
bets: List[ActiveBet]
bets_active: int
class BetHistoryRequest(BaseResource):
bets: List[BetHistory]
bets_settled: int
last_page: int
total_bets: int

def __repr__(self) -> str:
return f"Bets Active: {self.bets_active}"
return f"Bets Settled: {self.bets_settled}"


class BetHistoryRequest(BaseResource):
bets: List[BetHistory]
last_page: int
total_bets: int
class SelectionsForMarket(BaseResource):
name: str
competitor: str
prices: List[Price]

def __repr__(self) -> str:
return f"Bets #: {len(self.bets)}"
return f"Selection: {self.name}, Prices #:{len(self.prices)}"


class SelectionsForMarket(BaseResource):
source_fixture_id: str
source_market_id: str
source_market_type_id: str
source_selection_id: str
trading_status: str
class LineMarketsSelectionsForMarket(BaseResource):
name: str
competitor_id: Optional[str] = Field(default=None)
ut: datetime
order: Optional[int] = Field(default=None)
max_price: Optional[float] = Field(default=None)
competitor: str
line: float
prices: List[Price]
outcome: Optional[str] = Field(default=None)

def __repr__(self) -> str:
return f"Selection: {self.name}, Line: {self.line}, Prices #:{len(self.prices)}"


class Viewed(BaseResource):
bet_request_id: UUID
bet_type_name: Optional[str] = Field(default=None)
competition_name: str
fixture_name: str
liability: float
market_name: str
price: float
price_denominator: int
price_numerator: int
requested_stake: float
selection_name: str
sport_name: str
start_time_utc: datetime

# noinspection PyMethodParameters
@field_validator("ut", mode="before")
@field_validator("start_time_utc", mode="before")
def date_parser(cls, v) -> datetime:
if isinstance(v, str):
return datetime.fromisoformat(v)
Expand All @@ -667,30 +645,14 @@ def date_parser(cls, v) -> datetime:
else:
raise TypeError(f"Expected value of type str or datetime")


class LineMarketsSelectionsForMarket(BaseResource):
name: str
display_name: str
handicap: str
line_data: List[SelectionsForMarket]


class Viewed(BaseResource):
prev: UUID
next: UUID

def __repr__(self) -> str:
return f"Prev: {self.prev}->Next: {self.next}"
return f"Bet: {str(self.bet_request_id)}, Competition: {self.competition_name}, Selection: {self.selection_name},Price: {self.price}, Stake: {self.requested_stake}"


class BetRequestMatchMore(BaseResource):
matched: bool
available: bool
viewed: Viewed
class LockBet(BaseResource):
bet_request_id: UUID
amount_locked: float
seconds_locked: int

def __repr__(self) -> str:
return f"Matched: {self.matched}, Available: {self.available}"


class LockBet(BaseResource):
pass
return f"Bet: {str(self.bet_request_id)}, Amount Locked: {self.amount_locked}, Seconds: {self.seconds_locked}"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
"pydantic==2.12.3",
"pydantic>=2.12.3",
"requests<2.33.0",
"python-decouple==3.8",
]
Expand Down
16 changes: 0 additions & 16 deletions tests/unit/endpoints/test_betting/test_betting.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,22 +360,6 @@ def test_bet_request_stop(
assert isinstance(bet_request_stop, resources.ResponseMessage)
request.assert_called()

def test_get_active_bet_requests(
self,
mocker: MockerFixture,
mock_betting_endpoint: Betting,
mock_bet_get_active_bet_requests_response: Tuple[
Response, Dict[str, Any], float
],
):
request = mocker.patch(
"betconnect.endpoints.baseendpoint.BaseEndpoint._request",
return_value=mock_bet_get_active_bet_requests_response,
)
active_bets = mock_betting_endpoint.get_active_bet_requests()
assert isinstance(active_bets, resources.ActiveBetRequests)
request.assert_called()

def test_get_viewed_next_page(
self,
mocker: MockerFixture,
Expand Down