hubble-futures 0.2.13__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.
@@ -0,0 +1,151 @@
1
+ """
2
+ Exchange client factory and registry.
3
+
4
+ Usage:
5
+ from hubble_futures import create_client, ExchangeConfig
6
+
7
+ config = ExchangeConfig(
8
+ name="asterdex",
9
+ api_key="your_api_key",
10
+ api_secret="your_api_secret"
11
+ )
12
+ client = create_client(config)
13
+ klines = client.get_klines("BTCUSDT")
14
+
15
+ Function logging:
16
+ from hubble_futures import start_function_log, record_function_call, finish_function_call, export_function_log
17
+
18
+ start_function_log()
19
+ record_function_call("open_position", {"symbol": "BTCUSDT", "side": "BUY"})
20
+ finish_function_call("open_position", {"order_id": "12345", "status": "filled"})
21
+ result = export_function_log(clear=True)
22
+ """
23
+
24
+ from dataclasses import dataclass
25
+
26
+ from .aster import AsterFuturesClient
27
+ from .base import BaseFuturesClient
28
+ from .config import ExchangeConfig
29
+ from .function_log import (
30
+ add_error,
31
+ add_warning,
32
+ clear_function_log,
33
+ export_function_log,
34
+ finish_function_call,
35
+ get_function_log,
36
+ record_function_call,
37
+ set_trading_summary,
38
+ start_function_log,
39
+ )
40
+ from .version import __version__
41
+ from .weex import WeexFuturesClient
42
+
43
+
44
+ @dataclass
45
+ class ExchangeInfo:
46
+ """Exchange registration info - single source of truth."""
47
+ client_class: type[BaseFuturesClient]
48
+ default_url: str
49
+
50
+
51
+ # Single registry - add new exchanges here
52
+ # Each exchange only needs ONE entry (use primary name)
53
+ _EXCHANGE_REGISTRY: dict[str, ExchangeInfo] = {
54
+ "asterdex": ExchangeInfo(AsterFuturesClient, "https://fapi.asterdex.com"),
55
+ "weex": ExchangeInfo(WeexFuturesClient, "https://api-contract.weex.com"),
56
+ # "binance": ExchangeInfo(BinanceFuturesClient, "https://fapi.binance.com"),
57
+ # "okx": ExchangeInfo(OkxFuturesClient, "https://www.okx.com"),
58
+ }
59
+
60
+ # Aliases (alternative names that map to the same exchange)
61
+ _ALIASES: dict[str, str] = {
62
+ "aster": "asterdex",
63
+ }
64
+
65
+
66
+ def _resolve_name(name: str) -> str:
67
+ """Resolve alias to canonical name."""
68
+ name = name.lower()
69
+ return _ALIASES.get(name, name)
70
+
71
+
72
+ # Legacy compatibility - derived from registry
73
+ EXCHANGES: dict[str, type[BaseFuturesClient]] = {
74
+ name: info.client_class for name, info in _EXCHANGE_REGISTRY.items()
75
+ }
76
+ EXCHANGES.update({alias: _EXCHANGE_REGISTRY[target].client_class for alias, target in _ALIASES.items()})
77
+
78
+ DEFAULT_BASE_URLS: dict[str, str] = {
79
+ name: info.default_url for name, info in _EXCHANGE_REGISTRY.items()
80
+ }
81
+ DEFAULT_BASE_URLS.update({alias: _EXCHANGE_REGISTRY[target].default_url for alias, target in _ALIASES.items()})
82
+
83
+
84
+ def create_client(config: ExchangeConfig) -> BaseFuturesClient:
85
+ """
86
+ Factory function to create exchange client from config.
87
+
88
+ Args:
89
+ config: ExchangeConfig with exchange name and credentials
90
+
91
+ Returns:
92
+ Exchange client instance
93
+
94
+ Raises:
95
+ ValueError: If exchange is not supported
96
+
97
+ Example:
98
+ from hubble_futures import create_client, ExchangeConfig
99
+
100
+ config = ExchangeConfig(
101
+ name="asterdex",
102
+ api_key="...",
103
+ api_secret="..."
104
+ )
105
+ client = create_client(config)
106
+ """
107
+ canonical_name = _resolve_name(config.name)
108
+
109
+ if canonical_name not in _EXCHANGE_REGISTRY:
110
+ available = ", ".join(sorted(list(_EXCHANGE_REGISTRY.keys()) + list(_ALIASES.keys())))
111
+ raise ValueError(
112
+ f"Unknown exchange: '{config.name}'. "
113
+ f"Available exchanges: {available}"
114
+ )
115
+
116
+ exchange_info = _EXCHANGE_REGISTRY[canonical_name]
117
+ return exchange_info.client_class.from_config(config)
118
+
119
+
120
+ def list_exchanges() -> list: # type: ignore[type-arg]
121
+ """List all supported exchange names."""
122
+ return sorted(set(EXCHANGES.keys()))
123
+
124
+
125
+ def get_default_base_url(exchange_name: str) -> str:
126
+ """Get default base URL for an exchange."""
127
+ return DEFAULT_BASE_URLS.get(exchange_name.lower(), "")
128
+
129
+
130
+ __all__ = [
131
+ "create_client",
132
+ "list_exchanges",
133
+ "get_default_base_url",
134
+ "ExchangeConfig",
135
+ "BaseFuturesClient",
136
+ "AsterFuturesClient",
137
+ "WeexFuturesClient",
138
+ "EXCHANGES",
139
+ "DEFAULT_BASE_URLS",
140
+ "__version__",
141
+ # Function logging
142
+ "start_function_log",
143
+ "record_function_call",
144
+ "finish_function_call",
145
+ "set_trading_summary",
146
+ "add_warning",
147
+ "add_error",
148
+ "export_function_log",
149
+ "get_function_log",
150
+ "clear_function_log",
151
+ ]