architect-py 5.1.4rc1__py3-none-any.whl → 5.1.6__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 +24 -4
- architect_py/async_client.py +121 -67
- architect_py/client.pyi +16 -37
- architect_py/grpc/models/Accounts/ResetPaperAccountRequest.py +59 -0
- architect_py/grpc/models/Accounts/ResetPaperAccountResponse.py +20 -0
- architect_py/grpc/models/Boss/OptionsTransactionsRequest.py +42 -0
- architect_py/grpc/models/Boss/OptionsTransactionsResponse.py +27 -0
- architect_py/grpc/models/Core/ConfigResponse.py +7 -2
- architect_py/grpc/models/Folio/AccountSummary.py +7 -1
- architect_py/grpc/models/Marketdata/Candle.py +6 -0
- architect_py/grpc/models/Marketdata/L1BookSnapshot.py +6 -0
- architect_py/grpc/models/Marketdata/L2BookSnapshot.py +6 -0
- architect_py/grpc/models/Marketdata/Liquidation.py +6 -0
- architect_py/grpc/models/Marketdata/Ticker.py +6 -0
- architect_py/grpc/models/Marketdata/Trade.py +6 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChain.py +5 -5
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeks.py +5 -5
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeksRequest.py +5 -1
- architect_py/grpc/models/OptionsMarketdata/OptionsChainRequest.py +5 -1
- architect_py/grpc/models/OptionsMarketdata/OptionsContract.py +45 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsContractGreeksRequest.py +40 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsContractRequest.py +40 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirations.py +4 -1
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirationsRequest.py +8 -1
- architect_py/grpc/models/OptionsMarketdata/OptionsGreeks.py +58 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsWraps.py +28 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsWrapsRequest.py +40 -0
- architect_py/grpc/models/__init__.py +11 -1
- architect_py/grpc/models/definitions.py +57 -86
- architect_py/grpc/orderflow.py +3 -7
- architect_py/grpc/server.py +1 -3
- architect_py/tests/test_order_entry.py +120 -1
- architect_py/tests/test_positions.py +364 -0
- architect_py/tests/test_rounding.py +28 -28
- architect_py/utils/pandas.py +50 -1
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.6.dist-info}/METADATA +1 -1
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.6.dist-info}/RECORD +49 -38
- examples/external_cpty.py +2 -1
- examples/funding_rate_mean_reversion_algo.py +4 -4
- examples/order_sending.py +3 -3
- examples/orderflow_channel.py +75 -56
- examples/stream_l1_marketdata.py +3 -1
- examples/stream_l2_marketdata.py +3 -1
- examples/tutorial_async.py +3 -2
- examples/tutorial_sync.py +4 -3
- scripts/generate_functions_md.py +2 -1
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.6.dist-info}/WHEEL +0 -0
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.6.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.6.dist-info}/top_level.txt +0 -0
architect_py/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# ruff: noqa:I001
|
2
2
|
|
3
|
-
__version__ = "5.1.
|
3
|
+
__version__ = "5.1.6"
|
4
4
|
|
5
5
|
from .utils.nearest_tick import TickRoundMethod
|
6
6
|
from .async_client import AsyncClient
|
@@ -21,6 +21,7 @@ from .grpc.models.definitions import (
|
|
21
21
|
HealthMetric,
|
22
22
|
HealthStatus,
|
23
23
|
L2BookDiff,
|
24
|
+
OptionsTransaction,
|
24
25
|
OrderId,
|
25
26
|
OrderOut,
|
26
27
|
OrderRejectReason,
|
@@ -29,6 +30,7 @@ from .grpc.models.definitions import (
|
|
29
30
|
OrderStatus,
|
30
31
|
OrderType,
|
31
32
|
ProductCatalogInfo,
|
33
|
+
PutOrCall,
|
32
34
|
RqdAccountStatistics,
|
33
35
|
SortTickersBy,
|
34
36
|
Statement,
|
@@ -53,7 +55,6 @@ from .grpc.models.definitions import (
|
|
53
55
|
Future,
|
54
56
|
Perpetual,
|
55
57
|
Unknown,
|
56
|
-
PutOrCall,
|
57
58
|
SnapshotOrUpdateForStringAndProductCatalogInfo1,
|
58
59
|
SnapshotOrUpdateForStringAndProductCatalogInfo2,
|
59
60
|
SnapshotOrUpdateForStringAndString1,
|
@@ -73,8 +74,6 @@ from .grpc.models.definitions import (
|
|
73
74
|
CptyLoginRequest,
|
74
75
|
ExecutionInfo,
|
75
76
|
Fill,
|
76
|
-
OptionsContract,
|
77
|
-
OptionsGreeks,
|
78
77
|
OptionsSeriesInfo,
|
79
78
|
OrderAck,
|
80
79
|
OrderCanceled,
|
@@ -105,6 +104,8 @@ from .grpc.models.definitions import (
|
|
105
104
|
)
|
106
105
|
from .grpc.models.Accounts.AccountsRequest import AccountsRequest
|
107
106
|
from .grpc.models.Accounts.AccountsResponse import AccountsResponse
|
107
|
+
from .grpc.models.Accounts.ResetPaperAccountRequest import ResetPaperAccountRequest
|
108
|
+
from .grpc.models.Accounts.ResetPaperAccountResponse import ResetPaperAccountResponse
|
108
109
|
from .grpc.models.Algo.AlgoOrder import AlgoOrder
|
109
110
|
from .grpc.models.Algo.AlgoOrderRequest import AlgoOrderRequest
|
110
111
|
from .grpc.models.Algo.AlgoOrdersRequest import AlgoOrdersRequest
|
@@ -123,6 +124,8 @@ from .grpc.models.Auth.CreateJwtRequest import CreateJwtRequest
|
|
123
124
|
from .grpc.models.Auth.CreateJwtResponse import CreateJwtResponse
|
124
125
|
from .grpc.models.Boss.DepositsRequest import DepositsRequest
|
125
126
|
from .grpc.models.Boss.DepositsResponse import DepositsResponse
|
127
|
+
from .grpc.models.Boss.OptionsTransactionsRequest import OptionsTransactionsRequest
|
128
|
+
from .grpc.models.Boss.OptionsTransactionsResponse import OptionsTransactionsResponse
|
126
129
|
from .grpc.models.Boss.RqdAccountStatisticsRequest import RqdAccountStatisticsRequest
|
127
130
|
from .grpc.models.Boss.RqdAccountStatisticsResponse import RqdAccountStatisticsResponse
|
128
131
|
from .grpc.models.Boss.StatementUrlRequest import StatementUrlRequest
|
@@ -206,10 +209,18 @@ from .grpc.models.OptionsMarketdata.OptionsChainGreeksRequest import (
|
|
206
209
|
OptionsChainGreeksRequest,
|
207
210
|
)
|
208
211
|
from .grpc.models.OptionsMarketdata.OptionsChainRequest import OptionsChainRequest
|
212
|
+
from .grpc.models.OptionsMarketdata.OptionsContract import OptionsContract
|
213
|
+
from .grpc.models.OptionsMarketdata.OptionsContractGreeksRequest import (
|
214
|
+
OptionsContractGreeksRequest,
|
215
|
+
)
|
216
|
+
from .grpc.models.OptionsMarketdata.OptionsContractRequest import OptionsContractRequest
|
209
217
|
from .grpc.models.OptionsMarketdata.OptionsExpirations import OptionsExpirations
|
210
218
|
from .grpc.models.OptionsMarketdata.OptionsExpirationsRequest import (
|
211
219
|
OptionsExpirationsRequest,
|
212
220
|
)
|
221
|
+
from .grpc.models.OptionsMarketdata.OptionsGreeks import OptionsGreeks
|
222
|
+
from .grpc.models.OptionsMarketdata.OptionsWraps import OptionsWraps
|
223
|
+
from .grpc.models.OptionsMarketdata.OptionsWrapsRequest import OptionsWrapsRequest
|
213
224
|
from .grpc.models.Orderflow.Dropcopy import Dropcopy
|
214
225
|
from .grpc.models.Orderflow.DropcopyRequest import DropcopyRequest
|
215
226
|
from .grpc.models.Orderflow.Orderflow import Orderflow
|
@@ -350,12 +361,19 @@ __all__ = [
|
|
350
361
|
"OptionsChainGreeksRequest",
|
351
362
|
"OptionsChainRequest",
|
352
363
|
"OptionsContract",
|
364
|
+
"OptionsContractGreeksRequest",
|
365
|
+
"OptionsContractRequest",
|
353
366
|
"OptionsExerciseType",
|
354
367
|
"OptionsExpirations",
|
355
368
|
"OptionsExpirationsRequest",
|
356
369
|
"OptionsGreeks",
|
357
370
|
"OptionsSeriesInfo",
|
358
371
|
"OptionsSeriesInstance",
|
372
|
+
"OptionsTransaction",
|
373
|
+
"OptionsTransactionsRequest",
|
374
|
+
"OptionsTransactionsResponse",
|
375
|
+
"OptionsWraps",
|
376
|
+
"OptionsWrapsRequest",
|
359
377
|
"Order",
|
360
378
|
"OrderAck",
|
361
379
|
"OrderCanceled",
|
@@ -384,6 +402,8 @@ __all__ = [
|
|
384
402
|
"PruneExpiredSymbolsRequest",
|
385
403
|
"PruneExpiredSymbolsResponse",
|
386
404
|
"PutOrCall",
|
405
|
+
"ResetPaperAccountRequest",
|
406
|
+
"ResetPaperAccountResponse",
|
387
407
|
"RestartCptyRequest",
|
388
408
|
"RestartCptyResponse",
|
389
409
|
"RqdAccountStatistics",
|
architect_py/async_client.py
CHANGED
@@ -44,7 +44,7 @@ from architect_py.grpc.orderflow import OrderflowChannel
|
|
44
44
|
from architect_py.grpc.resolve_endpoint import PAPER_GRPC_PORT, resolve_endpoint
|
45
45
|
from architect_py.utils.nearest_tick import TickRoundMethod
|
46
46
|
from architect_py.utils.orderbook import update_orderbook_side
|
47
|
-
from architect_py.utils.pandas import candles_to_dataframe
|
47
|
+
from architect_py.utils.pandas import candles_to_dataframe, tickers_to_dataframe
|
48
48
|
from architect_py.utils.price_bands import price_band_pairs
|
49
49
|
from architect_py.utils.symbol_parsing import nominative_expiration
|
50
50
|
|
@@ -146,7 +146,7 @@ class AsyncClient:
|
|
146
146
|
await client.refresh_jwt()
|
147
147
|
|
148
148
|
logging.info("Discovering marketdata endpoints...")
|
149
|
-
await client.
|
149
|
+
await client._discover_marketdata()
|
150
150
|
|
151
151
|
return client
|
152
152
|
|
@@ -260,7 +260,7 @@ class AsyncClient:
|
|
260
260
|
except Exception as e:
|
261
261
|
logging.error("Failed to refresh gRPC credentials: %s", e)
|
262
262
|
|
263
|
-
def
|
263
|
+
def _set_jwt(self, jwt: str | None, jwt_expiration: datetime | None = None):
|
264
264
|
"""
|
265
265
|
Manually set the JWT for gRPC authentication.
|
266
266
|
|
@@ -272,18 +272,18 @@ class AsyncClient:
|
|
272
272
|
self.jwt = jwt
|
273
273
|
self.jwt_expiration = jwt_expiration
|
274
274
|
|
275
|
-
async def
|
275
|
+
async def _discover_marketdata(self):
|
276
276
|
"""
|
277
277
|
Load marketdata endpoints from the server config.
|
278
278
|
|
279
279
|
The Architect core is responsible for telling you where to find marketdata as per
|
280
280
|
its configuration. You can also manually set marketdata endpoints by calling
|
281
|
-
|
281
|
+
_set_marketdata directly.
|
282
282
|
|
283
283
|
This method is called on AsyncClient.connect.
|
284
284
|
"""
|
285
285
|
try:
|
286
|
-
grpc_client = await self.
|
286
|
+
grpc_client = await self._core()
|
287
287
|
req = ConfigRequest()
|
288
288
|
res: ConfigResponse = await grpc_client.unary_unary(req)
|
289
289
|
for venue, endpoint in res.marketdata.items():
|
@@ -329,7 +329,7 @@ class AsyncClient:
|
|
329
329
|
except Exception as e:
|
330
330
|
logging.error("Failed to set marketdata endpoint: %s", e)
|
331
331
|
|
332
|
-
async def
|
332
|
+
async def _marketdata(self, venue: Venue) -> GrpcClient:
|
333
333
|
"""
|
334
334
|
Get the marketdata client for a venue.
|
335
335
|
"""
|
@@ -364,7 +364,7 @@ class AsyncClient:
|
|
364
364
|
except Exception as e:
|
365
365
|
logging.error("Failed to set hmart endpoint: %s", e)
|
366
366
|
|
367
|
-
async def
|
367
|
+
async def _hmart(self) -> GrpcClient:
|
368
368
|
"""
|
369
369
|
Get the hmart (historical marketdata service) client.
|
370
370
|
"""
|
@@ -379,7 +379,7 @@ class AsyncClient:
|
|
379
379
|
self.grpc_hmart.set_jwt(self.jwt)
|
380
380
|
return self.grpc_hmart
|
381
381
|
|
382
|
-
async def
|
382
|
+
async def _core(self) -> GrpcClient:
|
383
383
|
"""
|
384
384
|
Get the core client.
|
385
385
|
"""
|
@@ -400,8 +400,11 @@ class AsyncClient:
|
|
400
400
|
res = await self.graphql_client.user_id_query()
|
401
401
|
return res.user_id, res.user_email
|
402
402
|
|
403
|
-
async def
|
404
|
-
|
403
|
+
async def _auth_info(self) -> AuthInfoResponse:
|
404
|
+
"""
|
405
|
+
Gets auth info mapping
|
406
|
+
"""
|
407
|
+
grpc_client = await self._core()
|
405
408
|
req = AuthInfoRequest()
|
406
409
|
res: AuthInfoResponse = await grpc_client.unary_unary(req)
|
407
410
|
return res
|
@@ -420,7 +423,7 @@ class AsyncClient:
|
|
420
423
|
"""
|
421
424
|
Get cpty status.
|
422
425
|
"""
|
423
|
-
grpc_client = await self.
|
426
|
+
grpc_client = await self._core()
|
424
427
|
req = CptyStatusRequest(kind=kind, instance=instance)
|
425
428
|
res: CptyStatus = await grpc_client.unary_unary(req)
|
426
429
|
return res
|
@@ -440,9 +443,9 @@ class AsyncClient:
|
|
440
443
|
cross-referencing symbols or checking availability.
|
441
444
|
"""
|
442
445
|
if marketdata is not None:
|
443
|
-
grpc_client = await self.
|
446
|
+
grpc_client = await self._marketdata(marketdata)
|
444
447
|
else:
|
445
|
-
grpc_client = await self.
|
448
|
+
grpc_client = await self._core()
|
446
449
|
req = SymbolsRequest()
|
447
450
|
res: SymbolsResponse = await grpc_client.unary_unary(req)
|
448
451
|
return res.symbols
|
@@ -487,6 +490,20 @@ class AsyncClient:
|
|
487
490
|
None if the symbol does not exist
|
488
491
|
"""
|
489
492
|
res = await self.graphql_client.get_product_info_query(symbol)
|
493
|
+
if res.product_info is None:
|
494
|
+
if "/" in symbol:
|
495
|
+
assert ValueError(
|
496
|
+
f"Product info not found for symbol: {symbol}.\n"
|
497
|
+
"for calling get_product_info, "
|
498
|
+
f"symbol {symbol} should not have a quote (ie should not end with /USD);"
|
499
|
+
"either use the base() method of TradableProduct, or remove the quote from the symbol"
|
500
|
+
)
|
501
|
+
raise ValueError(
|
502
|
+
f"Product info not found for symbol: {symbol}."
|
503
|
+
"Please ensure it is of the form 'ES 20250620 CME Future' or 'AAPL US Equity'."
|
504
|
+
"(note that Future and Equity are not completely capitalized)."
|
505
|
+
)
|
506
|
+
|
490
507
|
return res.product_info
|
491
508
|
|
492
509
|
async def get_product_infos(
|
@@ -629,7 +646,7 @@ class AsyncClient:
|
|
629
646
|
futures.sort()
|
630
647
|
return TradableProduct(futures[0], "USD")
|
631
648
|
else:
|
632
|
-
grpc_client = await self.
|
649
|
+
grpc_client = await self._marketdata(venue)
|
633
650
|
req = TickersRequest(
|
634
651
|
symbols=[TradableProduct(f"{future}/USD") for future in futures],
|
635
652
|
k=SortTickersBy.VOLUME_DESC,
|
@@ -723,7 +740,7 @@ class AsyncClient:
|
|
723
740
|
symbol: the symbol to get the market status for, e.g. "ES 20250321 CME Future/USD"
|
724
741
|
venue: the venue that the symbol is traded at, e.g. CME
|
725
742
|
"""
|
726
|
-
grpc_client = await self.
|
743
|
+
grpc_client = await self._marketdata(venue)
|
727
744
|
req = MarketStatusRequest(symbol=str(symbol), venue=venue)
|
728
745
|
res: MarketStatus = await grpc_client.unary_unary(req)
|
729
746
|
return res
|
@@ -805,25 +822,17 @@ class AsyncClient:
|
|
805
822
|
as_dataframe: if True, return a pandas DataFrame
|
806
823
|
|
807
824
|
"""
|
808
|
-
grpc_client = await self.
|
809
|
-
if start.tzinfo
|
810
|
-
raise ValueError(
|
811
|
-
|
812
|
-
|
813
|
-
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
814
|
-
)
|
815
|
-
if end.tzinfo is not timezone.utc:
|
816
|
-
raise ValueError(
|
817
|
-
"end must be a utc datetime:\n"
|
818
|
-
"for example datetime.now(timezone.utc) or \n"
|
819
|
-
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
820
|
-
)
|
825
|
+
grpc_client = await self._hmart()
|
826
|
+
if not start.tzinfo:
|
827
|
+
raise ValueError("start time must be timezone-aware")
|
828
|
+
if not end.tzinfo:
|
829
|
+
raise ValueError("end time must be timezone-aware")
|
821
830
|
req = HistoricalCandlesRequest(
|
822
831
|
venue=venue,
|
823
832
|
symbol=str(symbol),
|
824
833
|
candle_width=candle_width,
|
825
|
-
start_date=start,
|
826
|
-
end_date=end,
|
834
|
+
start_date=start.astimezone(timezone.utc),
|
835
|
+
end_date=end.astimezone(timezone.utc),
|
827
836
|
)
|
828
837
|
res: HistoricalCandlesResponse = await grpc_client.unary_unary(req)
|
829
838
|
|
@@ -844,7 +853,7 @@ class AsyncClient:
|
|
844
853
|
symbol: the symbol to get the l1 book snapshot for
|
845
854
|
venue: the venue that the symbol is traded at
|
846
855
|
"""
|
847
|
-
grpc_client = await self.
|
856
|
+
grpc_client = await self._marketdata(venue)
|
848
857
|
req = L1BookSnapshotRequest(symbol=str(symbol), venue=venue)
|
849
858
|
res: L1BookSnapshot = await grpc_client.unary_unary(req)
|
850
859
|
return res
|
@@ -859,7 +868,7 @@ class AsyncClient:
|
|
859
868
|
symbols: the symbols to get the l1 book snapshots for
|
860
869
|
venue: the venue that the symbols are traded at
|
861
870
|
"""
|
862
|
-
grpc_client = await self.
|
871
|
+
grpc_client = await self._marketdata(venue)
|
863
872
|
req = L1BookSnapshotsRequest(symbols=symbols)
|
864
873
|
res: ArrayOfL1BookSnapshot = await grpc_client.unary_unary(
|
865
874
|
req # pyright: ignore[reportArgumentType]
|
@@ -876,7 +885,7 @@ class AsyncClient:
|
|
876
885
|
symbol: the symbol to get the l2 book snapshot for
|
877
886
|
venue: the venue that the symbol is traded at
|
878
887
|
"""
|
879
|
-
grpc_client = await self.
|
888
|
+
grpc_client = await self._marketdata(venue)
|
880
889
|
req = L2BookSnapshotRequest(symbol=str(symbol), venue=venue)
|
881
890
|
res: L2BookSnapshot = await grpc_client.unary_unary(req)
|
882
891
|
return res
|
@@ -885,11 +894,42 @@ class AsyncClient:
|
|
885
894
|
"""
|
886
895
|
Gets the ticker for a symbol.
|
887
896
|
"""
|
888
|
-
grpc_client = await self.
|
897
|
+
grpc_client = await self._marketdata(venue)
|
889
898
|
req = TickerRequest(symbol=str(symbol), venue=venue)
|
890
899
|
res: Ticker = await grpc_client.unary_unary(req)
|
891
900
|
return res
|
892
901
|
|
902
|
+
async def get_tickers(
|
903
|
+
self,
|
904
|
+
*,
|
905
|
+
venue: Venue,
|
906
|
+
symbols: Optional[Sequence[TradableProduct | str]] = None,
|
907
|
+
include_options: bool = False,
|
908
|
+
sort_by: Optional[SortTickersBy | str] = None,
|
909
|
+
offset: Optional[int] = None,
|
910
|
+
limit: Optional[int] = None,
|
911
|
+
as_dataframe: bool = False,
|
912
|
+
) -> Union[Sequence[Ticker], pd.DataFrame]:
|
913
|
+
"""
|
914
|
+
Gets the tickers for a list of symbols.
|
915
|
+
"""
|
916
|
+
grpc_client = await self._marketdata(venue)
|
917
|
+
sort_by = SortTickersBy(sort_by) if sort_by else None
|
918
|
+
symbols = [str(symbol) for symbol in symbols] if symbols else None
|
919
|
+
req = TickersRequest.new(
|
920
|
+
offset=offset,
|
921
|
+
include_options=include_options,
|
922
|
+
sort_by=sort_by,
|
923
|
+
limit=limit,
|
924
|
+
symbols=symbols,
|
925
|
+
venue=venue,
|
926
|
+
)
|
927
|
+
res: TickersResponse = await grpc_client.unary_unary(req)
|
928
|
+
if as_dataframe:
|
929
|
+
return tickers_to_dataframe(res.tickers)
|
930
|
+
else:
|
931
|
+
return res.tickers
|
932
|
+
|
893
933
|
async def stream_l1_book_snapshots(
|
894
934
|
self,
|
895
935
|
symbols: Sequence[TradableProduct | str],
|
@@ -905,7 +945,7 @@ class AsyncClient:
|
|
905
945
|
If symbols=None, subscribe to all symbols available for the venue.
|
906
946
|
venue: the venue to subscribe to
|
907
947
|
"""
|
908
|
-
grpc_client = await self.
|
948
|
+
grpc_client = await self._marketdata(venue)
|
909
949
|
req = SubscribeL1BookSnapshotsRequest(
|
910
950
|
symbols=list(symbols),
|
911
951
|
venue=venue,
|
@@ -927,7 +967,7 @@ class AsyncClient:
|
|
927
967
|
symbol: the symbol to subscribe to
|
928
968
|
venue: the marketdata venue
|
929
969
|
"""
|
930
|
-
grpc_client = await self.
|
970
|
+
grpc_client = await self._marketdata(venue)
|
931
971
|
req = SubscribeL2BookUpdatesRequest(symbol=str(symbol), venue=venue)
|
932
972
|
async for res in grpc_client.unary_stream(
|
933
973
|
req # pyright: ignore[reportArgumentType]
|
@@ -960,7 +1000,7 @@ class AsyncClient:
|
|
960
1000
|
else:
|
961
1001
|
self.l1_books[venue] = {}
|
962
1002
|
|
963
|
-
grpc_client = await self.
|
1003
|
+
grpc_client = await self._marketdata(venue)
|
964
1004
|
book = L1BookSnapshot(symbol, 0, 0)
|
965
1005
|
self.l1_books[venue][symbol] = (
|
966
1006
|
book,
|
@@ -1038,7 +1078,7 @@ class AsyncClient:
|
|
1038
1078
|
else:
|
1039
1079
|
self.l2_books[venue] = {}
|
1040
1080
|
|
1041
|
-
grpc_client = await self.
|
1081
|
+
grpc_client = await self._marketdata(venue)
|
1042
1082
|
book = L2BookSnapshot([], [], 0, 0, 0, 0)
|
1043
1083
|
self.l2_books[venue][symbol] = (
|
1044
1084
|
book,
|
@@ -1097,7 +1137,7 @@ class AsyncClient:
|
|
1097
1137
|
"""
|
1098
1138
|
Subscribe to a stream of trades for a symbol.
|
1099
1139
|
"""
|
1100
|
-
grpc_client = await self.
|
1140
|
+
grpc_client = await self._marketdata(venue)
|
1101
1141
|
req = SubscribeTradesRequest(symbol=str(symbol), venue=venue)
|
1102
1142
|
async for res in grpc_client.unary_stream(req):
|
1103
1143
|
yield res
|
@@ -1111,7 +1151,7 @@ class AsyncClient:
|
|
1111
1151
|
"""
|
1112
1152
|
Subscribe to a stream of candles for a symbol.
|
1113
1153
|
"""
|
1114
|
-
grpc_client = await self.
|
1154
|
+
grpc_client = await self._marketdata(venue)
|
1115
1155
|
req = SubscribeCandlesRequest(
|
1116
1156
|
symbol=str(symbol),
|
1117
1157
|
venue=venue,
|
@@ -1133,7 +1173,7 @@ class AsyncClient:
|
|
1133
1173
|
a list of AccountWithPermissions for the user that the API key belongs to
|
1134
1174
|
(use who_am_i to get the user_id / email)
|
1135
1175
|
"""
|
1136
|
-
grpc_client = await self.
|
1176
|
+
grpc_client = await self._core()
|
1137
1177
|
req = AccountsRequest(paper=self.paper_trading)
|
1138
1178
|
res = await grpc_client.unary_unary(req)
|
1139
1179
|
return res.accounts
|
@@ -1146,11 +1186,32 @@ class AsyncClient:
|
|
1146
1186
|
account: account uuid or name
|
1147
1187
|
Examples: "00000000-0000-0000-0000-000000000000", "STONEX:000000/JDoe"
|
1148
1188
|
"""
|
1149
|
-
grpc_client = await self.
|
1189
|
+
grpc_client = await self._core()
|
1150
1190
|
req = AccountSummaryRequest(account=account)
|
1151
1191
|
res = await grpc_client.unary_unary(req)
|
1152
1192
|
return res
|
1153
1193
|
|
1194
|
+
async def get_positions(
|
1195
|
+
self,
|
1196
|
+
accounts: Optional[list[str]] = None,
|
1197
|
+
trader: Optional[str] = None,
|
1198
|
+
) -> dict[str, Decimal]:
|
1199
|
+
"""
|
1200
|
+
Get positions for the specified symbols.
|
1201
|
+
|
1202
|
+
Args:
|
1203
|
+
symbols: list of symbol strings
|
1204
|
+
"""
|
1205
|
+
account_summaries = await self.get_account_summaries(
|
1206
|
+
accounts=accounts, trader=trader
|
1207
|
+
)
|
1208
|
+
positions: dict[str, Decimal] = {}
|
1209
|
+
for summary in account_summaries:
|
1210
|
+
for symbol, summary in summary.positions.items():
|
1211
|
+
for pos in summary:
|
1212
|
+
positions[symbol] = positions.get(symbol, Decimal(0)) + pos.quantity
|
1213
|
+
return positions
|
1214
|
+
|
1154
1215
|
async def get_account_summaries(
|
1155
1216
|
self,
|
1156
1217
|
accounts: Optional[list[str]] = None,
|
@@ -1165,7 +1226,7 @@ class AsyncClient:
|
|
1165
1226
|
|
1166
1227
|
If both arguments are given, the union of matching accounts are returned.
|
1167
1228
|
"""
|
1168
|
-
grpc_client = await self.
|
1229
|
+
grpc_client = await self._core()
|
1169
1230
|
request = AccountSummariesRequest(
|
1170
1231
|
accounts=accounts,
|
1171
1232
|
trader=trader,
|
@@ -1182,7 +1243,7 @@ class AsyncClient:
|
|
1182
1243
|
"""
|
1183
1244
|
Get historical sequence of account summaries for the given account.
|
1184
1245
|
"""
|
1185
|
-
grpc_client = await self.
|
1246
|
+
grpc_client = await self._core()
|
1186
1247
|
if from_inclusive is not None:
|
1187
1248
|
assert from_inclusive.tzinfo is timezone.utc, (
|
1188
1249
|
"from_inclusive must be a utc datetime:\n"
|
@@ -1230,7 +1291,7 @@ class AsyncClient:
|
|
1230
1291
|
Returns:
|
1231
1292
|
Open orders that match the union of the filters
|
1232
1293
|
"""
|
1233
|
-
grpc_client = await self.
|
1294
|
+
grpc_client = await self._core()
|
1234
1295
|
open_orders_request = OpenOrdersRequest(
|
1235
1296
|
venue=venue,
|
1236
1297
|
account=account,
|
@@ -1279,7 +1340,7 @@ class AsyncClient:
|
|
1279
1340
|
If order_ids is not specified, then from_inclusive and to_exclusive
|
1280
1341
|
MUST be specified.
|
1281
1342
|
"""
|
1282
|
-
grpc_client = await self.
|
1343
|
+
grpc_client = await self._core()
|
1283
1344
|
|
1284
1345
|
if from_inclusive is not None:
|
1285
1346
|
assert from_inclusive.tzinfo is timezone.utc, (
|
@@ -1320,7 +1381,7 @@ class AsyncClient:
|
|
1320
1381
|
Args:
|
1321
1382
|
order_id: the order id to get
|
1322
1383
|
"""
|
1323
|
-
grpc_client = await self.
|
1384
|
+
grpc_client = await self._core()
|
1324
1385
|
req = OpenOrdersRequest.new(
|
1325
1386
|
order_ids=[order_id],
|
1326
1387
|
)
|
@@ -1344,7 +1405,7 @@ class AsyncClient:
|
|
1344
1405
|
Args:
|
1345
1406
|
order_ids: a list of order ids to get
|
1346
1407
|
"""
|
1347
|
-
grpc_client = await self.
|
1408
|
+
grpc_client = await self._core()
|
1348
1409
|
orders_dict: dict[OrderId, Optional[Order]] = {
|
1349
1410
|
order_id: None for order_id in order_ids
|
1350
1411
|
}
|
@@ -1388,7 +1449,7 @@ class AsyncClient:
|
|
1388
1449
|
account: account uuid or name
|
1389
1450
|
order_id: the order id to get fills for
|
1390
1451
|
"""
|
1391
|
-
grpc_client = await self.
|
1452
|
+
grpc_client = await self._core()
|
1392
1453
|
if from_inclusive is not None:
|
1393
1454
|
assert from_inclusive.tzinfo is timezone.utc, (
|
1394
1455
|
"from_inclusive must be a utc datetime:\n"
|
@@ -1442,7 +1503,7 @@ class AsyncClient:
|
|
1442
1503
|
print(event)
|
1443
1504
|
```
|
1444
1505
|
"""
|
1445
|
-
grpc_client = await self.
|
1506
|
+
grpc_client = await self._core()
|
1446
1507
|
req: SubscribeOrderflowRequest = SubscribeOrderflowRequest(
|
1447
1508
|
account=account, execution_venue=execution_venue, trader=trader
|
1448
1509
|
)
|
@@ -1512,7 +1573,7 @@ class AsyncClient:
|
|
1512
1573
|
trigger_price=trigger_price,
|
1513
1574
|
)
|
1514
1575
|
"""
|
1515
|
-
grpc_client = await self.
|
1576
|
+
grpc_client = await self._core()
|
1516
1577
|
|
1517
1578
|
res = await asyncio.gather(
|
1518
1579
|
*[
|
@@ -1531,7 +1592,7 @@ class AsyncClient:
|
|
1531
1592
|
execution_venue: Optional[str] = None,
|
1532
1593
|
dir: OrderDir,
|
1533
1594
|
quantity: Decimal,
|
1534
|
-
limit_price: Decimal,
|
1595
|
+
limit_price: Optional[Decimal] = None,
|
1535
1596
|
order_type: OrderType = OrderType.LIMIT,
|
1536
1597
|
time_in_force: TimeInForce = TimeInForce.DAY,
|
1537
1598
|
price_round_method: Optional[TickRoundMethod] = None,
|
@@ -1551,7 +1612,7 @@ class AsyncClient:
|
|
1551
1612
|
symbol: the symbol to send the order for
|
1552
1613
|
execution_venue: the execution venue to send the order to,
|
1553
1614
|
if execution_venue is set to None, the OMS will send the order to the primary_exchange
|
1554
|
-
the primary_exchange can be deduced from `get_product_info`
|
1615
|
+
the primary_exchange can be deduced from `get_product_info` (generally will be "CME" or "US-EQUITIES")
|
1555
1616
|
dir: the direction of the order, BUY or SELL
|
1556
1617
|
quantity: the quantity of the order
|
1557
1618
|
limit_price: the limit price of the order
|
@@ -1563,7 +1624,7 @@ class AsyncClient:
|
|
1563
1624
|
While technically optional, for most order types, the account is required
|
1564
1625
|
trader: the trader to send the order for, defaults to the user's trader
|
1565
1626
|
for when sending order for another user, not relevant for vast majority of users
|
1566
|
-
post_only: whether the order should be post only,
|
1627
|
+
post_only: whether the order should be post only, NOT SUPPORTED BY ALL EXCHANGES (e.g. CME)
|
1567
1628
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
1568
1629
|
stop_loss_price: the stop loss price for a bracket order.
|
1569
1630
|
profit_price: the take profit price for a bracket order.
|
@@ -1573,17 +1634,10 @@ class AsyncClient:
|
|
1573
1634
|
|
1574
1635
|
If the order is rejected, the order.reject_reason and order.reject_message will be set
|
1575
1636
|
"""
|
1576
|
-
grpc_client = await self.
|
1637
|
+
grpc_client = await self._core()
|
1577
1638
|
assert quantity > 0, "quantity must be positive"
|
1578
1639
|
|
1579
|
-
if
|
1580
|
-
if "odir" in kwargs and isinstance(kwargs["odir"], OrderDir):
|
1581
|
-
logging.warning("odir is deprecated, use dir instead")
|
1582
|
-
dir = kwargs["odir"]
|
1583
|
-
else:
|
1584
|
-
raise ValueError("dir is required")
|
1585
|
-
|
1586
|
-
if price_round_method is not None:
|
1640
|
+
if limit_price is not None and price_round_method is not None:
|
1587
1641
|
if execution_venue is None:
|
1588
1642
|
product_info = await self.get_product_info(symbol)
|
1589
1643
|
if product_info is None:
|
@@ -1727,7 +1781,7 @@ class AsyncClient:
|
|
1727
1781
|
Returns:
|
1728
1782
|
the CancelFields object
|
1729
1783
|
"""
|
1730
|
-
grpc_client = await self.
|
1784
|
+
grpc_client = await self._core()
|
1731
1785
|
req = CancelOrderRequest(id=order_id)
|
1732
1786
|
res = await grpc_client.unary_unary(req)
|
1733
1787
|
return res
|
@@ -1770,7 +1824,7 @@ class AsyncClient:
|
|
1770
1824
|
# res = await grpc_client.unary_unary(req)
|
1771
1825
|
# return True
|
1772
1826
|
|
1773
|
-
async def
|
1827
|
+
async def place_algo_order(
|
1774
1828
|
self,
|
1775
1829
|
*,
|
1776
1830
|
params: SpreaderParams,
|
@@ -1780,7 +1834,7 @@ class AsyncClient:
|
|
1780
1834
|
"""
|
1781
1835
|
Sends an advanced algo order such as the spreader.
|
1782
1836
|
"""
|
1783
|
-
grpc_client = await self.
|
1837
|
+
grpc_client = await self._core()
|
1784
1838
|
|
1785
1839
|
if isinstance(params, SpreaderParams):
|
1786
1840
|
algo = "SPREADER"
|