architect-py 5.1.4b1__py3-none-any.whl → 5.1.4rc1__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.
- architect_py/__init__.py +19 -1
- architect_py/async_client.py +102 -34
- architect_py/client.py +4 -0
- architect_py/client.pyi +20 -7
- architect_py/grpc/client.py +24 -9
- architect_py/grpc/models/AlgoHelper/AlgoParamTypes.py +31 -0
- architect_py/grpc/models/AlgoHelper/__init__.py +2 -0
- architect_py/grpc/models/Auth/AuthInfoRequest.py +37 -0
- architect_py/grpc/models/Auth/AuthInfoResponse.py +30 -0
- architect_py/grpc/models/Folio/AccountHistoryRequest.py +35 -4
- architect_py/grpc/models/Marketdata/L1BookSnapshot.py +11 -3
- architect_py/grpc/models/Oms/Order.py +38 -14
- architect_py/grpc/models/Oms/PlaceOrderRequest.py +38 -14
- architect_py/grpc/models/__init__.py +4 -1
- architect_py/grpc/models/definitions.py +153 -0
- architect_py/grpc/orderflow.py +138 -0
- architect_py/tests/test_order_entry.py +9 -6
- architect_py/tests/test_orderflow.py +116 -27
- {architect_py-5.1.4b1.dist-info → architect_py-5.1.4rc1.dist-info}/METADATA +1 -1
- {architect_py-5.1.4b1.dist-info → architect_py-5.1.4rc1.dist-info}/RECORD +25 -20
- examples/funding_rate_mean_reversion_algo.py +23 -47
- scripts/postprocess_grpc.py +17 -2
- {architect_py-5.1.4b1.dist-info → architect_py-5.1.4rc1.dist-info}/WHEEL +0 -0
- {architect_py-5.1.4b1.dist-info → architect_py-5.1.4rc1.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.1.4b1.dist-info → architect_py-5.1.4rc1.dist-info}/top_level.txt +0 -0
architect_py/__init__.py
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# ruff: noqa:I001
|
2
2
|
|
3
|
-
__version__ = "5.1.
|
3
|
+
__version__ = "5.1.4rc1"
|
4
4
|
|
5
5
|
from .utils.nearest_tick import TickRoundMethod
|
6
6
|
from .async_client import AsyncClient
|
7
7
|
from .client import Client
|
8
8
|
from .common_types import OrderDir, TradableProduct, TimeInForce, Venue
|
9
9
|
from .grpc.models.definitions import (
|
10
|
+
AccountHistoryGranularity,
|
10
11
|
AccountIdOrName,
|
11
12
|
AccountPosition,
|
12
13
|
AccountStatistics,
|
@@ -32,12 +33,14 @@ from .grpc.models.definitions import (
|
|
32
33
|
SortTickersBy,
|
33
34
|
Statement,
|
34
35
|
TraderIdOrEmail,
|
36
|
+
TriggerLimitOrderType,
|
35
37
|
UserId,
|
36
38
|
Withdrawal,
|
37
39
|
AccountPermissions,
|
38
40
|
AliasKind,
|
39
41
|
DerivativeKind,
|
40
42
|
FillKind,
|
43
|
+
HumanDuration,
|
41
44
|
Unit,
|
42
45
|
MinOrderQuantityUnit,
|
43
46
|
OptionsExerciseType,
|
@@ -55,6 +58,7 @@ from .grpc.models.definitions import (
|
|
55
58
|
SnapshotOrUpdateForStringAndProductCatalogInfo2,
|
56
59
|
SnapshotOrUpdateForStringAndString1,
|
57
60
|
SnapshotOrUpdateForStringAndString2,
|
61
|
+
SpreaderPhase,
|
58
62
|
SimpleDecimal,
|
59
63
|
Varying1,
|
60
64
|
Varying,
|
@@ -82,6 +86,8 @@ from .grpc.models.definitions import (
|
|
82
86
|
SnapshotOrUpdateForStringAndOptionsSeriesInfo2,
|
83
87
|
SnapshotOrUpdateForStringAndSnapshotOrUpdateForStringAndProductCatalogInfo1,
|
84
88
|
SnapshotOrUpdateForStringAndSnapshotOrUpdateForStringAndProductCatalogInfo2,
|
89
|
+
SpreaderParams,
|
90
|
+
SpreaderStatus,
|
85
91
|
Account,
|
86
92
|
FutureSpread,
|
87
93
|
Option,
|
@@ -110,6 +116,9 @@ from .grpc.models.Algo.StartAlgoRequest import StartAlgoRequest
|
|
110
116
|
from .grpc.models.Algo.StartAlgoResponse import StartAlgoResponse
|
111
117
|
from .grpc.models.Algo.StopAlgoRequest import StopAlgoRequest
|
112
118
|
from .grpc.models.Algo.StopAlgoResponse import StopAlgoResponse
|
119
|
+
from .grpc.models.AlgoHelper.AlgoParamTypes import AlgoParamTypes
|
120
|
+
from .grpc.models.Auth.AuthInfoRequest import AuthInfoRequest
|
121
|
+
from .grpc.models.Auth.AuthInfoResponse import AuthInfoResponse
|
113
122
|
from .grpc.models.Auth.CreateJwtRequest import CreateJwtRequest
|
114
123
|
from .grpc.models.Auth.CreateJwtResponse import CreateJwtResponse
|
115
124
|
from .grpc.models.Boss.DepositsRequest import DepositsRequest
|
@@ -236,6 +245,7 @@ from .grpc.models.Symbology.UploadSymbologyResponse import UploadSymbologyRespon
|
|
236
245
|
__all__ = [
|
237
246
|
"AberrantFill",
|
238
247
|
"Account",
|
248
|
+
"AccountHistoryGranularity",
|
239
249
|
"AccountHistoryRequest",
|
240
250
|
"AccountHistoryResponse",
|
241
251
|
"AccountIdOrName",
|
@@ -255,9 +265,12 @@ __all__ = [
|
|
255
265
|
"AlgoOrderStatus",
|
256
266
|
"AlgoOrdersRequest",
|
257
267
|
"AlgoOrdersResponse",
|
268
|
+
"AlgoParamTypes",
|
258
269
|
"AliasKind",
|
259
270
|
"ArrayOfL1BookSnapshot",
|
260
271
|
"AsyncClient",
|
272
|
+
"AuthInfoRequest",
|
273
|
+
"AuthInfoResponse",
|
261
274
|
"Cancel",
|
262
275
|
"CancelAllOrdersRequest",
|
263
276
|
"CancelAllOrdersResponse",
|
@@ -315,6 +328,7 @@ __all__ = [
|
|
315
328
|
"HistoricalFillsResponse",
|
316
329
|
"HistoricalOrdersRequest",
|
317
330
|
"HistoricalOrdersResponse",
|
331
|
+
"HumanDuration",
|
318
332
|
"Index",
|
319
333
|
"L1BookSnapshot",
|
320
334
|
"L1BookSnapshotRequest",
|
@@ -394,6 +408,9 @@ __all__ = [
|
|
394
408
|
"SnapshotOrUpdateForStringAndString2",
|
395
409
|
"SortTickersBy",
|
396
410
|
"SpreadLeg",
|
411
|
+
"SpreaderParams",
|
412
|
+
"SpreaderPhase",
|
413
|
+
"SpreaderStatus",
|
397
414
|
"StartAlgoRequest",
|
398
415
|
"StartAlgoResponse",
|
399
416
|
"Statement",
|
@@ -428,6 +445,7 @@ __all__ = [
|
|
428
445
|
"TradableProduct",
|
429
446
|
"Trade",
|
430
447
|
"TraderIdOrEmail",
|
448
|
+
"TriggerLimitOrderType",
|
431
449
|
"Unit",
|
432
450
|
"Unknown",
|
433
451
|
"UploadProductCatalogRequest",
|
architect_py/async_client.py
CHANGED
@@ -6,7 +6,6 @@ from decimal import Decimal
|
|
6
6
|
from typing import (
|
7
7
|
Any,
|
8
8
|
AsyncGenerator,
|
9
|
-
AsyncIterator,
|
10
9
|
List,
|
11
10
|
Literal,
|
12
11
|
Optional,
|
@@ -16,7 +15,6 @@ from typing import (
|
|
16
15
|
overload,
|
17
16
|
)
|
18
17
|
|
19
|
-
import grpc
|
20
18
|
import pandas as pd
|
21
19
|
|
22
20
|
# cannot do architect_py import * due to circular import
|
@@ -38,12 +36,11 @@ from architect_py.grpc.models.definitions import (
|
|
38
36
|
OrderSource,
|
39
37
|
OrderType,
|
40
38
|
SortTickersBy,
|
39
|
+
SpreaderParams,
|
41
40
|
TraderIdOrEmail,
|
41
|
+
TriggerLimitOrderType,
|
42
42
|
)
|
43
|
-
from architect_py.grpc.
|
44
|
-
OrderflowRequest_route,
|
45
|
-
OrderflowRequestUnannotatedResponseType,
|
46
|
-
)
|
43
|
+
from architect_py.grpc.orderflow import OrderflowChannel
|
47
44
|
from architect_py.grpc.resolve_endpoint import PAPER_GRPC_PORT, resolve_endpoint
|
48
45
|
from architect_py.utils.nearest_tick import TickRoundMethod
|
49
46
|
from architect_py.utils.orderbook import update_orderbook_side
|
@@ -56,6 +53,8 @@ class AsyncClient:
|
|
56
53
|
api_key: Optional[str] = None
|
57
54
|
api_secret: Optional[str] = None
|
58
55
|
paper_trading: bool
|
56
|
+
as_user: Optional[str] = None
|
57
|
+
as_role: Optional[str] = None
|
59
58
|
graphql_client: GraphQLClient
|
60
59
|
grpc_options: Sequence[Tuple[str, Any]] | None = None
|
61
60
|
grpc_core: Optional[GrpcClient] = None
|
@@ -80,6 +79,8 @@ class AsyncClient:
|
|
80
79
|
endpoint: str = "https://app.architect.co",
|
81
80
|
graphql_port: Optional[int] = None,
|
82
81
|
grpc_options: Sequence[Tuple[str, Any]] | None = None,
|
82
|
+
as_user: Optional[str] = None,
|
83
|
+
as_role: Optional[str] = None,
|
83
84
|
**kwargs: Any,
|
84
85
|
) -> "AsyncClient":
|
85
86
|
"""
|
@@ -131,6 +132,8 @@ class AsyncClient:
|
|
131
132
|
api_key=api_key,
|
132
133
|
api_secret=api_secret,
|
133
134
|
paper_trading=paper_trading,
|
135
|
+
as_user=as_user,
|
136
|
+
as_role=as_role,
|
134
137
|
grpc_host=grpc_host,
|
135
138
|
grpc_port=grpc_port,
|
136
139
|
grpc_options=grpc_options,
|
@@ -153,6 +156,8 @@ class AsyncClient:
|
|
153
156
|
api_key: Optional[str] = None,
|
154
157
|
api_secret: Optional[str] = None,
|
155
158
|
paper_trading: bool,
|
159
|
+
as_user: Optional[str] = None,
|
160
|
+
as_role: Optional[str] = None,
|
156
161
|
grpc_host: str = "app.architect.co",
|
157
162
|
grpc_port: int,
|
158
163
|
grpc_options: Sequence[Tuple[str, Any]] | None = None,
|
@@ -184,6 +189,8 @@ class AsyncClient:
|
|
184
189
|
self.api_key = api_key
|
185
190
|
self.api_secret = api_secret
|
186
191
|
self.paper_trading = paper_trading
|
192
|
+
self.as_user = as_user
|
193
|
+
self.as_role = as_role
|
187
194
|
self.graphql_client = GraphQLClient(
|
188
195
|
host=grpc_host,
|
189
196
|
port=graphql_port,
|
@@ -193,7 +200,12 @@ class AsyncClient:
|
|
193
200
|
)
|
194
201
|
self.grpc_options = grpc_options
|
195
202
|
self.grpc_core = GrpcClient(
|
196
|
-
host=grpc_host,
|
203
|
+
host=grpc_host,
|
204
|
+
port=grpc_port,
|
205
|
+
use_ssl=use_ssl,
|
206
|
+
options=grpc_options,
|
207
|
+
as_user=as_user,
|
208
|
+
as_role=as_role,
|
197
209
|
)
|
198
210
|
|
199
211
|
async def close(self):
|
@@ -238,7 +250,9 @@ class AsyncClient:
|
|
238
250
|
):
|
239
251
|
try:
|
240
252
|
req = CreateJwtRequest(api_key=self.api_key, api_secret=self.api_secret)
|
241
|
-
res: CreateJwtResponse = await self.grpc_core.unary_unary(
|
253
|
+
res: CreateJwtResponse = await self.grpc_core.unary_unary(
|
254
|
+
req, no_metadata=True
|
255
|
+
)
|
242
256
|
self.jwt = res.jwt
|
243
257
|
# CR alee: actually read the JWT to get the expiration time;
|
244
258
|
# for now, we just "know" that the JWTs are granted for an hour
|
@@ -287,6 +301,8 @@ class AsyncClient:
|
|
287
301
|
port=grpc_port,
|
288
302
|
use_ssl=use_ssl,
|
289
303
|
options=self.grpc_options,
|
304
|
+
as_user=self.as_user,
|
305
|
+
as_role=self.as_role,
|
290
306
|
)
|
291
307
|
except Exception as e:
|
292
308
|
logging.error("Failed to set marketdata endpoint: %s", e)
|
@@ -304,6 +320,8 @@ class AsyncClient:
|
|
304
320
|
port=grpc_port,
|
305
321
|
use_ssl=use_ssl,
|
306
322
|
options=self.grpc_options,
|
323
|
+
as_user=self.as_user,
|
324
|
+
as_role=self.as_role,
|
307
325
|
)
|
308
326
|
logging.debug(
|
309
327
|
f"Setting marketdata endpoint for {venue}: {grpc_host}:{grpc_port} use_ssl={use_ssl}"
|
@@ -340,6 +358,8 @@ class AsyncClient:
|
|
340
358
|
port=grpc_port,
|
341
359
|
use_ssl=use_ssl,
|
342
360
|
options=self.grpc_options,
|
361
|
+
as_user=self.as_user,
|
362
|
+
as_role=self.as_role,
|
343
363
|
)
|
344
364
|
except Exception as e:
|
345
365
|
logging.error("Failed to set hmart endpoint: %s", e)
|
@@ -380,6 +400,12 @@ class AsyncClient:
|
|
380
400
|
res = await self.graphql_client.user_id_query()
|
381
401
|
return res.user_id, res.user_email
|
382
402
|
|
403
|
+
async def auth_info(self) -> AuthInfoResponse:
|
404
|
+
grpc_client = await self.core()
|
405
|
+
req = AuthInfoRequest()
|
406
|
+
res: AuthInfoResponse = await grpc_client.unary_unary(req)
|
407
|
+
return res
|
408
|
+
|
383
409
|
def enable_orderflow(self):
|
384
410
|
"""
|
385
411
|
@deprecated(reason="No longer needed; orderflow is enabled by default")
|
@@ -865,7 +891,11 @@ class AsyncClient:
|
|
865
891
|
return res
|
866
892
|
|
867
893
|
async def stream_l1_book_snapshots(
|
868
|
-
self,
|
894
|
+
self,
|
895
|
+
symbols: Sequence[TradableProduct | str],
|
896
|
+
venue: Venue,
|
897
|
+
*,
|
898
|
+
send_initial_snapshots: Optional[bool] = False,
|
869
899
|
) -> AsyncGenerator[L1BookSnapshot, None]:
|
870
900
|
"""
|
871
901
|
Subscribe to the stream of L1BookSnapshots for a symbol.
|
@@ -876,7 +906,11 @@ class AsyncClient:
|
|
876
906
|
venue: the venue to subscribe to
|
877
907
|
"""
|
878
908
|
grpc_client = await self.marketdata(venue)
|
879
|
-
req = SubscribeL1BookSnapshotsRequest(
|
909
|
+
req = SubscribeL1BookSnapshotsRequest(
|
910
|
+
symbols=list(symbols),
|
911
|
+
venue=venue,
|
912
|
+
send_initial_snapshots=send_initial_snapshots,
|
913
|
+
)
|
880
914
|
async for res in grpc_client.unary_stream(req):
|
881
915
|
yield res
|
882
916
|
|
@@ -1381,30 +1415,17 @@ class AsyncClient:
|
|
1381
1415
|
|
1382
1416
|
async def orderflow(
|
1383
1417
|
self,
|
1384
|
-
|
1385
|
-
) ->
|
1418
|
+
max_queue_size: int = 1024,
|
1419
|
+
) -> OrderflowChannel:
|
1386
1420
|
"""
|
1387
1421
|
A two-way channel for both order entry and listening to order updates (fills, acks, outs, etc.).
|
1388
1422
|
|
1389
1423
|
This is considered the most efficient way to trade in this SDK.
|
1390
1424
|
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
This WILL block the event loop until the stream is closed.
|
1425
|
+
This requires advanced knowledge of the SDK and asyncio, not recommended for beginners.
|
1426
|
+
See the OrderflowManager documentation for more details.
|
1395
1427
|
"""
|
1396
|
-
|
1397
|
-
decoder = grpc_client.get_decoder(OrderflowRequestUnannotatedResponseType)
|
1398
|
-
stub: grpc.aio.StreamStreamMultiCallable = grpc_client.channel.stream_stream(
|
1399
|
-
OrderflowRequest_route,
|
1400
|
-
request_serializer=grpc_client.encoder().encode,
|
1401
|
-
response_deserializer=decoder.decode,
|
1402
|
-
)
|
1403
|
-
call: grpc.aio._base_call.StreamStreamCall[OrderflowRequest, Orderflow] = stub(
|
1404
|
-
request_iterator, metadata=(("authorization", f"Bearer {grpc_client.jwt}"),)
|
1405
|
-
)
|
1406
|
-
async for update in call:
|
1407
|
-
yield update
|
1428
|
+
return OrderflowChannel(self, max_queue_size=max_queue_size)
|
1408
1429
|
|
1409
1430
|
async def stream_orderflow(
|
1410
1431
|
self,
|
@@ -1438,9 +1459,27 @@ class AsyncClient:
|
|
1438
1459
|
**kwargs,
|
1439
1460
|
) -> Order:
|
1440
1461
|
"""
|
1441
|
-
@deprecated(reason="Use
|
1462
|
+
@deprecated(reason="Use place_order instead")
|
1442
1463
|
"""
|
1443
|
-
|
1464
|
+
logging.warning(
|
1465
|
+
"send_limit_order is deprecated, use place_order instead. "
|
1466
|
+
"This will be removed in a future version."
|
1467
|
+
)
|
1468
|
+
return await self.place_order(*args, **kwargs)
|
1469
|
+
|
1470
|
+
async def place_limit_order(
|
1471
|
+
self,
|
1472
|
+
*args,
|
1473
|
+
**kwargs,
|
1474
|
+
) -> Order:
|
1475
|
+
"""
|
1476
|
+
@deprecated(reason="Use place_order instead")
|
1477
|
+
"""
|
1478
|
+
logging.warning(
|
1479
|
+
"place_limit_order is deprecated, use place_order instead. "
|
1480
|
+
"This will be removed in a future version."
|
1481
|
+
)
|
1482
|
+
return await self.place_order(*args, **kwargs)
|
1444
1483
|
|
1445
1484
|
async def place_orders(
|
1446
1485
|
self, order_requests: Sequence[PlaceOrderRequest]
|
@@ -1484,13 +1523,13 @@ class AsyncClient:
|
|
1484
1523
|
|
1485
1524
|
return res
|
1486
1525
|
|
1487
|
-
async def
|
1526
|
+
async def place_order(
|
1488
1527
|
self,
|
1489
1528
|
*,
|
1490
1529
|
id: Optional[OrderId] = None,
|
1491
1530
|
symbol: TradableProduct | str,
|
1492
1531
|
execution_venue: Optional[str] = None,
|
1493
|
-
dir:
|
1532
|
+
dir: OrderDir,
|
1494
1533
|
quantity: Decimal,
|
1495
1534
|
limit_price: Decimal,
|
1496
1535
|
order_type: OrderType = OrderType.LIMIT,
|
@@ -1498,12 +1537,14 @@ class AsyncClient:
|
|
1498
1537
|
price_round_method: Optional[TickRoundMethod] = None,
|
1499
1538
|
account: Optional[str] = None,
|
1500
1539
|
trader: Optional[str] = None,
|
1501
|
-
post_only: bool =
|
1540
|
+
post_only: Optional[bool] = None,
|
1502
1541
|
trigger_price: Optional[Decimal] = None,
|
1542
|
+
stop_loss: Optional[TriggerLimitOrderType] = None,
|
1543
|
+
take_profit_price: Optional[Decimal] = None,
|
1503
1544
|
**kwargs: Any,
|
1504
1545
|
) -> Order:
|
1505
1546
|
"""
|
1506
|
-
Sends a regular
|
1547
|
+
Sends a regular order.
|
1507
1548
|
|
1508
1549
|
Args:
|
1509
1550
|
id: in case user wants to generate their own order id, otherwise it will be generated automatically
|
@@ -1524,6 +1565,8 @@ class AsyncClient:
|
|
1524
1565
|
for when sending order for another user, not relevant for vast majority of users
|
1525
1566
|
post_only: whether the order should be post only, not supported by all exchanges
|
1526
1567
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
1568
|
+
stop_loss_price: the stop loss price for a bracket order.
|
1569
|
+
profit_price: the take profit price for a bracket order.
|
1527
1570
|
Returns:
|
1528
1571
|
the Order object for the order
|
1529
1572
|
The order.status should be "PENDING" until the order is "OPEN" / "REJECTED" / "OUT" / "CANCELED" / "STALE"
|
@@ -1580,6 +1623,8 @@ class AsyncClient:
|
|
1580
1623
|
execution_venue=execution_venue,
|
1581
1624
|
post_only=post_only,
|
1582
1625
|
trigger_price=trigger_price,
|
1626
|
+
stop_loss=stop_loss,
|
1627
|
+
take_profit_price=take_profit_price,
|
1583
1628
|
)
|
1584
1629
|
res = await grpc_client.unary_unary(req)
|
1585
1630
|
return res
|
@@ -1724,3 +1769,26 @@ class AsyncClient:
|
|
1724
1769
|
# )
|
1725
1770
|
# res = await grpc_client.unary_unary(req)
|
1726
1771
|
# return True
|
1772
|
+
|
1773
|
+
async def create_algo_order(
|
1774
|
+
self,
|
1775
|
+
*,
|
1776
|
+
params: SpreaderParams,
|
1777
|
+
id: Optional[str] = None,
|
1778
|
+
trader: Optional[str] = None,
|
1779
|
+
):
|
1780
|
+
"""
|
1781
|
+
Sends an advanced algo order such as the spreader.
|
1782
|
+
"""
|
1783
|
+
grpc_client = await self.core()
|
1784
|
+
|
1785
|
+
if isinstance(params, SpreaderParams):
|
1786
|
+
algo = "SPREADER"
|
1787
|
+
else:
|
1788
|
+
raise ValueError(
|
1789
|
+
"Unsupported algo type. Only SpreaderParams is supported for now."
|
1790
|
+
)
|
1791
|
+
|
1792
|
+
req = CreateAlgoOrderRequest(algo=algo, params=params, id=id, trader=trader)
|
1793
|
+
res = await grpc_client.unary_unary(req)
|
1794
|
+
return res
|
architect_py/client.py
CHANGED
@@ -56,6 +56,8 @@ class Client:
|
|
56
56
|
api_key: str,
|
57
57
|
api_secret: str,
|
58
58
|
paper_trading: bool,
|
59
|
+
as_user: Optional[str] = None,
|
60
|
+
as_role: Optional[str] = None,
|
59
61
|
endpoint: str = "https://app.architect.co",
|
60
62
|
graphql_port: Optional[int] = None,
|
61
63
|
grpc_options: Sequence[tuple[str, Any]] | None = None,
|
@@ -85,6 +87,8 @@ class Client:
|
|
85
87
|
api_key=api_key,
|
86
88
|
api_secret=api_secret,
|
87
89
|
paper_trading=paper_trading,
|
90
|
+
as_user=as_user,
|
91
|
+
as_role=as_role,
|
88
92
|
endpoint=endpoint,
|
89
93
|
graphql_port=graphql_port,
|
90
94
|
grpc_options=grpc_options,
|
architect_py/client.pyi
CHANGED
@@ -9,8 +9,8 @@ from architect_py.graphql_client import GraphQLClient as GraphQLClient
|
|
9
9
|
from architect_py.graphql_client.exceptions import GraphQLClientGraphQLMultiError as GraphQLClientGraphQLMultiError
|
10
10
|
from architect_py.graphql_client.fragments import ExecutionInfoFields as ExecutionInfoFields, ProductInfoFields as ProductInfoFields
|
11
11
|
from architect_py.grpc.client import GrpcClient as GrpcClient
|
12
|
-
from architect_py.grpc.models.
|
13
|
-
from architect_py.grpc.
|
12
|
+
from architect_py.grpc.models.definitions import AccountIdOrName as AccountIdOrName, AccountWithPermissions as AccountWithPermissions, CandleWidth as CandleWidth, L2BookDiff as L2BookDiff, OrderId as OrderId, OrderSource as OrderSource, OrderType as OrderType, SortTickersBy as SortTickersBy, SpreaderParams as SpreaderParams, TraderIdOrEmail as TraderIdOrEmail, TriggerLimitOrderType as TriggerLimitOrderType
|
13
|
+
from architect_py.grpc.orderflow import OrderflowChannel as OrderflowChannel
|
14
14
|
from architect_py.grpc.resolve_endpoint import PAPER_GRPC_PORT as PAPER_GRPC_PORT, resolve_endpoint as resolve_endpoint
|
15
15
|
from architect_py.utils.nearest_tick import TickRoundMethod as TickRoundMethod
|
16
16
|
from architect_py.utils.orderbook import update_orderbook_side as update_orderbook_side
|
@@ -19,7 +19,7 @@ from architect_py.utils.price_bands import price_band_pairs as price_band_pairs
|
|
19
19
|
from architect_py.utils.symbol_parsing import nominative_expiration as nominative_expiration
|
20
20
|
from datetime import date, datetime
|
21
21
|
from decimal import Decimal
|
22
|
-
from typing import Any, AsyncGenerator,
|
22
|
+
from typing import Any, AsyncGenerator, Literal, Sequence, overload
|
23
23
|
|
24
24
|
class Client:
|
25
25
|
"""
|
@@ -37,6 +37,8 @@ class Client:
|
|
37
37
|
api_key: str | None
|
38
38
|
api_secret: str | None
|
39
39
|
paper_trading: bool
|
40
|
+
as_user: str | None
|
41
|
+
as_role: str | None
|
40
42
|
graphql_client: GraphQLClient
|
41
43
|
grpc_options: Sequence[tuple[str, Any]] | None
|
42
44
|
grpc_core: GrpcClient | None
|
@@ -45,7 +47,7 @@ class Client:
|
|
45
47
|
jwt: str | None
|
46
48
|
jwt_expiration: datetime | None
|
47
49
|
l1_books: dict[Venue, dict[TradableProduct, tuple[L1BookSnapshot, asyncio.Task]]]
|
48
|
-
def __init__(self, *, api_key: str, api_secret: str, paper_trading: bool, endpoint: str = 'https://app.architect.co', graphql_port: int | None = None, grpc_options: Sequence[tuple[str, Any]] | None = None, event_loop: asyncio.events.AbstractEventLoop | None = None) -> None:
|
50
|
+
def __init__(self, *, api_key: str, api_secret: str, paper_trading: bool, as_user: str | None = None, as_role: str | None = None, endpoint: str = 'https://app.architect.co', graphql_port: int | None = None, grpc_options: Sequence[tuple[str, Any]] | None = None, event_loop: asyncio.events.AbstractEventLoop | None = None) -> None:
|
49
51
|
"""
|
50
52
|
Create a new Client instance.
|
51
53
|
|
@@ -119,6 +121,7 @@ class Client:
|
|
119
121
|
Returns:
|
120
122
|
(user_id, user_email)
|
121
123
|
"""
|
124
|
+
def auth_info(self) -> AuthInfoResponse: ...
|
122
125
|
def cpty_status(self, kind: str, instance: str | None = None) -> CptyStatus:
|
123
126
|
"""
|
124
127
|
Get cpty status.
|
@@ -451,7 +454,11 @@ class Client:
|
|
451
454
|
'''
|
452
455
|
def send_limit_order(self, *args, **kwargs) -> Order:
|
453
456
|
'''
|
454
|
-
@deprecated(reason="Use
|
457
|
+
@deprecated(reason="Use place_order instead")
|
458
|
+
'''
|
459
|
+
def place_limit_order(self, *args, **kwargs) -> Order:
|
460
|
+
'''
|
461
|
+
@deprecated(reason="Use place_order instead")
|
455
462
|
'''
|
456
463
|
def place_orders(self, order_requests: Sequence[PlaceOrderRequest]) -> list[Order]:
|
457
464
|
"""
|
@@ -482,9 +489,9 @@ class Client:
|
|
482
489
|
trigger_price=trigger_price,
|
483
490
|
)
|
484
491
|
"""
|
485
|
-
def
|
492
|
+
def place_order(self, *, id: OrderId | None = None, symbol: TradableProduct | str, execution_venue: str | None = None, dir: OrderDir, quantity: Decimal, limit_price: Decimal, order_type: OrderType = ..., time_in_force: TimeInForce = ..., price_round_method: TickRoundMethod | None = None, account: str | None = None, trader: str | None = None, post_only: bool | None = None, trigger_price: Decimal | None = None, stop_loss: TriggerLimitOrderType | None = None, take_profit_price: Decimal | None = None, **kwargs: Any) -> Order:
|
486
493
|
'''
|
487
|
-
Sends a regular
|
494
|
+
Sends a regular order.
|
488
495
|
|
489
496
|
Args:
|
490
497
|
id: in case user wants to generate their own order id, otherwise it will be generated automatically
|
@@ -505,6 +512,8 @@ class Client:
|
|
505
512
|
for when sending order for another user, not relevant for vast majority of users
|
506
513
|
post_only: whether the order should be post only, not supported by all exchanges
|
507
514
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
515
|
+
stop_loss_price: the stop loss price for a bracket order.
|
516
|
+
profit_price: the take profit price for a bracket order.
|
508
517
|
Returns:
|
509
518
|
the Order object for the order
|
510
519
|
The order.status should be "PENDING" until the order is "OPEN" / "REJECTED" / "OUT" / "CANCELED" / "STALE"
|
@@ -549,3 +558,7 @@ class Client:
|
|
549
558
|
True if all orders were cancelled successfully
|
550
559
|
False if there was an error
|
551
560
|
"""
|
561
|
+
def create_algo_order(self, *, params: SpreaderParams, id: str | None = None, trader: str | None = None):
|
562
|
+
"""
|
563
|
+
Sends an advanced algo order such as the spreader.
|
564
|
+
"""
|
architect_py/grpc/client.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from types import UnionType
|
2
2
|
from typing import Any, AsyncIterator, Sequence, Tuple
|
3
3
|
|
4
|
-
import grpc
|
4
|
+
import grpc.aio
|
5
5
|
import msgspec
|
6
6
|
|
7
7
|
from . import *
|
@@ -17,6 +17,8 @@ class GrpcClient:
|
|
17
17
|
endpoint: str
|
18
18
|
channel: grpc.aio.Channel
|
19
19
|
jwt: str | None = None
|
20
|
+
as_user: str | None = None
|
21
|
+
as_role: str | None = None
|
20
22
|
|
21
23
|
def __init__(
|
22
24
|
self,
|
@@ -25,9 +27,13 @@ class GrpcClient:
|
|
25
27
|
port: int,
|
26
28
|
use_ssl: bool = False,
|
27
29
|
options: Sequence[Tuple[str, Any]] | None = None,
|
30
|
+
as_user: str | None = None,
|
31
|
+
as_role: str | None = None,
|
28
32
|
):
|
29
33
|
scheme = "https" if use_ssl else "http"
|
30
34
|
self.endpoint = f"{scheme}://{host}:{port}"
|
35
|
+
self.as_user = as_user
|
36
|
+
self.as_role = as_role
|
31
37
|
if use_ssl:
|
32
38
|
credentials = grpc.ssl_channel_credentials()
|
33
39
|
self.channel = grpc.aio.secure_channel(
|
@@ -39,6 +45,16 @@ class GrpcClient:
|
|
39
45
|
def set_jwt(self, jwt: str | None):
|
40
46
|
self.jwt = jwt
|
41
47
|
|
48
|
+
def metadata(self) -> Sequence[Tuple[str, str]]:
|
49
|
+
metadata = []
|
50
|
+
if self.jwt is not None:
|
51
|
+
metadata.append(("authorization", f"Bearer {self.jwt}"))
|
52
|
+
if self.as_user is not None:
|
53
|
+
metadata.append(("x-architect-user", self.as_user))
|
54
|
+
if self.as_role is not None:
|
55
|
+
metadata.append(("x-architect-role", self.as_role))
|
56
|
+
return metadata
|
57
|
+
|
42
58
|
async def close(self):
|
43
59
|
await self.channel.close()
|
44
60
|
|
@@ -59,6 +75,8 @@ class GrpcClient:
|
|
59
75
|
async def unary_unary(
|
60
76
|
self,
|
61
77
|
request: RequestType[ResponseTypeGeneric],
|
78
|
+
*,
|
79
|
+
no_metadata: bool = False,
|
62
80
|
) -> ResponseTypeGeneric:
|
63
81
|
"""
|
64
82
|
Generic function for making a unary RPC call to the gRPC server.
|
@@ -75,10 +93,10 @@ class GrpcClient:
|
|
75
93
|
request_serializer=encoder.encode,
|
76
94
|
response_deserializer=decoder.decode,
|
77
95
|
)
|
78
|
-
if
|
79
|
-
metadata = (("authorization", f"Bearer {self.jwt}"),)
|
80
|
-
else:
|
96
|
+
if no_metadata:
|
81
97
|
metadata = ()
|
98
|
+
else:
|
99
|
+
metadata = self.metadata()
|
82
100
|
return await stub(request, metadata=metadata)
|
83
101
|
|
84
102
|
async def unary_stream(
|
@@ -100,11 +118,8 @@ class GrpcClient:
|
|
100
118
|
request_serializer=encoder.encode,
|
101
119
|
response_deserializer=decoder.decode,
|
102
120
|
)
|
103
|
-
|
104
|
-
|
105
|
-
else:
|
106
|
-
metadata = ()
|
107
|
-
call: grpc.aio._base_call.UnaryStreamCall[
|
121
|
+
metadata = self.metadata()
|
122
|
+
call: grpc.aio.UnaryStreamCall[
|
108
123
|
RequestType[ResponseTypeGeneric], ResponseTypeGeneric
|
109
124
|
] = stub(request, metadata=metadata)
|
110
125
|
async for update in call:
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# generated by datamodel-codegen:
|
2
|
+
# filename: AlgoHelper/AlgoParamTypes.json
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import List, Union
|
7
|
+
|
8
|
+
from msgspec import Struct
|
9
|
+
|
10
|
+
from .. import definitions
|
11
|
+
|
12
|
+
|
13
|
+
class AlgoParamTypes(Struct, omit_defaults=True):
|
14
|
+
"""
|
15
|
+
this is used to coerce creation of the params in the schema.json
|
16
|
+
"""
|
17
|
+
|
18
|
+
spreader: List[Union[definitions.SpreaderParams, definitions.SpreaderStatus]]
|
19
|
+
|
20
|
+
# Constructor that takes all field titles as arguments for convenience
|
21
|
+
@classmethod
|
22
|
+
def new(
|
23
|
+
cls,
|
24
|
+
spreader: List[Union[definitions.SpreaderParams, definitions.SpreaderStatus]],
|
25
|
+
):
|
26
|
+
return cls(
|
27
|
+
spreader,
|
28
|
+
)
|
29
|
+
|
30
|
+
def __str__(self) -> str:
|
31
|
+
return f"AlgoParamTypes(spreader={self.spreader})"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# generated by datamodel-codegen:
|
2
|
+
# filename: Auth/AuthInfoRequest.json
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
from architect_py.grpc.models.Auth.AuthInfoResponse import AuthInfoResponse
|
6
|
+
|
7
|
+
from msgspec import Struct
|
8
|
+
|
9
|
+
|
10
|
+
class AuthInfoRequest(Struct, omit_defaults=True):
|
11
|
+
pass
|
12
|
+
|
13
|
+
# Constructor that takes all field titles as arguments for convenience
|
14
|
+
@classmethod
|
15
|
+
def new(
|
16
|
+
cls,
|
17
|
+
):
|
18
|
+
return cls()
|
19
|
+
|
20
|
+
def __str__(self) -> str:
|
21
|
+
return f"AuthInfoRequest()"
|
22
|
+
|
23
|
+
@staticmethod
|
24
|
+
def get_response_type():
|
25
|
+
return AuthInfoResponse
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def get_unannotated_response_type():
|
29
|
+
return AuthInfoResponse
|
30
|
+
|
31
|
+
@staticmethod
|
32
|
+
def get_route() -> str:
|
33
|
+
return "/json.architect.Auth/AuthInfo"
|
34
|
+
|
35
|
+
@staticmethod
|
36
|
+
def get_rpc_method():
|
37
|
+
return "unary"
|