dcex 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. dcex/__init__.py +59 -0
  2. dcex/async_support/__init__.py +104 -0
  3. dcex/async_support/binance/__init__.py +3 -0
  4. dcex/async_support/binance/_account_http.py +74 -0
  5. dcex/async_support/binance/_http_manager.py +141 -0
  6. dcex/async_support/binance/_market_http.py +276 -0
  7. dcex/async_support/binance/_trade_http.py +544 -0
  8. dcex/async_support/binance/client.py +50 -0
  9. dcex/async_support/binance/endpoints/account.py +22 -0
  10. dcex/async_support/binance/endpoints/market.py +29 -0
  11. dcex/async_support/binance/endpoints/trade.py +28 -0
  12. dcex/async_support/binance/enums.py +13 -0
  13. dcex/async_support/bingx/__init__.py +3 -0
  14. dcex/async_support/bingx/_account_http.py +131 -0
  15. dcex/async_support/bingx/_http_manager.py +185 -0
  16. dcex/async_support/bingx/_market_http.py +157 -0
  17. dcex/async_support/bingx/_trade_http.py +936 -0
  18. dcex/async_support/bingx/client.py +50 -0
  19. dcex/async_support/bingx/endpoints/account.py +15 -0
  20. dcex/async_support/bingx/endpoints/market.py +16 -0
  21. dcex/async_support/bingx/endpoints/trade.py +30 -0
  22. dcex/async_support/bitmart/__init__.py +3 -0
  23. dcex/async_support/bitmart/_account_http.py +240 -0
  24. dcex/async_support/bitmart/_http_manager.py +215 -0
  25. dcex/async_support/bitmart/_market_http.py +274 -0
  26. dcex/async_support/bitmart/_trade_http.py +1151 -0
  27. dcex/async_support/bitmart/client.py +50 -0
  28. dcex/async_support/bitmart/endpoints/account.py +30 -0
  29. dcex/async_support/bitmart/endpoints/market.py +32 -0
  30. dcex/async_support/bitmart/endpoints/trade.py +44 -0
  31. dcex/async_support/bitmex/__init__.py +3 -0
  32. dcex/async_support/bitmex/_account_http.py +63 -0
  33. dcex/async_support/bitmex/_http_manager.py +258 -0
  34. dcex/async_support/bitmex/_market_http.py +324 -0
  35. dcex/async_support/bitmex/_position_http.py +235 -0
  36. dcex/async_support/bitmex/_trade_http.py +602 -0
  37. dcex/async_support/bitmex/_trading_http.py +171 -0
  38. dcex/async_support/bitmex/client.py +54 -0
  39. dcex/async_support/bitmex/endpoints/funds.py +22 -0
  40. dcex/async_support/bitmex/endpoints/market.py +28 -0
  41. dcex/async_support/bitmex/endpoints/order.py +26 -0
  42. dcex/async_support/bitmex/endpoints/positions.py +27 -0
  43. dcex/async_support/bitmex/endpoints/trading.py +25 -0
  44. dcex/async_support/bybit/__init__.py +3 -0
  45. dcex/async_support/bybit/_account_http.py +311 -0
  46. dcex/async_support/bybit/_asset_http.py +604 -0
  47. dcex/async_support/bybit/_http_manager.py +238 -0
  48. dcex/async_support/bybit/_market_http.py +273 -0
  49. dcex/async_support/bybit/_position_http.py +162 -0
  50. dcex/async_support/bybit/_trade_http.py +950 -0
  51. dcex/async_support/bybit/client.py +54 -0
  52. dcex/async_support/bybit/endpoints/account.py +33 -0
  53. dcex/async_support/bybit/endpoints/asset.py +41 -0
  54. dcex/async_support/bybit/endpoints/market.py +29 -0
  55. dcex/async_support/bybit/endpoints/position.py +26 -0
  56. dcex/async_support/bybit/endpoints/trade.py +53 -0
  57. dcex/async_support/gateio/__init__.py +3 -0
  58. dcex/async_support/gateio/_account_http.py +244 -0
  59. dcex/async_support/gateio/_http_manager.py +234 -0
  60. dcex/async_support/gateio/_market_http.py +428 -0
  61. dcex/async_support/gateio/_trade_http.py +1266 -0
  62. dcex/async_support/gateio/client.py +50 -0
  63. dcex/async_support/gateio/endpoints/account.py +53 -0
  64. dcex/async_support/gateio/endpoints/market.py +61 -0
  65. dcex/async_support/gateio/endpoints/trade.py +79 -0
  66. dcex/async_support/okx/__init__.py +3 -0
  67. dcex/async_support/okx/_account_http.py +827 -0
  68. dcex/async_support/okx/_asset_http.py +531 -0
  69. dcex/async_support/okx/_http_manager.py +235 -0
  70. dcex/async_support/okx/_market_http.py +143 -0
  71. dcex/async_support/okx/_public_http.py +151 -0
  72. dcex/async_support/okx/_trade_http.py +1014 -0
  73. dcex/async_support/okx/client.py +54 -0
  74. dcex/async_support/okx/endpoints/account.py +34 -0
  75. dcex/async_support/okx/endpoints/asset.py +27 -0
  76. dcex/async_support/okx/endpoints/market.py +15 -0
  77. dcex/async_support/okx/endpoints/public.py +15 -0
  78. dcex/async_support/okx/endpoints/trade.py +25 -0
  79. dcex/async_support/product_table/fetch.py +913 -0
  80. dcex/async_support/product_table/manager.py +554 -0
  81. dcex/binance/__init__.py +3 -0
  82. dcex/binance/_account_http.py +74 -0
  83. dcex/binance/_http_manager.py +180 -0
  84. dcex/binance/_market_http.py +269 -0
  85. dcex/binance/_trade_http.py +543 -0
  86. dcex/binance/client.py +33 -0
  87. dcex/binance/endpoints/account.py +22 -0
  88. dcex/binance/endpoints/market.py +28 -0
  89. dcex/binance/endpoints/trade.py +28 -0
  90. dcex/binance/enums.py +13 -0
  91. dcex/bitmart/__init__.py +3 -0
  92. dcex/bitmart/_account_http.py +254 -0
  93. dcex/bitmart/_http_manager.py +224 -0
  94. dcex/bitmart/_market_http.py +314 -0
  95. dcex/bitmart/_trade_http.py +1520 -0
  96. dcex/bitmart/client.py +45 -0
  97. dcex/bitmart/endpoints/account.py +40 -0
  98. dcex/bitmart/endpoints/market.py +42 -0
  99. dcex/bitmart/endpoints/trade.py +54 -0
  100. dcex/bitmex/__init__.py +3 -0
  101. dcex/bitmex/_account_http.py +63 -0
  102. dcex/bitmex/_http_manager.py +259 -0
  103. dcex/bitmex/_market_http.py +324 -0
  104. dcex/bitmex/_position_http.py +234 -0
  105. dcex/bitmex/_trade_http.py +648 -0
  106. dcex/bitmex/_trading_http.py +184 -0
  107. dcex/bitmex/client.py +69 -0
  108. dcex/bitmex/endpoints/funds.py +22 -0
  109. dcex/bitmex/endpoints/market.py +29 -0
  110. dcex/bitmex/endpoints/order.py +28 -0
  111. dcex/bitmex/endpoints/positions.py +28 -0
  112. dcex/bitmex/endpoints/trading.py +27 -0
  113. dcex/bybit/__init__.py +3 -0
  114. dcex/bybit/_account_http.py +313 -0
  115. dcex/bybit/_asset_http.py +604 -0
  116. dcex/bybit/_http_manager.py +231 -0
  117. dcex/bybit/_market_http.py +273 -0
  118. dcex/bybit/_position_http.py +159 -0
  119. dcex/bybit/_trade_http.py +945 -0
  120. dcex/bybit/client.py +50 -0
  121. dcex/bybit/endpoints/account.py +37 -0
  122. dcex/bybit/endpoints/asset.py +45 -0
  123. dcex/bybit/endpoints/market.py +30 -0
  124. dcex/bybit/endpoints/position.py +29 -0
  125. dcex/bybit/endpoints/trade.py +59 -0
  126. dcex/gateio/__init__.py +3 -0
  127. dcex/gateio/_account_http.py +231 -0
  128. dcex/gateio/_http_manager.py +224 -0
  129. dcex/gateio/_market_http.py +415 -0
  130. dcex/gateio/_trade_http.py +1602 -0
  131. dcex/gateio/client.py +66 -0
  132. dcex/gateio/endpoints/account.py +60 -0
  133. dcex/gateio/endpoints/market.py +72 -0
  134. dcex/gateio/endpoints/trade.py +89 -0
  135. dcex/okx/__init__.py +3 -0
  136. dcex/okx/_account_http.py +825 -0
  137. dcex/okx/_asset_http.py +526 -0
  138. dcex/okx/_http_manager.py +251 -0
  139. dcex/okx/_market_http.py +139 -0
  140. dcex/okx/_public_http.py +106 -0
  141. dcex/okx/_trade_http.py +995 -0
  142. dcex/okx/client.py +66 -0
  143. dcex/okx/endpoints/account.py +49 -0
  144. dcex/okx/endpoints/asset.py +42 -0
  145. dcex/okx/endpoints/market.py +28 -0
  146. dcex/okx/endpoints/public.py +27 -0
  147. dcex/okx/endpoints/trade.py +40 -0
  148. dcex/product_table/fetch.py +581 -0
  149. dcex/product_table/manager.py +482 -0
  150. dcex/utils/address_utils.py +14 -0
  151. dcex/utils/common.py +21 -0
  152. dcex/utils/common_dataframe.py +35 -0
  153. dcex/utils/decimal_utils.py +15 -0
  154. dcex/utils/errors.py +74 -0
  155. dcex/utils/helpers.py +88 -0
  156. dcex/utils/jupyter_helper.py +105 -0
  157. dcex/utils/timeframe_utils.py +126 -0
  158. dcex-0.7.0.dist-info/METADATA +171 -0
  159. dcex-0.7.0.dist-info/RECORD +162 -0
  160. dcex-0.7.0.dist-info/WHEEL +5 -0
  161. dcex-0.7.0.dist-info/licenses/LICENSE +21 -0
  162. dcex-0.7.0.dist-info/top_level.txt +1 -0
