From 3e1755586774d4c3f55636b2770f730029c2fe0a Mon Sep 17 00:00:00 2001 From: Martin Kersner Date: Fri, 26 Jul 2024 15:39:56 +0900 Subject: [PATCH] Forex, ticker, premium (#47) * feat: forex * feat: ticker * feat: premium * feat: /v1 -> /api/v1 * fix: missing import * fix: remove additional premium param * feat: pandas conversion * fix: flake8 * feat: bump up version to v0.14.0 * feat: docs --- datamaxi/__version__.py | 2 +- datamaxi/datamaxi/__init__.py | 6 ++ datamaxi/datamaxi/candle.py | 16 ++--- datamaxi/datamaxi/dex_trade.py | 8 +-- datamaxi/datamaxi/forex.py | 65 ++++++++++++++++++ datamaxi/datamaxi/funding_rate.py | 12 ++-- datamaxi/datamaxi/premium.py | 106 ++++++++++++++++++++++++++++++ datamaxi/datamaxi/ticker.py | 99 ++++++++++++++++++++++++++++ datamaxi/defillama/__init__.py | 56 ++++++++-------- datamaxi/google/__init__.py | 8 +-- datamaxi/naver/__init__.py | 8 +-- docs/forex.md | 6 ++ docs/premium.md | 6 ++ docs/ticker.md | 6 ++ mkdocs.yml | 3 + pyproject.toml | 2 +- 16 files changed, 353 insertions(+), 56 deletions(-) create mode 100644 datamaxi/datamaxi/forex.py create mode 100644 datamaxi/datamaxi/premium.py create mode 100644 datamaxi/datamaxi/ticker.py create mode 100644 docs/forex.md create mode 100644 docs/premium.md create mode 100644 docs/ticker.md diff --git a/datamaxi/__version__.py b/datamaxi/__version__.py index f23a6b3..9e78220 100644 --- a/datamaxi/__version__.py +++ b/datamaxi/__version__.py @@ -1 +1 @@ -__version__ = "0.13.0" +__version__ = "0.14.0" diff --git a/datamaxi/datamaxi/__init__.py b/datamaxi/datamaxi/__init__.py index 2a6631c..9d7b63f 100644 --- a/datamaxi/datamaxi/__init__.py +++ b/datamaxi/datamaxi/__init__.py @@ -3,6 +3,9 @@ from datamaxi.datamaxi.candle import Candle from datamaxi.datamaxi.funding_rate import FundingRate from datamaxi.datamaxi.dex_trade import DexTrade +from datamaxi.datamaxi.forex import Forex +from datamaxi.datamaxi.ticker import Ticker +from datamaxi.datamaxi.premium import Premium class Datamaxi: @@ -21,3 +24,6 @@ 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) + self.forex = Forex(api_key, **kwargs) + self.ticker = Ticker(api_key, **kwargs) + self.premium = Premium(api_key, **kwargs) diff --git a/datamaxi/datamaxi/candle.py b/datamaxi/datamaxi/candle.py index a1c11a1..fe2cfc3 100644 --- a/datamaxi/datamaxi/candle.py +++ b/datamaxi/datamaxi/candle.py @@ -33,7 +33,7 @@ def get( ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: """Fetch candle data - `GET /v1/candle` + `GET /api/v1/candle` @@ -90,7 +90,7 @@ def get( "sort": sort, } - res = self.query("/v1/candle", params) + res = self.query("/api/v1/candle", params) if res["data"] is None: raise ValueError("no data found") @@ -119,7 +119,7 @@ def exchanges(self, market: str = "spot") -> List[str]: [datamaxi.Candle.get](./#datamaxi.datamaxi.Candle.get) API. - `GET /v1/candle/exchanges` + `GET /api/v1/candle/exchanges` @@ -135,7 +135,7 @@ def exchanges(self, market: str = "spot") -> List[str]: raise ValueError("market must be either spot or futures") params = {"market": market} - url_path = "/v1/candle/exchanges" + url_path = "/api/v1/candle/exchanges" return self.query(url_path, params) def symbols(self, exchange: str, market: str = "spot") -> List[str]: @@ -143,7 +143,7 @@ def symbols(self, exchange: str, market: str = "spot") -> List[str]: [datamaxi.Candle.get](./#datamaxi.datamaxi.Candle.get) API. - `GET /v1/candle/symbols` + `GET /api/v1/candle/symbols` @@ -165,7 +165,7 @@ def symbols(self, exchange: str, market: str = "spot") -> List[str]: raise ValueError("market must be either spot or futures") params = {"exchange": exchange, "market": market} - url_path = "/v1/candle/symbols" + url_path = "/api/v1/candle/symbols" return self.query(url_path, params) def intervals(self, exchange: str, market: str = "spot") -> List[str]: @@ -173,7 +173,7 @@ def intervals(self, exchange: str, market: str = "spot") -> List[str]: [datamaxi.Candle.get](./#datamaxi.datamaxi.Candle.get) API. - `GET /v1/candle/intervals` + `GET /api/v1/candle/intervals` @@ -192,5 +192,5 @@ def intervals(self, exchange: str, market: str = "spot") -> List[str]: ) params = {"exchange": exchange, "market": market} - url_path = "/v1/candle/intervals" + url_path = "/api/v1/candle/intervals" return self.query(url_path, params) diff --git a/datamaxi/datamaxi/dex_trade.py b/datamaxi/datamaxi/dex_trade.py index e3cedd9..57bfcb4 100644 --- a/datamaxi/datamaxi/dex_trade.py +++ b/datamaxi/datamaxi/dex_trade.py @@ -30,7 +30,7 @@ def get( ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: """Fetch DEX trade data - `GET /v1/dex/trade` + `GET /api/v1/dex/trade` @@ -77,7 +77,7 @@ def get( "sort": sort, } - res = self.query("/v1/dex/trade", params) + res = self.query("/api/v1/dex/trade", params) if res["data"] is None: raise ValueError("no data found") @@ -104,12 +104,12 @@ def exchanges(self) -> List[str]: [datamaxi.DexTrade.get](./#datamaxi.datamaxi.DexTrade.get) API. - `GET /v1/dex/trade/exchanges` + `GET /api/v1/dex/trade/exchanges` Returns: List of supported exchanges """ - url_path = "/v1/dex/trade/exchanges" + url_path = "/api/v1/dex/trade/exchanges" return self.query(url_path) diff --git a/datamaxi/datamaxi/forex.py b/datamaxi/datamaxi/forex.py new file mode 100644 index 0000000..0fa5907 --- /dev/null +++ b/datamaxi/datamaxi/forex.py @@ -0,0 +1,65 @@ +from typing import Any, List, Dict, Union +import pandas as pd +from datamaxi.api import API +from datamaxi.lib.utils import check_required_parameter + + +class Forex(API): + """Client to fetch forex data from DataMaxi+ API.""" + + def __init__(self, api_key=None, **kwargs: Any): + """Initialize forex 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, + symbol: str, + pandas: bool = True, + ) -> Union[Dict, pd.DataFrame]: + """Fetch forex data + + `GET /api/v1/forex` + + + + Args: + symbol (str): Symbol name + pandas (bool): Return data as pandas DataFrame + + Returns: + Forex data in pandas DataFrame + """ + check_required_parameter(symbol, "symbol") + + params = { + "symbol": symbol, + } + + res = self.query("/api/v1/forex", params) + + if pandas: + df = pd.DataFrame(res) + df = df.set_index("d") + return df + else: + return res + + def symbols(self) -> List[str]: + """Fetch supported symbols accepted by + [datamaxi.Forex.get](./#datamaxi.datamaxi.Forex.get) + API. + + `GET /api/v1/forex/symbols` + + + + Returns: + List of supported symbols + """ + url_path = "/api/v1/forex/symbols" + return self.query(url_path) diff --git a/datamaxi/datamaxi/funding_rate.py b/datamaxi/datamaxi/funding_rate.py index 756bc2b..71c847a 100644 --- a/datamaxi/datamaxi/funding_rate.py +++ b/datamaxi/datamaxi/funding_rate.py @@ -31,7 +31,7 @@ def get( ) -> Union[Tuple[Dict, Callable], Tuple[pd.DataFrame, Callable]]: """Fetch funding rate data - `GET /v1/funding-rate` + `GET /api/v1/funding-rate` @@ -79,7 +79,7 @@ def get( "sort": sort, } - res = self.query("/v1/funding-rate", params) + res = self.query("/api/v1/funding-rate", params) if res["data"] is None: raise ValueError("no data found") @@ -106,14 +106,14 @@ def exchanges(self) -> List[str]: [datamaxi.FundingRate.get](./#datamaxi.datamaxi.FundingRate.get) API. - `GET /v1/funding-rate/exchanges` + `GET /api/v1/funding-rate/exchanges` Returns: List of supported exchanges """ - url_path = "/v1/funding-rate/exchanges" + url_path = "/api/v1/funding-rate/exchanges" return self.query(url_path) def symbols(self, exchange: str, market: str = "spot") -> List[str]: @@ -121,7 +121,7 @@ def symbols(self, exchange: str, market: str = "spot") -> List[str]: [datamaxi.FundingRate.get](./#datamaxi.datamaxi.FundingRate.get) API. - `GET /v1/funding-rate/symbols` + `GET /api/v1/funding-rate/symbols` @@ -133,5 +133,5 @@ def symbols(self, exchange: str, market: str = "spot") -> List[str]: """ check_required_parameter(exchange, "exchange") params = {"exchange": exchange} - url_path = "/v1/funding-rate/symbols" + url_path = "/api/v1/funding-rate/symbols" return self.query(url_path, params) diff --git a/datamaxi/datamaxi/premium.py b/datamaxi/datamaxi/premium.py new file mode 100644 index 0000000..7ee6df6 --- /dev/null +++ b/datamaxi/datamaxi/premium.py @@ -0,0 +1,106 @@ +from typing import Any, List, Dict, Union +import pandas as pd +from datamaxi.api import API +from datamaxi.lib.utils import check_required_parameters + + +class Premium(API): + """Client to fetch premium data from DataMaxi+ API.""" + + def __init__(self, api_key=None, **kwargs: Any): + """Initialize premium 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, + sourceExchange: str, + targetExchange: str, + symbol: str, + pandas: bool = True, + ) -> Union[Dict, pd.DataFrame]: + """Fetch premium data + + `GET /api/v1/premium` + + + + Args: + sourceExchange (str): Source exchange name + targetExchange (str): Target exchange name + symbol (str): Symbol name + pandas (bool): Return data as pandas DataFrame + + Returns: + Premium data in pandas DataFrame + """ + + check_required_parameters( + [ + [sourceExchange, "sourceExchange"], + [targetExchange, "targetExchange"], + [symbol, "symbol"], + ] + ) + + params = { + "sourceExchange": sourceExchange, + "targetExchange": targetExchange, + "symbol": symbol, + } + + res = self.query("/api/v1/premium", params) + + if pandas: + df = pd.DataFrame(res) + df = df.set_index("d") + return df + else: + return res + + def exchanges(self) -> List[str]: + """Fetch supported exchanges accepted by + [datamaxi.Premium.get](./#datamaxi.datamaxi.Premium.get) + API. + + `GET /api/v1/Premium/exchanges` + + + + Returns: + List of supported exchange + """ + url_path = "/api/v1/premium/exchanges" + return self.query(url_path) + + def symbols(self, sourceExchange: str, targetExchange: str) -> List[str]: + """Fetch supported symbols accepted by + [datamaxi.Premium.get](./#datamaxi.datamaxi.Premium.get) + API. + + `GET /api/v1/premium/symbols` + + + + Args: + sourceExchange (str): Source exchange name + targetExchange (str): Target exchange name + + Returns: + List of supported symbols + """ + check_required_parameters( + [ + [sourceExchange, "sourceExchange"], + [targetExchange, "targetExchange"], + ] + ) + + params = {"sourceExchange": sourceExchange, "targetExchange": targetExchange} + + url_path = "/api/v1/premium/symbols" + return self.query(url_path, params) diff --git a/datamaxi/datamaxi/ticker.py b/datamaxi/datamaxi/ticker.py new file mode 100644 index 0000000..8bcd3b4 --- /dev/null +++ b/datamaxi/datamaxi/ticker.py @@ -0,0 +1,99 @@ +from typing import Any, List, Dict, Union +import pandas as pd +from datamaxi.api import API +from datamaxi.lib.utils import check_required_parameters +from datamaxi.lib.utils import check_required_parameter + + +class Ticker(API): + """Client to fetch ticker data from DataMaxi+ API.""" + + def __init__(self, api_key=None, **kwargs: Any): + """Initialize ticker 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, + pandas: bool = True, + ) -> Union[Dict, pd.DataFrame]: + """Fetch ticker data + + `GET /api/v1/ticker` + + + + Args: + exchange (str): Exchange name + symbol (str): Symbol name + pandas (bool): Return data as pandas DataFrame + + Returns: + Ticker data in pandas DataFrame + """ + + check_required_parameters( + [ + [exchange, "exchange"], + [symbol, "symbol"], + ] + ) + + params = { + "exchange": exchange, + "symbol": symbol, + } + + res = self.query("/api/v1/ticker", params) + + if pandas: + df = pd.DataFrame(res) + df = df.set_index("d") + return df + else: + return res + + def exchanges(self) -> List[str]: + """Fetch supported exchanges accepted by + [datamaxi.Ticker.get](./#datamaxi.datamaxi.Ticker.get) + API. + + `GET /api/v1/ticker/exchanges` + + + + Returns: + List of supported exchange + """ + url_path = "/api/v1/ticker/exchanges" + return self.query(url_path) + + def symbols(self, exchange: str) -> List[str]: + """Fetch supported symbols accepted by + [datamaxi.Ticker.get](./#datamaxi.datamaxi.Ticker.get) + API. + + `GET /api/v1/ticker/symbols` + + + + Args: + exchange (str): Exchange name + + Returns: + List of supported symbols + """ + check_required_parameter(exchange, "exchange") + + params = { + "exchange": exchange, + } + + url_path = "/api/v1/ticker/symbols" + return self.query(url_path, params) diff --git a/datamaxi/defillama/__init__.py b/datamaxi/defillama/__init__.py index 8993864..f127bc4 100644 --- a/datamaxi/defillama/__init__.py +++ b/datamaxi/defillama/__init__.py @@ -24,53 +24,53 @@ def __init__(self, api_key=None, **kwargs: Any): def protocols(self) -> List[str]: """Get supported protocols - `GET /v1/defillama/protocol` + `GET /api/v1/defillama/protocol` Returns: List of supported protocols """ - url_path = "/v1/defillama/protocol" + url_path = "/api/v1/defillama/protocol" return self.query(url_path) def chains(self) -> List[str]: """Get supported chains - `GET /v1/defillama/chain` + `GET /api/v1/defillama/chain` Returns: List of supported chains """ - url_path = "/v1/defillama/chain" + url_path = "/api/v1/defillama/chain" return self.query(url_path) def pools(self) -> List[str]: """Get supported pools - `GET /v1/defillama/pool` + `GET /api/v1/defillama/pool` Returns: List of supported pools """ - url_path = "/v1/defillama/pool" + url_path = "/api/v1/defillama/pool" return self.query(url_path) def stablecoins(self) -> List[str]: """Get supported stablecoins - `GET /v1/defillama/stablecoin` + `GET /api/v1/defillama/stablecoin` Returns: List of supported stablecoins """ - url_path = "/v1/defillama/stablecoin" + url_path = "/api/v1/defillama/stablecoin" return self.query(url_path) @postprocess() @@ -79,7 +79,7 @@ def tvl( ) -> Union[List, pd.DataFrame]: """Get total TVL across all chains and protocols - `GET /v1/defillama/tvl` + `GET /api/v1/defillama/tvl` @@ -98,7 +98,7 @@ def tvl( if chain is not None: params["chain"] = chain - url_path = "/v1/defillama/tvl" + url_path = "/api/v1/defillama/tvl" return self.query(url_path, params) @postprocess(num_index=2) @@ -107,7 +107,7 @@ def tvl_detail( ) -> Union[List, pd.DataFrame]: """Get TVL detail for given protocol and chain - `GET /v1/defillama/tvl/detail` + `GET /api/v1/defillama/tvl/detail` @@ -129,14 +129,14 @@ def tvl_detail( if token: params["token"] = str(token).lower() - url_path = "/v1/defillama/tvl/detail" + url_path = "/api/v1/defillama/tvl/detail" return self.query(url_path, params) @postprocess() def mcap(self, protocol: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """Get market cap for given protocol - `GET /v1/defillama/mcap` + `GET /api/v1/defillama/mcap` @@ -151,13 +151,13 @@ def mcap(self, protocol: str, pandas: bool = True) -> Union[List, pd.DataFrame]: params = { "protocol": protocol, } - return self.query("/v1/defillama/mcap", params) + return self.query("/api/v1/defillama/mcap", params) @postprocess() def pool_yield(self, poolId: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """Get yield for given pool - `GET /v1/defillama/pool/yield` + `GET /api/v1/defillama/pool/yield` @@ -172,7 +172,7 @@ def pool_yield(self, poolId: str, pandas: bool = True) -> Union[List, pd.DataFra params = { "poolId": poolId, } - return self.query("/v1/defillama/pool/yield", params) + return self.query("/api/v1/defillama/pool/yield", params) @postprocess() def stablecoin_mcap( @@ -180,7 +180,7 @@ def stablecoin_mcap( ) -> Union[List, pd.DataFrame]: """Get market cap for given stablecoin and chain - `GET /v1/defillama/stablecoin/mcap` + `GET /api/v1/defillama/stablecoin/mcap` @@ -200,7 +200,7 @@ def stablecoin_mcap( if chain is not None: params["chain"] = chain - return self.query("/v1/defillama/stablecoin/mcap", params) + return self.query("/api/v1/defillama/stablecoin/mcap", params) @postprocess() def stablecoin_price( @@ -208,7 +208,7 @@ def stablecoin_price( ) -> Union[List, pd.DataFrame]: """Get price for given stablecoin - `GET /v1/defillama/stablecoin/price` + `GET /api/v1/defillama/stablecoin/price` @@ -223,7 +223,7 @@ def stablecoin_price( params = { "stablecoin": stablecoin, } - return self.query("/v1/defillama/stablecoin/price", params) + return self.query("/api/v1/defillama/stablecoin/price", params) @postprocess() def fee( @@ -235,7 +235,7 @@ def fee( ) -> Union[List, pd.DataFrame]: """Get fee for given protocol or chain - `GET /v1/defillama/fee` + `GET /api/v1/defillama/fee` @@ -263,7 +263,7 @@ def fee( check_required_parameter(chain, "chain") params["chain"] = chain - return self.query("/v1/defillama/fee", params) + return self.query("/api/v1/defillama/fee", params) @postprocess() def revenue( @@ -275,7 +275,7 @@ def revenue( ) -> Union[List, pd.DataFrame]: """Get revenue for given protocol or chain - `GET /v1/defillama/revenue` + `GET /api/v1/defillama/revenue` @@ -303,7 +303,7 @@ def revenue( check_required_parameter(chain, "chain") params["chain"] = chain - return self.query("/v1/defillama/revenue", params) + return self.query("/api/v1/defillama/revenue", params) @postprocess(num_index=-1) def fee_detail( @@ -315,7 +315,7 @@ def fee_detail( ) -> Union[List, pd.DataFrame]: """Get fee detail for given protocol and chain - `GET /v1/defillama/fee/detail` + `GET /api/v1/defillama/fee/detail` @@ -340,7 +340,7 @@ def fee_detail( if chain is not None: params["chain"] = chain - return self.query("/v1/defillama/fee/detail", params) + return self.query("/api/v1/defillama/fee/detail", params) @postprocess(num_index=-1) def revenue_detail( @@ -352,7 +352,7 @@ def revenue_detail( ) -> Union[List, pd.DataFrame]: """Get revenue detail for given protocol and chain - `GET /v1/defillama/revenue/detail` + `GET /api/v1/defillama/revenue/detail` @@ -377,4 +377,4 @@ def revenue_detail( if chain is not None: params["chain"] = chain - return self.query("/v1/defillama/revenue/detail", params) + return self.query("/api/v1/defillama/revenue/detail", params) diff --git a/datamaxi/google/__init__.py b/datamaxi/google/__init__.py index 3796f2f..4accca6 100644 --- a/datamaxi/google/__init__.py +++ b/datamaxi/google/__init__.py @@ -23,21 +23,21 @@ def __init__(self, api_key=None, **kwargs: Any): def keywords(self) -> List[str]: """Get Google trend supported keywords - `GET /v1/google/keywords` + `GET /api/v1/google/keywords` Returns: List of supported Google trend keywords """ - url_path = "/v1/google/keywords" + url_path = "/api/v1/google/keywords" return self.query(url_path) @postprocess() def trend(self, keyword: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """Get Google trend for given keyword - `GET /v1/google/trend` + `GET /api/v1/google/trend` @@ -50,4 +50,4 @@ def trend(self, keyword: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """ check_required_parameter(keyword, "keyword") params = {"keyword": keyword} - return self.query("/v1/google/trend", params) + return self.query("/api/v1/google/trend", params) diff --git a/datamaxi/naver/__init__.py b/datamaxi/naver/__init__.py index c840162..913e852 100644 --- a/datamaxi/naver/__init__.py +++ b/datamaxi/naver/__init__.py @@ -23,21 +23,21 @@ def __init__(self, api_key=None, **kwargs: Any): def symbols(self) -> List[str]: """Get Naver trend supported token symbols - `GET /v1/naver/symbols` + `GET /api/v1/naver/symbols` Returns: List of supported Naver trend token symbols """ - url_path = "/v1/naver/symbols" + url_path = "/api/v1/naver/symbols" return self.query(url_path) @postprocess() def trend(self, symbol: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """Get Naver trend for given token symbol - `GET /v1/naver/trend` + `GET /api/v1/naver/trend` @@ -50,4 +50,4 @@ def trend(self, symbol: str, pandas: bool = True) -> Union[List, pd.DataFrame]: """ check_required_parameter(symbol, "symbol") params = {"symbol": symbol} - return self.query("/v1/naver/trend", params) + return self.query("/api/v1/naver/trend", params) diff --git a/docs/forex.md b/docs/forex.md new file mode 100644 index 0000000..7db2cbe --- /dev/null +++ b/docs/forex.md @@ -0,0 +1,6 @@ +# Forex + +::: datamaxi.datamaxi.Forex + options: + show_submodules: true + show_source: false diff --git a/docs/premium.md b/docs/premium.md new file mode 100644 index 0000000..7ac2acd --- /dev/null +++ b/docs/premium.md @@ -0,0 +1,6 @@ +# Premium + +::: datamaxi.datamaxi.Premium + options: + show_submodules: true + show_source: false diff --git a/docs/ticker.md b/docs/ticker.md new file mode 100644 index 0000000..6e40c94 --- /dev/null +++ b/docs/ticker.md @@ -0,0 +1,6 @@ +# Ticker + +::: datamaxi.datamaxi.Ticker + options: + show_submodules: true + show_source: false diff --git a/mkdocs.yml b/mkdocs.yml index 8cb1c8c..d1eb65d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,9 @@ nav: - Candle: candle.md - Funding Rate: funding-rate.md - DEX Trade: dex-trade.md + - Forex: forex.md + - Ticker: ticker.md + - Premium: premium.md - Defillama: defillama.md - Trend: - Naver Trend: naver-trend.md diff --git a/pyproject.toml b/pyproject.toml index 51b8440..068de09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "datamaxi" -version = "0.13.0" +version = "0.14.0" authors = [ { name="Bisonai", email="business@bisonai.com" }, ]