crypticorn-utils 0.1.0rc1__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.
@@ -1,17 +1,9 @@
1
1
  """Comprehensive error handling system defining various API error types, HTTP exceptions, and error content structures."""
2
2
 
3
- from enum import Enum
3
+ from enum import StrEnum
4
4
 
5
- from crypticorn_utils.mixins import ApiErrorFallback
6
- from fastapi import status
7
5
 
8
- try:
9
- from enum import StrEnum
10
- except ImportError:
11
- from strenum import StrEnum
12
-
13
-
14
- class ApiErrorType(StrEnum):
6
+ class ErrorType(StrEnum):
15
7
  """Type of the API error."""
16
8
 
17
9
  USER_ERROR = "user error"
@@ -24,892 +16,10 @@ class ApiErrorType(StrEnum):
24
16
  """error that does not need to be handled or does not affect the program or is a placeholder."""
25
17
 
26
18
 
27
- class ApiErrorLevel(StrEnum):
19
+ class ErrorLevel(StrEnum):
28
20
  """Level of the API error."""
29
21
 
30
22
  ERROR = "error"
31
23
  INFO = "info"
32
24
  SUCCESS = "success"
33
25
  WARNING = "warning"
34
-
35
-
36
- class ApiErrorIdentifier(StrEnum):
37
- """Unique identifier of the API error."""
38
-
39
- ALLOCATION_BELOW_EXPOSURE = "allocation_below_current_exposure"
40
- ALLOCATION_BELOW_MINIMUM = "allocation_below_min_amount"
41
- ALLOCATION_LIMIT_EXCEEDED = "allocation_limit_exceeded"
42
- BLACK_SWAN = "black_swan"
43
- BOT_ALREADY_DELETED = "bot_already_deleted"
44
- BOT_STOPPING_COMPLETED = "bot_stopping_completed"
45
- BOT_STOPPING_STARTED = "bot_stopping_started"
46
- CANCELLED_OPEN_ORDER = "cancelled_open_order"
47
- CLIENT_ORDER_ID_REPEATED = "client_order_id_already_exists"
48
- CONTENT_TYPE_ERROR = "invalid_content_type"
49
- COUPON_INVALID = "coupon_invalid"
50
- DELETE_BOT_ERROR = "delete_bot_error"
51
- EXCHANGE_HTTP_ERROR = "exchange_http_request_error"
52
- EXCHANGE_INVALID_PARAMETER = "exchange_invalid_parameter"
53
- EXCHANGE_INVALID_SIGNATURE = "exchange_invalid_signature"
54
- EXCHANGE_INVALID_TIMESTAMP = "exchange_invalid_timestamp"
55
- EXCHANGE_IP_RESTRICTED = "exchange_ip_address_is_not_authorized"
56
- EXCHANGE_KEY_ALREADY_EXISTS = "exchange_key_already_exists"
57
- EXCHANGE_KEY_IN_USE = "exchange_key_in_use"
58
- EXCHANGE_MAINTENANCE = "exchange_system_under_maintenance"
59
- EXCHANGE_RATE_LIMIT = "exchange_rate_limit_exceeded"
60
- EXCHANGE_PERMISSION_DENIED = "insufficient_permissions_spot_and_futures_required"
61
- EXCHANGE_SERVICE_UNAVAILABLE = "exchange_service_temporarily_unavailable"
62
- EXCHANGE_SYSTEM_BUSY = "exchange_system_is_busy"
63
- EXCHANGE_SYSTEM_CONFIG_ERROR = "exchange_system_configuration_error"
64
- EXCHANGE_SYSTEM_ERROR = "exchange_internal_system_error"
65
- EXCHANGE_USER_FROZEN = "exchange_user_account_is_frozen"
66
- EXPIRED_API_KEY = "api_key_expired"
67
- EXPIRED_BEARER = "bearer_token_expired"
68
- FAILED_OPEN_ORDER = "failed_open_order"
69
- FORBIDDEN = "forbidden"
70
- HEDGE_MODE_NOT_ACTIVE = "hedge_mode_not_active"
71
- INSUFFICIENT_BALANCE = "insufficient_balance"
72
- INSUFFICIENT_MARGIN = "insufficient_margin"
73
- INSUFFICIENT_SCOPES = "insufficient_scopes"
74
- INVALID_API_KEY = "invalid_api_key"
75
- INVALID_BASIC_AUTH = "invalid_basic_auth"
76
- INVALID_BEARER = "invalid_bearer"
77
- INVALID_DATA_REQUEST = "invalid_data"
78
- INVALID_DATA_RESPONSE = "invalid_data_response"
79
- INVALID_EXCHANGE_KEY = "invalid_exchange_key"
80
- INVALID_MODEL_NAME = "invalid_model_name"
81
- LEVERAGE_EXCEEDED = "leverage_limit_exceeded"
82
- LIQUIDATION_PRICE_VIOLATION = "order_violates_liquidation_price_constraints"
83
- MARGIN_MODE_CLASH = "margin_mode_clash"
84
- NAME_NOT_UNIQUE = "name_not_unique"
85
- NO_CREDENTIALS = "no_credentials"
86
- NOW_API_DOWN = "now_api_down"
87
- OBJECT_ALREADY_EXISTS = "object_already_exists"
88
- OBJECT_CREATED = "object_created"
89
- OBJECT_DELETED = "object_deleted"
90
- OBJECT_LOCKED = "object_locked"
91
- OBJECT_NOT_FOUND = "object_not_found"
92
- OBJECT_UPDATED = "object_updated"
93
- ORDER_ALREADY_FILLED = "order_is_already_filled"
94
- ORDER_IN_PROCESS = "order_is_being_processed"
95
- ORDER_LIMIT_EXCEEDED = "order_quantity_limit_exceeded"
96
- ORDER_NOT_FOUND = "order_does_not_exist"
97
- ORDER_PRICE_INVALID = "order_price_is_invalid"
98
- ORDER_SIZE_TOO_LARGE = "order_size_too_large"
99
- ORDER_SIZE_TOO_SMALL = "order_size_too_small"
100
- ORPHAN_OPEN_ORDER = "orphan_open_order"
101
- ORPHAN_CLOSE_ORDER = "orphan_close_order"
102
- POSITION_LIMIT_EXCEEDED = "position_limit_exceeded"
103
- POSITION_NOT_FOUND = "position_does_not_exist"
104
- POSITION_SUSPENDED = "position_opening_temporarily_suspended"
105
- POST_ONLY_REJECTED = "post_only_order_would_immediately_match"
106
- REQUEST_SCOPE_EXCEEDED = "request_scope_limit_exceeded"
107
- RISK_LIMIT_EXCEEDED = "risk_limit_exceeded"
108
- RPC_TIMEOUT = "rpc_timeout"
109
- SETTLEMENT_IN_PROGRESS = "system_settlement_in_process"
110
- STRATEGY_DISABLED = "strategy_disabled"
111
- STRATEGY_LEVERAGE_MISMATCH = "strategy_leverage_mismatch"
112
- STRATEGY_NOT_SUPPORTING_EXCHANGE = "strategy_not_supporting_exchange"
113
- SUCCESS = "success"
114
- SYMBOL_NOT_FOUND = "symbol_does_not_exist"
115
- TRADING_ACTION_EXPIRED = "trading_action_expired"
116
- TRADING_ACTION_SKIPPED_BOT_STOPPING = "trading_action_skipped_bot_stopping"
117
- TRADING_LOCKED = "trading_has_been_locked"
118
- TRADING_SUSPENDED = "trading_is_suspended"
119
- UNKNOWN_ERROR = "unknown_error_occurred"
120
- URL_NOT_FOUND = "requested_resource_not_found"
121
-
122
- def get_error(self) -> "ApiError":
123
- """Get the corresponding ApiError."""
124
- return getattr(ApiError, self.name)
125
-
126
-
127
- class ApiError(Enum, metaclass=ApiErrorFallback):
128
- # Fallback to UNKNOWN_ERROR for error codes not yet published to PyPI.
129
- """Crypticorn API error enumeration."""
130
-
131
- ALLOCATION_BELOW_EXPOSURE = (
132
- ApiErrorIdentifier.ALLOCATION_BELOW_EXPOSURE,
133
- ApiErrorType.USER_ERROR,
134
- ApiErrorLevel.ERROR,
135
- )
136
- ALLOCATION_BELOW_MINIMUM = (
137
- ApiErrorIdentifier.ALLOCATION_BELOW_MINIMUM,
138
- ApiErrorType.USER_ERROR,
139
- ApiErrorLevel.ERROR,
140
- )
141
- ALLOCATION_LIMIT_EXCEEDED = (
142
- ApiErrorIdentifier.ALLOCATION_LIMIT_EXCEEDED,
143
- ApiErrorType.NO_ERROR,
144
- ApiErrorLevel.INFO,
145
- )
146
- BLACK_SWAN = (
147
- ApiErrorIdentifier.BLACK_SWAN,
148
- ApiErrorType.EXCHANGE_ERROR,
149
- ApiErrorLevel.INFO,
150
- )
151
- BOT_ALREADY_DELETED = (
152
- ApiErrorIdentifier.BOT_ALREADY_DELETED,
153
- ApiErrorType.USER_ERROR,
154
- ApiErrorLevel.INFO,
155
- )
156
- BOT_STOPPING_COMPLETED = (
157
- ApiErrorIdentifier.BOT_STOPPING_COMPLETED,
158
- ApiErrorType.NO_ERROR,
159
- ApiErrorLevel.SUCCESS,
160
- )
161
- BOT_STOPPING_STARTED = (
162
- ApiErrorIdentifier.BOT_STOPPING_STARTED,
163
- ApiErrorType.NO_ERROR,
164
- ApiErrorLevel.SUCCESS,
165
- )
166
- CANCELLED_OPEN_ORDER = (
167
- ApiErrorIdentifier.CANCELLED_OPEN_ORDER,
168
- ApiErrorType.NO_ERROR,
169
- ApiErrorLevel.INFO,
170
- )
171
- CLIENT_ORDER_ID_REPEATED = (
172
- ApiErrorIdentifier.CLIENT_ORDER_ID_REPEATED,
173
- ApiErrorType.SERVER_ERROR,
174
- ApiErrorLevel.ERROR,
175
- )
176
- CONTENT_TYPE_ERROR = (
177
- ApiErrorIdentifier.CONTENT_TYPE_ERROR,
178
- ApiErrorType.SERVER_ERROR,
179
- ApiErrorLevel.ERROR,
180
- )
181
- COUPON_INVALID = (
182
- ApiErrorIdentifier.COUPON_INVALID,
183
- ApiErrorType.USER_ERROR,
184
- ApiErrorLevel.ERROR,
185
- )
186
- DELETE_BOT_ERROR = (
187
- ApiErrorIdentifier.DELETE_BOT_ERROR,
188
- ApiErrorType.SERVER_ERROR,
189
- ApiErrorLevel.ERROR,
190
- )
191
- EXCHANGE_HTTP_ERROR = (
192
- ApiErrorIdentifier.EXCHANGE_HTTP_ERROR,
193
- ApiErrorType.EXCHANGE_ERROR,
194
- ApiErrorLevel.ERROR,
195
- )
196
- EXCHANGE_INVALID_PARAMETER = (
197
- ApiErrorIdentifier.EXCHANGE_INVALID_PARAMETER,
198
- ApiErrorType.SERVER_ERROR,
199
- ApiErrorLevel.ERROR,
200
- )
201
- EXCHANGE_INVALID_SIGNATURE = (
202
- ApiErrorIdentifier.EXCHANGE_INVALID_SIGNATURE,
203
- ApiErrorType.SERVER_ERROR,
204
- ApiErrorLevel.ERROR,
205
- )
206
- EXCHANGE_INVALID_TIMESTAMP = (
207
- ApiErrorIdentifier.EXCHANGE_INVALID_TIMESTAMP,
208
- ApiErrorType.SERVER_ERROR,
209
- ApiErrorLevel.ERROR,
210
- )
211
- EXCHANGE_IP_RESTRICTED = (
212
- ApiErrorIdentifier.EXCHANGE_IP_RESTRICTED,
213
- ApiErrorType.USER_ERROR,
214
- ApiErrorLevel.ERROR,
215
- )
216
- EXCHANGE_KEY_ALREADY_EXISTS = (
217
- ApiErrorIdentifier.EXCHANGE_KEY_ALREADY_EXISTS,
218
- ApiErrorType.USER_ERROR,
219
- ApiErrorLevel.ERROR,
220
- )
221
- EXCHANGE_KEY_IN_USE = (
222
- ApiErrorIdentifier.EXCHANGE_KEY_IN_USE,
223
- ApiErrorType.USER_ERROR,
224
- ApiErrorLevel.ERROR,
225
- )
226
- EXCHANGE_MAINTENANCE = (
227
- ApiErrorIdentifier.EXCHANGE_MAINTENANCE,
228
- ApiErrorType.EXCHANGE_ERROR,
229
- ApiErrorLevel.ERROR,
230
- )
231
- EXCHANGE_RATE_LIMIT = (
232
- ApiErrorIdentifier.EXCHANGE_RATE_LIMIT,
233
- ApiErrorType.SERVER_ERROR,
234
- ApiErrorLevel.ERROR,
235
- )
236
- EXCHANGE_PERMISSION_DENIED = (
237
- ApiErrorIdentifier.EXCHANGE_PERMISSION_DENIED,
238
- ApiErrorType.USER_ERROR,
239
- ApiErrorLevel.ERROR,
240
- )
241
- EXCHANGE_SERVICE_UNAVAILABLE = (
242
- ApiErrorIdentifier.EXCHANGE_SERVICE_UNAVAILABLE,
243
- ApiErrorType.EXCHANGE_ERROR,
244
- ApiErrorLevel.ERROR,
245
- )
246
- EXCHANGE_SYSTEM_BUSY = (
247
- ApiErrorIdentifier.EXCHANGE_SYSTEM_BUSY,
248
- ApiErrorType.EXCHANGE_ERROR,
249
- ApiErrorLevel.ERROR,
250
- )
251
- EXCHANGE_SYSTEM_CONFIG_ERROR = (
252
- ApiErrorIdentifier.EXCHANGE_SYSTEM_CONFIG_ERROR,
253
- ApiErrorType.EXCHANGE_ERROR,
254
- ApiErrorLevel.ERROR,
255
- )
256
- EXCHANGE_SYSTEM_ERROR = (
257
- ApiErrorIdentifier.EXCHANGE_SYSTEM_ERROR,
258
- ApiErrorType.EXCHANGE_ERROR,
259
- ApiErrorLevel.ERROR,
260
- )
261
- EXCHANGE_USER_FROZEN = (
262
- ApiErrorIdentifier.EXCHANGE_USER_FROZEN,
263
- ApiErrorType.USER_ERROR,
264
- ApiErrorLevel.ERROR,
265
- )
266
- EXPIRED_API_KEY = (
267
- ApiErrorIdentifier.EXPIRED_API_KEY,
268
- ApiErrorType.USER_ERROR,
269
- ApiErrorLevel.ERROR,
270
- )
271
- EXPIRED_BEARER = (
272
- ApiErrorIdentifier.EXPIRED_BEARER,
273
- ApiErrorType.USER_ERROR,
274
- ApiErrorLevel.ERROR,
275
- )
276
- FAILED_OPEN_ORDER = (
277
- ApiErrorIdentifier.FAILED_OPEN_ORDER,
278
- ApiErrorType.NO_ERROR,
279
- ApiErrorLevel.INFO,
280
- )
281
- FORBIDDEN = (
282
- ApiErrorIdentifier.FORBIDDEN,
283
- ApiErrorType.USER_ERROR,
284
- ApiErrorLevel.ERROR,
285
- )
286
- HEDGE_MODE_NOT_ACTIVE = (
287
- ApiErrorIdentifier.HEDGE_MODE_NOT_ACTIVE,
288
- ApiErrorType.USER_ERROR,
289
- ApiErrorLevel.ERROR,
290
- )
291
- INSUFFICIENT_BALANCE = (
292
- ApiErrorIdentifier.INSUFFICIENT_BALANCE,
293
- ApiErrorType.USER_ERROR,
294
- ApiErrorLevel.ERROR,
295
- )
296
- INSUFFICIENT_MARGIN = (
297
- ApiErrorIdentifier.INSUFFICIENT_MARGIN,
298
- ApiErrorType.USER_ERROR,
299
- ApiErrorLevel.ERROR,
300
- )
301
- INSUFFICIENT_SCOPES = (
302
- ApiErrorIdentifier.INSUFFICIENT_SCOPES,
303
- ApiErrorType.USER_ERROR,
304
- ApiErrorLevel.ERROR,
305
- )
306
- INVALID_API_KEY = (
307
- ApiErrorIdentifier.INVALID_API_KEY,
308
- ApiErrorType.USER_ERROR,
309
- ApiErrorLevel.ERROR,
310
- )
311
- INVALID_BASIC_AUTH = (
312
- ApiErrorIdentifier.INVALID_BASIC_AUTH,
313
- ApiErrorType.USER_ERROR,
314
- ApiErrorLevel.ERROR,
315
- )
316
- INVALID_BEARER = (
317
- ApiErrorIdentifier.INVALID_BEARER,
318
- ApiErrorType.USER_ERROR,
319
- ApiErrorLevel.ERROR,
320
- )
321
- INVALID_DATA_REQUEST = (
322
- ApiErrorIdentifier.INVALID_DATA_REQUEST,
323
- ApiErrorType.USER_ERROR,
324
- ApiErrorLevel.ERROR,
325
- )
326
- INVALID_DATA_RESPONSE = (
327
- ApiErrorIdentifier.INVALID_DATA_RESPONSE,
328
- ApiErrorType.SERVER_ERROR,
329
- ApiErrorLevel.ERROR,
330
- )
331
- INVALID_EXCHANGE_KEY = (
332
- ApiErrorIdentifier.INVALID_EXCHANGE_KEY,
333
- ApiErrorType.USER_ERROR,
334
- ApiErrorLevel.ERROR,
335
- )
336
- INVALID_MODEL_NAME = (
337
- ApiErrorIdentifier.INVALID_MODEL_NAME,
338
- ApiErrorType.USER_ERROR,
339
- ApiErrorLevel.ERROR,
340
- )
341
- LEVERAGE_EXCEEDED = (
342
- ApiErrorIdentifier.LEVERAGE_EXCEEDED,
343
- ApiErrorType.SERVER_ERROR,
344
- ApiErrorLevel.ERROR,
345
- )
346
- LIQUIDATION_PRICE_VIOLATION = (
347
- ApiErrorIdentifier.LIQUIDATION_PRICE_VIOLATION,
348
- ApiErrorType.SERVER_ERROR,
349
- ApiErrorLevel.ERROR,
350
- )
351
- MARGIN_MODE_CLASH = (
352
- ApiErrorIdentifier.MARGIN_MODE_CLASH,
353
- ApiErrorType.USER_ERROR,
354
- ApiErrorLevel.ERROR,
355
- )
356
- NAME_NOT_UNIQUE = (
357
- ApiErrorIdentifier.NAME_NOT_UNIQUE,
358
- ApiErrorType.USER_ERROR,
359
- ApiErrorLevel.ERROR,
360
- )
361
- NO_CREDENTIALS = (
362
- ApiErrorIdentifier.NO_CREDENTIALS,
363
- ApiErrorType.USER_ERROR,
364
- ApiErrorLevel.ERROR,
365
- )
366
- NOW_API_DOWN = (
367
- ApiErrorIdentifier.NOW_API_DOWN,
368
- ApiErrorType.SERVER_ERROR,
369
- ApiErrorLevel.ERROR,
370
- )
371
- OBJECT_ALREADY_EXISTS = (
372
- ApiErrorIdentifier.OBJECT_ALREADY_EXISTS,
373
- ApiErrorType.USER_ERROR,
374
- ApiErrorLevel.ERROR,
375
- )
376
- OBJECT_CREATED = (
377
- ApiErrorIdentifier.OBJECT_CREATED,
378
- ApiErrorType.NO_ERROR,
379
- ApiErrorLevel.SUCCESS,
380
- )
381
- OBJECT_DELETED = (
382
- ApiErrorIdentifier.OBJECT_DELETED,
383
- ApiErrorType.NO_ERROR,
384
- ApiErrorLevel.SUCCESS,
385
- )
386
- OBJECT_LOCKED = (
387
- ApiErrorIdentifier.OBJECT_LOCKED,
388
- ApiErrorType.NO_ERROR,
389
- ApiErrorLevel.INFO,
390
- )
391
- OBJECT_NOT_FOUND = (
392
- ApiErrorIdentifier.OBJECT_NOT_FOUND,
393
- ApiErrorType.USER_ERROR,
394
- ApiErrorLevel.ERROR,
395
- )
396
- OBJECT_UPDATED = (
397
- ApiErrorIdentifier.OBJECT_UPDATED,
398
- ApiErrorType.NO_ERROR,
399
- ApiErrorLevel.SUCCESS,
400
- )
401
- ORDER_ALREADY_FILLED = (
402
- ApiErrorIdentifier.ORDER_ALREADY_FILLED,
403
- ApiErrorType.SERVER_ERROR,
404
- ApiErrorLevel.INFO,
405
- )
406
- ORDER_IN_PROCESS = (
407
- ApiErrorIdentifier.ORDER_IN_PROCESS,
408
- ApiErrorType.NO_ERROR,
409
- ApiErrorLevel.INFO,
410
- )
411
- ORDER_LIMIT_EXCEEDED = (
412
- ApiErrorIdentifier.ORDER_LIMIT_EXCEEDED,
413
- ApiErrorType.USER_ERROR,
414
- ApiErrorLevel.ERROR,
415
- )
416
- ORDER_NOT_FOUND = (
417
- ApiErrorIdentifier.ORDER_NOT_FOUND,
418
- ApiErrorType.SERVER_ERROR,
419
- ApiErrorLevel.ERROR,
420
- )
421
- ORDER_PRICE_INVALID = (
422
- ApiErrorIdentifier.ORDER_PRICE_INVALID,
423
- ApiErrorType.SERVER_ERROR,
424
- ApiErrorLevel.ERROR,
425
- )
426
- ORDER_SIZE_TOO_LARGE = (
427
- ApiErrorIdentifier.ORDER_SIZE_TOO_LARGE,
428
- ApiErrorType.USER_ERROR,
429
- ApiErrorLevel.WARNING,
430
- )
431
- ORDER_SIZE_TOO_SMALL = (
432
- ApiErrorIdentifier.ORDER_SIZE_TOO_SMALL,
433
- ApiErrorType.USER_ERROR,
434
- ApiErrorLevel.WARNING,
435
- )
436
- ORPHAN_OPEN_ORDER = (
437
- ApiErrorIdentifier.ORPHAN_OPEN_ORDER,
438
- ApiErrorType.NO_ERROR,
439
- ApiErrorLevel.WARNING,
440
- )
441
- ORPHAN_CLOSE_ORDER = (
442
- ApiErrorIdentifier.ORPHAN_CLOSE_ORDER,
443
- ApiErrorType.NO_ERROR,
444
- ApiErrorLevel.WARNING,
445
- )
446
- POSITION_LIMIT_EXCEEDED = (
447
- ApiErrorIdentifier.POSITION_LIMIT_EXCEEDED,
448
- ApiErrorType.USER_ERROR,
449
- ApiErrorLevel.ERROR,
450
- )
451
- POSITION_NOT_FOUND = (
452
- ApiErrorIdentifier.POSITION_NOT_FOUND,
453
- ApiErrorType.NO_ERROR,
454
- ApiErrorLevel.WARNING,
455
- )
456
- POSITION_SUSPENDED = (
457
- ApiErrorIdentifier.POSITION_SUSPENDED,
458
- ApiErrorType.EXCHANGE_ERROR,
459
- ApiErrorLevel.ERROR,
460
- )
461
- POST_ONLY_REJECTED = (
462
- ApiErrorIdentifier.POST_ONLY_REJECTED,
463
- ApiErrorType.SERVER_ERROR,
464
- ApiErrorLevel.ERROR,
465
- )
466
- REQUEST_SCOPE_EXCEEDED = (
467
- ApiErrorIdentifier.REQUEST_SCOPE_EXCEEDED,
468
- ApiErrorType.EXCHANGE_ERROR,
469
- ApiErrorLevel.ERROR,
470
- )
471
- RISK_LIMIT_EXCEEDED = (
472
- ApiErrorIdentifier.RISK_LIMIT_EXCEEDED,
473
- ApiErrorType.SERVER_ERROR,
474
- ApiErrorLevel.ERROR,
475
- )
476
- RPC_TIMEOUT = (
477
- ApiErrorIdentifier.RPC_TIMEOUT,
478
- ApiErrorType.EXCHANGE_ERROR,
479
- ApiErrorLevel.ERROR,
480
- )
481
- SETTLEMENT_IN_PROGRESS = (
482
- ApiErrorIdentifier.SETTLEMENT_IN_PROGRESS,
483
- ApiErrorType.EXCHANGE_ERROR,
484
- ApiErrorLevel.ERROR,
485
- )
486
- STRATEGY_DISABLED = (
487
- ApiErrorIdentifier.STRATEGY_DISABLED,
488
- ApiErrorType.NO_ERROR,
489
- ApiErrorLevel.WARNING,
490
- )
491
- STRATEGY_LEVERAGE_MISMATCH = (
492
- ApiErrorIdentifier.STRATEGY_LEVERAGE_MISMATCH,
493
- ApiErrorType.USER_ERROR,
494
- ApiErrorLevel.ERROR,
495
- )
496
- STRATEGY_NOT_SUPPORTING_EXCHANGE = (
497
- ApiErrorIdentifier.STRATEGY_NOT_SUPPORTING_EXCHANGE,
498
- ApiErrorType.NO_ERROR,
499
- ApiErrorLevel.WARNING,
500
- )
501
- SUCCESS = (ApiErrorIdentifier.SUCCESS, ApiErrorType.NO_ERROR, ApiErrorLevel.SUCCESS)
502
- SYMBOL_NOT_FOUND = (
503
- ApiErrorIdentifier.SYMBOL_NOT_FOUND,
504
- ApiErrorType.SERVER_ERROR,
505
- ApiErrorLevel.ERROR,
506
- )
507
- TRADING_ACTION_EXPIRED = (
508
- ApiErrorIdentifier.TRADING_ACTION_EXPIRED,
509
- ApiErrorType.NO_ERROR,
510
- ApiErrorLevel.INFO,
511
- )
512
- TRADING_ACTION_SKIPPED_BOT_STOPPING = (
513
- ApiErrorIdentifier.TRADING_ACTION_SKIPPED_BOT_STOPPING,
514
- ApiErrorType.NO_ERROR,
515
- ApiErrorLevel.INFO,
516
- )
517
- TRADING_LOCKED = (
518
- ApiErrorIdentifier.TRADING_LOCKED,
519
- ApiErrorType.EXCHANGE_ERROR,
520
- ApiErrorLevel.ERROR,
521
- )
522
- TRADING_SUSPENDED = (
523
- ApiErrorIdentifier.TRADING_SUSPENDED,
524
- ApiErrorType.EXCHANGE_ERROR,
525
- ApiErrorLevel.ERROR,
526
- )
527
- UNKNOWN_ERROR = (
528
- ApiErrorIdentifier.UNKNOWN_ERROR,
529
- ApiErrorType.SERVER_ERROR,
530
- ApiErrorLevel.ERROR,
531
- )
532
- URL_NOT_FOUND = (
533
- ApiErrorIdentifier.URL_NOT_FOUND,
534
- ApiErrorType.SERVER_ERROR,
535
- ApiErrorLevel.ERROR,
536
- )
537
-
538
- @property
539
- def identifier(self) -> str:
540
- """Identifier of the error."""
541
- return self.value[0]
542
-
543
- @property
544
- def type(self) -> ApiErrorType:
545
- """Type of the error."""
546
- return self.value[1]
547
-
548
- @property
549
- def level(self) -> ApiErrorLevel:
550
- """Level of the error."""
551
- return self.value[2]
552
-
553
- @property
554
- def http_code(self) -> int:
555
- """HTTP status code for the error."""
556
- return StatusCodeMapper.get_http_code(self)
557
-
558
- @property
559
- def websocket_code(self) -> int:
560
- """WebSocket status code for the error."""
561
- return StatusCodeMapper.get_websocket_code(self)
562
-
563
- @classmethod
564
- def from_json(cls, data: dict) -> "ApiError":
565
- """Load an ApiError from a dictionary. Must contain the identifier with the key 'code'."""
566
- return next(error for error in cls if error.identifier == data["code"])
567
-
568
-
569
- class StatusCodeMapper:
570
- """Mapping of API errors to HTTP/Websocket status codes."""
571
-
572
- _mapping = {
573
- # Authentication/Authorization
574
- ApiError.EXPIRED_BEARER: (
575
- status.HTTP_401_UNAUTHORIZED,
576
- status.WS_1008_POLICY_VIOLATION,
577
- ),
578
- ApiError.INVALID_BASIC_AUTH: (
579
- status.HTTP_401_UNAUTHORIZED,
580
- status.WS_1008_POLICY_VIOLATION,
581
- ),
582
- ApiError.INVALID_BEARER: (
583
- status.HTTP_401_UNAUTHORIZED,
584
- status.WS_1008_POLICY_VIOLATION,
585
- ),
586
- ApiError.EXPIRED_API_KEY: (
587
- status.HTTP_401_UNAUTHORIZED,
588
- status.WS_1008_POLICY_VIOLATION,
589
- ),
590
- ApiError.INVALID_API_KEY: (
591
- status.HTTP_401_UNAUTHORIZED,
592
- status.WS_1008_POLICY_VIOLATION,
593
- ),
594
- ApiError.NO_CREDENTIALS: (
595
- status.HTTP_401_UNAUTHORIZED,
596
- status.WS_1008_POLICY_VIOLATION,
597
- ),
598
- ApiError.INSUFFICIENT_SCOPES: (
599
- status.HTTP_403_FORBIDDEN,
600
- status.WS_1008_POLICY_VIOLATION,
601
- ),
602
- ApiError.EXCHANGE_PERMISSION_DENIED: (
603
- status.HTTP_403_FORBIDDEN,
604
- status.WS_1008_POLICY_VIOLATION,
605
- ),
606
- ApiError.EXCHANGE_USER_FROZEN: (
607
- status.HTTP_403_FORBIDDEN,
608
- status.WS_1008_POLICY_VIOLATION,
609
- ),
610
- ApiError.TRADING_LOCKED: (
611
- status.HTTP_403_FORBIDDEN,
612
- status.WS_1008_POLICY_VIOLATION,
613
- ),
614
- ApiError.FORBIDDEN: (
615
- status.HTTP_403_FORBIDDEN,
616
- status.WS_1008_POLICY_VIOLATION,
617
- ),
618
- # Not Found
619
- ApiError.URL_NOT_FOUND: (
620
- status.HTTP_404_NOT_FOUND,
621
- status.WS_1008_POLICY_VIOLATION,
622
- ),
623
- ApiError.OBJECT_NOT_FOUND: (
624
- status.HTTP_404_NOT_FOUND,
625
- status.WS_1008_POLICY_VIOLATION,
626
- ),
627
- ApiError.ORDER_NOT_FOUND: (
628
- status.HTTP_404_NOT_FOUND,
629
- status.WS_1008_POLICY_VIOLATION,
630
- ),
631
- ApiError.POSITION_NOT_FOUND: (
632
- status.HTTP_404_NOT_FOUND,
633
- status.WS_1008_POLICY_VIOLATION,
634
- ),
635
- ApiError.SYMBOL_NOT_FOUND: (
636
- status.HTTP_404_NOT_FOUND,
637
- status.WS_1008_POLICY_VIOLATION,
638
- ),
639
- # Conflicts/Duplicates
640
- ApiError.CLIENT_ORDER_ID_REPEATED: (
641
- status.HTTP_409_CONFLICT,
642
- status.WS_1008_POLICY_VIOLATION,
643
- ),
644
- ApiError.OBJECT_ALREADY_EXISTS: (
645
- status.HTTP_409_CONFLICT,
646
- status.WS_1008_POLICY_VIOLATION,
647
- ),
648
- ApiError.EXCHANGE_KEY_ALREADY_EXISTS: (
649
- status.HTTP_409_CONFLICT,
650
- status.WS_1008_POLICY_VIOLATION,
651
- ),
652
- ApiError.BOT_ALREADY_DELETED: (
653
- status.HTTP_409_CONFLICT,
654
- status.WS_1008_POLICY_VIOLATION,
655
- ),
656
- ApiError.NAME_NOT_UNIQUE: (
657
- status.HTTP_409_CONFLICT,
658
- status.WS_1008_POLICY_VIOLATION,
659
- ),
660
- # Invalid Content
661
- ApiError.CONTENT_TYPE_ERROR: (
662
- status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
663
- status.WS_1003_UNSUPPORTED_DATA,
664
- ),
665
- ApiError.INVALID_DATA_REQUEST: (
666
- status.HTTP_422_UNPROCESSABLE_ENTITY,
667
- status.WS_1007_INVALID_FRAME_PAYLOAD_DATA,
668
- ),
669
- ApiError.INVALID_DATA_RESPONSE: (
670
- status.HTTP_422_UNPROCESSABLE_ENTITY,
671
- status.WS_1007_INVALID_FRAME_PAYLOAD_DATA,
672
- ),
673
- # Rate Limits
674
- ApiError.EXCHANGE_RATE_LIMIT: (
675
- status.HTTP_429_TOO_MANY_REQUESTS,
676
- status.WS_1013_TRY_AGAIN_LATER,
677
- ),
678
- ApiError.REQUEST_SCOPE_EXCEEDED: (
679
- status.HTTP_429_TOO_MANY_REQUESTS,
680
- status.WS_1013_TRY_AGAIN_LATER,
681
- ),
682
- # Server Errors
683
- ApiError.UNKNOWN_ERROR: (
684
- status.HTTP_500_INTERNAL_SERVER_ERROR,
685
- status.WS_1011_INTERNAL_ERROR,
686
- ),
687
- ApiError.EXCHANGE_SYSTEM_ERROR: (
688
- status.HTTP_500_INTERNAL_SERVER_ERROR,
689
- status.WS_1011_INTERNAL_ERROR,
690
- ),
691
- ApiError.NOW_API_DOWN: (
692
- status.HTTP_500_INTERNAL_SERVER_ERROR,
693
- status.WS_1011_INTERNAL_ERROR,
694
- ),
695
- ApiError.RPC_TIMEOUT: (
696
- status.HTTP_500_INTERNAL_SERVER_ERROR,
697
- status.WS_1011_INTERNAL_ERROR,
698
- ),
699
- # Service Unavailable
700
- ApiError.EXCHANGE_SERVICE_UNAVAILABLE: (
701
- status.HTTP_503_SERVICE_UNAVAILABLE,
702
- status.WS_1011_INTERNAL_ERROR,
703
- ),
704
- ApiError.EXCHANGE_MAINTENANCE: (
705
- status.HTTP_503_SERVICE_UNAVAILABLE,
706
- status.WS_1011_INTERNAL_ERROR,
707
- ),
708
- ApiError.EXCHANGE_SYSTEM_BUSY: (
709
- status.HTTP_503_SERVICE_UNAVAILABLE,
710
- status.WS_1011_INTERNAL_ERROR,
711
- ),
712
- ApiError.SETTLEMENT_IN_PROGRESS: (
713
- status.HTTP_503_SERVICE_UNAVAILABLE,
714
- status.WS_1011_INTERNAL_ERROR,
715
- ),
716
- ApiError.POSITION_SUSPENDED: (
717
- status.HTTP_503_SERVICE_UNAVAILABLE,
718
- status.WS_1011_INTERNAL_ERROR,
719
- ),
720
- ApiError.TRADING_SUSPENDED: (
721
- status.HTTP_503_SERVICE_UNAVAILABLE,
722
- status.WS_1011_INTERNAL_ERROR,
723
- ),
724
- # Bad Requests (400) - Invalid parameters or states
725
- ApiError.MARGIN_MODE_CLASH: (
726
- status.HTTP_400_BAD_REQUEST,
727
- status.WS_1008_POLICY_VIOLATION,
728
- ),
729
- ApiError.INVALID_MODEL_NAME: (
730
- status.HTTP_400_BAD_REQUEST,
731
- status.WS_1008_POLICY_VIOLATION,
732
- ),
733
- ApiError.ALLOCATION_BELOW_EXPOSURE: (
734
- status.HTTP_400_BAD_REQUEST,
735
- status.WS_1008_POLICY_VIOLATION,
736
- ),
737
- ApiError.ALLOCATION_LIMIT_EXCEEDED: (
738
- status.HTTP_400_BAD_REQUEST,
739
- status.WS_1008_POLICY_VIOLATION,
740
- ),
741
- ApiError.ALLOCATION_BELOW_MINIMUM: (
742
- status.HTTP_400_BAD_REQUEST,
743
- status.WS_1008_POLICY_VIOLATION,
744
- ),
745
- ApiError.BLACK_SWAN: (
746
- status.HTTP_400_BAD_REQUEST,
747
- status.WS_1008_POLICY_VIOLATION,
748
- ),
749
- ApiError.DELETE_BOT_ERROR: (
750
- status.HTTP_400_BAD_REQUEST,
751
- status.WS_1008_POLICY_VIOLATION,
752
- ),
753
- ApiError.EXCHANGE_INVALID_SIGNATURE: (
754
- status.HTTP_400_BAD_REQUEST,
755
- status.WS_1008_POLICY_VIOLATION,
756
- ),
757
- ApiError.EXCHANGE_INVALID_TIMESTAMP: (
758
- status.HTTP_400_BAD_REQUEST,
759
- status.WS_1008_POLICY_VIOLATION,
760
- ),
761
- ApiError.EXCHANGE_IP_RESTRICTED: (
762
- status.HTTP_400_BAD_REQUEST,
763
- status.WS_1008_POLICY_VIOLATION,
764
- ),
765
- ApiError.EXCHANGE_KEY_IN_USE: (
766
- status.HTTP_400_BAD_REQUEST,
767
- status.WS_1008_POLICY_VIOLATION,
768
- ),
769
- ApiError.EXCHANGE_SYSTEM_CONFIG_ERROR: (
770
- status.HTTP_400_BAD_REQUEST,
771
- status.WS_1008_POLICY_VIOLATION,
772
- ),
773
- ApiError.HEDGE_MODE_NOT_ACTIVE: (
774
- status.HTTP_400_BAD_REQUEST,
775
- status.WS_1008_POLICY_VIOLATION,
776
- ),
777
- ApiError.EXCHANGE_HTTP_ERROR: (
778
- status.HTTP_400_BAD_REQUEST,
779
- status.WS_1008_POLICY_VIOLATION,
780
- ),
781
- ApiError.INSUFFICIENT_BALANCE: (
782
- status.HTTP_400_BAD_REQUEST,
783
- status.WS_1008_POLICY_VIOLATION,
784
- ),
785
- ApiError.INSUFFICIENT_MARGIN: (
786
- status.HTTP_400_BAD_REQUEST,
787
- status.WS_1008_POLICY_VIOLATION,
788
- ),
789
- ApiError.INVALID_EXCHANGE_KEY: (
790
- status.HTTP_400_BAD_REQUEST,
791
- status.WS_1008_POLICY_VIOLATION,
792
- ),
793
- ApiError.EXCHANGE_INVALID_PARAMETER: (
794
- status.HTTP_400_BAD_REQUEST,
795
- status.WS_1008_POLICY_VIOLATION,
796
- ),
797
- ApiError.LEVERAGE_EXCEEDED: (
798
- status.HTTP_400_BAD_REQUEST,
799
- status.WS_1008_POLICY_VIOLATION,
800
- ),
801
- ApiError.LIQUIDATION_PRICE_VIOLATION: (
802
- status.HTTP_400_BAD_REQUEST,
803
- status.WS_1008_POLICY_VIOLATION,
804
- ),
805
- ApiError.ORDER_ALREADY_FILLED: (
806
- status.HTTP_400_BAD_REQUEST,
807
- status.WS_1008_POLICY_VIOLATION,
808
- ),
809
- ApiError.ORDER_IN_PROCESS: (
810
- status.HTTP_400_BAD_REQUEST,
811
- status.WS_1008_POLICY_VIOLATION,
812
- ),
813
- ApiError.ORDER_LIMIT_EXCEEDED: (
814
- status.HTTP_400_BAD_REQUEST,
815
- status.WS_1008_POLICY_VIOLATION,
816
- ),
817
- ApiError.ORDER_PRICE_INVALID: (
818
- status.HTTP_400_BAD_REQUEST,
819
- status.WS_1008_POLICY_VIOLATION,
820
- ),
821
- ApiError.ORDER_SIZE_TOO_LARGE: (
822
- status.HTTP_400_BAD_REQUEST,
823
- status.WS_1008_POLICY_VIOLATION,
824
- ),
825
- ApiError.ORDER_SIZE_TOO_SMALL: (
826
- status.HTTP_400_BAD_REQUEST,
827
- status.WS_1008_POLICY_VIOLATION,
828
- ),
829
- ApiError.ORPHAN_OPEN_ORDER: (
830
- status.HTTP_400_BAD_REQUEST,
831
- status.WS_1008_POLICY_VIOLATION,
832
- ),
833
- ApiError.ORPHAN_CLOSE_ORDER: (
834
- status.HTTP_400_BAD_REQUEST,
835
- status.WS_1008_POLICY_VIOLATION,
836
- ),
837
- ApiError.POSITION_LIMIT_EXCEEDED: (
838
- status.HTTP_400_BAD_REQUEST,
839
- status.WS_1008_POLICY_VIOLATION,
840
- ),
841
- ApiError.POST_ONLY_REJECTED: (
842
- status.HTTP_400_BAD_REQUEST,
843
- status.WS_1008_POLICY_VIOLATION,
844
- ),
845
- ApiError.RISK_LIMIT_EXCEEDED: (
846
- status.HTTP_400_BAD_REQUEST,
847
- status.WS_1008_POLICY_VIOLATION,
848
- ),
849
- ApiError.STRATEGY_DISABLED: (
850
- status.HTTP_400_BAD_REQUEST,
851
- status.WS_1008_POLICY_VIOLATION,
852
- ),
853
- ApiError.STRATEGY_LEVERAGE_MISMATCH: (
854
- status.HTTP_400_BAD_REQUEST,
855
- status.WS_1008_POLICY_VIOLATION,
856
- ),
857
- ApiError.STRATEGY_NOT_SUPPORTING_EXCHANGE: (
858
- status.HTTP_400_BAD_REQUEST,
859
- status.WS_1008_POLICY_VIOLATION,
860
- ),
861
- ApiError.TRADING_ACTION_EXPIRED: (
862
- status.HTTP_400_BAD_REQUEST,
863
- status.WS_1008_POLICY_VIOLATION,
864
- ),
865
- ApiError.TRADING_ACTION_SKIPPED_BOT_STOPPING: (
866
- status.HTTP_400_BAD_REQUEST,
867
- status.WS_1008_POLICY_VIOLATION,
868
- ),
869
- # Success cases
870
- ApiError.SUCCESS: (status.HTTP_200_OK, status.WS_1000_NORMAL_CLOSURE),
871
- ApiError.BOT_STOPPING_COMPLETED: (
872
- status.HTTP_200_OK,
873
- status.WS_1000_NORMAL_CLOSURE,
874
- ),
875
- ApiError.BOT_STOPPING_STARTED: (
876
- status.HTTP_200_OK,
877
- status.WS_1000_NORMAL_CLOSURE,
878
- ),
879
- ApiError.OBJECT_CREATED: (
880
- status.HTTP_201_CREATED,
881
- status.WS_1000_NORMAL_CLOSURE,
882
- ),
883
- ApiError.OBJECT_UPDATED: (status.HTTP_200_OK, status.WS_1000_NORMAL_CLOSURE),
884
- ApiError.OBJECT_DELETED: (
885
- status.HTTP_204_NO_CONTENT,
886
- status.WS_1000_NORMAL_CLOSURE,
887
- ),
888
- ApiError.CANCELLED_OPEN_ORDER: (
889
- status.HTTP_200_OK,
890
- status.WS_1008_POLICY_VIOLATION,
891
- ),
892
- ApiError.FAILED_OPEN_ORDER: (
893
- status.HTTP_200_OK,
894
- status.WS_1008_POLICY_VIOLATION,
895
- ),
896
- ApiError.COUPON_INVALID: (
897
- status.HTTP_200_OK,
898
- status.WS_1000_NORMAL_CLOSURE,
899
- ),
900
- # Miscellaneous
901
- ApiError.OBJECT_LOCKED: (
902
- status.HTTP_423_LOCKED,
903
- status.WS_1013_TRY_AGAIN_LATER,
904
- ),
905
- }
906
-
907
- @classmethod
908
- def get_http_code(cls, error: ApiError) -> int:
909
- """Get the HTTP status code for the error. If the error is not in the mapping, return 500."""
910
- return cls._mapping.get(error, cls._mapping[ApiError.UNKNOWN_ERROR])[0]
911
-
912
- @classmethod
913
- def get_websocket_code(cls, error: ApiError) -> int:
914
- """Get the WebSocket status code for the error. If the error is not in the mapping, return 1008."""
915
- return cls._mapping.get(error, cls._mapping[ApiError.UNKNOWN_ERROR])[1]