dcex/__init__.py ADDED
@@ -0,0 +1,59 @@
1
+ """
2
+ dcex - dex & cex trading library.
3
+
4
+ A comprehensive library for cryptocurrency exchange interactions with both sync and async support.
5
+ Automatically handles Jupyter Notebook compatibility with nest_asyncio.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from .binance.client import Client as BinanceClient
11
+ from .bitmart.client import Client as BitmartClient
12
+ from .bitmex.client import Client as BitmexClient
13
+ from .bybit.client import Client as BybitClient
14
+ from .gateio.client import Client as GateioClient
15
+ from .okx.client import Client as OKXClient
16
+ from .utils.jupyter_helper import auto_apply_nest_asyncio
17
+
18
+ auto_apply_nest_asyncio(verbose=False)
19
+
20
+
21
+ # Create callable functions for each exchange (synchronous clients)
22
+ def binance(**kwargs: Any) -> BinanceClient: # noqa: ANN401
23
+ """Create a Binance client instance."""
24
+ return BinanceClient(**kwargs)
25
+
26
+
27
+ def bitmart(**kwargs: Any) -> BitmartClient: # noqa: ANN401
28
+ """Create a BitMart client instance."""
29
+ return BitmartClient(**kwargs)
30
+
31
+
32
+ def bitmex(**kwargs: Any) -> BitmexClient: # noqa: ANN401
33
+ """Create a BitMEX client instance."""
34
+ return BitmexClient(**kwargs)
35
+
36
+
37
+ def bybit(**kwargs: Any) -> BybitClient: # noqa: ANN401
38
+ """Create a Bybit client instance."""
39
+ return BybitClient(**kwargs)
40
+
41
+
42
+ def gateio(**kwargs: Any) -> GateioClient: # noqa: ANN401
43
+ """Create a Gate.io client instance."""
44
+ return GateioClient(**kwargs)
45
+
46
+
47
+ def okx(**kwargs: Any) -> OKXClient: # noqa: ANN401
48
+ """Create an OKX client instance."""
49
+ return OKXClient(**kwargs)
50
+
51
+
52
+ __all__ = [
53
+ "binance",
54
+ "bitmart",
55
+ "bitmex",
56
+ "bybit",
57
+ "gateio",
58
+ "okx",
59
+ ]
@@ -0,0 +1,104 @@
1
+ """
2
+ Async exchange entry points.
3
+
4
+ This module exposes coroutine factory functions for each supported exchange,
5
+ which return an initialized async client (after awaiting `async_init`).
6
+ """
7
+
8
+ # Import exchange client classes and create callable functions
9
+ from typing import Any, cast
10
+
11
+ from .binance.client import Client as BinanceClient
12
+ from .bingx.client import Client as BingXClient
13
+ from .bitmart.client import Client as BitmartClient
14
+ from .bitmex.client import Client as BitmexClient
15
+ from .bybit.client import Client as BybitClient
16
+ from .gateio.client import Client as GateioClient
17
+ from .hyperliquid.client import Client as HyperliquidClient
18
+ from .kucoin.client import Client as KuCoinClient
19
+ from .okx.client import Client as OKXClient
20
+ from .zoomex.client import Client as ZoomexClient
21
+
22
+
23
+ async def binance(
24
+ **kwargs: Any, # noqa: ANN401
25
+ ) -> BinanceClient:
26
+ """Create and initialize a Binance client instance."""
27
+ return cast(BinanceClient, await BinanceClient(**kwargs).async_init())
28
+
29
+
30
+ async def bingx(
31
+ **kwargs: Any, # noqa: ANN401
32
+ ) -> BingXClient:
33
+ """Create and initialize a BingX client instance."""
34
+ return cast(BingXClient, await BingXClient(**kwargs).async_init())
35
+
36
+
37
+ async def bitmart(
38
+ **kwargs: Any, # noqa: ANN401
39
+ ) -> BitmartClient:
40
+ """Create and initialize a BitMart client instance."""
41
+ return cast(BitmartClient, await BitmartClient(**kwargs).async_init())
42
+
43
+
44
+ async def bitmex(
45
+ **kwargs: Any, # noqa: ANN401
46
+ ) -> BitmexClient:
47
+ """Create and initialize a BitMEX client instance."""
48
+ return cast(BitmexClient, await BitmexClient(**kwargs).async_init())
49
+
50
+
51
+ async def bybit(
52
+ **kwargs: Any, # noqa: ANN401
53
+ ) -> BybitClient:
54
+ """Create and initialize a Bybit client instance."""
55
+ return cast(BybitClient, await BybitClient(**kwargs).async_init())
56
+
57
+
58
+ async def gateio(
59
+ **kwargs: Any, # noqa: ANN401
60
+ ) -> GateioClient:
61
+ """Create and initialize a Gate.io client instance."""
62
+ return cast(GateioClient, await GateioClient(**kwargs).async_init())
63
+
64
+
65
+ async def hyperliquid(
66
+ **kwargs: Any, # noqa: ANN401
67
+ ) -> HyperliquidClient:
68
+ """Create and initialize a Hyperliquid client instance."""
69
+ return cast(HyperliquidClient, await HyperliquidClient(**kwargs).async_init())
70
+
71
+
72
+ async def kucoin(
73
+ **kwargs: Any, # noqa: ANN401
74
+ ) -> KuCoinClient:
75
+ """Create and initialize a KuCoin client instance."""
76
+ return cast(KuCoinClient, await KuCoinClient(**kwargs).async_init())
77
+
78
+
79
+ async def okx(
80
+ **kwargs: Any, # noqa: ANN401
81
+ ) -> OKXClient:
82
+ """Create and initialize an OKX client instance."""
83
+ return cast(OKXClient, await OKXClient(**kwargs).async_init())
84
+
85
+
86
+ async def zoomex(
87
+ **kwargs: Any, # noqa: ANN401
88
+ ) -> ZoomexClient:
89
+ """Create and initialize a Zoomex client instance."""
90
+ return cast(ZoomexClient, await ZoomexClient(**kwargs).async_init())
91
+
92
+
93
+ __all__ = [
94
+ "binance",
95
+ "bingx",
96
+ "bitmart",
97
+ "bitmex",
98
+ "bybit",
99
+ "gateio",
100
+ "hyperliquid",
101
+ "kucoin",
102
+ "okx",
103
+ "zoomex",
104
+ ]
@@ -0,0 +1,3 @@
1
+ from .client import Client
2
+
3
+ __all__ = ["Client"]
@@ -0,0 +1,74 @@
1
+ from ...utils.common import Common
2
+ from ._http_manager import HTTPManager
3
+ from .endpoints.account import FuturesAccount, SpotAccount
4
+ from .enums import BinanceProductType
5
+
6
+
7
+ class AccountHTTP(HTTPManager):
8
+ """HTTP client for Binance account-related API endpoints."""
9
+
10
+ async def get_account_balance(
11
+ self,
12
+ market_type: str,
13
+ ) -> dict:
14
+ """
15
+ Get account balance.
16
+
17
+ Args:
18
+ market_type: Market type ("spot" or "swap")
19
+
20
+ Returns:
21
+ dict: Account balance information
22
+ """
23
+ res = await self._request(
24
+ method="GET",
25
+ path=SpotAccount.ACCOUNT_BALANCE
26
+ if market_type == BinanceProductType.SPOT
27
+ else FuturesAccount.ACCOUNT_BALANCE,
28
+ query={},
29
+ )
30
+ return res
31
+
32
+ async def get_income_history(
33
+ self,
34
+ product_symbol: str | None = None,
35
+ incomeType: str | None = None,
36
+ startTime: int | None = None,
37
+ endTime: int | None = None,
38
+ page: int | None = None,
39
+ limit: int | None = None,
40
+ ) -> dict:
41
+ """
42
+ Get futures income history.
43
+
44
+ Args:
45
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
46
+ incomeType: Income type (TRANSFER, WELCOME_BONUS, REALIZED_PNL, FUNDING_FEE, etc.)
47
+ startTime: Start time in milliseconds
48
+ endTime: End time in milliseconds
49
+ page: Page number for pagination
50
+ limit: Number of records per page
51
+
52
+ Returns:
53
+ dict: Income history data
54
+ """
55
+ payload = {}
56
+ if product_symbol is not None:
57
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
58
+ if incomeType is not None:
59
+ payload["incomeType"] = incomeType
60
+ if startTime is not None:
61
+ payload["startTime"] = startTime
62
+ if endTime is not None:
63
+ payload["endTime"] = endTime
64
+ if page is not None:
65
+ payload["page"] = page
66
+ if limit is not None:
67
+ payload["limit"] = limit
68
+
69
+ res = await self._request(
70
+ method="GET",
71
+ path=FuturesAccount.INCOME_HISTORY,
72
+ query=payload,
73
+ )
74
+ return res
@@ -0,0 +1,141 @@
1
+ import hashlib
2
+ import hmac
3
+ import logging
4
+ import time
5
+ from dataclasses import dataclass, field
6
+ from typing import Self
7
+ from urllib.parse import urlencode
8
+
9
+ import httpx
10
+
11
+ from ...utils.common import Common
12
+ from ...utils.errors import FailedRequestError
13
+ from ...utils.helpers import generate_timestamp
14
+ from ..product_table.manager import ProductTableManager
15
+ from .endpoints.account import FuturesAccount, SpotAccount
16
+ from .endpoints.market import FuturesMarket, SpotMarket
17
+ from .endpoints.trade import FuturesTrade, SpotTrade
18
+
19
+
20
+ @dataclass
21
+ class HTTPManager:
22
+ api_key: str | None = field(default=None)
23
+ api_secret: str | None = field(default=None)
24
+ timeout: int = field(default=10)
25
+ logger: logging.Logger | None = field(default=None)
26
+ session: httpx.AsyncClient | None = field(default=None, init=False)
27
+ ptm: ProductTableManager = field(init=False)
28
+ preload_product_table: bool = field(default=True)
29
+
30
+ api_map = {
31
+ "https://fapi.binance.com": {
32
+ FuturesTrade,
33
+ FuturesMarket,
34
+ FuturesAccount,
35
+ },
36
+ "https://api.binance.com": {
37
+ SpotMarket,
38
+ SpotTrade,
39
+ SpotAccount,
40
+ },
41
+ }
42
+
43
+ async def async_init(self) -> Self:
44
+ self.session = httpx.AsyncClient(timeout=self.timeout)
45
+ self._logger = self.logger or logging.getLogger(__name__)
46
+ if self.preload_product_table:
47
+ self.ptm = await ProductTableManager.get_instance(Common.BINANCE)
48
+ return self
49
+
50
+ def _get_base_url(
51
+ self,
52
+ path: SpotAccount | FuturesAccount | SpotMarket | FuturesMarket | SpotTrade | FuturesTrade,
53
+ ) -> str:
54
+ for base_url, enums in self.api_map.items():
55
+ if type(path) in enums:
56
+ return base_url
57
+ raise ValueError(f"Unknown API path: {path} (type={type(path)})")
58
+
59
+ def _sign(self, params: dict) -> str:
60
+ if self.api_secret is None:
61
+ raise ValueError("API secret is required for signing")
62
+ query_string = urlencode(params)
63
+ return hmac.new(self.api_secret.encode(), query_string.encode(), hashlib.sha256).hexdigest()
64
+
65
+ def _headers(self) -> dict[str, str]:
66
+ return {"X-MBX-APIKEY": self.api_key} if self.api_key else {}
67
+
68
+ async def _request(
69
+ self,
70
+ method: str,
71
+ path: SpotAccount | FuturesAccount | SpotMarket | FuturesMarket | SpotTrade | FuturesTrade,
72
+ query: dict | None = None,
73
+ signed: bool = True,
74
+ ) -> dict:
75
+ if self.session is None or self.session.is_closed:
76
+ await self.async_init()
77
+
78
+ if query is None:
79
+ query = {}
80
+
81
+ if signed:
82
+ if not (self.api_key and self.api_secret):
83
+ raise ValueError("Signed request requires API Key and Secret.")
84
+ query["timestamp"] = int(time.time() * 1000)
85
+ query["recvWindow"] = 5000
86
+ query["signature"] = self._sign(query)
87
+
88
+ response = None
89
+ try:
90
+ if self.session is None:
91
+ raise ValueError("Session is not initialized")
92
+ base_url = self._get_base_url(path)
93
+ url = f"{base_url}{path}"
94
+ if method.upper() == "GET":
95
+ url += f"?{urlencode(query)}" if query else ""
96
+ response = await self.session.get(url, headers=self._headers())
97
+ elif method.upper() == "POST":
98
+ response = await self.session.post(url, headers=self._headers(), data=query)
99
+ elif method.upper() == "DELETE":
100
+ url += f"?{urlencode(query)}" if query else ""
101
+ response = await self.session.delete(url, headers=self._headers())
102
+ else:
103
+ raise ValueError(f"Unsupported method: {method}")
104
+
105
+ except httpx.RequestError as e:
106
+ raise FailedRequestError(
107
+ request=f"{method.upper()} {url} | Params: {query}",
108
+ message=f"Request failed: {str(e)}",
109
+ status_code=response.status_code if response else "Unknown",
110
+ time=str(query.get("timestamp", "Unknown")),
111
+ resp_headers=dict(response.headers) if response else None,
112
+ ) from e
113
+ else:
114
+ try:
115
+ data = response.json()
116
+ except Exception:
117
+ data = {}
118
+
119
+ timestamp = generate_timestamp(iso_format=True)
120
+
121
+ if isinstance(data, dict) and "code" in data and str(data["code"]) != "200":
122
+ code = data.get("code", "Unknown")
123
+ error_message = data.get("msg", "Unknown error")
124
+ raise FailedRequestError(
125
+ request=f"{method} {url} | Body: {query}",
126
+ message=f"BINANCE API Error: [{code}] {error_message}",
127
+ status_code=response.status_code,
128
+ time=str(timestamp),
129
+ resp_headers=dict(response.headers),
130
+ )
131
+
132
+ if not response.status_code // 100 == 2:
133
+ raise FailedRequestError(
134
+ request=f"{method.upper()} {url} | Body: {query}",
135
+ message=f"HTTP Error {response.status_code}: {response.text}",
136
+ status_code=response.status_code,
137
+ time=str(timestamp),
138
+ resp_headers=dict(response.headers),
139
+ )
140
+
141
+ return data
@@ -0,0 +1,276 @@
1
+ from ...utils.common import Common
2
+ from ._http_manager import HTTPManager
3
+ from .endpoints.market import FuturesMarket, SpotMarket
4
+ from .enums import BinanceProductType
5
+
6
+
7
+ class MarketHTTP(HTTPManager):
8
+ """HTTP client for Binance market data API endpoints."""
9
+
10
+ async def get_spot_exchange_info(
11
+ self,
12
+ product_symbol: str | None = None,
13
+ product_symbols: list | None = None,
14
+ symbolStatus: str | None = None,
15
+ ) -> dict:
16
+ """
17
+ Get spot exchange information.
18
+
19
+ Args:
20
+ product_symbol: Single trading pair symbol (e.g., 'BTCUSDT')
21
+ product_symbols: List of trading pair symbols
22
+ symbolStatus: Symbol status filter (TRADING, HALT, BREAK)
23
+
24
+ Returns:
25
+ dict: Exchange information including symbols, filters, and trading rules
26
+ """
27
+ payload = {}
28
+ if product_symbol is not None:
29
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
30
+ if product_symbols is not None:
31
+ formatted_symbols = [
32
+ self.ptm.get_exchange_symbol(Common.BINANCE, symbol) for symbol in product_symbols
33
+ ]
34
+ payload["symbols"] = str(formatted_symbols).replace("'", '"')
35
+ if symbolStatus is not None:
36
+ payload["symbolStatus"] = symbolStatus
37
+
38
+ res = await self._request(
39
+ method="GET",
40
+ path=SpotMarket.EXCHANGE_INFO,
41
+ query=payload,
42
+ signed=False,
43
+ )
44
+ return res
45
+
46
+ async def get_spot_orderbook(
47
+ self,
48
+ product_symbol: str,
49
+ limit: int | None = None,
50
+ ) -> dict:
51
+ """
52
+ Get spot order book data.
53
+
54
+ Args:
55
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
56
+ limit: Number of orders to return (5, 10, 20, 50, 100, 500, 1000, 5000)
57
+
58
+ Returns:
59
+ dict: Order book data including bids and asks
60
+ """
61
+ payload = {
62
+ "symbol": self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol),
63
+ }
64
+ if limit is not None:
65
+ payload["limit"] = str(limit)
66
+ res = await self._request(
67
+ method="GET",
68
+ path=SpotMarket.ORDERBOOK,
69
+ query=payload,
70
+ signed=False,
71
+ )
72
+ return res
73
+
74
+ async def get_spot_trades(
75
+ self,
76
+ product_symbol: str,
77
+ limit: int | None = None,
78
+ ) -> dict:
79
+ """
80
+ Get recent spot trades.
81
+
82
+ Args:
83
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
84
+ limit: Number of trades to return (max 1000)
85
+
86
+ Returns:
87
+ dict: Recent trade data
88
+ """
89
+ payload = {
90
+ "symbol": self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol),
91
+ }
92
+ if limit is not None:
93
+ payload["limit"] = str(limit)
94
+
95
+ res = await self._request(
96
+ method="GET",
97
+ path=SpotMarket.TRADES,
98
+ query=payload,
99
+ signed=False,
100
+ )
101
+ return res
102
+
103
+ async def get_spot_price(
104
+ self,
105
+ product_symbol: str | None = None,
106
+ product_symbols: list | None = None,
107
+ ) -> dict:
108
+ """
109
+ Get spot price information.
110
+
111
+ Args:
112
+ product_symbol: Single trading pair symbol (e.g., 'BTCUSDT')
113
+ product_symbols: List of trading pair symbols
114
+
115
+ Returns:
116
+ dict: Price information
117
+ """
118
+ payload = {}
119
+ if product_symbol is not None:
120
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
121
+ if product_symbols is not None:
122
+ formatted_symbols = [
123
+ self.ptm.get_exchange_symbol(Common.BINANCE, symbol) for symbol in product_symbols
124
+ ]
125
+ payload["symbols"] = str(formatted_symbols).replace("'", '"')
126
+
127
+ res = await self._request(
128
+ method="GET",
129
+ path=SpotMarket.PRICE,
130
+ query=payload,
131
+ signed=False,
132
+ )
133
+ return res
134
+
135
+ async def get_klines(
136
+ self,
137
+ product_symbol: str,
138
+ interval: str,
139
+ start_time: int | None = None,
140
+ limit: int | None = None,
141
+ ) -> dict:
142
+ """
143
+ Get kline/candlestick data.
144
+
145
+ Args:
146
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
147
+ interval: Time interval (1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M)
148
+ start_time: Start time in milliseconds
149
+ limit: Number of klines to return (max 1000)
150
+
151
+ Returns:
152
+ dict: Kline data including OHLCV
153
+ """
154
+ payload = {
155
+ "symbol": self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol),
156
+ "interval": interval,
157
+ }
158
+ if start_time is not None:
159
+ payload["startTime"] = str(start_time)
160
+ if limit is not None:
161
+ payload["limit"] = str(limit)
162
+
163
+ res = await self._request(
164
+ method="GET",
165
+ path=SpotMarket.KLINES
166
+ if self.ptm.get_exchange_type(Common.BINANCE, product_symbol=product_symbol)
167
+ == BinanceProductType.SPOT
168
+ else FuturesMarket.KLINES,
169
+ query=payload,
170
+ signed=False,
171
+ )
172
+ return res
173
+
174
+ async def get_futures_exchange_info(
175
+ self,
176
+ ) -> dict:
177
+ """
178
+ Get futures exchange information.
179
+
180
+ Returns:
181
+ dict: Futures exchange information including symbols and trading rules
182
+ """
183
+ res = await self._request(
184
+ method="GET",
185
+ path=FuturesMarket.EXCHANGE_INFO,
186
+ query={},
187
+ signed=False,
188
+ )
189
+ return res
190
+
191
+ async def get_futures_ticker(
192
+ self,
193
+ product_symbol: str | None = None,
194
+ ) -> dict:
195
+ """
196
+ Get futures ticker information.
197
+
198
+ Args:
199
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
200
+
201
+ Returns:
202
+ dict: Futures ticker data including price and volume
203
+ """
204
+ payload = {}
205
+ if product_symbol is not None:
206
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
207
+
208
+ res = await self._request(
209
+ method="GET",
210
+ path=FuturesMarket.BOOK_TICKER,
211
+ query=payload,
212
+ signed=False,
213
+ )
214
+ return res
215
+
216
+ async def get_futures_premium_index(
217
+ self,
218
+ product_symbol: str | None = None,
219
+ ) -> dict:
220
+ """
221
+ Get futures premium index.
222
+
223
+ Args:
224
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
225
+
226
+ Returns:
227
+ dict: Premium index data
228
+ """
229
+ payload = {}
230
+ if product_symbol is not None:
231
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
232
+
233
+ res = await self._request(
234
+ method="GET",
235
+ path=FuturesMarket.PREMIUM_INDEX,
236
+ query=payload,
237
+ signed=False,
238
+ )
239
+ return res
240
+
241
+ async def get_futures_funding_rate(
242
+ self,
243
+ product_symbol: str | None = None,
244
+ startTime: int | None = None,
245
+ endTime: int | None = None,
246
+ limit: int | None = None,
247
+ ) -> dict:
248
+ """
249
+ Get futures funding rate history.
250
+
251
+ Args:
252
+ product_symbol: Trading pair symbol (e.g., 'BTCUSDT')
253
+ startTime: Start time in milliseconds
254
+ endTime: End time in milliseconds
255
+ limit: Number of records to return (max 1000)
256
+
257
+ Returns:
258
+ dict: Funding rate history data
259
+ """
260
+ payload = {}
261
+ if product_symbol is not None:
262
+ payload["symbol"] = self.ptm.get_exchange_symbol(Common.BINANCE, product_symbol)
263
+ if startTime is not None:
264
+ payload["startTime"] = startTime
265
+ if endTime is not None:
266
+ payload["endTime"] = endTime
267
+ if limit is not None:
268
+ payload["limit"] = limit
269
+
270
+ res = await self._request(
271
+ method="GET",
272
+ path=FuturesMarket.FUNDING_RATE_HISTORY,
273
+ query=payload,
274
+ signed=False,
275
+ )
276
+ return res