diff --git a/datamaxi/__version__.py b/datamaxi/__version__.py index ea370a8..f23a6b3 100644 --- a/datamaxi/__version__.py +++ b/datamaxi/__version__.py @@ -1 +1 @@ -__version__ = "0.12.0" +__version__ = "0.13.0" diff --git a/datamaxi/datamaxi/__init__.py b/datamaxi/datamaxi/__init__.py index a7f0959..2a6631c 100644 --- a/datamaxi/datamaxi/__init__.py +++ b/datamaxi/datamaxi/__init__.py @@ -2,6 +2,7 @@ from datamaxi.lib.constants import BASE_URL from datamaxi.datamaxi.candle import Candle from datamaxi.datamaxi.funding_rate import FundingRate +from datamaxi.datamaxi.dex_trade import DexTrade class Datamaxi: @@ -19,3 +20,4 @@ def __init__(self, api_key=None, **kwargs: Any): self.candle = Candle(api_key, **kwargs) self.funding_rate = FundingRate(api_key, **kwargs) + self.dex_trade = DexTrade(api_key, **kwargs) diff --git a/datamaxi/datamaxi/candle.py b/datamaxi/datamaxi/candle.py index 4ee1291..a1c11a1 100644 --- a/datamaxi/datamaxi/candle.py +++ b/datamaxi/datamaxi/candle.py @@ -95,7 +95,7 @@ def get( raise ValueError("no data found") def next_request(): - return self.candle( + return self.get( exchange, symbol, interval, diff --git a/datamaxi/datamaxi/dex_trade.py b/datamaxi/datamaxi/dex_trade.py new file mode 100644 index 0000000..e3cedd9 --- /dev/null +++ b/datamaxi/datamaxi/dex_trade.py @@ -0,0 +1,115 @@ +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_parameters +from datamaxi.datamaxi.utils import convert_data_to_data_frame + + +class DexTrade(API): + """Client to fetch DEX trade data from DataMaxi+ API.""" + + def __init__(self, api_key=None, **kwargs: Any): + """Initialize DEX trade client. + + Args: + api_key (str): The DataMaxi+ API key + **kwargs: Keyword arguments used by `datamaxi.api.API`. + """ + super().__init__(api_key, **kwargs) + + def get( + self, + exchange: str, + symbol: str, + page: int = 1, + limit: int = 1000, + fromDateTime: str = None, + toDateTime: str = None, + sort: str = "desc", + pandas: bool = True, + ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: + """Fetch DEX trade data + + `GET /v1/dex/trade` + + + + Args: + exchange (str): Exchange name + symbol (str): Symbol name + 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: + DEX trade data in pandas DataFrame and next request function + """ + check_required_parameters( + [ + [exchange, "exchange"], + [symbol, "symbol"], + ] + ) + 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, + "page": page, + "limit": limit, + "fromDateTime": fromDateTime, + "toDateTime": toDateTime, + "sort": sort, + } + + res = self.query("/v1/dex/trade", params) + if res["data"] is None: + raise ValueError("no data found") + + def next_request(): + return self.get( + exchange, + symbol, + page + 1, + limit, + fromDateTime, + toDateTime, + sort, + pandas, + ) + + if pandas: + df = convert_data_to_data_frame(res["data"], ["b", "bq", "qq", "p", "usd"]) + return df, next_request + else: + return res, next_request + + def exchanges(self) -> List[str]: + """Fetch supported exchanges accepted by + [datamaxi.DexTrade.get](./#datamaxi.datamaxi.DexTrade.get) + API. + + `GET /v1/dex/trade/exchanges` + + + + Returns: + List of supported exchanges + """ + url_path = "/v1/dex/trade/exchanges" + return self.query(url_path) diff --git a/datamaxi/datamaxi/funding_rate.py b/datamaxi/datamaxi/funding_rate.py index fe4d742..756bc2b 100644 --- a/datamaxi/datamaxi/funding_rate.py +++ b/datamaxi/datamaxi/funding_rate.py @@ -84,7 +84,7 @@ def get( raise ValueError("no data found") def next_request(): - return self.funding_rate( + return self.get( exchange, symbol, page + 1, diff --git a/datamaxi/datamaxi/utils.py b/datamaxi/datamaxi/utils.py index caca32b..7024af2 100644 --- a/datamaxi/datamaxi/utils.py +++ b/datamaxi/datamaxi/utils.py @@ -2,9 +2,21 @@ import pandas as pd -def convert_data_to_data_frame(data: List) -> pd.DataFrame: +def convert_data_to_data_frame( + data: List, + columns_to_replace: List[str] = [], +) -> pd.DataFrame: df = pd.DataFrame(data) df = df.set_index("d") - df.replace("NaN", pd.NA, inplace=True) - df = df.apply(pd.to_numeric, errors="coerce") + + if len(columns_to_replace) == 0: + df.replace("NaN", pd.NA, inplace=True) + df = df.apply(pd.to_numeric, errors="coerce") + return df + + df[columns_to_replace] = df[columns_to_replace].replace("NaN", pd.NA) + df[columns_to_replace] = df[columns_to_replace].apply( + pd.to_numeric, errors="coerce" + ) + return df diff --git a/docs/dex-trade.md b/docs/dex-trade.md new file mode 100644 index 0000000..9b68b99 --- /dev/null +++ b/docs/dex-trade.md @@ -0,0 +1,6 @@ +# DEX Trade + +::: datamaxi.datamaxi.DexTrade + options: + show_submodules: true + show_source: false diff --git a/mkdocs.yml b/mkdocs.yml index 9f1dd45..8cb1c8c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,6 +34,7 @@ nav: - Datamaxi: - Candle: candle.md - Funding Rate: funding-rate.md + - DEX Trade: dex-trade.md - Defillama: defillama.md - Trend: - Naver Trend: naver-trend.md diff --git a/pyproject.toml b/pyproject.toml index 1c2ab6e..51b8440 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "datamaxi" -version = "0.12.0" +version = "0.13.0" authors = [ { name="Bisonai", email="business@bisonai.com" }, ]