crypticorn-utils 0.1.1rc1__py3-none-any.whl → 1.0.0rc1__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.
- crypticorn_utils/__init__.py +50 -16
- crypticorn_utils/_migration.py +2 -1
- crypticorn_utils/ansi_colors.py +1 -4
- crypticorn_utils/auth.py +112 -54
- crypticorn_utils/enums.py +3 -122
- crypticorn_utils/errors.py +3 -893
- crypticorn_utils/exceptions.py +244 -139
- crypticorn_utils/logging.py +5 -19
- crypticorn_utils/metrics.py +1 -2
- crypticorn_utils/middleware.py +7 -40
- crypticorn_utils/utils.py +1 -52
- crypticorn_utils/warnings.py +0 -28
- {crypticorn_utils-0.1.1rc1.dist-info → crypticorn_utils-1.0.0rc1.dist-info}/METADATA +13 -12
- crypticorn_utils-1.0.0rc1.dist-info/RECORD +21 -0
- {crypticorn_utils-0.1.1rc1.dist-info → crypticorn_utils-1.0.0rc1.dist-info}/licenses/LICENSE +1 -1
- crypticorn_utils/cli/__init__.py +0 -4
- crypticorn_utils/cli/__main__.py +0 -17
- crypticorn_utils/cli/init.py +0 -127
- crypticorn_utils/cli/templates/auth.py +0 -33
- crypticorn_utils/cli/version.py +0 -8
- crypticorn_utils/mixins.py +0 -68
- crypticorn_utils/openapi.py +0 -10
- crypticorn_utils/router/admin_router.py +0 -117
- crypticorn_utils/router/status_router.py +0 -36
- crypticorn_utils-0.1.1rc1.dist-info/RECORD +0 -30
- /crypticorn_utils/{cli/templates/__init__.py → py.typed} +0 -0
- {crypticorn_utils-0.1.1rc1.dist-info → crypticorn_utils-1.0.0rc1.dist-info}/WHEEL +0 -0
- {crypticorn_utils-0.1.1rc1.dist-info → crypticorn_utils-1.0.0rc1.dist-info}/entry_points.txt +0 -0
- {crypticorn_utils-0.1.1rc1.dist-info → crypticorn_utils-1.0.0rc1.dist-info}/top_level.txt +0 -0
crypticorn_utils/__init__.py
CHANGED
@@ -1,16 +1,50 @@
|
|
1
|
-
from crypticorn_utils.
|
2
|
-
from crypticorn_utils.
|
3
|
-
from crypticorn_utils.
|
4
|
-
from crypticorn_utils.
|
5
|
-
from crypticorn_utils.
|
6
|
-
from crypticorn_utils.
|
7
|
-
from crypticorn_utils.
|
8
|
-
from crypticorn_utils.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
from crypticorn_utils.auth import AuthHandler
|
2
|
+
from crypticorn_utils.decorators import partial_model
|
3
|
+
from crypticorn_utils.enums import ApiEnv, BaseUrl, Exchange, MarketType
|
4
|
+
from crypticorn_utils.errors import ErrorLevel, ErrorType
|
5
|
+
from crypticorn_utils.exceptions import BaseError, ExceptionHandler, ExceptionType
|
6
|
+
from crypticorn_utils.logging import configure_logging, disable_logging
|
7
|
+
from crypticorn_utils.middleware import add_middleware
|
8
|
+
from crypticorn_utils.pagination import (
|
9
|
+
FilterParams,
|
10
|
+
HeavyPageSortFilterParams,
|
11
|
+
HeavyPaginationParams,
|
12
|
+
PageFilterParams,
|
13
|
+
PageSortFilterParams,
|
14
|
+
PageSortParams,
|
15
|
+
PaginatedResponse,
|
16
|
+
PaginationParams,
|
17
|
+
SortFilterParams,
|
18
|
+
SortParams,
|
19
|
+
)
|
20
|
+
from crypticorn_utils.utils import datetime_to_timestamp, gen_random_id, optional_import
|
21
|
+
|
22
|
+
__all__ = [
|
23
|
+
"AuthHandler",
|
24
|
+
"partial_model",
|
25
|
+
"Exchange",
|
26
|
+
"MarketType",
|
27
|
+
"ApiEnv",
|
28
|
+
"BaseUrl",
|
29
|
+
"ErrorType",
|
30
|
+
"ErrorLevel",
|
31
|
+
"BaseError",
|
32
|
+
"ExceptionHandler",
|
33
|
+
"ExceptionType",
|
34
|
+
"configure_logging",
|
35
|
+
"disable_logging",
|
36
|
+
"add_middleware",
|
37
|
+
"PaginatedResponse",
|
38
|
+
"PaginationParams",
|
39
|
+
"HeavyPaginationParams",
|
40
|
+
"SortParams",
|
41
|
+
"FilterParams",
|
42
|
+
"SortFilterParams",
|
43
|
+
"PageFilterParams",
|
44
|
+
"PageSortParams",
|
45
|
+
"PageSortFilterParams",
|
46
|
+
"HeavyPageSortFilterParams",
|
47
|
+
"gen_random_id",
|
48
|
+
"datetime_to_timestamp",
|
49
|
+
"optional_import",
|
50
|
+
]
|
crypticorn_utils/_migration.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# This file is used to check if the crypticorn version is greater than 2.18
|
2
2
|
# This is to be compatible with this new utils library
|
3
|
+
# otherwise prometheus reqisters metrics twice, resulting in an exception
|
3
4
|
|
4
5
|
import importlib.metadata
|
5
6
|
from importlib.metadata import PackageNotFoundError
|
@@ -9,4 +10,4 @@ try:
|
|
9
10
|
parts = crypticorn_version.split(".")
|
10
11
|
has_migrated = parts[0] >= "2" and parts[1] > "18"
|
11
12
|
except PackageNotFoundError:
|
12
|
-
has_migrated =
|
13
|
+
has_migrated = True
|
crypticorn_utils/ansi_colors.py
CHANGED
crypticorn_utils/auth.py
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
import json
|
2
|
+
from enum import StrEnum
|
2
3
|
from typing import Union
|
3
4
|
|
4
5
|
from crypticorn.auth import AuthClient, Configuration, Verify200Response
|
5
6
|
from crypticorn.auth.client.exceptions import ApiException
|
6
|
-
from crypticorn_utils.enums import
|
7
|
-
from crypticorn_utils.exceptions import
|
8
|
-
|
7
|
+
from crypticorn_utils.enums import BaseUrl
|
8
|
+
from crypticorn_utils.exceptions import (
|
9
|
+
BaseError,
|
10
|
+
ErrorLevel,
|
11
|
+
ErrorType,
|
12
|
+
ExceptionHandler,
|
13
|
+
)
|
14
|
+
from fastapi import Depends, HTTPException, Query, status
|
9
15
|
from fastapi.security import (
|
10
16
|
APIKeyHeader,
|
11
17
|
HTTPAuthorizationCredentials,
|
@@ -16,6 +22,79 @@ from fastapi.security import (
|
|
16
22
|
)
|
17
23
|
from typing_extensions import Annotated
|
18
24
|
|
25
|
+
|
26
|
+
class AuthErrorCodes(StrEnum):
|
27
|
+
INVALID_API_KEY = "invalid_api_key"
|
28
|
+
EXPIRED_API_KEY = "expired_api_key"
|
29
|
+
INVALID_BEARER = "invalid_bearer"
|
30
|
+
EXPIRED_BEARER = "expired_bearer"
|
31
|
+
INVALID_BASIC_AUTH = "invalid_basic_auth"
|
32
|
+
NO_CREDENTIALS = "no_credentials"
|
33
|
+
INSUFFICIENT_SCOPES = "insufficient_scopes"
|
34
|
+
UNKNOWN_ERROR = "unknown_error"
|
35
|
+
|
36
|
+
|
37
|
+
class AuthError(BaseError):
|
38
|
+
INVALID_API_KEY = (
|
39
|
+
AuthErrorCodes.INVALID_API_KEY,
|
40
|
+
ErrorType.USER_ERROR,
|
41
|
+
ErrorLevel.ERROR,
|
42
|
+
status.HTTP_401_UNAUTHORIZED,
|
43
|
+
status.WS_1008_POLICY_VIOLATION,
|
44
|
+
)
|
45
|
+
INVALID_BASIC_AUTH = (
|
46
|
+
AuthErrorCodes.INVALID_BASIC_AUTH,
|
47
|
+
ErrorType.USER_ERROR,
|
48
|
+
ErrorLevel.ERROR,
|
49
|
+
status.HTTP_401_UNAUTHORIZED,
|
50
|
+
status.WS_1008_POLICY_VIOLATION,
|
51
|
+
)
|
52
|
+
INVALID_BEARER = (
|
53
|
+
AuthErrorCodes.INVALID_BEARER,
|
54
|
+
ErrorType.USER_ERROR,
|
55
|
+
ErrorLevel.ERROR,
|
56
|
+
status.HTTP_401_UNAUTHORIZED,
|
57
|
+
status.WS_1008_POLICY_VIOLATION,
|
58
|
+
)
|
59
|
+
EXPIRED_API_KEY = (
|
60
|
+
AuthErrorCodes.EXPIRED_API_KEY,
|
61
|
+
ErrorType.USER_ERROR,
|
62
|
+
ErrorLevel.ERROR,
|
63
|
+
status.HTTP_401_UNAUTHORIZED,
|
64
|
+
status.WS_1008_POLICY_VIOLATION,
|
65
|
+
)
|
66
|
+
EXPIRED_BEARER = (
|
67
|
+
AuthErrorCodes.EXPIRED_BEARER,
|
68
|
+
ErrorType.USER_ERROR,
|
69
|
+
ErrorLevel.ERROR,
|
70
|
+
status.HTTP_401_UNAUTHORIZED,
|
71
|
+
status.WS_1008_POLICY_VIOLATION,
|
72
|
+
)
|
73
|
+
NO_CREDENTIALS = (
|
74
|
+
AuthErrorCodes.NO_CREDENTIALS,
|
75
|
+
ErrorType.USER_ERROR,
|
76
|
+
ErrorLevel.ERROR,
|
77
|
+
status.HTTP_401_UNAUTHORIZED,
|
78
|
+
status.WS_1008_POLICY_VIOLATION,
|
79
|
+
)
|
80
|
+
INSUFFICIENT_SCOPES = (
|
81
|
+
AuthErrorCodes.INSUFFICIENT_SCOPES,
|
82
|
+
ErrorType.USER_ERROR,
|
83
|
+
ErrorLevel.ERROR,
|
84
|
+
status.HTTP_403_FORBIDDEN,
|
85
|
+
status.WS_1008_POLICY_VIOLATION,
|
86
|
+
)
|
87
|
+
UNKNOWN_ERROR = (
|
88
|
+
AuthErrorCodes.UNKNOWN_ERROR,
|
89
|
+
ErrorType.SERVER_ERROR,
|
90
|
+
ErrorLevel.ERROR,
|
91
|
+
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
92
|
+
status.WS_1011_INTERNAL_ERROR,
|
93
|
+
)
|
94
|
+
|
95
|
+
|
96
|
+
handler = ExceptionHandler(callback=AuthError.from_identifier)
|
97
|
+
|
19
98
|
AUTHENTICATE_HEADER = "WWW-Authenticate"
|
20
99
|
BEARER_AUTH_SCHEME = "Bearer"
|
21
100
|
APIKEY_AUTH_SCHEME = "X-API-Key"
|
@@ -80,19 +159,17 @@ class AuthHandler:
|
|
80
159
|
return await self.client.login.verify_basic_auth(basic.username, basic.password)
|
81
160
|
|
82
161
|
async def _validate_scopes(
|
83
|
-
self, api_scopes: list[
|
84
|
-
) ->
|
162
|
+
self, api_scopes: list[str], user_scopes: list[str]
|
163
|
+
) -> None:
|
85
164
|
"""
|
86
165
|
Checks if the required scopes are a subset of the user scopes.
|
87
166
|
"""
|
88
167
|
if not set(api_scopes).issubset(user_scopes):
|
89
|
-
raise
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
+ ")",
|
95
|
-
),
|
168
|
+
raise handler.build_exception(
|
169
|
+
AuthErrorCodes.INSUFFICIENT_SCOPES,
|
170
|
+
"Insufficient scopes to access this resource (required: "
|
171
|
+
+ ", ".join(api_scopes)
|
172
|
+
+ ")",
|
96
173
|
)
|
97
174
|
|
98
175
|
async def _extract_message(self, e: ApiException) -> str:
|
@@ -119,33 +196,24 @@ class AuthHandler:
|
|
119
196
|
# Unfortunately, we cannot share the error messages defined in python/crypticorn/common/errors.py with the typescript client
|
120
197
|
message = await self._extract_message(e)
|
121
198
|
if message == "Invalid API key":
|
122
|
-
error =
|
199
|
+
error = AuthErrorCodes.INVALID_API_KEY
|
123
200
|
elif message == "API key expired":
|
124
|
-
error =
|
201
|
+
error = AuthErrorCodes.EXPIRED_API_KEY
|
125
202
|
elif message == "jwt expired":
|
126
|
-
error =
|
203
|
+
error = AuthErrorCodes.EXPIRED_BEARER
|
127
204
|
elif message == "Invalid basic authentication credentials":
|
128
|
-
error =
|
205
|
+
error = AuthErrorCodes.INVALID_BASIC_AUTH
|
129
206
|
else:
|
130
207
|
message = "Invalid bearer token"
|
131
208
|
error = (
|
132
|
-
|
209
|
+
AuthErrorCodes.INVALID_BEARER
|
133
210
|
) # jwt malformed, jwt not active (https://www.npmjs.com/package/jsonwebtoken#errors--codes)
|
134
|
-
return
|
135
|
-
|
136
|
-
error=error,
|
137
|
-
message=message,
|
138
|
-
),
|
139
|
-
)
|
211
|
+
return handler.build_exception(error, message)
|
212
|
+
|
140
213
|
elif isinstance(e, HTTPException):
|
141
214
|
return e
|
142
215
|
else:
|
143
|
-
return
|
144
|
-
content=ExceptionContent(
|
145
|
-
error=ApiError.UNKNOWN_ERROR,
|
146
|
-
message=str(e),
|
147
|
-
),
|
148
|
-
)
|
216
|
+
return handler.build_exception(AuthErrorCodes.UNKNOWN_ERROR, str(e))
|
149
217
|
|
150
218
|
async def api_key_auth(
|
151
219
|
self,
|
@@ -162,11 +230,9 @@ class AuthHandler:
|
|
162
230
|
bearer=None, api_key=api_key, basic=None, sec=sec
|
163
231
|
)
|
164
232
|
except HTTPException as e:
|
165
|
-
raise
|
166
|
-
|
167
|
-
|
168
|
-
message=e.detail.get("message"),
|
169
|
-
),
|
233
|
+
raise handler.build_exception(
|
234
|
+
e.detail.get("code"),
|
235
|
+
e.detail.get("message"),
|
170
236
|
headers={AUTHENTICATE_HEADER: APIKEY_AUTH_SCHEME},
|
171
237
|
)
|
172
238
|
|
@@ -188,11 +254,9 @@ class AuthHandler:
|
|
188
254
|
bearer=bearer, api_key=None, basic=None, sec=sec
|
189
255
|
)
|
190
256
|
except HTTPException as e:
|
191
|
-
raise
|
192
|
-
|
193
|
-
|
194
|
-
message=e.detail.get("message"),
|
195
|
-
),
|
257
|
+
raise handler.build_exception(
|
258
|
+
e.detail.get("code"),
|
259
|
+
e.detail.get("message"),
|
196
260
|
headers={AUTHENTICATE_HEADER: BEARER_AUTH_SCHEME},
|
197
261
|
)
|
198
262
|
|
@@ -208,11 +272,9 @@ class AuthHandler:
|
|
208
272
|
basic=credentials, bearer=None, api_key=None, sec=None
|
209
273
|
)
|
210
274
|
except HTTPException as e:
|
211
|
-
raise
|
212
|
-
|
213
|
-
|
214
|
-
message=e.detail.get("message"),
|
215
|
-
),
|
275
|
+
raise handler.build_exception(
|
276
|
+
e.detail.get("code"),
|
277
|
+
e.detail.get("message"),
|
216
278
|
headers={AUTHENTICATE_HEADER: BASIC_AUTH_SCHEME},
|
217
279
|
)
|
218
280
|
|
@@ -235,11 +297,9 @@ class AuthHandler:
|
|
235
297
|
basic=None, bearer=bearer, api_key=api_key, sec=sec
|
236
298
|
)
|
237
299
|
except HTTPException as e:
|
238
|
-
raise
|
239
|
-
|
240
|
-
|
241
|
-
message=e.detail.get("message"),
|
242
|
-
),
|
300
|
+
raise handler.build_exception(
|
301
|
+
e.detail.get("code"),
|
302
|
+
e.detail.get("message"),
|
243
303
|
headers={
|
244
304
|
AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}"
|
245
305
|
},
|
@@ -287,11 +347,9 @@ class AuthHandler:
|
|
287
347
|
if last_error:
|
288
348
|
raise last_error
|
289
349
|
else:
|
290
|
-
raise
|
291
|
-
|
292
|
-
|
293
|
-
message="No credentials provided. Check the WWW-Authenticate header for the available authentication methods.",
|
294
|
-
),
|
350
|
+
raise handler.build_exception(
|
351
|
+
AuthErrorCodes.NO_CREDENTIALS,
|
352
|
+
"No credentials provided. Check the WWW-Authenticate header for the available authentication methods.",
|
295
353
|
headers={
|
296
354
|
AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}, {BASIC_AUTH_SCHEME}"
|
297
355
|
},
|
crypticorn_utils/enums.py
CHANGED
@@ -1,108 +1,9 @@
|
|
1
1
|
"""Defines common enumerations used throughout the codebase for type safety and consistency."""
|
2
2
|
|
3
|
-
|
4
|
-
from enum import StrEnum
|
5
|
-
except ImportError:
|
6
|
-
from strenum import StrEnum
|
3
|
+
from enum import StrEnum
|
7
4
|
|
8
|
-
import warnings
|
9
5
|
|
10
|
-
|
11
|
-
from crypticorn_utils.warnings import CrypticornDeprecatedSince215
|
12
|
-
|
13
|
-
|
14
|
-
class Scope(StrEnum):
|
15
|
-
"""
|
16
|
-
The permission scopes for the API.
|
17
|
-
"""
|
18
|
-
|
19
|
-
# If you update anything here, also update the scopes in the auth-service repository
|
20
|
-
|
21
|
-
WRITE_ADMIN = "write:admin"
|
22
|
-
READ_ADMIN = "read:admin"
|
23
|
-
|
24
|
-
# Scopes that can be purchased - these actually exist in the jwt token
|
25
|
-
READ_PREDICTIONS = "read:predictions"
|
26
|
-
READ_DEX_SIGNALS = "read:dex:signals"
|
27
|
-
|
28
|
-
# Hive scopes
|
29
|
-
READ_HIVE_MODEL = "read:hive:model"
|
30
|
-
READ_HIVE_DATA = "read:hive:data"
|
31
|
-
WRITE_HIVE_MODEL = "write:hive:model"
|
32
|
-
|
33
|
-
# Trade scopes
|
34
|
-
READ_TRADE_BOTS = "read:trade:bots"
|
35
|
-
WRITE_TRADE_BOTS = "write:trade:bots"
|
36
|
-
READ_TRADE_EXCHANGEKEYS = "read:trade:exchangekeys"
|
37
|
-
WRITE_TRADE_EXCHANGEKEYS = "write:trade:exchangekeys"
|
38
|
-
READ_TRADE_ORDERS = "read:trade:orders"
|
39
|
-
READ_TRADE_ACTIONS = "read:trade:actions"
|
40
|
-
WRITE_TRADE_ACTIONS = "write:trade:actions"
|
41
|
-
READ_TRADE_EXCHANGES = "read:trade:exchanges"
|
42
|
-
READ_TRADE_FUTURES = "read:trade:futures"
|
43
|
-
WRITE_TRADE_FUTURES = "write:trade:futures"
|
44
|
-
READ_TRADE_NOTIFICATIONS = "read:trade:notifications"
|
45
|
-
WRITE_TRADE_NOTIFICATIONS = "write:trade:notifications"
|
46
|
-
READ_TRADE_STRATEGIES = "read:trade:strategies"
|
47
|
-
WRITE_TRADE_STRATEGIES = "write:trade:strategies"
|
48
|
-
|
49
|
-
# Payment scopes
|
50
|
-
READ_PAY_PAYMENTS = "read:pay:payments"
|
51
|
-
READ_PAY_PRODUCTS = "read:pay:products"
|
52
|
-
WRITE_PAY_PRODUCTS = "write:pay:products"
|
53
|
-
READ_PAY_NOW = "read:pay:now"
|
54
|
-
WRITE_PAY_NOW = "write:pay:now"
|
55
|
-
WRITE_PAY_COUPONS = "write:pay:coupons"
|
56
|
-
READ_PAY_COUPONS = "read:pay:coupons"
|
57
|
-
|
58
|
-
# Metrics scopes
|
59
|
-
READ_METRICS_MARKETCAP = "read:metrics:marketcap"
|
60
|
-
READ_METRICS_INDICATORS = "read:metrics:indicators"
|
61
|
-
READ_METRICS_EXCHANGES = "read:metrics:exchanges"
|
62
|
-
READ_METRICS_TOKENS = "read:metrics:tokens"
|
63
|
-
READ_METRICS_MARKETS = "read:metrics:markets"
|
64
|
-
|
65
|
-
# Sentiment scopes
|
66
|
-
READ_SENTIMENT = "read:sentiment"
|
67
|
-
|
68
|
-
# Klines scopes
|
69
|
-
READ_KLINES = "read:klines"
|
70
|
-
|
71
|
-
@classmethod
|
72
|
-
def admin_scopes(cls) -> list["Scope"]:
|
73
|
-
"""Scopes that are only available to admins."""
|
74
|
-
return [
|
75
|
-
cls.WRITE_TRADE_STRATEGIES,
|
76
|
-
cls.WRITE_PAY_PRODUCTS,
|
77
|
-
cls.WRITE_PAY_COUPONS,
|
78
|
-
cls.WRITE_ADMIN,
|
79
|
-
cls.READ_ADMIN,
|
80
|
-
]
|
81
|
-
|
82
|
-
@classmethod
|
83
|
-
def internal_scopes(cls) -> list["Scope"]:
|
84
|
-
"""Scopes that are only available to internal services."""
|
85
|
-
return [
|
86
|
-
cls.WRITE_TRADE_ACTIONS,
|
87
|
-
]
|
88
|
-
|
89
|
-
@classmethod
|
90
|
-
def purchaseable_scopes(cls) -> list["Scope"]:
|
91
|
-
"""Scopes that can be purchased."""
|
92
|
-
return [
|
93
|
-
cls.READ_PREDICTIONS,
|
94
|
-
cls.READ_METRICS_MARKETCAP,
|
95
|
-
cls.READ_METRICS_INDICATORS,
|
96
|
-
cls.READ_METRICS_EXCHANGES,
|
97
|
-
cls.READ_METRICS_TOKENS,
|
98
|
-
cls.READ_METRICS_MARKETS,
|
99
|
-
cls.READ_KLINES,
|
100
|
-
cls.READ_SENTIMENT,
|
101
|
-
cls.READ_DEX_SIGNALS,
|
102
|
-
]
|
103
|
-
|
104
|
-
|
105
|
-
class Exchange(ValidateEnumMixin, StrEnum):
|
6
|
+
class Exchange(StrEnum):
|
106
7
|
"""All exchanges used in the crypticorn ecosystem. Refer to the APIs for support for a specific usecase (data, trading, etc.)."""
|
107
8
|
|
108
9
|
KUCOIN = "kucoin"
|
@@ -115,26 +16,7 @@ class Exchange(ValidateEnumMixin, StrEnum):
|
|
115
16
|
BITSTAMP = "bitstamp"
|
116
17
|
|
117
18
|
|
118
|
-
class
|
119
|
-
"""All exchanges we are using, including public (Exchange)"""
|
120
|
-
|
121
|
-
KUCOIN = "kucoin"
|
122
|
-
BINGX = "bingx"
|
123
|
-
BINANCE = "binance"
|
124
|
-
BYBIT = "bybit"
|
125
|
-
HYPERLIQUID = "hyperliquid"
|
126
|
-
BITGET = "bitget"
|
127
|
-
|
128
|
-
@classmethod
|
129
|
-
def __getattr__(cls, name):
|
130
|
-
warnings.warn(
|
131
|
-
"The `InternalExchange` enum is deprecated; use `Exchange` instead.",
|
132
|
-
category=CrypticornDeprecatedSince215,
|
133
|
-
)
|
134
|
-
return super().__getattr__(name)
|
135
|
-
|
136
|
-
|
137
|
-
class MarketType(ValidateEnumMixin, StrEnum):
|
19
|
+
class MarketType(StrEnum):
|
138
20
|
"""
|
139
21
|
Market types
|
140
22
|
"""
|
@@ -171,4 +53,3 @@ class BaseUrl(StrEnum):
|
|
171
53
|
return cls.LOCAL
|
172
54
|
elif env == ApiEnv.DOCKER:
|
173
55
|
return cls.DOCKER
|
174
|
-
|