From 71a8d40441eb18365879abcc6f380efae0c4f901 Mon Sep 17 00:00:00 2001 From: Martin Kersner Date: Tue, 9 Jul 2024 11:45:52 +0900 Subject: [PATCH 1/4] feat: pagination --- datamaxi/binance/__init__.py | 50 +++++++++++++++++++++++---- datamaxi/datamaxi/__init__.py | 64 +++++++++++++++++++++++++++++++---- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/datamaxi/binance/__init__.py b/datamaxi/binance/__init__.py index cb19c91..e9eee4a 100644 --- a/datamaxi/binance/__init__.py +++ b/datamaxi/binance/__init__.py @@ -1,4 +1,4 @@ -from typing import Any, List, Union +from typing import Any, Callable, Dict, Tuple, Union import pandas as pd from datamaxi.api import API from datamaxi.lib.utils import check_required_parameters @@ -21,12 +21,16 @@ def __init__(self, api_key=None, **kwargs: Any): super().__init__(api_key, **kwargs) - @postprocess() def funding_rate( self, symbol: str, + page: int = 1, + limit: int = 1000, + fromDateTime: str = None, + toDateTime: str = None, + sort: str = "desc", pandas: bool = True, - ) -> Union[List, pd.DataFrame]: + ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: """Get Binance funding rate data `GET /v1/raw/binance/funding-rate` @@ -35,12 +39,46 @@ def funding_rate( Args: symbol (str): Binance symbol + page (int): Page number + limit (int): Limit of data + fromDateTime (str): Start date and time (accepts format "2006-01-02 15:04:05" or "2006-01-02") + toDateTime (str): End date and time (accepts format "2006-01-02 15:04:05" or "2006-01-02") + sort (str): Sort order pandas (bool): Return data as pandas DataFrame Returns: - Binance funding rate data for a given symbol in pandas DataFrame + Binance funding rate data for a given symbol in pandas DataFrame and next request function """ check_required_parameters([[symbol, "symbol"]]) - params = {"symbol": symbol} - return self.query("/v1/raw/binance/funding-rate", params) + params = { + "symbol": symbol, + "page": page, + "limit": limit, + "fromDateTime": fromDateTime, + "toDateTime": toDateTime, + "sort": sort, + } + + res = self.query("/v1/raw/binance/funding-rate", params) + if res["data"] is None: + raise ValueError("no data found") + + next_request = lambda: self.funding_rate( + symbol, + page + 1, + limit, + fromDateTime, + toDateTime, + sort, + pandas, + ) + + if pandas: + df = pd.DataFrame(res["data"]) + df = df.set_index("d") + df.replace("NaN", pd.NA, inplace=True) + df = df.apply(pd.to_numeric, errors="coerce") + return df, next_request + else: + return res, next_request diff --git a/datamaxi/datamaxi/__init__.py b/datamaxi/datamaxi/__init__.py index 881f4d7..fa1b99e 100644 --- a/datamaxi/datamaxi/__init__.py +++ b/datamaxi/datamaxi/__init__.py @@ -1,9 +1,8 @@ -from typing import Any, List, Union +from typing import Any, Callable, Tuple, List, Dict, Union import pandas as pd from datamaxi.api import API from datamaxi.lib.utils import check_required_parameter from datamaxi.lib.utils import check_required_parameters -from datamaxi.lib.utils import postprocess from datamaxi.lib.constants import BASE_URL @@ -58,15 +57,19 @@ def intervals(self, exchange: str) -> List[str]: url_path = "/v1/intervals" return self.query(url_path, params) - @postprocess() def candle( self, exchange: str, symbol: str, interval: str = "1d", market: str = "spot", + page: int = 1, + limit: int = 1000, + fromDateTime: str = None, + toDateTime: str = None, + sort: str = "desc", pandas: bool = True, - ) -> Union[List, pd.DataFrame]: + ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: """Get candle data `GET /v1/candle` @@ -78,10 +81,15 @@ def candle( symbol (str): Symbol name interval (str): Candle interval market (str): Market type (spot/futures) + page (int): Page number + limit (int): Limit of data + fromDateTime (str): Start date and time (accepts format "2006-01-02 15:04:05" or "2006-01-02") + toDateTime (str): End date and time (accepts format "2006-01-02 15:04:05" or "2006-01-02") + sort (str): Sort order pandas (bool): Return data as pandas DataFrame Returns: - Candle data for a given symbol, interval and market in pandas DataFrame + Candle data for a given symbol, interval and market in pandas DataFrame and next request function """ check_required_parameters( [ @@ -95,10 +103,54 @@ def candle( if market not in ["spot", "futures"]: raise ValueError("market must be either spot or futures") + if page < 1: + raise ValueError("page must be greater than 0") + + if limit < 1: + raise ValueError("limit must be greater than 0") + + if fromDateTime is not None and toDateTime is not None: + raise ValueError( + "fromDateTime and toDateTime cannot be set at the same time" + ) + + if sort not in ["asc", "desc"]: + raise ValueError("sort must be either asc or desc") + params = { "exchange": exchange, "symbol": symbol, "interval": interval, "market": market, + "page": page, + "limit": limit, + "fromDateTime": fromDateTime, + "toDateTime": toDateTime, + "sort": sort, } - return self.query("/v1/candle", params) + + res = self.query("/v1/candle", params) + if res["data"] is None: + raise ValueError("no data found") + + next_request = lambda: self.candle( + exchange, + symbol, + interval, + market, + page + 1, + limit, + fromDateTime, + toDateTime, + sort, + pandas, + ) + + if pandas: + df = pd.DataFrame(res["data"]) + df = df.set_index("d") + df.replace("NaN", pd.NA, inplace=True) + df = df.apply(pd.to_numeric, errors="coerce") + return df, next_request + else: + return res, next_request From b16e65cdc7c55bb93e8c40baf4927c11cd969b6d Mon Sep 17 00:00:00 2001 From: Martin Kersner Date: Tue, 9 Jul 2024 11:54:05 +0900 Subject: [PATCH 2/4] feat: convert lambda to def --- datamaxi/binance/__init__.py | 20 ++++++++++---------- datamaxi/datamaxi/__init__.py | 25 +++++++++++++------------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/datamaxi/binance/__init__.py b/datamaxi/binance/__init__.py index e9eee4a..39f0dce 100644 --- a/datamaxi/binance/__init__.py +++ b/datamaxi/binance/__init__.py @@ -2,7 +2,6 @@ import pandas as pd from datamaxi.api import API from datamaxi.lib.utils import check_required_parameters -from datamaxi.lib.utils import postprocess from datamaxi.lib.constants import BASE_URL @@ -64,15 +63,16 @@ def funding_rate( if res["data"] is None: raise ValueError("no data found") - next_request = lambda: self.funding_rate( - symbol, - page + 1, - limit, - fromDateTime, - toDateTime, - sort, - pandas, - ) + def next_request(): + return self.funding_rate( + symbol, + page + 1, + limit, + fromDateTime, + toDateTime, + sort, + pandas, + ) if pandas: df = pd.DataFrame(res["data"]) diff --git a/datamaxi/datamaxi/__init__.py b/datamaxi/datamaxi/__init__.py index fa1b99e..9df12d8 100644 --- a/datamaxi/datamaxi/__init__.py +++ b/datamaxi/datamaxi/__init__.py @@ -133,18 +133,19 @@ def candle( if res["data"] is None: raise ValueError("no data found") - next_request = lambda: self.candle( - exchange, - symbol, - interval, - market, - page + 1, - limit, - fromDateTime, - toDateTime, - sort, - pandas, - ) + def next_request(): + return self.candle( + exchange, + symbol, + interval, + market, + page + 1, + limit, + fromDateTime, + toDateTime, + sort, + pandas, + ) if pandas: df = pd.DataFrame(res["data"]) From 8f61177ca77c569f7cf32a6f3aecd2feb130c1ee Mon Sep 17 00:00:00 2001 From: Martin Kersner Date: Tue, 9 Jul 2024 11:59:54 +0900 Subject: [PATCH 3/4] chore: remove binance funding rate test --- tests/binance/test_binance_funding_rate.py | 35 ---------------------- 1 file changed, 35 deletions(-) delete mode 100644 tests/binance/test_binance_funding_rate.py diff --git a/tests/binance/test_binance_funding_rate.py b/tests/binance/test_binance_funding_rate.py deleted file mode 100644 index 7054411..0000000 --- a/tests/binance/test_binance_funding_rate.py +++ /dev/null @@ -1,35 +0,0 @@ -import responses - -from datamaxi.binance import Binance as Client -from tests.util import random_str -from tests.util import mock_http_response -from urllib.parse import urlencode - - -mock_item = [ - [ - "Date", - "Funding Rate", - "Mark Price", - ], - ["07/03/2024 16:00:00", "0.00010000", "60178.96865957"], -] - -key = random_str() -client = Client(key) - -req_params = {"symbol": "BTC-USDT"} -params = {"symbol": "BTC-USDT", "pandas": False} - - -@mock_http_response( - responses.GET, - "/v1/raw/binance/funding-rate\\?" + urlencode(req_params), - mock_item, - 200, -) -def test_binance_funding_rate(): - """Tests the API endpoint to get Binance funding rate.""" - - response = client.funding_rate(**params) - response.should.equal(mock_item) From f570537656bae537610ab5e34b150d537adca489 Mon Sep 17 00:00:00 2001 From: Martin Kersner Date: Tue, 9 Jul 2024 13:28:31 +0900 Subject: [PATCH 4/4] chore: bump up version --- datamaxi/__version__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/datamaxi/__version__.py b/datamaxi/__version__.py index 3e2f46a..61fb31c 100644 --- a/datamaxi/__version__.py +++ b/datamaxi/__version__.py @@ -1 +1 @@ -__version__ = "0.9.0" +__version__ = "0.10.0" diff --git a/pyproject.toml b/pyproject.toml index fda66ae..aa2b292 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "datamaxi" -version = "0.9.0" +version = "0.10.0" authors = [ { name="Bisonai", email="business@bisonai.com" }, ]