crypticorn 2.17.0rc6__py3-none-any.whl → 2.18.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.
- crypticorn/auth/client/api/admin_api.py +2 -0
- crypticorn/auth/client/api/auth_api.py +1417 -545
- crypticorn/auth/client/api/service_api.py +4 -0
- crypticorn/auth/client/api/user_api.py +4 -0
- crypticorn/auth/client/api/wallet_api.py +4 -0
- crypticorn/auth/client/api_client.py +5 -0
- crypticorn/auth/client/configuration.py +2 -2
- crypticorn/auth/client/models/add_wallet_request.py +1 -1
- crypticorn/auth/client/models/authorize_user_request.py +1 -1
- crypticorn/auth/client/models/create_api_key_request.py +3 -3
- crypticorn/auth/client/models/create_user_request.py +1 -1
- crypticorn/auth/client/models/get_api_keys200_response_inner.py +3 -3
- crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py +1 -1
- crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet.py +1 -1
- crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet_vesting_wallets_inner.py +1 -1
- crypticorn/auth/client/models/list_wallets200_response_data_inner.py +1 -1
- crypticorn/auth/client/models/logout_default_response.py +1 -1
- crypticorn/auth/client/models/oauth_callback200_response_user.py +1 -1
- crypticorn/auth/client/models/refresh_token_info200_response_user_session.py +1 -1
- crypticorn/auth/client/models/rotate_tokens200_response.py +1 -1
- crypticorn/auth/client/models/token_info200_response.py +1 -1
- crypticorn/auth/client/models/update_user_request.py +1 -1
- crypticorn/auth/client/models/user_by_username200_response.py +1 -1
- crypticorn/auth/client/models/verify200_response.py +1 -1
- crypticorn/auth/client/models/verify_email200_response_auth.py +1 -1
- crypticorn/auth/client/models/verify_email200_response_auth_auth.py +1 -1
- crypticorn/auth/client/models/whoami200_response.py +1 -1
- crypticorn/common/__init__.py +11 -11
- crypticorn/common/auth.py +109 -57
- crypticorn/common/decorators.py +1 -1
- crypticorn/common/enums.py +1 -0
- crypticorn/common/errors.py +7 -21
- crypticorn/common/exceptions.py +33 -17
- crypticorn/common/logging.py +5 -4
- crypticorn/common/metrics.py +17 -5
- crypticorn/common/middleware.py +61 -12
- crypticorn/common/mixins.py +2 -1
- crypticorn/common/pagination.py +3 -2
- crypticorn/common/router/admin_router.py +17 -6
- crypticorn/common/router/status_router.py +3 -29
- crypticorn/common/utils.py +6 -6
- crypticorn/common/warnings.py +1 -0
- crypticorn/dex/client/api/admin_api.py +3 -0
- crypticorn/dex/client/api/signals_api.py +27 -23
- crypticorn/dex/client/api/status_api.py +3 -0
- crypticorn/dex/client/api_client.py +5 -0
- crypticorn/dex/client/configuration.py +2 -2
- crypticorn/dex/client/models/exception_detail.py +1 -1
- crypticorn/dex/client/models/paginated_response_signal_with_token.py +1 -1
- crypticorn/dex/client/models/signal_overview_stats.py +4 -2
- crypticorn/dex/client/models/signal_volume.py +4 -4
- crypticorn/dex/client/models/signal_with_token.py +2 -2
- crypticorn/dex/client/models/token_detail.py +1 -1
- crypticorn/klines/main.py +1 -1
- crypticorn/metrics/main.py +1 -1
- crypticorn/trade/client/__init__.py +1 -7
- crypticorn/trade/client/api/admin_api.py +0 -402
- crypticorn/trade/client/api/trading_actions_api.py +86 -315
- crypticorn/trade/client/models/__init__.py +1 -7
- crypticorn/trade/client/models/actions_count.py +88 -0
- crypticorn/trade/client/models/api_error_identifier.py +1 -0
- crypticorn/trade/client/models/exchange_key.py +1 -1
- crypticorn/trade/client/models/exchange_key_balance.py +1 -1
- crypticorn/trade/client/models/execution_ids.py +1 -1
- crypticorn/trade/client/models/notification_create.py +1 -1
- crypticorn/trade/client/models/post_futures_action.py +1 -1
- crypticorn/trade/client/models/spot_balance.py +6 -7
- crypticorn/trade/client/models/tpsl.py +4 -19
- crypticorn/trade/client/models/tpsl_create.py +6 -19
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/METADATA +1 -1
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/RECORD +75 -77
- crypticorn/trade/client/models/paginated_response_union_futures_trading_action_spot_trading_action.py +0 -141
- crypticorn/trade/client/models/paginated_response_union_futures_trading_action_spot_trading_action_data_inner.py +0 -165
- crypticorn/trade/client/models/spot_trading_action.py +0 -207
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/WHEEL +0 -0
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/entry_points.txt +0 -0
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/licenses/LICENSE +0 -0
- {crypticorn-2.17.0rc6.dist-info → crypticorn-2.18.0.dist-info}/top_level.txt +0 -0
crypticorn/common/errors.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
"""Comprehensive error handling system defining various API error types, HTTP exceptions, and error content structures."""
|
2
2
|
|
3
3
|
from enum import Enum
|
4
|
-
|
4
|
+
|
5
5
|
from crypticorn.common.mixins import ApiErrorFallback
|
6
|
+
from fastapi import status
|
6
7
|
|
7
8
|
try:
|
8
9
|
from enum import StrEnum
|
@@ -80,8 +81,6 @@ class ApiErrorIdentifier(StrEnum):
|
|
80
81
|
LIQUIDATION_PRICE_VIOLATION = "order_violates_liquidation_price_constraints"
|
81
82
|
MARGIN_MODE_CLASH = "margin_mode_clash"
|
82
83
|
NAME_NOT_UNIQUE = "name_not_unique"
|
83
|
-
NO_API_KEY = "no_api_key"
|
84
|
-
NO_BEARER = "no_bearer"
|
85
84
|
NO_CREDENTIALS = "no_credentials"
|
86
85
|
NOW_API_DOWN = "now_api_down"
|
87
86
|
OBJECT_ALREADY_EXISTS = "object_already_exists"
|
@@ -353,16 +352,6 @@ class ApiError(Enum, metaclass=ApiErrorFallback):
|
|
353
352
|
ApiErrorType.USER_ERROR,
|
354
353
|
ApiErrorLevel.ERROR,
|
355
354
|
)
|
356
|
-
NO_API_KEY = (
|
357
|
-
ApiErrorIdentifier.NO_API_KEY,
|
358
|
-
ApiErrorType.USER_ERROR,
|
359
|
-
ApiErrorLevel.ERROR,
|
360
|
-
)
|
361
|
-
NO_BEARER = (
|
362
|
-
ApiErrorIdentifier.NO_BEARER,
|
363
|
-
ApiErrorType.USER_ERROR,
|
364
|
-
ApiErrorLevel.ERROR,
|
365
|
-
)
|
366
355
|
NO_CREDENTIALS = (
|
367
356
|
ApiErrorIdentifier.NO_CREDENTIALS,
|
368
357
|
ApiErrorType.USER_ERROR,
|
@@ -565,6 +554,11 @@ class ApiError(Enum, metaclass=ApiErrorFallback):
|
|
565
554
|
"""WebSocket status code for the error."""
|
566
555
|
return StatusCodeMapper.get_websocket_code(self)
|
567
556
|
|
557
|
+
@classmethod
|
558
|
+
def from_json(cls, data: dict) -> "ApiError":
|
559
|
+
"""Load an ApiError from a dictionary. Must contain the identifier with the key 'code'."""
|
560
|
+
return next(error for error in cls if error.identifier == data["code"])
|
561
|
+
|
568
562
|
|
569
563
|
class StatusCodeMapper:
|
570
564
|
"""Mapping of API errors to HTTP/Websocket status codes."""
|
@@ -595,14 +589,6 @@ class StatusCodeMapper:
|
|
595
589
|
status.HTTP_401_UNAUTHORIZED,
|
596
590
|
status.WS_1008_POLICY_VIOLATION,
|
597
591
|
),
|
598
|
-
ApiError.NO_API_KEY: (
|
599
|
-
status.HTTP_401_UNAUTHORIZED,
|
600
|
-
status.WS_1008_POLICY_VIOLATION,
|
601
|
-
),
|
602
|
-
ApiError.NO_BEARER: (
|
603
|
-
status.HTTP_401_UNAUTHORIZED,
|
604
|
-
status.WS_1008_POLICY_VIOLATION,
|
605
|
-
),
|
606
592
|
ApiError.INSUFFICIENT_SCOPES: (
|
607
593
|
status.HTTP_403_FORBIDDEN,
|
608
594
|
status.WS_1008_POLICY_VIOLATION,
|
crypticorn/common/exceptions.py
CHANGED
@@ -1,11 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
from
|
1
|
+
import json
|
2
|
+
import logging
|
3
|
+
from typing import Any, Optional
|
4
|
+
|
5
|
+
from crypticorn.common.errors import (
|
6
|
+
ApiError,
|
7
|
+
ApiErrorIdentifier,
|
8
|
+
ApiErrorLevel,
|
9
|
+
ApiErrorType,
|
10
|
+
)
|
11
|
+
from fastapi import FastAPI
|
12
|
+
from fastapi import HTTPException as FastAPIHTTPException
|
13
|
+
from fastapi import Request
|
4
14
|
from fastapi.exceptions import RequestValidationError, ResponseValidationError
|
5
15
|
from fastapi.responses import JSONResponse
|
6
|
-
from
|
7
|
-
import logging
|
8
|
-
import json
|
16
|
+
from pydantic import BaseModel, Field
|
9
17
|
|
10
18
|
try:
|
11
19
|
from enum import StrEnum
|
@@ -66,7 +74,7 @@ class HTTPException(FastAPIHTTPException):
|
|
66
74
|
def __init__(
|
67
75
|
self,
|
68
76
|
content: ExceptionContent,
|
69
|
-
headers: Optional[
|
77
|
+
headers: Optional[dict[str, str]] = None,
|
70
78
|
_type: Optional[_ExceptionType] = _ExceptionType.HTTP,
|
71
79
|
):
|
72
80
|
self.content = content
|
@@ -86,7 +94,7 @@ class WebSocketException(HTTPException):
|
|
86
94
|
"""
|
87
95
|
|
88
96
|
def __init__(
|
89
|
-
self, content: ExceptionContent, headers: Optional[
|
97
|
+
self, content: ExceptionContent, headers: Optional[dict[str, str]] = None
|
90
98
|
):
|
91
99
|
super().__init__(content, headers, _type=_ExceptionType.WEBSOCKET)
|
92
100
|
|
@@ -102,11 +110,13 @@ class WebSocketException(HTTPException):
|
|
102
110
|
async def general_handler(request: Request, exc: Exception) -> JSONResponse:
|
103
111
|
"""Default exception handler for all exceptions."""
|
104
112
|
body = ExceptionContent(message=str(exc), error=ApiError.UNKNOWN_ERROR)
|
113
|
+
http_exc = HTTPException(content=body)
|
105
114
|
res = JSONResponse(
|
106
|
-
status_code=
|
107
|
-
content=
|
115
|
+
status_code=http_exc.status_code,
|
116
|
+
content=http_exc.detail,
|
117
|
+
headers=http_exc.headers,
|
108
118
|
)
|
109
|
-
_logger.error(f"
|
119
|
+
_logger.error(f"General error: {json.loads(res.__dict__.get('body'))}")
|
110
120
|
return res
|
111
121
|
|
112
122
|
|
@@ -115,11 +125,13 @@ async def request_validation_handler(
|
|
115
125
|
) -> JSONResponse:
|
116
126
|
"""Exception handler for all request validation errors."""
|
117
127
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_REQUEST)
|
128
|
+
http_exc = HTTPException(content=body)
|
118
129
|
res = JSONResponse(
|
119
|
-
status_code=
|
120
|
-
content=
|
130
|
+
status_code=http_exc.status_code,
|
131
|
+
content=http_exc.detail,
|
132
|
+
headers=http_exc.headers,
|
121
133
|
)
|
122
|
-
_logger.error(f"
|
134
|
+
_logger.error(f"Request validation error: {json.loads(res.__dict__.get('body'))}")
|
123
135
|
return res
|
124
136
|
|
125
137
|
|
@@ -128,9 +140,11 @@ async def response_validation_handler(
|
|
128
140
|
) -> JSONResponse:
|
129
141
|
"""Exception handler for all response validation errors."""
|
130
142
|
body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_RESPONSE)
|
143
|
+
http_exc = HTTPException(content=body)
|
131
144
|
res = JSONResponse(
|
132
|
-
status_code=
|
133
|
-
content=
|
145
|
+
status_code=http_exc.status_code,
|
146
|
+
content=http_exc.detail,
|
147
|
+
headers=http_exc.headers,
|
134
148
|
)
|
135
149
|
_logger.error(f"Response validation error: {json.loads(res.__dict__.get('body'))}")
|
136
150
|
return res
|
@@ -138,7 +152,9 @@ async def response_validation_handler(
|
|
138
152
|
|
139
153
|
async def http_handler(request: Request, exc: HTTPException) -> JSONResponse:
|
140
154
|
"""Exception handler for HTTPExceptions. It unwraps the HTTPException and returns the detail in a flat JSON response."""
|
141
|
-
res = JSONResponse(
|
155
|
+
res = JSONResponse(
|
156
|
+
status_code=exc.status_code, content=exc.detail, headers=exc.headers
|
157
|
+
)
|
142
158
|
_logger.error(f"HTTP error: {json.loads(res.__dict__.get('body'))}")
|
143
159
|
return res
|
144
160
|
|
crypticorn/common/logging.py
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import logging
|
4
|
-
|
4
|
+
import os
|
5
5
|
import sys
|
6
|
-
from crypticorn.common.mixins import ValidateEnumMixin
|
7
|
-
from crypticorn.common.ansi_colors import AnsiColors as C
|
8
6
|
from datetime import datetime
|
9
|
-
import
|
7
|
+
from logging.handlers import RotatingFileHandler
|
8
|
+
|
9
|
+
from crypticorn.common.ansi_colors import AnsiColors as C
|
10
|
+
from crypticorn.common.mixins import ValidateEnumMixin
|
10
11
|
|
11
12
|
try:
|
12
13
|
from enum import StrEnum
|
crypticorn/common/metrics.py
CHANGED
@@ -1,18 +1,30 @@
|
|
1
1
|
# metrics/registry.py
|
2
|
-
from prometheus_client import Counter, Histogram
|
2
|
+
from prometheus_client import CollectorRegistry, Counter, Histogram
|
3
3
|
|
4
4
|
registry = CollectorRegistry()
|
5
5
|
|
6
|
-
|
6
|
+
HTTP_REQUESTS_COUNT = Counter(
|
7
7
|
"http_requests_total",
|
8
8
|
"Total HTTP requests",
|
9
|
-
["method", "endpoint", "status_code"],
|
9
|
+
["method", "endpoint", "status_code", "auth_type"],
|
10
10
|
registry=registry,
|
11
11
|
)
|
12
12
|
|
13
|
-
|
13
|
+
HTTP_REQUEST_DURATION = Histogram(
|
14
14
|
"http_request_duration_seconds",
|
15
15
|
"HTTP request duration in seconds",
|
16
|
-
["endpoint"],
|
16
|
+
["endpoint", "method"],
|
17
|
+
registry=registry,
|
18
|
+
)
|
19
|
+
|
20
|
+
REQUEST_SIZE = Histogram(
|
21
|
+
"http_request_size_bytes", "Size of HTTP request bodies", ["method", "endpoint"]
|
22
|
+
)
|
23
|
+
|
24
|
+
|
25
|
+
RESPONSE_SIZE = Histogram(
|
26
|
+
"http_response_size_bytes",
|
27
|
+
"Size of HTTP responses",
|
28
|
+
["method", "endpoint"],
|
17
29
|
registry=registry,
|
18
30
|
)
|
crypticorn/common/middleware.py
CHANGED
@@ -1,30 +1,79 @@
|
|
1
1
|
import time
|
2
|
-
|
2
|
+
import warnings
|
3
|
+
from contextlib import asynccontextmanager
|
4
|
+
|
5
|
+
from crypticorn.common.logging import configure_logging
|
6
|
+
from crypticorn.common.metrics import (
|
7
|
+
HTTP_REQUEST_DURATION,
|
8
|
+
HTTP_REQUESTS_COUNT,
|
9
|
+
REQUEST_SIZE,
|
10
|
+
RESPONSE_SIZE,
|
11
|
+
)
|
12
|
+
from crypticorn.common.warnings import CrypticornDeprecatedSince217
|
13
|
+
from fastapi import FastAPI, Request
|
3
14
|
from fastapi.middleware.cors import CORSMiddleware
|
4
15
|
from starlette.middleware.base import BaseHTTPMiddleware
|
5
|
-
from crypticorn.common.logging import configure_logging
|
6
|
-
from contextlib import asynccontextmanager
|
7
16
|
from typing_extensions import deprecated
|
8
|
-
import warnings
|
9
|
-
from crypticorn.common.warnings import CrypticornDeprecatedSince217
|
10
|
-
from crypticorn.common.metrics import http_requests_total, http_request_duration_seconds
|
11
17
|
|
12
18
|
|
13
19
|
class PrometheusMiddleware(BaseHTTPMiddleware):
|
14
|
-
async def dispatch(self, request, call_next):
|
20
|
+
async def dispatch(self, request: Request, call_next):
|
21
|
+
|
22
|
+
if "authorization" in request.headers:
|
23
|
+
auth_type = (
|
24
|
+
request.headers["authorization"].split()[0]
|
25
|
+
if " " in request.headers["authorization"]
|
26
|
+
else "none"
|
27
|
+
)
|
28
|
+
elif "x-api-key" in request.headers:
|
29
|
+
auth_type = "X-API-KEY"
|
30
|
+
else:
|
31
|
+
auth_type = "none"
|
32
|
+
|
33
|
+
try:
|
34
|
+
endpoint = request.get(
|
35
|
+
"route"
|
36
|
+
).path # use /time/{type} instead of dynamic route to avoid high cardinality
|
37
|
+
except Exception:
|
38
|
+
endpoint = request.url.path
|
39
|
+
|
15
40
|
start = time.perf_counter()
|
16
41
|
response = await call_next(request)
|
17
42
|
duration = time.perf_counter() - start
|
18
43
|
|
19
|
-
|
44
|
+
HTTP_REQUESTS_COUNT.labels(
|
20
45
|
method=request.method,
|
21
|
-
endpoint=
|
46
|
+
endpoint=endpoint,
|
22
47
|
status_code=response.status_code,
|
48
|
+
auth_type=auth_type,
|
23
49
|
).inc()
|
24
50
|
|
25
|
-
|
26
|
-
|
27
|
-
|
51
|
+
try:
|
52
|
+
body = await request.body()
|
53
|
+
size = len(body)
|
54
|
+
except Exception:
|
55
|
+
size = 0
|
56
|
+
|
57
|
+
REQUEST_SIZE.labels(
|
58
|
+
method=request.method,
|
59
|
+
endpoint=endpoint,
|
60
|
+
).observe(size)
|
61
|
+
|
62
|
+
try:
|
63
|
+
body = await response.body()
|
64
|
+
size = len(body)
|
65
|
+
except Exception:
|
66
|
+
size = 0
|
67
|
+
|
68
|
+
RESPONSE_SIZE.labels(
|
69
|
+
method=request.method,
|
70
|
+
endpoint=endpoint,
|
71
|
+
).observe(size)
|
72
|
+
|
73
|
+
HTTP_REQUEST_DURATION.labels(
|
74
|
+
endpoint=endpoint,
|
75
|
+
method=request.method,
|
76
|
+
).observe(duration)
|
28
77
|
|
29
78
|
return response
|
30
79
|
|
crypticorn/common/mixins.py
CHANGED
crypticorn/common/pagination.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
"""Utilities for handling paginated API responses, cursor-based pagination, filtering, sorting, etc."""
|
2
2
|
|
3
|
-
from typing import Annotated, Any, Generic, Type, TypeVar, Optional, Literal
|
4
|
-
from pydantic import BaseModel, Field, model_validator
|
5
3
|
import math
|
4
|
+
from typing import Annotated, Any, Generic, Literal, Optional, Type, TypeVar
|
5
|
+
|
6
|
+
from pydantic import BaseModel, Field, model_validator
|
6
7
|
|
7
8
|
T = TypeVar("T")
|
8
9
|
|
@@ -2,19 +2,22 @@
|
|
2
2
|
This module contains the admin router for the API.
|
3
3
|
It provides endpoints for monitoring the server and getting information about the environment.
|
4
4
|
ONLY ALLOW ACCESS TO THIS ROUTER WITH ADMIN SCOPES.
|
5
|
-
>>> app.include_router(admin_router, dependencies=[Security(auth_handler.
|
5
|
+
>>> app.include_router(admin_router, dependencies=[Security(auth_handler.full_auth, scopes=[Scope.READ_ADMIN, Scope.WRITE_ADMIN])])
|
6
6
|
"""
|
7
7
|
|
8
|
-
import os
|
9
8
|
import importlib.metadata
|
9
|
+
import logging
|
10
|
+
import os
|
11
|
+
import re
|
10
12
|
import threading
|
11
13
|
import time
|
12
|
-
import psutil
|
13
|
-
import re
|
14
|
-
import logging
|
15
14
|
from typing import Literal
|
16
|
-
|
15
|
+
|
16
|
+
import psutil
|
17
17
|
from crypticorn.common.logging import LogLevel
|
18
|
+
from crypticorn.common.metrics import registry
|
19
|
+
from fastapi import APIRouter, Query, Response
|
20
|
+
from prometheus_client import CONTENT_TYPE_LATEST, generate_latest
|
18
21
|
|
19
22
|
router = APIRouter(tags=["Admin"], prefix="/admin")
|
20
23
|
|
@@ -104,3 +107,11 @@ def list_installed_packages(
|
|
104
107
|
or any(re.match(pattern, dist.metadata["Name"]) for pattern in include)
|
105
108
|
}
|
106
109
|
return dict(sorted(packages.items()))
|
110
|
+
|
111
|
+
|
112
|
+
@router.get("/metrics", operation_id="getMetrics")
|
113
|
+
def metrics():
|
114
|
+
"""
|
115
|
+
Get Prometheus metrics for the application. Returns plain text.
|
116
|
+
"""
|
117
|
+
return Response(generate_latest(registry), media_type=CONTENT_TYPE_LATEST)
|
@@ -10,28 +10,11 @@ Then include the router in the FastAPI app.
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
from datetime import datetime
|
13
|
-
from
|
14
|
-
from typing import Annotated, Literal
|
15
|
-
from fastapi import APIRouter, Response, Depends
|
16
|
-
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
|
17
|
-
from crypticorn.common.metrics import registry
|
18
|
-
from crypticorn.common.auth import AuthHandler, basic_auth
|
19
|
-
|
20
|
-
class EnhancedApiRouter(APIRouter):
|
21
|
-
def __init__(self, enable_metrics: bool = False, auth_handler: AuthHandler = None, *args, **kwargs):
|
22
|
-
"""
|
23
|
-
Enhanced API Router that allows for metrics and authentication.
|
24
|
-
If enable_metrics is True, the router will include the metrics endpoint.
|
25
|
-
If auth_handler is provided, the router will use the auth handler to authenticate requests with
|
26
|
-
"""
|
27
|
-
super().__init__(*args, **kwargs)
|
28
|
-
self.enable_metrics = enable_metrics
|
29
|
-
self.auth_handler = auth_handler
|
13
|
+
from typing import Literal
|
30
14
|
|
31
|
-
|
32
|
-
raise ValueError("auth_handler must be provided if enable_metrics is True")
|
15
|
+
from fastapi import APIRouter, Request
|
33
16
|
|
34
|
-
router =
|
17
|
+
router = APIRouter(tags=["Status"], prefix="")
|
35
18
|
|
36
19
|
|
37
20
|
@router.get("/", operation_id="ping")
|
@@ -51,12 +34,3 @@ async def time(type: Literal["iso", "unix"] = "iso") -> str:
|
|
51
34
|
return datetime.now().isoformat()
|
52
35
|
elif type == "unix":
|
53
36
|
return str(int(datetime.now().timestamp()))
|
54
|
-
|
55
|
-
|
56
|
-
@router.get("/metrics", operation_id="getMetrics", include_in_schema=router.enable_metrics)
|
57
|
-
def metrics(username: Annotated[str, Depends(basic_auth)]):
|
58
|
-
"""
|
59
|
-
Get Prometheus metrics for the application. Returns plain text.
|
60
|
-
"""
|
61
|
-
return Response(generate_latest(registry), media_type=CONTENT_TYPE_LATEST)
|
62
|
-
|
crypticorn/common/utils.py
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
"""General utility functions and helper methods used across the codebase."""
|
2
2
|
|
3
|
-
from datetime import datetime
|
4
|
-
from typing import Any, Union
|
5
|
-
from decimal import Decimal
|
6
|
-
import string
|
7
3
|
import random
|
8
|
-
import
|
4
|
+
import string
|
9
5
|
import warnings
|
6
|
+
from datetime import datetime
|
7
|
+
from decimal import Decimal
|
8
|
+
from typing import Any, Union
|
10
9
|
|
11
|
-
|
10
|
+
import typing_extensions
|
11
|
+
from crypticorn.common.exceptions import ApiError, ExceptionContent, HTTPException
|
12
12
|
from crypticorn.common.warnings import CrypticornDeprecatedSince25
|
13
13
|
|
14
14
|
|
crypticorn/common/warnings.py
CHANGED
@@ -16,6 +16,9 @@ from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
|
|
16
16
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
17
17
|
from typing_extensions import Annotated
|
18
18
|
|
19
|
+
from pydantic import Field, StrictFloat, StrictInt, StrictStr, field_validator
|
20
|
+
from typing import Any, Dict, List, Optional, Union
|
21
|
+
from typing_extensions import Annotated
|
19
22
|
from crypticorn.dex.client.models.log_level import LogLevel
|
20
23
|
|
21
24
|
from crypticorn.dex.client.api_client import ApiClient, RequestSerialized
|
@@ -11,10 +11,14 @@ Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
11
11
|
Do not edit the class manually.
|
12
12
|
""" # noqa: E501
|
13
13
|
|
14
|
+
import warnings
|
14
15
|
from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
|
15
16
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
16
17
|
from typing_extensions import Annotated
|
17
18
|
|
19
|
+
from pydantic import Field, StrictInt, StrictStr, field_validator
|
20
|
+
from typing import Optional
|
21
|
+
from typing_extensions import Annotated
|
18
22
|
from crypticorn.dex.client.models.paginated_response_signal_with_token import (
|
19
23
|
PaginatedResponseSignalWithToken,
|
20
24
|
)
|
@@ -176,7 +180,7 @@ class SignalsApi:
|
|
176
180
|
) -> SignalOverviewStats:
|
177
181
|
"""Get Stats
|
178
182
|
|
179
|
-
|
183
|
+
Retrieve comprehensive statistics and analytics for all trading signals. Returns hourly-updated aggregated metrics including performance summaries and trading volumes.
|
180
184
|
|
181
185
|
:param _request_timeout: timeout setting for this request. If one
|
182
186
|
number provided, it will be total request
|
@@ -236,7 +240,7 @@ class SignalsApi:
|
|
236
240
|
) -> ApiResponse[SignalOverviewStats]:
|
237
241
|
"""Get Stats
|
238
242
|
|
239
|
-
|
243
|
+
Retrieve comprehensive statistics and analytics for all trading signals. Returns hourly-updated aggregated metrics including performance summaries and trading volumes.
|
240
244
|
|
241
245
|
:param _request_timeout: timeout setting for this request. If one
|
242
246
|
number provided, it will be total request
|
@@ -295,7 +299,7 @@ class SignalsApi:
|
|
295
299
|
) -> RESTResponseType:
|
296
300
|
"""Get Stats
|
297
301
|
|
298
|
-
|
302
|
+
Retrieve comprehensive statistics and analytics for all trading signals. Returns hourly-updated aggregated metrics including performance summaries and trading volumes.
|
299
303
|
|
300
304
|
:param _request_timeout: timeout setting for this request. If one
|
301
305
|
number provided, it will be total request
|
@@ -465,7 +469,7 @@ class SignalsApi:
|
|
465
469
|
Optional[StrictStr], Field(description="The field to filter by")
|
466
470
|
] = None,
|
467
471
|
filter_value: Annotated[
|
468
|
-
Optional[
|
472
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
469
473
|
] = None,
|
470
474
|
sort_order: Annotated[
|
471
475
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -532,7 +536,7 @@ class SignalsApi:
|
|
532
536
|
Optional[StrictStr], Field(description="The field to filter by")
|
533
537
|
] = None,
|
534
538
|
filter_value: Annotated[
|
535
|
-
Optional[
|
539
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
536
540
|
] = None,
|
537
541
|
sort_order: Annotated[
|
538
542
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -599,7 +603,7 @@ class SignalsApi:
|
|
599
603
|
Optional[StrictStr], Field(description="The field to filter by")
|
600
604
|
] = None,
|
601
605
|
filter_value: Annotated[
|
602
|
-
Optional[
|
606
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
603
607
|
] = None,
|
604
608
|
sort_order: Annotated[
|
605
609
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -667,7 +671,7 @@ class SignalsApi:
|
|
667
671
|
Optional[StrictStr], Field(description="The field to filter by")
|
668
672
|
] = None,
|
669
673
|
filter_value: Annotated[
|
670
|
-
Optional[
|
674
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
671
675
|
] = None,
|
672
676
|
sort_order: Annotated[
|
673
677
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -698,12 +702,12 @@ class SignalsApi:
|
|
698
702
|
) -> PaginatedResponseSignalWithToken:
|
699
703
|
"""Get Signals
|
700
704
|
|
701
|
-
|
705
|
+
Retrieve all trading signals with pagination, filtering, and sorting support. Returns signals enriched with token metadata. Default sort is by call time (newest first).
|
702
706
|
|
703
707
|
:param filter_by: The field to filter by
|
704
708
|
:type filter_by: str
|
705
709
|
:param filter_value: The value to filter with
|
706
|
-
:type filter_value:
|
710
|
+
:type filter_value: str
|
707
711
|
:param sort_order: The order to sort by
|
708
712
|
:type sort_order: str
|
709
713
|
:param sort_by: The field to sort by
|
@@ -766,7 +770,7 @@ class SignalsApi:
|
|
766
770
|
Optional[StrictStr], Field(description="The field to filter by")
|
767
771
|
] = None,
|
768
772
|
filter_value: Annotated[
|
769
|
-
Optional[
|
773
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
770
774
|
] = None,
|
771
775
|
sort_order: Annotated[
|
772
776
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -797,12 +801,12 @@ class SignalsApi:
|
|
797
801
|
) -> ApiResponse[PaginatedResponseSignalWithToken]:
|
798
802
|
"""Get Signals
|
799
803
|
|
800
|
-
|
804
|
+
Retrieve all trading signals with pagination, filtering, and sorting support. Returns signals enriched with token metadata. Default sort is by call time (newest first).
|
801
805
|
|
802
806
|
:param filter_by: The field to filter by
|
803
807
|
:type filter_by: str
|
804
808
|
:param filter_value: The value to filter with
|
805
|
-
:type filter_value:
|
809
|
+
:type filter_value: str
|
806
810
|
:param sort_order: The order to sort by
|
807
811
|
:type sort_order: str
|
808
812
|
:param sort_by: The field to sort by
|
@@ -864,7 +868,7 @@ class SignalsApi:
|
|
864
868
|
Optional[StrictStr], Field(description="The field to filter by")
|
865
869
|
] = None,
|
866
870
|
filter_value: Annotated[
|
867
|
-
Optional[
|
871
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
868
872
|
] = None,
|
869
873
|
sort_order: Annotated[
|
870
874
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -895,12 +899,12 @@ class SignalsApi:
|
|
895
899
|
) -> RESTResponseType:
|
896
900
|
"""Get Signals
|
897
901
|
|
898
|
-
|
902
|
+
Retrieve all trading signals with pagination, filtering, and sorting support. Returns signals enriched with token metadata. Default sort is by call time (newest first).
|
899
903
|
|
900
904
|
:param filter_by: The field to filter by
|
901
905
|
:type filter_by: str
|
902
906
|
:param filter_value: The value to filter with
|
903
|
-
:type filter_value:
|
907
|
+
:type filter_value: str
|
904
908
|
:param sort_order: The order to sort by
|
905
909
|
:type sort_order: str
|
906
910
|
:param sort_by: The field to sort by
|
@@ -960,7 +964,7 @@ class SignalsApi:
|
|
960
964
|
Optional[StrictStr], Field(description="The field to filter by")
|
961
965
|
] = None,
|
962
966
|
filter_value: Annotated[
|
963
|
-
Optional[
|
967
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
964
968
|
] = None,
|
965
969
|
sort_order: Annotated[
|
966
970
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -1011,7 +1015,7 @@ class SignalsApi:
|
|
1011
1015
|
Optional[StrictStr], Field(description="The field to filter by")
|
1012
1016
|
] = None,
|
1013
1017
|
filter_value: Annotated[
|
1014
|
-
Optional[
|
1018
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
1015
1019
|
] = None,
|
1016
1020
|
sort_order: Annotated[
|
1017
1021
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -1062,7 +1066,7 @@ class SignalsApi:
|
|
1062
1066
|
Optional[StrictStr], Field(description="The field to filter by")
|
1063
1067
|
] = None,
|
1064
1068
|
filter_value: Annotated[
|
1065
|
-
Optional[
|
1069
|
+
Optional[StrictStr], Field(description="The value to filter with")
|
1066
1070
|
] = None,
|
1067
1071
|
sort_order: Annotated[
|
1068
1072
|
Optional[StrictStr], Field(description="The order to sort by")
|
@@ -1170,7 +1174,7 @@ class SignalsApi:
|
|
1170
1174
|
)
|
1171
1175
|
|
1172
1176
|
# authentication setting
|
1173
|
-
_auth_settings: List[str] = [
|
1177
|
+
_auth_settings: List[str] = []
|
1174
1178
|
|
1175
1179
|
return self.api_client.param_serialize(
|
1176
1180
|
method="GET",
|
@@ -1385,7 +1389,7 @@ class SignalsApi:
|
|
1385
1389
|
) -> PaginatedResponseSignalWithToken:
|
1386
1390
|
"""Get Top Signals
|
1387
1391
|
|
1388
|
-
|
1392
|
+
Retrieve top-performing signals ranked by performance within a specified time window. Returns the highest-performing signals from the last X hours (default: 24 hours).
|
1389
1393
|
|
1390
1394
|
:param page: The current page number
|
1391
1395
|
:type page: int
|
@@ -1469,7 +1473,7 @@ class SignalsApi:
|
|
1469
1473
|
) -> ApiResponse[PaginatedResponseSignalWithToken]:
|
1470
1474
|
"""Get Top Signals
|
1471
1475
|
|
1472
|
-
|
1476
|
+
Retrieve top-performing signals ranked by performance within a specified time window. Returns the highest-performing signals from the last X hours (default: 24 hours).
|
1473
1477
|
|
1474
1478
|
:param page: The current page number
|
1475
1479
|
:type page: int
|
@@ -1552,7 +1556,7 @@ class SignalsApi:
|
|
1552
1556
|
) -> RESTResponseType:
|
1553
1557
|
"""Get Top Signals
|
1554
1558
|
|
1555
|
-
|
1559
|
+
Retrieve top-performing signals ranked by performance within a specified time window. Returns the highest-performing signals from the last X hours (default: 24 hours).
|
1556
1560
|
|
1557
1561
|
:param page: The current page number
|
1558
1562
|
:type page: int
|
@@ -1776,7 +1780,7 @@ class SignalsApi:
|
|
1776
1780
|
)
|
1777
1781
|
|
1778
1782
|
# authentication setting
|
1779
|
-
_auth_settings: List[str] = [
|
1783
|
+
_auth_settings: List[str] = []
|
1780
1784
|
|
1781
1785
|
return self.api_client.param_serialize(
|
1782
1786
|
method="GET",
|