polymarket-apis 0.2.2__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.
Potentially problematic release.
This version of polymarket-apis might be problematic. Click here for more details.
- polymarket_apis/__init__.py +2 -0
- polymarket_apis/clients/__init__.py +0 -0
- polymarket_apis/clients/clob_client.py +730 -0
- polymarket_apis/clients/data_client.py +234 -0
- polymarket_apis/clients/gamma_client.py +311 -0
- polymarket_apis/clients/web3_client.py +261 -0
- polymarket_apis/clients/websockets_client.py +131 -0
- polymarket_apis/types/__init__.py +0 -0
- polymarket_apis/types/clob_types.py +494 -0
- polymarket_apis/types/common.py +49 -0
- polymarket_apis/types/data_types.py +161 -0
- polymarket_apis/types/gamma_types.py +313 -0
- polymarket_apis/types/websockets_types.py +191 -0
- polymarket_apis/utilities/__init__.py +0 -0
- polymarket_apis/utilities/config.py +36 -0
- polymarket_apis/utilities/constants.py +26 -0
- polymarket_apis/utilities/endpoints.py +37 -0
- polymarket_apis/utilities/exceptions.py +11 -0
- polymarket_apis/utilities/headers.py +54 -0
- polymarket_apis/utilities/order_builder/__init__.py +0 -0
- polymarket_apis/utilities/order_builder/builder.py +240 -0
- polymarket_apis/utilities/order_builder/helpers.py +61 -0
- polymarket_apis/utilities/signing/__init__.py +0 -0
- polymarket_apis/utilities/signing/eip712.py +28 -0
- polymarket_apis/utilities/signing/hmac.py +20 -0
- polymarket_apis/utilities/signing/model.py +8 -0
- polymarket_apis/utilities/signing/signer.py +25 -0
- polymarket_apis/utilities/web3/__init__.py +0 -0
- polymarket_apis/utilities/web3/abis/CTFExchange.json +1851 -0
- polymarket_apis/utilities/web3/abis/ConditionalTokens.json +705 -0
- polymarket_apis/utilities/web3/abis/NegRiskAdapter.json +999 -0
- polymarket_apis/utilities/web3/abis/NegRiskCtfExchange.json +1856 -0
- polymarket_apis/utilities/web3/abis/ProxyWalletFactory.json +319 -0
- polymarket_apis/utilities/web3/abis/UChildERC20Proxy.json +1438 -0
- polymarket_apis/utilities/web3/abis/__init__.py +0 -0
- polymarket_apis/utilities/web3/abis/custom_contract_errors.py +31 -0
- polymarket_apis/utilities/web3/helpers.py +8 -0
- polymarket_apis-0.2.2.dist-info/METADATA +18 -0
- polymarket_apis-0.2.2.dist-info/RECORD +40 -0
- polymarket_apis-0.2.2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from json import load
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Literal, Optional
|
|
4
|
+
|
|
5
|
+
from web3 import Web3
|
|
6
|
+
from web3.exceptions import ContractCustomError
|
|
7
|
+
from web3.middleware import ExtraDataToPOAMiddleware, SignAndSendRawMiddlewareBuilder
|
|
8
|
+
|
|
9
|
+
from ..types.common import EthAddress, Keccak256
|
|
10
|
+
from ..utilities.config import get_contract_config
|
|
11
|
+
from ..utilities.constants import HASH_ZERO, POLYGON
|
|
12
|
+
from ..utilities.web3.abis.custom_contract_errors import CUSTOM_ERROR_DICT
|
|
13
|
+
from ..utilities.web3.helpers import get_index_set
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_abi(contract_name: str) -> list:
|
|
17
|
+
abi_path = Path(__file__).parent.parent/"utilities"/"web3"/"abis"/f"{contract_name}.json"
|
|
18
|
+
with Path.open(abi_path) as f:
|
|
19
|
+
return load(f)
|
|
20
|
+
|
|
21
|
+
class PolymarketWeb3Client:
|
|
22
|
+
def __init__(self, private_key: str , chain_id: Literal[137, 80002] = POLYGON):
|
|
23
|
+
|
|
24
|
+
self.w3 = Web3(Web3.HTTPProvider("https://polygon-rpc.com"))
|
|
25
|
+
self.w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
|
|
26
|
+
self.w3.middleware_onion.inject(SignAndSendRawMiddlewareBuilder.build(private_key), layer=0)
|
|
27
|
+
|
|
28
|
+
self.account = self.w3.eth.account.from_key(private_key)
|
|
29
|
+
|
|
30
|
+
self.config = get_contract_config(chain_id, neg_risk=False)
|
|
31
|
+
self.neg_risk_config = get_contract_config(chain_id, neg_risk=True)
|
|
32
|
+
|
|
33
|
+
self.usdc_address = Web3.to_checksum_address(self.config.collateral)
|
|
34
|
+
self.usdc_abi = _load_abi("UChildERC20Proxy")
|
|
35
|
+
self.usdc = self.contract(self.usdc_address, self.usdc_abi)
|
|
36
|
+
|
|
37
|
+
self.conditional_tokens_address = Web3.to_checksum_address(self.config.conditional_tokens)
|
|
38
|
+
self.conditional_tokens_abi = _load_abi("ConditionalTokens")
|
|
39
|
+
self.conditional_tokens = self.contract(self.conditional_tokens_address, self.conditional_tokens_abi)
|
|
40
|
+
|
|
41
|
+
self.exchange_address = Web3.to_checksum_address(self.config.exchange)
|
|
42
|
+
self.exchange_abi = _load_abi("CTFExchange")
|
|
43
|
+
self.exchange = self.contract(self.exchange_address, self.exchange_abi)
|
|
44
|
+
|
|
45
|
+
self.neg_risk_exchange_address = Web3.to_checksum_address(self.neg_risk_config.exchange)
|
|
46
|
+
self.neg_risk_exchange_abi = _load_abi("NegRiskCtfExchange")
|
|
47
|
+
self.neg_risk_exchange = self.contract(self.neg_risk_exchange_address, self.neg_risk_exchange_abi)
|
|
48
|
+
|
|
49
|
+
self.neg_risk_adapter_address = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296"
|
|
50
|
+
self.neg_risk_adapter_abi = _load_abi("NegRiskAdapter")
|
|
51
|
+
self.neg_risk_adapter = self.contract(self.neg_risk_adapter_address, self.neg_risk_adapter_abi)
|
|
52
|
+
|
|
53
|
+
self.proxy_factory_address = "0xaB45c5A4B0c941a2F231C04C3f49182e1A254052"
|
|
54
|
+
self.proxy_factory_abi = _load_abi("ProxyWalletFactory")
|
|
55
|
+
self.proxy_factory = self.contract(self.proxy_factory_address, self.proxy_factory_abi)
|
|
56
|
+
|
|
57
|
+
def _encode_split(self, condition_id: Keccak256, amount: int) -> str:
|
|
58
|
+
return self.conditional_tokens.encode_abi(
|
|
59
|
+
abi_element_identifier="splitPosition",
|
|
60
|
+
args=[self.usdc_address, HASH_ZERO, condition_id, [1, 2], amount],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def _encode_merge(self, condition_id: Keccak256, amount: int) -> str:
|
|
64
|
+
return self.conditional_tokens.encode_abi(
|
|
65
|
+
abi_element_identifier="mergePositions",
|
|
66
|
+
args=[self.usdc_address, HASH_ZERO, condition_id, [1, 2], amount],
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def _encode_redeem(self, condition_id: Keccak256) -> str:
|
|
70
|
+
return self.conditional_tokens.encode_abi(
|
|
71
|
+
abi_element_identifier="redeemPositions",
|
|
72
|
+
args=[self.usdc_address, HASH_ZERO, condition_id, [1, 2]],
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def _encode_redeem_neg_risk(self, condition_id: Keccak256, amounts: list[int]) -> str:
|
|
76
|
+
return self.neg_risk_adapter.encode_abi(
|
|
77
|
+
abi_element_identifier="redeemPositions",
|
|
78
|
+
args=[condition_id, amounts],
|
|
79
|
+
)
|
|
80
|
+
def _encode_convert(self, neg_risk_market_id: Keccak256, index_set: int, amount: int):
|
|
81
|
+
return self.neg_risk_adapter.encode_abi(
|
|
82
|
+
abi_element_identifier="convertPositions",
|
|
83
|
+
args=[neg_risk_market_id, index_set, amount],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def contract(self, address, abi):
|
|
87
|
+
return self.w3.eth.contract(
|
|
88
|
+
address=Web3.to_checksum_address(address),
|
|
89
|
+
abi=abi,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def get_usdc_balance(self, address: EthAddress | None = None) -> float:
|
|
93
|
+
"""
|
|
94
|
+
Get the usdc balance of the given address.
|
|
95
|
+
|
|
96
|
+
If no address is given, the balance of the proxy account corresponding to
|
|
97
|
+
the private key is returned (i.e. Polymarket balance).
|
|
98
|
+
Explicitly passing the proxy address is faster due to only one contract function call.
|
|
99
|
+
"""
|
|
100
|
+
if address is None:
|
|
101
|
+
address = self.exchange.functions.getPolyProxyWalletAddress(self.account.address).call()
|
|
102
|
+
balance_res = self.usdc.functions.balanceOf(address).call()
|
|
103
|
+
return float(balance_res / 1e6)
|
|
104
|
+
|
|
105
|
+
def get_token_balance(self, token_id: str, address: EthAddress | None = None) -> float:
|
|
106
|
+
"""Get the token balance of the given address."""
|
|
107
|
+
if address is None:
|
|
108
|
+
address = self.exchange.functions.getPolyProxyWalletAddress(self.account.address).call()
|
|
109
|
+
balance_res = self.conditional_tokens.functions.balanceOf(address, int(token_id)).call()
|
|
110
|
+
return float(balance_res / 1e6)
|
|
111
|
+
|
|
112
|
+
def get_token_complement(self, token_id: str) -> Optional[str]:
|
|
113
|
+
"""Get the complement of the given token."""
|
|
114
|
+
try:
|
|
115
|
+
return str(self.neg_risk_exchange.functions.getComplement(int(token_id)).call())
|
|
116
|
+
except ContractCustomError as e:
|
|
117
|
+
if e.args[0] in CUSTOM_ERROR_DICT:
|
|
118
|
+
try:
|
|
119
|
+
return str(self.exchange.functions.getComplement(int(token_id)).call())
|
|
120
|
+
except ContractCustomError as e2:
|
|
121
|
+
if e2.args[0] in CUSTOM_ERROR_DICT:
|
|
122
|
+
msg = f"{CUSTOM_ERROR_DICT[e2.args[0]]}"
|
|
123
|
+
raise ContractCustomError(
|
|
124
|
+
msg,
|
|
125
|
+
) from e2
|
|
126
|
+
|
|
127
|
+
def get_condition_id_neg_risk(self, question_id: Keccak256) -> Keccak256:
|
|
128
|
+
"""
|
|
129
|
+
Get the condition id for a given question id.
|
|
130
|
+
|
|
131
|
+
Warning: this works for neg risk markets (where the
|
|
132
|
+
outcomeSlotCount is represented by the last two digits of question id). Returns a keccak256 hash of
|
|
133
|
+
the oracle and question id.
|
|
134
|
+
"""
|
|
135
|
+
return "0x" + self.neg_risk_adapter.functions.getConditionId(question_id).call().hex()
|
|
136
|
+
|
|
137
|
+
def split_position(self, condition_id: Keccak256, amount: int, neg_risk: bool = True):
|
|
138
|
+
"""Splits usdc into two complementary positions of equal size."""
|
|
139
|
+
nonce = self.w3.eth.get_transaction_count(self.account.address)
|
|
140
|
+
amount = int(amount * 1e6)
|
|
141
|
+
|
|
142
|
+
proxy_txn = {
|
|
143
|
+
"typeCode": 1,
|
|
144
|
+
"to": self.neg_risk_adapter_address if neg_risk else self.conditional_tokens_address,
|
|
145
|
+
"value": 0,
|
|
146
|
+
"data": self._encode_split(condition_id, amount),
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Send transaction through proxy factory
|
|
150
|
+
txn_data = self.proxy_factory.functions.proxy([proxy_txn]).build_transaction({
|
|
151
|
+
"nonce": nonce,
|
|
152
|
+
"gasPrice": int(1.05 * self.w3.eth.gas_price),
|
|
153
|
+
"gas": 1000000,
|
|
154
|
+
"from": self.account.address,
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
# Sign and send transaction
|
|
158
|
+
signed_txn = self.account.sign_transaction(txn_data)
|
|
159
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction).hex()
|
|
160
|
+
|
|
161
|
+
print(f"Txn hash: {tx_hash}")
|
|
162
|
+
|
|
163
|
+
# Wait for transaction to be mined
|
|
164
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
165
|
+
|
|
166
|
+
print("Done!")
|
|
167
|
+
|
|
168
|
+
def merge_position(self, condition_id: Keccak256, amount: int, neg_risk: bool = True):
|
|
169
|
+
"""Merges two complementary positions into usdc."""
|
|
170
|
+
nonce = self.w3.eth.get_transaction_count(self.account.address)
|
|
171
|
+
amount = int(amount * 1e6)
|
|
172
|
+
|
|
173
|
+
proxy_txn = {
|
|
174
|
+
"typeCode": 1,
|
|
175
|
+
"to": self.neg_risk_adapter_address if neg_risk else self.conditional_tokens_address,
|
|
176
|
+
"value": 0,
|
|
177
|
+
"data": self._encode_merge(condition_id, amount),
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# Send transaction through proxy factory
|
|
181
|
+
txn_data = self.proxy_factory.functions.proxy([proxy_txn]).build_transaction({
|
|
182
|
+
"nonce": nonce,
|
|
183
|
+
"gasPrice": int(1.05 * self.w3.eth.gas_price),
|
|
184
|
+
"gas": 1000000,
|
|
185
|
+
"from": self.account.address,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
# Sign and send transaction
|
|
189
|
+
signed_txn = self.account.sign_transaction(txn_data)
|
|
190
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction).hex()
|
|
191
|
+
|
|
192
|
+
print(f"Txn hash: {tx_hash}")
|
|
193
|
+
|
|
194
|
+
# Wait for transaction to be mined
|
|
195
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
196
|
+
|
|
197
|
+
print("Done!")
|
|
198
|
+
def redeem_position(self, condition_id: Keccak256, amounts: list[float], neg_risk: bool = True):
|
|
199
|
+
"""
|
|
200
|
+
Redeem a position into usdc.
|
|
201
|
+
|
|
202
|
+
Takes a condition id and a list of sizes in shares [x, y]
|
|
203
|
+
where x is the number of shares of the first outcome
|
|
204
|
+
y is the number of shares of the second outcome.
|
|
205
|
+
"""
|
|
206
|
+
nonce = self.w3.eth.get_transaction_count(self.account.address)
|
|
207
|
+
amounts = [int(amount * 1e6) for amount in amounts]
|
|
208
|
+
|
|
209
|
+
proxy_txn = {
|
|
210
|
+
"typeCode": 1,
|
|
211
|
+
"to": self.neg_risk_adapter_address if neg_risk else self.conditional_tokens_address,
|
|
212
|
+
"value": 0,
|
|
213
|
+
"data": self._encode_redeem_neg_risk(condition_id, amounts) if neg_risk else self._encode_redeem(condition_id),
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
# Send transaction through proxy factory
|
|
217
|
+
txn_data = self.proxy_factory.functions.proxy([proxy_txn]).build_transaction({
|
|
218
|
+
"nonce": nonce,
|
|
219
|
+
"gasPrice": int(1.05 * self.w3.eth.gas_price),
|
|
220
|
+
"gas": 1000000,
|
|
221
|
+
"from": self.account.address,
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
# Sign and send transaction
|
|
225
|
+
signed_txn = self.account.sign_transaction(txn_data)
|
|
226
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction).hex()
|
|
227
|
+
|
|
228
|
+
print(f"Txn hash: {tx_hash}")
|
|
229
|
+
|
|
230
|
+
# Wait for transaction to be mined
|
|
231
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
232
|
+
|
|
233
|
+
print("Done!")
|
|
234
|
+
|
|
235
|
+
def convert_positions(self, question_ids: list[Keccak256], neg_risk_market_id: Keccak256, amount: int):
|
|
236
|
+
nonce = self.w3.eth.get_transaction_count(self.account.address)
|
|
237
|
+
amount = int(amount * 1e6)
|
|
238
|
+
|
|
239
|
+
proxy_txn = {
|
|
240
|
+
"typeCode": 1,
|
|
241
|
+
"to": self.neg_risk_adapter_address,
|
|
242
|
+
"value": 0,
|
|
243
|
+
"data": self._encode_convert(neg_risk_market_id, get_index_set(question_ids), amount),
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
txn_data = self.proxy_factory.functions.proxy([proxy_txn]).build_transaction({
|
|
247
|
+
"nonce": nonce,
|
|
248
|
+
"gasPrice": int(1.05 * self.w3.eth.gas_price),
|
|
249
|
+
"gas": 1000000,
|
|
250
|
+
"from": self.account.address,
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
signed_txn = self.account.sign_transaction(txn_data)
|
|
254
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction).hex()
|
|
255
|
+
|
|
256
|
+
print(f"Txn hash: {tx_hash}")
|
|
257
|
+
|
|
258
|
+
# Wait for transaction to be mined
|
|
259
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
260
|
+
|
|
261
|
+
print("Done!")
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from lomond import WebSocket
|
|
5
|
+
from lomond.persist import persist
|
|
6
|
+
from pydantic import ValidationError
|
|
7
|
+
|
|
8
|
+
from ..types.clob_types import ApiCreds
|
|
9
|
+
from ..types.websockets_types import (
|
|
10
|
+
CommentEvent,
|
|
11
|
+
LiveDataOrderMatchEvent,
|
|
12
|
+
LiveDataTradeEvent,
|
|
13
|
+
OrderBookSummaryEvent,
|
|
14
|
+
OrderEvent,
|
|
15
|
+
PriceChangeEvent,
|
|
16
|
+
QuoteEvent,
|
|
17
|
+
ReactionEvent,
|
|
18
|
+
RequestEvent,
|
|
19
|
+
TickSizeChangeEvent,
|
|
20
|
+
TradeEvent,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _process_market_event(event):
|
|
25
|
+
try:
|
|
26
|
+
event = event.json
|
|
27
|
+
for message in event:
|
|
28
|
+
match message["event_type"]:
|
|
29
|
+
case "book":
|
|
30
|
+
print(OrderBookSummaryEvent(**message), "\n")
|
|
31
|
+
case "price_change":
|
|
32
|
+
print(PriceChangeEvent(**message), "\n")
|
|
33
|
+
case "tick_size_change":
|
|
34
|
+
print(TickSizeChangeEvent(**message), "\n")
|
|
35
|
+
except ValidationError as e:
|
|
36
|
+
print(event.text)
|
|
37
|
+
print(e.errors(), "\n")
|
|
38
|
+
|
|
39
|
+
def _process_user_event(event):
|
|
40
|
+
try:
|
|
41
|
+
event = event.json
|
|
42
|
+
for message in event:
|
|
43
|
+
match message["event_type"]:
|
|
44
|
+
case "order":
|
|
45
|
+
print(OrderEvent(**message), "\n")
|
|
46
|
+
case "trade":
|
|
47
|
+
print(TradeEvent(**message), "\n")
|
|
48
|
+
except ValidationError as e:
|
|
49
|
+
print(event.text)
|
|
50
|
+
print(e.errors(), "\n")
|
|
51
|
+
|
|
52
|
+
def _process_live_data_event(event):
|
|
53
|
+
try:
|
|
54
|
+
message = event.json
|
|
55
|
+
match message["type"]:
|
|
56
|
+
case "trades":
|
|
57
|
+
print(LiveDataTradeEvent(**message), "\n")
|
|
58
|
+
case "orders_matched":
|
|
59
|
+
print(LiveDataOrderMatchEvent(**message), "\n")
|
|
60
|
+
case "comment_created" | "comment_removed":
|
|
61
|
+
print(CommentEvent(**message), "\n")
|
|
62
|
+
case "reaction_created" | "reaction_removed":
|
|
63
|
+
print(ReactionEvent(**message), "\n")
|
|
64
|
+
case "request_created" | "request_edited" | "request_canceled" | "request_expired":
|
|
65
|
+
print(RequestEvent(**message), "\n")
|
|
66
|
+
case "quote_created" | "quote_edited" | "quote_canceled" | "quote_expired":
|
|
67
|
+
print(QuoteEvent(**message), "\n")
|
|
68
|
+
except ValidationError as e:
|
|
69
|
+
print(event.text)
|
|
70
|
+
print(e.errors(), "\n")
|
|
71
|
+
|
|
72
|
+
class PolymarketWebsocketsClient:
|
|
73
|
+
def __init__(self):
|
|
74
|
+
self.url_market = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
|
|
75
|
+
self.url_user = "wss://ws-subscriptions-clob.polymarket.com/ws/user"
|
|
76
|
+
self.url_live_data = "wss://ws-live-data.polymarket.com"
|
|
77
|
+
|
|
78
|
+
def market_socket(self, token_ids: list[str], process_event: Callable = _process_market_event):
|
|
79
|
+
"""
|
|
80
|
+
Connect to the market websocket and subscribe to market events for specific token IDs.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
token_ids: List of token IDs to subscribe to
|
|
84
|
+
process_event: Callback function to process received events
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
websocket = WebSocket(self.url_market)
|
|
88
|
+
for event in persist(websocket): # persist automatically reconnects
|
|
89
|
+
if event.name == "ready":
|
|
90
|
+
websocket.send_json(
|
|
91
|
+
assets_ids=token_ids,
|
|
92
|
+
)
|
|
93
|
+
elif event.name == "text":
|
|
94
|
+
process_event(event)
|
|
95
|
+
|
|
96
|
+
def user_socket(self, creds: ApiCreds, process_event: Callable = _process_user_event):
|
|
97
|
+
"""
|
|
98
|
+
Connect to the user websocket and subscribe to user events.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
creds: API credentials for authentication
|
|
102
|
+
process_event: Callback function to process received events
|
|
103
|
+
|
|
104
|
+
"""
|
|
105
|
+
websocket = WebSocket(self.url_user)
|
|
106
|
+
for event in persist(websocket):
|
|
107
|
+
if event.name == "ready":
|
|
108
|
+
websocket.send_json(
|
|
109
|
+
auth = creds.model_dump(by_alias=True),
|
|
110
|
+
)
|
|
111
|
+
elif event.name == "text":
|
|
112
|
+
process_event(event)
|
|
113
|
+
|
|
114
|
+
def live_data_socket(self, subscriptions: list[dict[str, Any]], process_event: Callable = _process_live_data_event):
|
|
115
|
+
"""
|
|
116
|
+
Connect to the live data websocket and subscribe to specified events.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
subscriptions: List of subscription configurations
|
|
120
|
+
process_event: Callback function to process received events
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
websocket = WebSocket(self.url_live_data)
|
|
124
|
+
for event in persist(websocket):
|
|
125
|
+
if event.name == "ready":
|
|
126
|
+
websocket.send_json(
|
|
127
|
+
action="subscribe",
|
|
128
|
+
subscriptions=subscriptions,
|
|
129
|
+
)
|
|
130
|
+
elif event.name == "text":
|
|
131
|
+
process_event(event)
|
|
File without changes
|