alphasec-py 0.1.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.
- alphasec/__init__.py +10 -0
- alphasec/agent.py +191 -0
- alphasec/api/__init__.py +25 -0
- alphasec/api/api.py +474 -0
- alphasec/api/async_api.py +688 -0
- alphasec/api/constants.py +14 -0
- alphasec/api/utils.py +20 -0
- alphasec/async_agent.py +417 -0
- alphasec/exceptions.py +6 -0
- alphasec/perp/__init__.py +21 -0
- alphasec/perp/agent.py +428 -0
- alphasec/perp/async_agent.py +543 -0
- alphasec/perp/constants.py +19 -0
- alphasec/perp/ws.py +105 -0
- alphasec/transaction/__init__.py +0 -0
- alphasec/transaction/abi.py +360 -0
- alphasec/transaction/constants.py +47 -0
- alphasec/transaction/schemas.py +360 -0
- alphasec/transaction/sign.py +533 -0
- alphasec/transaction/utils.py +108 -0
- alphasec/websocket/__init__.py +8 -0
- alphasec/websocket/async_ws.py +616 -0
- alphasec/websocket/types.py +127 -0
- alphasec/websocket/ws.py +261 -0
- alphasec_py-0.1.0.dist-info/METADATA +96 -0
- alphasec_py-0.1.0.dist-info/RECORD +28 -0
- alphasec_py-0.1.0.dist-info/WHEEL +4 -0
- alphasec_py-0.1.0.dist-info/licenses/LICENSE +21 -0
alphasec/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .exceptions import AlphasecAPIError
|
|
2
|
+
from .transaction.utils import load_config
|
|
3
|
+
from .transaction.sign import AlphasecSigner
|
|
4
|
+
from .agent import Agent
|
|
5
|
+
from .async_agent import AsyncAgent
|
|
6
|
+
from .api.api import API
|
|
7
|
+
from .api.async_api import AsyncAPI
|
|
8
|
+
from .websocket.ws import WebsocketManager
|
|
9
|
+
from .websocket.async_ws import AsyncWebsocketManager
|
|
10
|
+
from .perp import decode_perp_event, PerpEvent, PerpAgent, AsyncPerpAgent
|
alphasec/agent.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from typing import Any, Callable, Optional
|
|
2
|
+
|
|
3
|
+
from alphasec.api.api import API
|
|
4
|
+
from alphasec.websocket.ws import WebsocketManager
|
|
5
|
+
from alphasec.transaction.sign import AlphasecSigner
|
|
6
|
+
from alphasec.api.utils import market_to_market_id
|
|
7
|
+
from alphasec.perp.agent import PerpAgent
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
# logging.basicConfig(level=logging.DEBUG)
|
|
11
|
+
|
|
12
|
+
class Agent:
|
|
13
|
+
def __init__(self, base_url: str, signer: Optional[AlphasecSigner] = None, timeout: Optional[int] = None):
|
|
14
|
+
self.api = API(base_url, timeout=timeout, signer=signer)
|
|
15
|
+
self.ws = WebsocketManager(base_url)
|
|
16
|
+
self.perp = PerpAgent(self)
|
|
17
|
+
|
|
18
|
+
# WebSocket lifecycle
|
|
19
|
+
def start(self) -> None:
|
|
20
|
+
self.ws.start()
|
|
21
|
+
|
|
22
|
+
def stop(self) -> None:
|
|
23
|
+
self.ws.stop()
|
|
24
|
+
|
|
25
|
+
# WebSocket subscriptions
|
|
26
|
+
def subscribe(self, channel: str, callback: Callable[[Any], None], timeout: Optional[int] = None) -> int:
|
|
27
|
+
"""
|
|
28
|
+
Subscribe to WebSocket channels with user-friendly channel format.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
channel : str
|
|
33
|
+
Channel in format 'type@target':
|
|
34
|
+
- 'trade@KAIA/USDT' for trade data
|
|
35
|
+
- 'ticker@BTC/USDT' for ticker data
|
|
36
|
+
- 'depth@ETH/USDT' for order book
|
|
37
|
+
- 'userEvent@0x123...' for user events
|
|
38
|
+
callback : Callable
|
|
39
|
+
Function to handle received messages
|
|
40
|
+
timeout : int, optional
|
|
41
|
+
Timeout in seconds
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
int
|
|
46
|
+
Subscription ID for later unsubscribing
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
agent.subscribe('trade@KAIA/USDT', print_trades)
|
|
51
|
+
agent.subscribe('userEvent@0x123...', print_events)
|
|
52
|
+
"""
|
|
53
|
+
if '@' not in channel:
|
|
54
|
+
raise ValueError(f"Channel format should be 'type@target', got: {channel}")
|
|
55
|
+
|
|
56
|
+
channel_type, target = channel.split('@', 1)
|
|
57
|
+
|
|
58
|
+
if channel_type in ['trade', 'ticker', 'depth']:
|
|
59
|
+
# Convert market name to market_id (lazy-load token metadata first)
|
|
60
|
+
self.api._ensure_initialized()
|
|
61
|
+
market_id = market_to_market_id(target, self.api.symbol_token_id_map)
|
|
62
|
+
actual_channel = f"{channel_type}@{market_id}"
|
|
63
|
+
elif channel_type == 'userEvent':
|
|
64
|
+
# Use address directly
|
|
65
|
+
actual_channel = f"{channel_type}@{target}"
|
|
66
|
+
else:
|
|
67
|
+
raise ValueError(f"Unsupported channel type: {channel_type}. Use 'trade', 'ticker', 'depth', or 'userEvent'")
|
|
68
|
+
|
|
69
|
+
return self.ws.subscribe(actual_channel, callback, timeout=timeout)
|
|
70
|
+
|
|
71
|
+
def unsubscribe(self, channel: str, subscription_id: int, timeout: Optional[int] = None) -> bool:
|
|
72
|
+
"""
|
|
73
|
+
Unsubscribe from WebSocket channels with user-friendly channel format.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
channel : str
|
|
78
|
+
Channel in format 'type@target' (same as used in subscribe)
|
|
79
|
+
subscription_id : int
|
|
80
|
+
ID returned from subscribe()
|
|
81
|
+
timeout : int, optional
|
|
82
|
+
Timeout in seconds
|
|
83
|
+
|
|
84
|
+
Examples
|
|
85
|
+
--------
|
|
86
|
+
agent.unsubscribe('trade@KAIA/USDT', sub_id)
|
|
87
|
+
agent.unsubscribe('userEvent@0x123...', sub_id)
|
|
88
|
+
"""
|
|
89
|
+
if '@' not in channel:
|
|
90
|
+
raise ValueError(f"Channel format should be 'type@target', got: {channel}")
|
|
91
|
+
|
|
92
|
+
channel_type, target = channel.split('@', 1)
|
|
93
|
+
|
|
94
|
+
if channel_type in ['trade', 'ticker', 'depth']:
|
|
95
|
+
# Convert market name to market_id (lazy-load token metadata first)
|
|
96
|
+
self.api._ensure_initialized()
|
|
97
|
+
market_id = market_to_market_id(target, self.api.symbol_token_id_map)
|
|
98
|
+
actual_channel = f"{channel_type}@{market_id}"
|
|
99
|
+
elif channel_type == 'userEvent':
|
|
100
|
+
# Use address directly
|
|
101
|
+
actual_channel = f"{channel_type}@{target}"
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError(f"Unsupported channel type: {channel_type}. Use 'trade', 'ticker', 'depth', or 'userEvent'")
|
|
104
|
+
|
|
105
|
+
return self.ws.unsubscribe(actual_channel, subscription_id, timeout=timeout)
|
|
106
|
+
|
|
107
|
+
# API helpers (commonly used)
|
|
108
|
+
def order(self, market: str, side: int, price: float, quantity: float, order_type: int, order_mode: int, tp_limit: Optional[float] = None, sl_trigger: Optional[float] = None, sl_limit: Optional[float] = None) -> dict:
|
|
109
|
+
return self.api.order(market, side, price, quantity, order_type, order_mode, tp_limit, sl_trigger, sl_limit)
|
|
110
|
+
|
|
111
|
+
def cancel(self, order_id: str) -> dict:
|
|
112
|
+
return self.api.cancel(order_id)
|
|
113
|
+
|
|
114
|
+
def cancel_all(self) -> dict:
|
|
115
|
+
return self.api.cancel_all()
|
|
116
|
+
|
|
117
|
+
def modify(self, order_id: str, new_price: Optional[float] = None, new_qty: Optional[float] = None, order_mode: Optional[int] = None) -> dict:
|
|
118
|
+
return self.api.modify(order_id, new_price, new_qty, order_mode)
|
|
119
|
+
|
|
120
|
+
def value_transfer(self, to: str, value: float) -> dict:
|
|
121
|
+
return self.api.value_transfer(to, value)
|
|
122
|
+
|
|
123
|
+
def token_transfer(self, to: str, value: float, token: str) -> dict:
|
|
124
|
+
return self.api.token_transfer(to, value, token)
|
|
125
|
+
|
|
126
|
+
def withdraw(self, token: str, value: float) -> dict:
|
|
127
|
+
return self.api.withdraw_to_kaia(token, value)
|
|
128
|
+
|
|
129
|
+
def deposit(self, token: str, value: float) -> dict:
|
|
130
|
+
return self.api.deposit_to_alphasec(token, value)
|
|
131
|
+
|
|
132
|
+
# State accessors
|
|
133
|
+
@property
|
|
134
|
+
def l1_address(self):
|
|
135
|
+
return self.api.signer.l1_address if self.api.signer else None
|
|
136
|
+
|
|
137
|
+
def is_session_enabled(self) -> bool:
|
|
138
|
+
return bool(self.api.signer and self.api.signer.session_enabled)
|
|
139
|
+
|
|
140
|
+
# Market data helpers
|
|
141
|
+
def get_depth(self, market: str, limit: int = 100) -> dict:
|
|
142
|
+
return self.api.get_depth(market, limit)
|
|
143
|
+
|
|
144
|
+
def get_ticker(self, market: str) -> dict:
|
|
145
|
+
return self.api.get_ticker(market)
|
|
146
|
+
|
|
147
|
+
def get_tickers(self) -> list[dict]:
|
|
148
|
+
return self.api.get_tickers()
|
|
149
|
+
|
|
150
|
+
def get_market_list(self) -> list[dict]:
|
|
151
|
+
return self.api.get_market_list()
|
|
152
|
+
|
|
153
|
+
def get_trades(self, market: str, limit: int = 100) -> list[dict]:
|
|
154
|
+
return self.api.get_trades(market, limit)
|
|
155
|
+
|
|
156
|
+
def get_tokens(self) -> list[dict]:
|
|
157
|
+
return self.api.get_tokens()
|
|
158
|
+
|
|
159
|
+
# Order history helpers
|
|
160
|
+
def get_open_orders(self, addr: str, market: str, limit: int = 100, from_msec: Optional[int] = None, end_msec: Optional[int] = None) -> list[dict]:
|
|
161
|
+
return self.api.get_open_orders(addr, market, limit, from_msec, end_msec)
|
|
162
|
+
|
|
163
|
+
def get_filled_canceled_orders(self, addr: str, market: str, limit: int = 100, from_msec: Optional[int] = None, end_msec: Optional[int] = None) -> list[dict]:
|
|
164
|
+
return self.api.get_filled_canceled_orders(addr, market, limit, from_msec, end_msec)
|
|
165
|
+
|
|
166
|
+
def get_order_by_id(self, order_id: str) -> dict:
|
|
167
|
+
return self.api.get_order_by_id(order_id)
|
|
168
|
+
|
|
169
|
+
# Wallet/session helpers
|
|
170
|
+
def get_balance(self, addr: str) -> dict:
|
|
171
|
+
return self.api.get_balance(addr)
|
|
172
|
+
|
|
173
|
+
def get_sessions(self, addr: str) -> list[dict]:
|
|
174
|
+
return self.api.get_sessions(addr)
|
|
175
|
+
|
|
176
|
+
def get_transfer_history(self, addr: str, token_id: Optional[int] = None, from_msec: Optional[int] = None, to_msec: Optional[int] = None, limit: int = 100) -> list[dict]:
|
|
177
|
+
return self.api.get_transfer_history(addr, token_id, from_msec, to_msec, limit)
|
|
178
|
+
|
|
179
|
+
# Session management
|
|
180
|
+
def create_session(self, session_id: str, session_wallet, expiry: int, nonce: int) -> dict:
|
|
181
|
+
return self.api.create_session(session_id, session_wallet, expiry, nonce)
|
|
182
|
+
|
|
183
|
+
def update_session(self, session_id: str, session_wallet, expiry: int, nonce: int) -> dict:
|
|
184
|
+
return self.api.update_session(session_id, session_wallet, expiry, nonce)
|
|
185
|
+
|
|
186
|
+
def delete_session(self, session_wallet) -> dict:
|
|
187
|
+
return self.api.delete_session(session_wallet)
|
|
188
|
+
|
|
189
|
+
# Additional trading helpers
|
|
190
|
+
def stop_order(self, market: str, stop_price: int, price: int, quantity: int, side: int, order_type: int, order_mode: int) -> dict:
|
|
191
|
+
return self.api.stop_order(market, stop_price, price, quantity, side, order_type, order_mode)
|
alphasec/api/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .constants import (
|
|
2
|
+
BUY,
|
|
3
|
+
SELL,
|
|
4
|
+
LIMIT,
|
|
5
|
+
MARKET,
|
|
6
|
+
BASE_MODE,
|
|
7
|
+
QUOTE_MODE,
|
|
8
|
+
MAINNET_URL,
|
|
9
|
+
KAIROS_URL,
|
|
10
|
+
ALPHASEC_MAINNET_URL,
|
|
11
|
+
ALPHASEC_KAIROS_URL,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BUY",
|
|
16
|
+
"SELL",
|
|
17
|
+
"LIMIT",
|
|
18
|
+
"MARKET",
|
|
19
|
+
"BASE_MODE",
|
|
20
|
+
"QUOTE_MODE",
|
|
21
|
+
"MAINNET_URL",
|
|
22
|
+
"KAIROS_URL",
|
|
23
|
+
"ALPHASEC_MAINNET_URL",
|
|
24
|
+
"ALPHASEC_KAIROS_URL",
|
|
25
|
+
]
|