Skip to content

Commit

Permalink
Merge pull request #330 from liampauling/release/2.8.0
Browse files Browse the repository at this point in the history
transaction count updated to 5000 as per change on 01/09/2020
  • Loading branch information
liampauling committed Sep 14, 2020
2 parents a639787 + ca3ba8f commit 63b119d
Show file tree
Hide file tree
Showing 28 changed files with 104 additions and 83 deletions.
13 changes: 13 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
Release History
---------------

2.8.0 (2020-09-14)
+++++++++++++++++++

**Improvements**

- Transaction count updated to 5000
- Minor codebase cleanup

**Dependencies**

- #328 ujson migrated to orjson
- black updated to 20.8b1

2.7.2 (2020-08-03)
+++++++++++++++++++

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[![Build Status](https://travis-ci.org/liampauling/betfair.svg?branch=master)](https://travis-ci.org/liampauling/betfair) [![Coverage Status](https://coveralls.io/repos/github/liampauling/betfair/badge.svg?branch=master)](https://coveralls.io/github/liampauling/betfair?branch=master) [![PyPI version](https://badge.fury.io/py/betfairlightweight.svg)](https://pypi.python.org/pypi/betfairlightweight) [![Downloads](https://pepy.tech/badge/betfairlightweight)](https://pepy.tech/project/betfairlightweight)

Lightweight, super fast (uses c libraries) pythonic wrapper for [Betfair API-NG](https://docs.developer.betfair.com/display/1smk3cen4v3lu3yomq5qye0ni) allowing all betting operations (including market and order streaming) and account operations, see [examples](https://github.com/liampauling/betfair/tree/master/examples).
Lightweight, super fast (uses C and Rust libraries) pythonic wrapper for [Betfair API-NG](https://docs.developer.betfair.com/display/1smk3cen4v3lu3yomq5qye0ni) allowing all betting operations (including market and order streaming) and account operations, see [examples](https://github.com/liampauling/betfair/tree/master/examples).

[docs](https://liampauling.github.io/betfair/)

Expand Down
2 changes: 1 addition & 1 deletion betfairlightweight/__version__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__title__ = "betfairlightweight"
__description__ = "Lightweight python wrapper for Betfair API-NG"
__url__ = "https://github.com/liampauling/betfair"
__version__ = "2.7.2"
__version__ = "2.8.0"
__author__ = "Liam Pauling"
__license__ = "MIT"
4 changes: 2 additions & 2 deletions betfairlightweight/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
numeric_types = (int, float)
integer_types = (int,)

# will attempt to use c libraries if installed
# will attempt to use C/Rust libraries if installed

try:
import ujson as json
import orjson as json
except ImportError:
import json

Expand Down
5 changes: 4 additions & 1 deletion betfairlightweight/endpoints/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ def get_account_statement(
method = "%s%s" % (self.URI, "getAccountStatement")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.AccountStatementResult, elapsed_time, lightweight,
response_json,
resources.AccountStatementResult,
elapsed_time,
lightweight,
)

def list_currency_rates(
Expand Down
34 changes: 26 additions & 8 deletions betfairlightweight/endpoints/betting.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ def list_event_types(
method = "%s%s" % (self.URI, "listEventTypes")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.EventTypeResult, elapsed_time, lightweight,
response_json,
resources.EventTypeResult,
elapsed_time,
lightweight,
)

def list_competitions(
Expand All @@ -61,7 +64,10 @@ def list_competitions(
method = "%s%s" % (self.URI, "listCompetitions")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.CompetitionResult, elapsed_time, lightweight,
response_json,
resources.CompetitionResult,
elapsed_time,
lightweight,
)

def list_time_ranges(
Expand All @@ -88,7 +94,10 @@ def list_time_ranges(
method = "%s%s" % (self.URI, "listTimeRanges")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.TimeRangeResult, elapsed_time, lightweight,
response_json,
resources.TimeRangeResult,
elapsed_time,
lightweight,
)

def list_events(
Expand Down Expand Up @@ -138,7 +147,10 @@ def list_market_types(
method = "%s%s" % (self.URI, "listMarketTypes")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.MarketTypeResult, elapsed_time, lightweight,
response_json,
resources.MarketTypeResult,
elapsed_time,
lightweight,
)

def list_countries(
Expand Down Expand Up @@ -220,7 +232,10 @@ def list_market_catalogue(
method = "%s%s" % (self.URI, "listMarketCatalogue")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.MarketCatalogue, elapsed_time, lightweight,
response_json,
resources.MarketCatalogue,
elapsed_time,
lightweight,
)

def list_market_book(
Expand Down Expand Up @@ -289,8 +304,8 @@ def list_runner_book(
lightweight: bool = None,
) -> Union[list, List[resources.MarketBook]]:
"""
Returns a list of dynamic data about a market and a specified runner.
Dynamic data includes prices, the status of the market, the status of selections,
Returns a list of dynamic data about a market and a specified runner.
Dynamic data includes prices, the status of the market, the status of selections,
the traded volume, and the status of any orders you have placed in the market
:param unicode market_id: The unique id for the market
Expand Down Expand Up @@ -445,7 +460,10 @@ def list_market_profit_and_loss(
method = "%s%s" % (self.URI, "listMarketProfitAndLoss")
(response, response_json, elapsed_time) = self.request(method, params, session)
return self.process_response(
response_json, resources.MarketProfitLoss, elapsed_time, lightweight,
response_json,
resources.MarketProfitLoss,
elapsed_time,
lightweight,
)

def place_orders(
Expand Down
2 changes: 1 addition & 1 deletion betfairlightweight/endpoints/historic.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def get_file_list(
def download_file(self, file_path: str, store_directory: str = None) -> str:
"""
Download a file from betfair historical and store in given directory or current directory.
:param file_path: the file path as given by get_file_list method.
:param store_directory: directory path to store data files in.
:return: name of file.
Expand Down
15 changes: 5 additions & 10 deletions betfairlightweight/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,16 +261,14 @@ class ExecutionReportErrorCode(Enum):


class StreamingProtocolErrors(Enum):
"""General errors not sent with id linking to specific request (as no request context)
"""
"""General errors not sent with id linking to specific request (as no request context)"""

INVALID_INPUT = "Failure code returned when an invalid input is provided (could not deserialize the message)"
TIMEOUT = "Failure code when a client times out (i.e. too slow sending data)"


class StreamingAuthenticationErrors(Enum):
"""Specific to authentication
"""
"""Specific to authentication"""

NO_APP_KEY = (
"Failure code returned when an application key is not found in the message"
Expand All @@ -294,8 +292,7 @@ class StreamingAuthenticationErrors(Enum):


class StreamingSubscriptionErrors(Enum):
"""Specific to subscription requests
"""
"""Specific to subscription requests"""

SUBSCRIPTION_LIMIT_EXCEEDED = (
"Customer tried to subscribe to more markets than allowed to"
Expand All @@ -307,8 +304,7 @@ class StreamingSubscriptionErrors(Enum):


class StreamingGeneralErrors(Enum):
"""General errors which may or may not be linked to specific request id
"""
"""General errors which may or may not be linked to specific request id"""

UNEXPECTED_ERROR = (
"Failure code returned when an internal error occurred on the server"
Expand All @@ -319,8 +315,7 @@ class StreamingGeneralErrors(Enum):


class StreamingSide(Enum):
"""Some enums are provided in shorthand
"""
"""Some enums are provided in shorthand"""

L = "LAY"
B = "BACK"
Expand Down
2 changes: 0 additions & 2 deletions betfairlightweight/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from typing import Union
from .utils import to_camel_case

from .resources import bettingresources


def streaming_market_filter(
market_ids: list = None,
Expand Down
2 changes: 1 addition & 1 deletion betfairlightweight/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
https://developer.betfair.com/exchange-api/
"""

transaction_limit = 1000 # place_orders / replace_orders
transaction_limit = 5000 # transactions per hour (£0.002 cost per transaction after)


order_limits = {
Expand Down
3 changes: 1 addition & 2 deletions betfairlightweight/resources/baseresource.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@


class BaseResource:
"""Lightweight data structure for resources.
"""
"""Lightweight data structure for resources."""

def __init__(self, **kwargs):
self.elapsed_time = kwargs.pop("elapsed_time", None)
Expand Down
25 changes: 15 additions & 10 deletions betfairlightweight/streaming/betfairstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ def start(self) -> None:
self._read_loop()

def stop(self) -> None:
"""Stops read loop and closes socket if it has been created.
"""
"""Stops read loop and closes socket if it has been created."""
self._running = False

if self._socket is None:
Expand All @@ -73,8 +72,7 @@ def stop(self) -> None:
self._socket = None

def authenticate(self) -> int:
"""Authentication request.
"""
"""Authentication request."""
unique_id = self.new_unique_id()
message = {
"op": "authentication",
Expand All @@ -86,8 +84,7 @@ def authenticate(self) -> int:
return unique_id

def heartbeat(self) -> int:
"""Heartbeat request to keep session alive.
"""
"""Heartbeat request to keep session alive."""
unique_id = self.new_unique_id()
message = {"op": "heartbeat", "id": unique_id}
self._send(message)
Expand Down Expand Up @@ -179,8 +176,7 @@ def new_unique_id(self) -> int:
return self._unique_id

def _connect(self) -> None:
"""Creates socket and sets running to True.
"""
"""Creates socket and sets running to True."""
self._socket = self._create_socket()
self._running = True

Expand Down Expand Up @@ -259,12 +255,21 @@ def _send(self, message: dict) -> None:
if not self._running:
self._connect()
self.authenticate()
message_dumped = json.dumps(message) + self.__CRLF

message_dumped = json.dumps(message)

if not isinstance(
message_dumped, bytes
): # handles orjson as `orjson.dumps -> bytes` but `json.dumps -> str`
message_dumped = message_dumped.encode(encoding=self.__encoding)
crlf = bytes(self.__CRLF, encoding=self.__encoding)
message_dumped += crlf

logger.debug(
"[Subscription: %s] Sending: %s" % (self._unique_id, repr(message_dumped))
)
try:
self._socket.sendall(message_dumped.encode())
self._socket.sendall(message_dumped)
except (socket.timeout, socket.error) as e:
self.stop()
raise SocketError("[Connect: %s]: Socket %s" % (self._unique_id, e))
Expand Down
3 changes: 1 addition & 2 deletions betfairlightweight/streaming/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ def __init__(
self.handicap = hc

def update_traded(self, traded_update: list) -> None:
""":param traded_update: [price, size]
"""
""":param traded_update: [price, size]"""
if not traded_update:
self.traded.clear()
else:
Expand Down
3 changes: 1 addition & 2 deletions betfairlightweight/streaming/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@


class BaseStream:
"""Separate stream class to hold market/order caches
"""
"""Separate stream class to hold market/order caches"""

_lookup = "mc"

Expand Down
4 changes: 2 additions & 2 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ or on a per request basis:

### Dependencies

By default betfairlightweight will install c based libraries if your os is either linux or darwin (Mac), due to difficulties in installation Windows users can install them seperatly:
By default betfairlightweight will install C and Rust based libraries if your os is either linux or darwin (Mac), due to difficulties in installation Windows users can install them separately:

```bash
pip install ciso8601=={version}
```
```bash
pip install ujson=={version}
pip install orjson=={version}
```

!!! hint
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ betfairlightweight relies on these libraries:
Linux and darwin platforms only:

* `ciso8601` - C based datetime parsing
* `ujson` - C based json parsing
* `orjson` - Rust based json parsing

## Installation

Expand Down
3 changes: 2 additions & 1 deletion examples/examplestreaminghistorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

# create historical stream (update file_path to your file location)
stream = trading.streaming.create_historical_generator_stream(
file_path="/tmp/BASIC-1.132153978", listener=listener,
file_path="/tmp/BASIC-1.132153978",
listener=listener,
)

# create generator
Expand Down
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Tests & Linting
black==19.10b0
black==20.8b1
coverage

# Documentation
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
requests<2.25.0
ciso8601==2.1.3; sys_platform == 'darwin' or sys_platform == 'linux'
ujson==3.1.0; sys_platform == 'darwin' or sys_platform == 'linux'
orjson==3.3.0; sys_platform == 'darwin' or sys_platform == 'linux'
1 change: 0 additions & 1 deletion tests/unit/test_baseclient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import datetime
import os
import unittest
from unittest import mock
Expand Down
1 change: 0 additions & 1 deletion tests/unit/test_baseresource.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import datetime
import unittest
from unittest import mock

from betfairlightweight.compat import json
from betfairlightweight.resources.baseresource import BaseResource
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/test_betfairstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import threading
from unittest import mock

from betfairlightweight.compat import json
from betfairlightweight.streaming.betfairstream import (
BetfairStream,
HistoricalStream,
Expand Down Expand Up @@ -308,6 +309,16 @@ def test_send(self, mock_connect, mock_authenticate):
assert mock_connect.call_count == 1
assert mock_authenticate.call_count == 1
assert mock_socket.sendall.call_count == 1
try:
import orjson

rust = True
except:
rust = False
if rust:
mock_socket.sendall.assert_called_with(b'{"message":1}\r\n')
else:
mock_socket.sendall.assert_called_with(b'{"message": 1}\r\n')

@mock.patch("betfairlightweight.streaming.betfairstream.BetfairStream.stop")
def test_send_timeout(self, mock_stop):
Expand Down

0 comments on commit 63b119d

Please sign in to comment.