ctrader-api-client 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.
Files changed (43) hide show
  1. ctrader_api_client/__init__.py +64 -0
  2. ctrader_api_client/_internal/__init__.py +26 -0
  3. ctrader_api_client/_internal/messages.py +348 -0
  4. ctrader_api_client/_internal/proto/OpenApiCommonMessages.py +42 -0
  5. ctrader_api_client/_internal/proto/OpenApiCommonModelMessages.py +30 -0
  6. ctrader_api_client/_internal/proto/OpenApiMessages.py +1112 -0
  7. ctrader_api_client/_internal/proto/OpenApiModelMessages.py +802 -0
  8. ctrader_api_client/_internal/proto/__init__.py +320 -0
  9. ctrader_api_client/_internal/serialization.py +84 -0
  10. ctrader_api_client/api/__init__.py +21 -0
  11. ctrader_api_client/api/accounts.py +71 -0
  12. ctrader_api_client/api/market_data.py +424 -0
  13. ctrader_api_client/api/symbols.py +171 -0
  14. ctrader_api_client/api/trading.py +506 -0
  15. ctrader_api_client/auth/__init__.py +14 -0
  16. ctrader_api_client/auth/credentials.py +72 -0
  17. ctrader_api_client/auth/manager.py +511 -0
  18. ctrader_api_client/client.py +475 -0
  19. ctrader_api_client/config.py +56 -0
  20. ctrader_api_client/connection/__init__.py +16 -0
  21. ctrader_api_client/connection/heartbeat.py +120 -0
  22. ctrader_api_client/connection/protocol.py +366 -0
  23. ctrader_api_client/connection/transport.py +123 -0
  24. ctrader_api_client/enums.py +138 -0
  25. ctrader_api_client/events/__init__.py +65 -0
  26. ctrader_api_client/events/emitter.py +254 -0
  27. ctrader_api_client/events/router.py +400 -0
  28. ctrader_api_client/events/types.py +340 -0
  29. ctrader_api_client/exceptions.py +231 -0
  30. ctrader_api_client/models/__init__.py +50 -0
  31. ctrader_api_client/models/_base.py +19 -0
  32. ctrader_api_client/models/account.py +177 -0
  33. ctrader_api_client/models/deal.py +242 -0
  34. ctrader_api_client/models/market_data.py +192 -0
  35. ctrader_api_client/models/order.py +262 -0
  36. ctrader_api_client/models/position.py +209 -0
  37. ctrader_api_client/models/requests.py +299 -0
  38. ctrader_api_client/models/symbol.py +194 -0
  39. ctrader_api_client/py.typed +0 -0
  40. ctrader_api_client-0.1.0.dist-info/METADATA +252 -0
  41. ctrader_api_client-0.1.0.dist-info/RECORD +43 -0
  42. ctrader_api_client-0.1.0.dist-info/WHEEL +4 -0
  43. ctrader_api_client-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,320 @@
1
+ """Generated protobuf messages for cTrader Open API."""
2
+
3
+ from .OpenApiCommonMessages import (
4
+ ProtoErrorRes,
5
+ ProtoHeartbeatEvent,
6
+ ProtoMessage,
7
+ )
8
+ from .OpenApiCommonModelMessages import (
9
+ ProtoErrorCode,
10
+ ProtoPayloadType,
11
+ )
12
+ from .OpenApiMessages import (
13
+ ProtoOAAccountAuthReq,
14
+ ProtoOAAccountAuthRes,
15
+ ProtoOAAccountDisconnectEvent,
16
+ ProtoOAAccountLogoutReq,
17
+ ProtoOAAccountLogoutRes,
18
+ ProtoOAAccountsTokenInvalidatedEvent,
19
+ ProtoOAAmendOrderReq,
20
+ ProtoOAAmendPositionSLTPReq,
21
+ ProtoOAApplicationAuthReq,
22
+ ProtoOAApplicationAuthRes,
23
+ ProtoOAAssetClassListReq,
24
+ ProtoOAAssetClassListRes,
25
+ ProtoOAAssetListReq,
26
+ ProtoOAAssetListRes,
27
+ ProtoOACancelOrderReq,
28
+ ProtoOACashFlowHistoryListReq,
29
+ ProtoOACashFlowHistoryListRes,
30
+ ProtoOAClientDisconnectEvent,
31
+ ProtoOAClosePositionReq,
32
+ ProtoOADealListByPositionIdReq,
33
+ ProtoOADealListByPositionIdRes,
34
+ ProtoOADealListReq,
35
+ ProtoOADealListRes,
36
+ ProtoOADealOffsetListReq,
37
+ ProtoOADealOffsetListRes,
38
+ ProtoOADepthEvent,
39
+ ProtoOAErrorRes,
40
+ ProtoOAExecutionEvent,
41
+ ProtoOAExpectedMarginReq,
42
+ ProtoOAExpectedMarginRes,
43
+ ProtoOAGetAccountListByAccessTokenReq,
44
+ ProtoOAGetAccountListByAccessTokenRes,
45
+ ProtoOAGetCtidProfileByTokenReq,
46
+ ProtoOAGetCtidProfileByTokenRes,
47
+ ProtoOAGetDynamicLeverageByIDReq,
48
+ ProtoOAGetDynamicLeverageByIDRes,
49
+ ProtoOAGetPositionUnrealizedPnLReq,
50
+ ProtoOAGetPositionUnrealizedPnLRes,
51
+ ProtoOAGetTickDataReq,
52
+ ProtoOAGetTickDataRes,
53
+ ProtoOAGetTrendbarsReq,
54
+ ProtoOAGetTrendbarsRes,
55
+ ProtoOAMarginCallListReq,
56
+ ProtoOAMarginCallListRes,
57
+ ProtoOAMarginCallTriggerEvent,
58
+ ProtoOAMarginCallUpdateEvent,
59
+ ProtoOAMarginCallUpdateReq,
60
+ ProtoOAMarginCallUpdateRes,
61
+ ProtoOAMarginChangedEvent,
62
+ ProtoOANewOrderReq,
63
+ ProtoOAOrderDetailsReq,
64
+ ProtoOAOrderDetailsRes,
65
+ ProtoOAOrderErrorEvent,
66
+ ProtoOAOrderListByPositionIdReq,
67
+ ProtoOAOrderListByPositionIdRes,
68
+ ProtoOAOrderListReq,
69
+ ProtoOAOrderListRes,
70
+ ProtoOAReconcileReq,
71
+ ProtoOAReconcileRes,
72
+ ProtoOARefreshTokenReq,
73
+ ProtoOARefreshTokenRes,
74
+ ProtoOASpotEvent,
75
+ ProtoOASubscribeDepthQuotesReq,
76
+ ProtoOASubscribeDepthQuotesRes,
77
+ ProtoOASubscribeLiveTrendbarReq,
78
+ ProtoOASubscribeLiveTrendbarRes,
79
+ ProtoOASubscribeSpotsReq,
80
+ ProtoOASubscribeSpotsRes,
81
+ ProtoOASymbolByIdReq,
82
+ ProtoOASymbolByIdRes,
83
+ ProtoOASymbolCategoryListReq,
84
+ ProtoOASymbolCategoryListRes,
85
+ ProtoOASymbolChangedEvent,
86
+ ProtoOASymbolsForConversionReq,
87
+ ProtoOASymbolsForConversionRes,
88
+ ProtoOASymbolsListReq,
89
+ ProtoOASymbolsListRes,
90
+ ProtoOATraderReq,
91
+ ProtoOATraderRes,
92
+ ProtoOATraderUpdatedEvent,
93
+ ProtoOATrailingSLChangedEvent,
94
+ ProtoOAUnsubscribeDepthQuotesReq,
95
+ ProtoOAUnsubscribeDepthQuotesRes,
96
+ ProtoOAUnsubscribeLiveTrendbarReq,
97
+ ProtoOAUnsubscribeLiveTrendbarRes,
98
+ ProtoOAUnsubscribeSpotsReq,
99
+ ProtoOAUnsubscribeSpotsRes,
100
+ ProtoOAv1PnLChangeEvent,
101
+ ProtoOAv1PnLChangeSubscribeReq,
102
+ ProtoOAv1PnLChangeSubscribeRes,
103
+ ProtoOAv1PnLChangeUnSubscribeReq,
104
+ ProtoOAv1PnLChangeUnSubscribeRes,
105
+ ProtoOAVersionReq,
106
+ ProtoOAVersionRes,
107
+ )
108
+ from .OpenApiModelMessages import (
109
+ ProtoOAAccessRights,
110
+ ProtoOAAccountType,
111
+ ProtoOAArchivedSymbol,
112
+ ProtoOAAsset,
113
+ ProtoOAAssetClass,
114
+ ProtoOABonusDepositWithdraw,
115
+ ProtoOAChangeBalanceType,
116
+ ProtoOAChangeBonusType,
117
+ ProtoOAClientPermissionScope,
118
+ ProtoOAClosePositionDetail,
119
+ ProtoOACommissionType,
120
+ ProtoOACtidProfile,
121
+ ProtoOACtidTraderAccount,
122
+ ProtoOADayOfWeek,
123
+ ProtoOADeal,
124
+ ProtoOADealOffset,
125
+ ProtoOADealStatus,
126
+ ProtoOADepositWithdraw,
127
+ ProtoOADepthQuote,
128
+ ProtoOADynamicLeverage,
129
+ ProtoOADynamicLeverageTier,
130
+ ProtoOAErrorCode,
131
+ ProtoOAExecutionType,
132
+ ProtoOAExpectedMargin,
133
+ ProtoOAHoliday,
134
+ ProtoOAInterval,
135
+ ProtoOALightSymbol,
136
+ ProtoOALimitedRiskMarginCalculationStrategy,
137
+ ProtoOAMarginCall,
138
+ ProtoOAMinCommissionType,
139
+ ProtoOANotificationType,
140
+ ProtoOAOrder,
141
+ ProtoOAOrderStatus,
142
+ ProtoOAOrderTriggerMethod,
143
+ ProtoOAOrderType,
144
+ ProtoOAPayloadType,
145
+ ProtoOAPosition,
146
+ ProtoOAPositionStatus,
147
+ ProtoOAPositionUnrealizedPnL,
148
+ ProtoOAQuoteType,
149
+ ProtoOAStopOutStrategy,
150
+ ProtoOASwapCalculationType,
151
+ ProtoOASymbol,
152
+ ProtoOASymbolCategory,
153
+ ProtoOASymbolDistanceType,
154
+ ProtoOATickData,
155
+ ProtoOATimeInForce,
156
+ ProtoOATotalMarginCalculationType,
157
+ ProtoOATradeData,
158
+ ProtoOATrader,
159
+ ProtoOATradeSide,
160
+ ProtoOATradingMode,
161
+ ProtoOATrendbar,
162
+ ProtoOATrendbarPeriod,
163
+ )
164
+
165
+
166
+ __all__ = [
167
+ "ProtoErrorCode",
168
+ "ProtoErrorRes",
169
+ "ProtoHeartbeatEvent",
170
+ "ProtoMessage",
171
+ "ProtoOAAccessRights",
172
+ "ProtoOAAccountAuthReq",
173
+ "ProtoOAAccountAuthRes",
174
+ "ProtoOAAccountDisconnectEvent",
175
+ "ProtoOAAccountLogoutReq",
176
+ "ProtoOAAccountLogoutRes",
177
+ "ProtoOAAccountType",
178
+ "ProtoOAAccountsTokenInvalidatedEvent",
179
+ "ProtoOAAmendOrderReq",
180
+ "ProtoOAAmendPositionSLTPReq",
181
+ "ProtoOAApplicationAuthReq",
182
+ "ProtoOAApplicationAuthRes",
183
+ "ProtoOAArchivedSymbol",
184
+ "ProtoOAAsset",
185
+ "ProtoOAAssetClass",
186
+ "ProtoOAAssetClassListReq",
187
+ "ProtoOAAssetClassListRes",
188
+ "ProtoOAAssetListReq",
189
+ "ProtoOAAssetListRes",
190
+ "ProtoOABonusDepositWithdraw",
191
+ "ProtoOACancelOrderReq",
192
+ "ProtoOACashFlowHistoryListReq",
193
+ "ProtoOACashFlowHistoryListRes",
194
+ "ProtoOAChangeBalanceType",
195
+ "ProtoOAChangeBonusType",
196
+ "ProtoOAClientDisconnectEvent",
197
+ "ProtoOAClientPermissionScope",
198
+ "ProtoOAClosePositionDetail",
199
+ "ProtoOAClosePositionReq",
200
+ "ProtoOACommissionType",
201
+ "ProtoOACtidProfile",
202
+ "ProtoOACtidTraderAccount",
203
+ "ProtoOADayOfWeek",
204
+ "ProtoOADeal",
205
+ "ProtoOADealListByPositionIdReq",
206
+ "ProtoOADealListByPositionIdRes",
207
+ "ProtoOADealListReq",
208
+ "ProtoOADealListRes",
209
+ "ProtoOADealOffset",
210
+ "ProtoOADealOffsetListReq",
211
+ "ProtoOADealOffsetListRes",
212
+ "ProtoOADealStatus",
213
+ "ProtoOADepositWithdraw",
214
+ "ProtoOADepthEvent",
215
+ "ProtoOADepthQuote",
216
+ "ProtoOADynamicLeverage",
217
+ "ProtoOADynamicLeverageTier",
218
+ "ProtoOAErrorCode",
219
+ "ProtoOAErrorRes",
220
+ "ProtoOAExecutionEvent",
221
+ "ProtoOAExecutionType",
222
+ "ProtoOAExpectedMargin",
223
+ "ProtoOAExpectedMarginReq",
224
+ "ProtoOAExpectedMarginRes",
225
+ "ProtoOAGetAccountListByAccessTokenReq",
226
+ "ProtoOAGetAccountListByAccessTokenRes",
227
+ "ProtoOAGetCtidProfileByTokenReq",
228
+ "ProtoOAGetCtidProfileByTokenRes",
229
+ "ProtoOAGetDynamicLeverageByIDReq",
230
+ "ProtoOAGetDynamicLeverageByIDRes",
231
+ "ProtoOAGetPositionUnrealizedPnLReq",
232
+ "ProtoOAGetPositionUnrealizedPnLRes",
233
+ "ProtoOAGetTickDataReq",
234
+ "ProtoOAGetTickDataRes",
235
+ "ProtoOAGetTrendbarsReq",
236
+ "ProtoOAGetTrendbarsRes",
237
+ "ProtoOAHoliday",
238
+ "ProtoOAInterval",
239
+ "ProtoOALightSymbol",
240
+ "ProtoOALimitedRiskMarginCalculationStrategy",
241
+ "ProtoOAMarginCall",
242
+ "ProtoOAMarginCallListReq",
243
+ "ProtoOAMarginCallListRes",
244
+ "ProtoOAMarginCallTriggerEvent",
245
+ "ProtoOAMarginCallUpdateEvent",
246
+ "ProtoOAMarginCallUpdateReq",
247
+ "ProtoOAMarginCallUpdateRes",
248
+ "ProtoOAMarginChangedEvent",
249
+ "ProtoOAMinCommissionType",
250
+ "ProtoOANewOrderReq",
251
+ "ProtoOANotificationType",
252
+ "ProtoOAOrder",
253
+ "ProtoOAOrderDetailsReq",
254
+ "ProtoOAOrderDetailsRes",
255
+ "ProtoOAOrderErrorEvent",
256
+ "ProtoOAOrderListByPositionIdReq",
257
+ "ProtoOAOrderListByPositionIdRes",
258
+ "ProtoOAOrderListReq",
259
+ "ProtoOAOrderListRes",
260
+ "ProtoOAOrderStatus",
261
+ "ProtoOAOrderTriggerMethod",
262
+ "ProtoOAOrderType",
263
+ "ProtoOAPayloadType",
264
+ "ProtoOAPosition",
265
+ "ProtoOAPositionStatus",
266
+ "ProtoOAPositionUnrealizedPnL",
267
+ "ProtoOAQuoteType",
268
+ "ProtoOAReconcileReq",
269
+ "ProtoOAReconcileRes",
270
+ "ProtoOARefreshTokenReq",
271
+ "ProtoOARefreshTokenRes",
272
+ "ProtoOASpotEvent",
273
+ "ProtoOAStopOutStrategy",
274
+ "ProtoOASubscribeDepthQuotesReq",
275
+ "ProtoOASubscribeDepthQuotesRes",
276
+ "ProtoOASubscribeLiveTrendbarReq",
277
+ "ProtoOASubscribeLiveTrendbarRes",
278
+ "ProtoOASubscribeSpotsReq",
279
+ "ProtoOASubscribeSpotsRes",
280
+ "ProtoOASwapCalculationType",
281
+ "ProtoOASymbol",
282
+ "ProtoOASymbolByIdReq",
283
+ "ProtoOASymbolByIdRes",
284
+ "ProtoOASymbolCategory",
285
+ "ProtoOASymbolCategoryListReq",
286
+ "ProtoOASymbolCategoryListRes",
287
+ "ProtoOASymbolChangedEvent",
288
+ "ProtoOASymbolDistanceType",
289
+ "ProtoOASymbolsForConversionReq",
290
+ "ProtoOASymbolsForConversionRes",
291
+ "ProtoOASymbolsListReq",
292
+ "ProtoOASymbolsListRes",
293
+ "ProtoOATickData",
294
+ "ProtoOATimeInForce",
295
+ "ProtoOATotalMarginCalculationType",
296
+ "ProtoOATradeData",
297
+ "ProtoOATradeSide",
298
+ "ProtoOATrader",
299
+ "ProtoOATraderReq",
300
+ "ProtoOATraderRes",
301
+ "ProtoOATraderUpdatedEvent",
302
+ "ProtoOATradingMode",
303
+ "ProtoOATrailingSLChangedEvent",
304
+ "ProtoOATrendbar",
305
+ "ProtoOATrendbarPeriod",
306
+ "ProtoOAUnsubscribeDepthQuotesReq",
307
+ "ProtoOAUnsubscribeDepthQuotesRes",
308
+ "ProtoOAUnsubscribeLiveTrendbarReq",
309
+ "ProtoOAUnsubscribeLiveTrendbarRes",
310
+ "ProtoOAUnsubscribeSpotsReq",
311
+ "ProtoOAUnsubscribeSpotsRes",
312
+ "ProtoOAVersionReq",
313
+ "ProtoOAVersionRes",
314
+ "ProtoOAv1PnLChangeEvent",
315
+ "ProtoOAv1PnLChangeSubscribeReq",
316
+ "ProtoOAv1PnLChangeSubscribeRes",
317
+ "ProtoOAv1PnLChangeUnSubscribeReq",
318
+ "ProtoOAv1PnLChangeUnSubscribeRes",
319
+ "ProtoPayloadType",
320
+ ]
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ import struct
4
+
5
+ import betterproto
6
+ from anyio.abc import ByteReceiveStream
7
+
8
+ from ..exceptions import FramingError
9
+
10
+
11
+ # Big-endian unsigned 4-byte integer format
12
+ _LENGTH_PREFIX_FORMAT = ">I"
13
+ _LENGTH_PREFIX_SIZE = 4
14
+
15
+ # Safety limit to prevent memory exhaustion from malformed messages
16
+ _MAX_MESSAGE_SIZE = 1024 * 1024 # 1MB
17
+
18
+
19
+ def encode_with_length_prefix(message: betterproto.Message) -> bytes:
20
+ """Encode a protobuf message with 4-byte big-endian length prefix.
21
+
22
+ Args:
23
+ message: A betterproto message to encode.
24
+
25
+ Returns:
26
+ The serialized message prefixed with its length as a 4-byte big-endian integer.
27
+ """
28
+ payload = bytes(message)
29
+ length_prefix = struct.pack(_LENGTH_PREFIX_FORMAT, len(payload))
30
+ return length_prefix + payload
31
+
32
+
33
+ async def read_exact(stream: ByteReceiveStream, num_bytes: int) -> bytes:
34
+ """Read exactly num_bytes from the stream.
35
+
36
+ Args:
37
+ stream: An async byte stream to read from.
38
+ num_bytes: The exact number of bytes to read.
39
+
40
+ Returns:
41
+ Exactly num_bytes of data.
42
+
43
+ Raises:
44
+ FramingError: If the stream closes before num_bytes are read.
45
+ """
46
+ chunks: list[bytes] = []
47
+ bytes_remaining = num_bytes
48
+
49
+ while bytes_remaining > 0:
50
+ chunk = await stream.receive(bytes_remaining)
51
+ if not chunk:
52
+ received = num_bytes - bytes_remaining
53
+ raise FramingError(expected_bytes=num_bytes, received_bytes=received)
54
+ chunks.append(chunk)
55
+ bytes_remaining -= len(chunk)
56
+
57
+ return b"".join(chunks)
58
+
59
+
60
+ async def read_framed_message(stream: ByteReceiveStream) -> bytes:
61
+ """Read a length-prefixed message from the stream.
62
+
63
+ Reads a 4-byte big-endian length prefix, then reads that many bytes as the payload.
64
+
65
+ Args:
66
+ stream: An async byte stream to read from.
67
+
68
+ Returns:
69
+ The message payload (without the length prefix).
70
+
71
+ Raises:
72
+ FramingError: If the stream closes before the complete message is read,
73
+ or if the message size exceeds _MAX_MESSAGE_SIZE.
74
+ """
75
+ # Read the 4-byte length prefix
76
+ length_bytes = await read_exact(stream, _LENGTH_PREFIX_SIZE)
77
+ (length,) = struct.unpack(_LENGTH_PREFIX_FORMAT, length_bytes)
78
+
79
+ # Validate message size
80
+ if length > _MAX_MESSAGE_SIZE:
81
+ raise FramingError(expected_bytes=_MAX_MESSAGE_SIZE, received_bytes=length)
82
+
83
+ # Read the payload
84
+ return await read_exact(stream, length)
@@ -0,0 +1,21 @@
1
+ """Domain-specific API classes for cTrader operations.
2
+
3
+ This module provides namespaced APIs for different aspects of trading:
4
+ - AccountsAPI: Account information retrieval
5
+ - SymbolsAPI: Symbol lookup and search
6
+ - TradingAPI: Order placement and position management
7
+ - MarketDataAPI: Market data subscriptions and historical data
8
+ """
9
+
10
+ from .accounts import AccountsAPI
11
+ from .market_data import MarketDataAPI
12
+ from .symbols import SymbolsAPI
13
+ from .trading import TradingAPI
14
+
15
+
16
+ __all__ = [
17
+ "AccountsAPI",
18
+ "MarketDataAPI",
19
+ "SymbolsAPI",
20
+ "TradingAPI",
21
+ ]
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .._internal.proto import (
6
+ ProtoOATraderReq,
7
+ ProtoOATraderRes,
8
+ )
9
+ from ..exceptions import APIError
10
+ from ..models import Account
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from ..connection import Protocol
15
+
16
+
17
+ class AccountsAPI:
18
+ """Account information operations.
19
+
20
+ Provides methods to retrieve account/trader details.
21
+
22
+ Example:
23
+ ```python
24
+ account = await client.accounts.get_trader(account_id)
25
+ print(f"Balance: {account.get_balance()}")
26
+ print(f"Leverage: {account.get_leverage()}")
27
+ ```
28
+ """
29
+
30
+ def __init__(self, protocol: Protocol, default_timeout: float = 30.0) -> None:
31
+ """Initialize the accounts API.
32
+
33
+ Args:
34
+ protocol: The protocol instance for sending requests.
35
+ default_timeout: Default request timeout in seconds.
36
+ """
37
+ self._protocol = protocol
38
+ self._default_timeout = default_timeout
39
+
40
+ async def get_trader(
41
+ self,
42
+ account_id: int,
43
+ timeout: float | None = None,
44
+ ) -> Account:
45
+ """Get full account/trader information.
46
+
47
+ Args:
48
+ account_id: The cTID trader account ID.
49
+ timeout: Request timeout (uses default if None).
50
+
51
+ Returns:
52
+ Full Account details including balance, leverage, etc.
53
+
54
+ Raises:
55
+ APIError: If request fails.
56
+ CTraderConnectionTimeoutError: If request times out.
57
+ """
58
+ request = ProtoOATraderReq(ctid_trader_account_id=account_id)
59
+
60
+ response = await self._protocol.send_request(
61
+ request,
62
+ timeout=timeout or self._default_timeout,
63
+ )
64
+
65
+ if not isinstance(response, ProtoOATraderRes):
66
+ raise APIError(
67
+ error_code="UNEXPECTED_RESPONSE",
68
+ description=f"Expected ProtoOATraderRes, got {type(response).__name__}",
69
+ )
70
+
71
+ return Account.from_proto(response.trader)