architect-py 5.0.0b1__py3-none-any.whl → 5.0.0b3__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 +10 -3
- architect_py/async_client.py +291 -174
- architect_py/client_interface.py +19 -18
- architect_py/common_types/order_dir.py +12 -6
- architect_py/graphql_client/__init__.py +2 -0
- architect_py/graphql_client/enums.py +5 -0
- architect_py/grpc/__init__.py +25 -7
- architect_py/grpc/client.py +13 -5
- architect_py/grpc/models/Accounts/AccountsRequest.py +4 -1
- architect_py/grpc/models/Algo/AlgoOrder.py +114 -0
- architect_py/grpc/models/Algo/{ModifyAlgoOrderRequestForTwapAlgo.py → AlgoOrderRequest.py} +11 -10
- architect_py/grpc/models/Algo/AlgoOrdersRequest.py +72 -0
- architect_py/grpc/models/Algo/AlgoOrdersResponse.py +27 -0
- architect_py/grpc/models/Algo/CreateAlgoOrderRequest.py +56 -0
- architect_py/grpc/models/Algo/PauseAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/PauseAlgoResponse.py +20 -0
- architect_py/grpc/models/Algo/StartAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/StartAlgoResponse.py +20 -0
- architect_py/grpc/models/Algo/StopAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/StopAlgoResponse.py +20 -0
- architect_py/grpc/models/Boss/DepositsRequest.py +40 -0
- architect_py/grpc/models/Boss/DepositsResponse.py +27 -0
- architect_py/grpc/models/Boss/RqdAccountStatisticsRequest.py +42 -0
- architect_py/grpc/models/Boss/RqdAccountStatisticsResponse.py +25 -0
- architect_py/grpc/models/Boss/StatementUrlRequest.py +40 -0
- architect_py/grpc/models/Boss/StatementUrlResponse.py +23 -0
- architect_py/grpc/models/Boss/StatementsRequest.py +40 -0
- architect_py/grpc/models/Boss/StatementsResponse.py +27 -0
- architect_py/grpc/models/Boss/WithdrawalsRequest.py +40 -0
- architect_py/grpc/models/Boss/WithdrawalsResponse.py +27 -0
- architect_py/grpc/models/Boss/__init__.py +2 -0
- architect_py/grpc/models/Folio/HistoricalFillsRequest.py +4 -1
- architect_py/grpc/models/Marketdata/L1BookSnapshot.py +16 -2
- architect_py/grpc/models/Oms/Cancel.py +67 -19
- architect_py/grpc/models/Oms/Order.py +4 -11
- architect_py/grpc/models/Oms/PlaceOrderRequest.py +13 -20
- architect_py/grpc/models/OptionsMarketdata/OptionsChain.py +30 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeks.py +30 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeksRequest.py +47 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainRequest.py +45 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirations.py +29 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirationsRequest.py +42 -0
- architect_py/grpc/models/OptionsMarketdata/__init__.py +2 -0
- architect_py/grpc/models/Symbology/ExecutionInfoRequest.py +47 -0
- architect_py/grpc/models/Symbology/ExecutionInfoResponse.py +27 -0
- architect_py/grpc/models/definitions.py +457 -790
- architect_py/grpc/resolve_endpoint.py +4 -1
- architect_py/internal_utils/__init__.py +0 -0
- architect_py/internal_utils/no_pandas.py +3 -0
- architect_py/tests/conftest.py +11 -6
- architect_py/tests/test_marketdata.py +19 -19
- architect_py/tests/test_orderflow.py +31 -28
- {architect_py-5.0.0b1.dist-info → architect_py-5.0.0b3.dist-info}/METADATA +2 -3
- {architect_py-5.0.0b1.dist-info → architect_py-5.0.0b3.dist-info}/RECORD +72 -42
- {architect_py-5.0.0b1.dist-info → architect_py-5.0.0b3.dist-info}/WHEEL +1 -1
- examples/book_subscription.py +2 -3
- examples/candles.py +3 -3
- examples/common.py +29 -20
- examples/external_cpty.py +4 -4
- examples/funding_rate_mean_reversion_algo.py +14 -20
- examples/order_sending.py +32 -33
- examples/stream_l1_marketdata.py +2 -2
- examples/stream_l2_marketdata.py +1 -3
- examples/trades.py +2 -2
- examples/tutorial_async.py +9 -7
- examples/tutorial_sync.py +5 -5
- scripts/generate_functions_md.py +3 -1
- scripts/generate_sync_interface.py +30 -11
- scripts/postprocess_grpc.py +21 -11
- scripts/preprocess_grpc_schema.py +174 -113
- architect_py/grpc/models/Algo/AlgoOrderForTwapAlgo.py +0 -61
- architect_py/grpc/models/Algo/CreateAlgoOrderRequestForTwapAlgo.py +0 -59
- {architect_py-5.0.0b1.dist-info → architect_py-5.0.0b3.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.0.0b1.dist-info → architect_py-5.0.0b3.dist-info}/top_level.txt +0 -0
architect_py/async_client.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
import asyncio
|
2
2
|
import logging
|
3
3
|
import re
|
4
|
-
from datetime import date, datetime, timedelta
|
4
|
+
from datetime import date, datetime, timedelta, timezone
|
5
5
|
from decimal import Decimal
|
6
6
|
from typing import (
|
7
|
+
Any,
|
8
|
+
AsyncGenerator,
|
7
9
|
AsyncIterator,
|
8
10
|
List,
|
9
11
|
Literal,
|
@@ -13,6 +15,17 @@ from typing import (
|
|
13
15
|
overload,
|
14
16
|
)
|
15
17
|
|
18
|
+
import grpc
|
19
|
+
import pandas as pd
|
20
|
+
|
21
|
+
from architect_py.grpc.models.Oms.Cancel import Cancel
|
22
|
+
from architect_py.grpc.models.Oms.CancelAllOrdersRequest import CancelAllOrdersRequest
|
23
|
+
from architect_py.grpc.models.Oms.CancelOrderRequest import CancelOrderRequest
|
24
|
+
from architect_py.grpc.models.Oms.OpenOrdersRequest import OpenOrdersRequest
|
25
|
+
from architect_py.grpc.models.Oms.Order import Order
|
26
|
+
from architect_py.grpc.models.Oms.PlaceOrderRequest import (
|
27
|
+
PlaceOrderRequest,
|
28
|
+
)
|
16
29
|
from architect_py.grpc.models.Orderflow.Orderflow import Orderflow
|
17
30
|
from architect_py.grpc.models.Orderflow.OrderflowRequest import (
|
18
31
|
OrderflowRequest,
|
@@ -25,38 +38,19 @@ from architect_py.grpc.models.Orderflow.SubscribeOrderflowRequest import (
|
|
25
38
|
|
26
39
|
from .common_types import OrderDir, TradableProduct, Venue
|
27
40
|
from .graphql_client import GraphQLClient
|
28
|
-
from .graphql_client.enums import (
|
29
|
-
OrderType,
|
30
|
-
TimeInForce,
|
31
|
-
)
|
32
41
|
from .graphql_client.exceptions import GraphQLClientGraphQLMultiError
|
33
42
|
from .graphql_client.fragments import (
|
34
|
-
AccountSummaryFields,
|
35
|
-
AccountWithPermissionsFields,
|
36
|
-
CancelFields,
|
37
43
|
ExecutionInfoFields,
|
38
|
-
OrderFields,
|
39
44
|
ProductInfoFields,
|
40
45
|
)
|
41
|
-
from .graphql_client.get_fills_query import GetFillsQueryFolioHistoricalFills
|
42
|
-
from .graphql_client.place_order_mutation import PlaceOrderMutationOms
|
43
46
|
from .grpc import *
|
44
47
|
from .grpc.client import GrpcClient
|
45
|
-
from .grpc.models import definitions as grpc_definitions
|
46
48
|
from .utils.nearest_tick import TickRoundMethod
|
47
49
|
from .utils.orderbook import update_orderbook_side
|
50
|
+
from .utils.pandas import candles_to_dataframe
|
48
51
|
from .utils.price_bands import price_band_pairs
|
49
52
|
from .utils.symbol_parsing import nominative_expiration
|
50
53
|
|
51
|
-
try:
|
52
|
-
import pandas as pd
|
53
|
-
|
54
|
-
from .utils.pandas import candles_to_dataframe
|
55
|
-
|
56
|
-
FEATURE_PANDAS = True
|
57
|
-
except ImportError:
|
58
|
-
FEATURE_PANDAS = False
|
59
|
-
|
60
54
|
|
61
55
|
class AsyncClient:
|
62
56
|
api_key: Optional[str] = None
|
@@ -84,6 +78,7 @@ class AsyncClient:
|
|
84
78
|
paper_trading: bool,
|
85
79
|
endpoint: str = "https://app.architect.co",
|
86
80
|
graphql_port: Optional[int] = None,
|
81
|
+
**kwargs: Any,
|
87
82
|
) -> "AsyncClient":
|
88
83
|
"""
|
89
84
|
Connect to an Architect installation.
|
@@ -95,11 +90,30 @@ class AsyncClient:
|
|
95
90
|
RESET = "\033[0m"
|
96
91
|
print(f"🧻 {COLOR} YOU ARE IN PAPER TRADING MODE {RESET}")
|
97
92
|
|
93
|
+
if "grpc_endpoint" in kwargs:
|
94
|
+
logging.warning(
|
95
|
+
"as of v5.0.0: grpc_endpoint parameter is deprecated; ignored"
|
96
|
+
)
|
97
|
+
if "host" in kwargs:
|
98
|
+
logging.warning(
|
99
|
+
"as of v5.0.0: host parameter is deprecated, use endpoint instead; setting endpoint to %s",
|
100
|
+
kwargs["endpoint"],
|
101
|
+
)
|
102
|
+
endpoint = kwargs["endpoint"]
|
103
|
+
|
98
104
|
grpc_host, grpc_port, use_ssl = await resolve_endpoint(endpoint)
|
99
105
|
logging.info(
|
100
106
|
f"Resolved endpoint {endpoint}: {grpc_host}:{grpc_port} use_ssl={use_ssl}"
|
101
107
|
)
|
102
108
|
|
109
|
+
# Sanity check paper trading on prod environments
|
110
|
+
if paper_trading:
|
111
|
+
if grpc_host == "app.architect.co" or grpc_host == "staging.architect.co":
|
112
|
+
if grpc_port != 10081:
|
113
|
+
raise ValueError("Wrong gRPC port for paper trading")
|
114
|
+
if graphql_port is not None and graphql_port != 5678:
|
115
|
+
raise ValueError("Wrong GraphQL port for paper trading")
|
116
|
+
|
103
117
|
client = AsyncClient(
|
104
118
|
api_key=api_key,
|
105
119
|
api_secret=api_secret,
|
@@ -146,11 +160,6 @@ class AsyncClient:
|
|
146
160
|
"API secret must be a Base64-encoded string, 44 characters long"
|
147
161
|
)
|
148
162
|
|
149
|
-
if paper_trading and (graphql_port is not None or grpc_port is not None):
|
150
|
-
raise ValueError(
|
151
|
-
"If paper_trading is True, graphql_port and grpc_port must be None"
|
152
|
-
)
|
153
|
-
|
154
163
|
if graphql_port is None:
|
155
164
|
if paper_trading:
|
156
165
|
graphql_port = 5678
|
@@ -318,6 +327,14 @@ class AsyncClient:
|
|
318
327
|
res = await self.graphql_client.user_id_query()
|
319
328
|
return res.user_id, res.user_email
|
320
329
|
|
330
|
+
def enable_orderflow(self):
|
331
|
+
"""
|
332
|
+
@deprecated(reason="No longer needed; orderflow is enabled by default")
|
333
|
+
"""
|
334
|
+
logging.warning(
|
335
|
+
"as of v5.0.0: enable_orderflow is deprecated; orderflow is enabled by default"
|
336
|
+
)
|
337
|
+
|
321
338
|
# ------------------------------------------------------------
|
322
339
|
# Symbology
|
323
340
|
# ------------------------------------------------------------
|
@@ -371,6 +388,10 @@ class AsyncClient:
|
|
371
388
|
|
372
389
|
Args:
|
373
390
|
symbol: the symbol to get information for
|
391
|
+
the symbol should *not* have a quote,
|
392
|
+
ie "ES 20250620 CME Future" instead of "ES 20250620 CME Future/USD"
|
393
|
+
|
394
|
+
If you used TradableProduct, you can use the base() method to get the symbol
|
374
395
|
|
375
396
|
Returns:
|
376
397
|
None if the symbol does not exist
|
@@ -459,6 +480,13 @@ class AsyncClient:
|
|
459
480
|
return None
|
460
481
|
return res.product_info.first_notice_date
|
461
482
|
|
483
|
+
async def get_future_series(self, series_symbol: str) -> list[str]:
|
484
|
+
"""
|
485
|
+
@deprecated(reason="Use get_futures_series instead")
|
486
|
+
"""
|
487
|
+
futures = await self.get_futures_series(series_symbol)
|
488
|
+
return futures
|
489
|
+
|
462
490
|
async def get_futures_series(self, series_symbol: str) -> list[str]:
|
463
491
|
"""
|
464
492
|
List all futures in a given series.
|
@@ -503,11 +531,14 @@ class AsyncClient:
|
|
503
531
|
the symbol for each future in the series
|
504
532
|
|
505
533
|
e.g.
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
534
|
+
```
|
535
|
+
[
|
536
|
+
(datetime.date(2025, 3, 21), 'ES 20250321 CME Future'),
|
537
|
+
(datetime.date(2025, 6, 20), 'ES 20250620 CME Future'),
|
538
|
+
(datetime.date(2025, 9, 19), 'ES 20250919 CME Future'),
|
539
|
+
# ...
|
510
540
|
]
|
541
|
+
```
|
511
542
|
"""
|
512
543
|
futures = await self.get_futures_series(series)
|
513
544
|
exp_and_futures = []
|
@@ -573,7 +604,7 @@ class AsyncClient:
|
|
573
604
|
symbol: the symbol to get the market snapshot for, e.g. "ES 20250321 CME Future/USD"
|
574
605
|
venue: the venue that the symbol is traded at, e.g. CME
|
575
606
|
Returns:
|
576
|
-
|
607
|
+
L1BookSnapshot for the symbol
|
577
608
|
"""
|
578
609
|
return await self.get_l1_book_snapshot(symbol=symbol, venue=venue)
|
579
610
|
|
@@ -591,7 +622,7 @@ class AsyncClient:
|
|
591
622
|
"""
|
592
623
|
return await self.get_l1_book_snapshots(
|
593
624
|
venue=venue,
|
594
|
-
symbols=symbols, #
|
625
|
+
symbols=symbols, # pyright: ignore[reportArgumentType]
|
595
626
|
)
|
596
627
|
|
597
628
|
@overload
|
@@ -634,13 +665,23 @@ class AsyncClient:
|
|
634
665
|
venue: the venue of the symbol
|
635
666
|
candle_width: the width of the candles
|
636
667
|
start: the start date to get candles for;
|
637
|
-
For naive datetimes, the server will assume UTC.
|
638
668
|
end: the end date to get candles for;
|
639
|
-
For naive datetimes, the server will assume UTC.
|
640
669
|
as_dataframe: if True, return a pandas DataFrame
|
641
670
|
|
642
671
|
"""
|
643
672
|
grpc_client = await self.hmart()
|
673
|
+
if start.tzinfo is not timezone.utc:
|
674
|
+
raise ValueError(
|
675
|
+
"start must be a utc datetime:\n"
|
676
|
+
"for example datetime.now(timezone.utc) or \n"
|
677
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
678
|
+
)
|
679
|
+
if end.tzinfo is not timezone.utc:
|
680
|
+
raise ValueError(
|
681
|
+
"end must be a utc datetime:\n"
|
682
|
+
"for example datetime.now(timezone.utc) or \n"
|
683
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
684
|
+
)
|
644
685
|
req = HistoricalCandlesRequest(
|
645
686
|
venue=venue,
|
646
687
|
symbol=str(symbol),
|
@@ -650,10 +691,8 @@ class AsyncClient:
|
|
650
691
|
)
|
651
692
|
res: HistoricalCandlesResponse = await grpc_client.unary_unary(req)
|
652
693
|
|
653
|
-
if as_dataframe
|
694
|
+
if as_dataframe:
|
654
695
|
return candles_to_dataframe(res.candles)
|
655
|
-
elif as_dataframe and not FEATURE_PANDAS:
|
656
|
-
raise RuntimeError("as_dataframe is True but pandas is not installed")
|
657
696
|
else:
|
658
697
|
return res.candles
|
659
698
|
|
@@ -686,7 +725,9 @@ class AsyncClient:
|
|
686
725
|
"""
|
687
726
|
grpc_client = await self.marketdata(venue)
|
688
727
|
req = L1BookSnapshotsRequest(symbols=symbols)
|
689
|
-
res: ArrayOfL1BookSnapshot = await grpc_client.unary_unary(
|
728
|
+
res: ArrayOfL1BookSnapshot = await grpc_client.unary_unary(
|
729
|
+
req # pyright: ignore[reportArgumentType]
|
730
|
+
)
|
690
731
|
return res
|
691
732
|
|
692
733
|
async def get_l2_book_snapshot(
|
@@ -715,7 +756,7 @@ class AsyncClient:
|
|
715
756
|
|
716
757
|
async def stream_l1_book_snapshots(
|
717
758
|
self, symbols: Sequence[TradableProduct | str], venue: Venue
|
718
|
-
) ->
|
759
|
+
) -> AsyncGenerator[L1BookSnapshot, None]:
|
719
760
|
"""
|
720
761
|
Subscribe to the stream of L1BookSnapshots for a symbol.
|
721
762
|
|
@@ -726,11 +767,12 @@ class AsyncClient:
|
|
726
767
|
"""
|
727
768
|
grpc_client = await self.marketdata(venue)
|
728
769
|
req = SubscribeL1BookSnapshotsRequest(symbols=list(symbols), venue=venue)
|
729
|
-
|
770
|
+
async for res in grpc_client.unary_stream(req):
|
771
|
+
yield res
|
730
772
|
|
731
773
|
async def stream_l2_book_updates(
|
732
774
|
self, symbol: TradableProduct | str, venue: Venue
|
733
|
-
) ->
|
775
|
+
) -> AsyncGenerator[L2BookUpdate, None]:
|
734
776
|
"""
|
735
777
|
Subscribe to the stream of L2BookUpdates for a symbol.
|
736
778
|
|
@@ -743,7 +785,10 @@ class AsyncClient:
|
|
743
785
|
"""
|
744
786
|
grpc_client = await self.marketdata(venue)
|
745
787
|
req = SubscribeL2BookUpdatesRequest(symbol=str(symbol), venue=venue)
|
746
|
-
|
788
|
+
async for res in grpc_client.unary_stream(
|
789
|
+
req # pyright: ignore[reportArgumentType]
|
790
|
+
):
|
791
|
+
yield res
|
747
792
|
|
748
793
|
async def subscribe_l1_book(
|
749
794
|
self, symbol: TradableProduct | str, venue: Venue
|
@@ -782,6 +827,9 @@ class AsyncClient:
|
|
782
827
|
return book
|
783
828
|
|
784
829
|
async def unsubscribe_l1_book(self, symbol: TradableProduct | str, venue: Venue):
|
830
|
+
"""
|
831
|
+
Unsubscribe from the L1 stream for a symbol, ie undoes subscribe_l1_book.
|
832
|
+
"""
|
785
833
|
symbol = TradableProduct(symbol)
|
786
834
|
try:
|
787
835
|
task = self.l1_books[venue][symbol][1]
|
@@ -865,7 +913,9 @@ class AsyncClient:
|
|
865
913
|
):
|
866
914
|
try:
|
867
915
|
req = SubscribeL2BookUpdatesRequest(symbol=str(symbol), venue=venue)
|
868
|
-
stream = grpc_client.unary_stream(
|
916
|
+
stream = grpc_client.unary_stream(
|
917
|
+
req # pyright: ignore[reportArgumentType]
|
918
|
+
)
|
869
919
|
async for up in stream:
|
870
920
|
if isinstance(up, L2BookDiff):
|
871
921
|
if (
|
@@ -899,20 +949,21 @@ class AsyncClient:
|
|
899
949
|
|
900
950
|
async def stream_trades(
|
901
951
|
self, symbol: TradableProduct | str, venue: Venue
|
902
|
-
) ->
|
952
|
+
) -> AsyncGenerator[Trade, None]:
|
903
953
|
"""
|
904
954
|
Subscribe to a stream of trades for a symbol.
|
905
955
|
"""
|
906
956
|
grpc_client = await self.marketdata(venue)
|
907
957
|
req = SubscribeTradesRequest(symbol=str(symbol), venue=venue)
|
908
|
-
|
958
|
+
async for res in grpc_client.unary_stream(req):
|
959
|
+
yield res
|
909
960
|
|
910
961
|
async def stream_candles(
|
911
962
|
self,
|
912
963
|
symbol: TradableProduct | str,
|
913
964
|
venue: Venue,
|
914
965
|
candle_widths: Optional[list[CandleWidth]],
|
915
|
-
) ->
|
966
|
+
) -> AsyncGenerator[Candle, None]:
|
916
967
|
"""
|
917
968
|
Subscribe to a stream of candles for a symbol.
|
918
969
|
"""
|
@@ -922,13 +973,14 @@ class AsyncClient:
|
|
922
973
|
venue=venue,
|
923
974
|
candle_widths=candle_widths,
|
924
975
|
)
|
925
|
-
|
976
|
+
async for res in grpc_client.unary_stream(req):
|
977
|
+
yield res
|
926
978
|
|
927
979
|
# ------------------------------------------------------------
|
928
980
|
# Portfolio management
|
929
981
|
# ------------------------------------------------------------
|
930
982
|
|
931
|
-
async def list_accounts(self) ->
|
983
|
+
async def list_accounts(self) -> List[AccountWithPermissions]:
|
932
984
|
"""
|
933
985
|
List accounts for the user that the API key belongs to.
|
934
986
|
|
@@ -937,17 +989,12 @@ class AsyncClient:
|
|
937
989
|
a list of AccountWithPermissions for the user that the API key belongs to
|
938
990
|
(use who_am_i to get the user_id / email)
|
939
991
|
"""
|
940
|
-
|
992
|
+
grpc_client = await self.core()
|
993
|
+
req = AccountsRequest(paper=self.paper_trading)
|
994
|
+
res = await grpc_client.unary_unary(req)
|
941
995
|
return res.accounts
|
942
996
|
|
943
|
-
|
944
|
-
async def list_accounts(self) -> List[grpc_definitions.AccountWithPermissions]:
|
945
|
-
request = AccountsRequest()
|
946
|
-
accounts = await self.grpc_client.request(request)
|
947
|
-
return accounts.accounts
|
948
|
-
"""
|
949
|
-
|
950
|
-
async def get_account_summary(self, account: str) -> AccountSummaryFields:
|
997
|
+
async def get_account_summary(self, account: str) -> AccountSummary:
|
951
998
|
"""
|
952
999
|
Get account summary, including balances, positions, pnls, etc.
|
953
1000
|
|
@@ -955,20 +1002,16 @@ class AsyncClient:
|
|
955
1002
|
account: account uuid or name
|
956
1003
|
Examples: "00000000-0000-0000-0000-000000000000", "STONEX:000000/JDoe"
|
957
1004
|
"""
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
request = AccountSummaryRequest(account=account)
|
963
|
-
account_summary = await self.grpc_client.request(request)
|
964
|
-
return account_summary
|
965
|
-
"""
|
1005
|
+
grpc_client = await self.core()
|
1006
|
+
req = AccountSummaryRequest(account=account)
|
1007
|
+
res = await grpc_client.unary_unary(req)
|
1008
|
+
return res
|
966
1009
|
|
967
1010
|
async def get_account_summaries(
|
968
1011
|
self,
|
969
1012
|
accounts: Optional[list[str]] = None,
|
970
1013
|
trader: Optional[str] = None,
|
971
|
-
) ->
|
1014
|
+
) -> list[AccountSummary]:
|
972
1015
|
"""
|
973
1016
|
Get account summaries for accounts matching the filters.
|
974
1017
|
|
@@ -978,45 +1021,24 @@ class AsyncClient:
|
|
978
1021
|
|
979
1022
|
If both arguments are given, the union of matching accounts are returned.
|
980
1023
|
"""
|
981
|
-
|
982
|
-
trader=trader, accounts=accounts
|
983
|
-
)
|
984
|
-
return res.account_summaries
|
985
|
-
"""
|
986
|
-
async def get_account_summaries(
|
987
|
-
self,
|
988
|
-
accounts: Optional[list[str]] = None,
|
989
|
-
trader: Optional[str] = None,
|
990
|
-
) -> list[AccountSummary]:
|
1024
|
+
grpc_client = await self.core()
|
991
1025
|
request = AccountSummariesRequest(
|
992
1026
|
accounts=accounts,
|
993
1027
|
trader=trader,
|
994
1028
|
)
|
995
|
-
|
996
|
-
return
|
997
|
-
"""
|
1029
|
+
res = await grpc_client.unary_unary(request)
|
1030
|
+
return res.account_summaries
|
998
1031
|
|
999
1032
|
async def get_account_history(
|
1000
1033
|
self,
|
1001
1034
|
account: str,
|
1002
1035
|
from_inclusive: Optional[datetime] = None,
|
1003
1036
|
to_exclusive: Optional[datetime] = None,
|
1004
|
-
) ->
|
1037
|
+
) -> list[AccountSummary]:
|
1005
1038
|
"""
|
1006
1039
|
Get historical sequence of account summaries for the given account.
|
1007
1040
|
"""
|
1008
|
-
|
1009
|
-
account=account, from_inclusive=from_inclusive, to_exclusive=to_exclusive
|
1010
|
-
)
|
1011
|
-
return res.account_history
|
1012
|
-
|
1013
|
-
"""
|
1014
|
-
async def get_account_history(
|
1015
|
-
self,
|
1016
|
-
account: str,
|
1017
|
-
from_inclusive: Optional[datetime] = None,
|
1018
|
-
to_exclusive: Optional[datetime] = None,
|
1019
|
-
) -> list[AccountSummary]:
|
1041
|
+
grpc_client = await self.core()
|
1020
1042
|
if from_inclusive is not None:
|
1021
1043
|
assert from_inclusive.tzinfo is timezone.utc, (
|
1022
1044
|
"from_inclusive must be a utc datetime:\n"
|
@@ -1031,12 +1053,11 @@ class AsyncClient:
|
|
1031
1053
|
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
1032
1054
|
)
|
1033
1055
|
|
1034
|
-
|
1056
|
+
req = AccountHistoryRequest(
|
1035
1057
|
account=account, from_inclusive=from_inclusive, to_exclusive=to_exclusive
|
1036
1058
|
)
|
1037
|
-
|
1038
|
-
return
|
1039
|
-
"""
|
1059
|
+
res = await grpc_client.unary_unary(req)
|
1060
|
+
return res.history
|
1040
1061
|
|
1041
1062
|
# ------------------------------------------------------------
|
1042
1063
|
# Order management
|
@@ -1044,13 +1065,13 @@ class AsyncClient:
|
|
1044
1065
|
|
1045
1066
|
async def get_open_orders(
|
1046
1067
|
self,
|
1047
|
-
order_ids: Optional[list[
|
1068
|
+
order_ids: Optional[list[OrderId]] = None,
|
1048
1069
|
venue: Optional[str] = None,
|
1049
1070
|
account: Optional[str] = None,
|
1050
1071
|
trader: Optional[str] = None,
|
1051
1072
|
symbol: Optional[str] = None,
|
1052
|
-
parent_order_id: Optional[
|
1053
|
-
) ->
|
1073
|
+
parent_order_id: Optional[OrderId] = None,
|
1074
|
+
) -> list[Order]:
|
1054
1075
|
"""
|
1055
1076
|
Returns a list of open orders for the user that match the filters.
|
1056
1077
|
|
@@ -1065,7 +1086,8 @@ class AsyncClient:
|
|
1065
1086
|
Returns:
|
1066
1087
|
Open orders that match the union of the filters
|
1067
1088
|
"""
|
1068
|
-
|
1089
|
+
grpc_client = await self.core()
|
1090
|
+
open_orders_request = OpenOrdersRequest(
|
1069
1091
|
venue=venue,
|
1070
1092
|
account=account,
|
1071
1093
|
trader=trader,
|
@@ -1073,26 +1095,27 @@ class AsyncClient:
|
|
1073
1095
|
parent_order_id=parent_order_id,
|
1074
1096
|
order_ids=order_ids,
|
1075
1097
|
)
|
1076
|
-
return res.open_orders
|
1077
1098
|
|
1078
|
-
|
1099
|
+
open_orders = await grpc_client.unary_unary(open_orders_request)
|
1100
|
+
return open_orders.open_orders
|
1101
|
+
|
1102
|
+
async def get_all_open_orders(self) -> list[Order]:
|
1079
1103
|
"""
|
1080
1104
|
@deprecated(reason="Use get_open_orders with no parameters instead")
|
1081
1105
|
|
1082
1106
|
Returns a list of all open orders for the authenticated user.
|
1083
1107
|
"""
|
1084
|
-
|
1085
|
-
return res.open_orders
|
1108
|
+
return await self.get_open_orders()
|
1086
1109
|
|
1087
1110
|
async def get_historical_orders(
|
1088
1111
|
self,
|
1089
|
-
order_ids: Optional[list[
|
1112
|
+
order_ids: Optional[list[OrderId]] = None,
|
1090
1113
|
from_inclusive: Optional[datetime] = None,
|
1091
1114
|
to_exclusive: Optional[datetime] = None,
|
1092
1115
|
venue: Optional[str] = None,
|
1093
1116
|
account: Optional[str] = None,
|
1094
|
-
parent_order_id: Optional[
|
1095
|
-
) ->
|
1117
|
+
parent_order_id: Optional[OrderId] = None,
|
1118
|
+
) -> list[Order]:
|
1096
1119
|
"""
|
1097
1120
|
Returns a list of all historical orders that match the filters.
|
1098
1121
|
|
@@ -1112,7 +1135,23 @@ class AsyncClient:
|
|
1112
1135
|
If order_ids is not specified, then from_inclusive and to_exclusive
|
1113
1136
|
MUST be specified.
|
1114
1137
|
"""
|
1115
|
-
|
1138
|
+
grpc_client = await self.core()
|
1139
|
+
|
1140
|
+
if from_inclusive is not None:
|
1141
|
+
assert from_inclusive.tzinfo is timezone.utc, (
|
1142
|
+
"from_inclusive must be a utc datetime:\n"
|
1143
|
+
"for example datetime.now(timezone.utc) or \n"
|
1144
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
1145
|
+
)
|
1146
|
+
|
1147
|
+
if to_exclusive is not None:
|
1148
|
+
assert to_exclusive.tzinfo is timezone.utc, (
|
1149
|
+
"to_exclusive must be a utc datetime:\n"
|
1150
|
+
"for example datetime.now(timezone.utc) or \n"
|
1151
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
1152
|
+
)
|
1153
|
+
|
1154
|
+
historical_orders_request = HistoricalOrdersRequest.new(
|
1116
1155
|
order_ids=order_ids,
|
1117
1156
|
venue=venue,
|
1118
1157
|
account=account,
|
@@ -1120,9 +1159,10 @@ class AsyncClient:
|
|
1120
1159
|
from_inclusive=from_inclusive,
|
1121
1160
|
to_exclusive=to_exclusive,
|
1122
1161
|
)
|
1123
|
-
|
1162
|
+
orders = await grpc_client.unary_unary(historical_orders_request)
|
1163
|
+
return orders.orders
|
1124
1164
|
|
1125
|
-
async def get_order(self, order_id:
|
1165
|
+
async def get_order(self, order_id: OrderId) -> Optional[Order]:
|
1126
1166
|
"""
|
1127
1167
|
Returns the specified order. Useful for looking at past sent orders.
|
1128
1168
|
Queries open_orders first, then queries historical_orders.
|
@@ -1130,18 +1170,23 @@ class AsyncClient:
|
|
1130
1170
|
Args:
|
1131
1171
|
order_id: the order id to get
|
1132
1172
|
"""
|
1133
|
-
|
1173
|
+
grpc_client = await self.core()
|
1174
|
+
req = OpenOrdersRequest.new(
|
1175
|
+
order_ids=[order_id],
|
1176
|
+
)
|
1177
|
+
res = await grpc_client.unary_unary(req)
|
1134
1178
|
for open_order in res.open_orders:
|
1135
1179
|
if open_order.id == order_id:
|
1136
1180
|
return open_order
|
1137
1181
|
|
1138
|
-
|
1139
|
-
order_ids=[order_id]
|
1182
|
+
req = HistoricalOrdersRequest.new(
|
1183
|
+
order_ids=[order_id],
|
1140
1184
|
)
|
1141
|
-
|
1142
|
-
|
1185
|
+
res = await grpc_client.unary_unary(req)
|
1186
|
+
if res.orders and len(res.orders) == 1:
|
1187
|
+
return res.orders[0]
|
1143
1188
|
|
1144
|
-
async def get_orders(self, order_ids: list[
|
1189
|
+
async def get_orders(self, order_ids: list[OrderId]) -> list[Optional[Order]]:
|
1145
1190
|
"""
|
1146
1191
|
Returns the specified orders. Useful for looking at past sent orders.
|
1147
1192
|
Plural form of get_order.
|
@@ -1149,24 +1194,27 @@ class AsyncClient:
|
|
1149
1194
|
Args:
|
1150
1195
|
order_ids: a list of order ids to get
|
1151
1196
|
"""
|
1152
|
-
|
1197
|
+
grpc_client = await self.core()
|
1198
|
+
orders_dict: dict[OrderId, Optional[Order]] = {
|
1153
1199
|
order_id: None for order_id in order_ids
|
1154
1200
|
}
|
1201
|
+
req = OpenOrdersRequest.new(
|
1202
|
+
order_ids=order_ids,
|
1203
|
+
)
|
1155
1204
|
|
1156
|
-
res = await
|
1157
|
-
|
1158
|
-
for open_order in open_orders:
|
1205
|
+
res = await grpc_client.unary_unary(req)
|
1206
|
+
for open_order in res.open_orders:
|
1159
1207
|
orders_dict[open_order.id] = open_order
|
1160
1208
|
|
1161
1209
|
not_open_order_ids = [
|
1162
1210
|
order_id for order_id in order_ids if orders_dict[order_id] is None
|
1163
1211
|
]
|
1164
1212
|
|
1165
|
-
|
1166
|
-
order_ids=not_open_order_ids
|
1213
|
+
req = HistoricalOrdersRequest.new(
|
1214
|
+
order_ids=not_open_order_ids,
|
1167
1215
|
)
|
1168
|
-
|
1169
|
-
for historical_order in
|
1216
|
+
res = await grpc_client.unary_unary(req)
|
1217
|
+
for historical_order in res.orders:
|
1170
1218
|
orders_dict[historical_order.id] = historical_order
|
1171
1219
|
|
1172
1220
|
return [orders_dict[order_id] for order_id in order_ids]
|
@@ -1177,8 +1225,9 @@ class AsyncClient:
|
|
1177
1225
|
to_exclusive: Optional[datetime] = None,
|
1178
1226
|
venue: Optional[str] = None,
|
1179
1227
|
account: Optional[str] = None,
|
1180
|
-
order_id: Optional[
|
1181
|
-
|
1228
|
+
order_id: Optional[OrderId] = None,
|
1229
|
+
limit: Optional[int] = None,
|
1230
|
+
) -> HistoricalFillsResponse:
|
1182
1231
|
"""
|
1183
1232
|
Returns all fills matching the given filters.
|
1184
1233
|
|
@@ -1189,15 +1238,35 @@ class AsyncClient:
|
|
1189
1238
|
account: account uuid or name
|
1190
1239
|
order_id: the order id to get fills for
|
1191
1240
|
"""
|
1192
|
-
|
1193
|
-
|
1241
|
+
grpc_client = await self.core()
|
1242
|
+
if from_inclusive is not None:
|
1243
|
+
assert from_inclusive.tzinfo is timezone.utc, (
|
1244
|
+
"from_inclusive must be a utc datetime:\n"
|
1245
|
+
"for example datetime.now(timezone.utc) or \n"
|
1246
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
1247
|
+
)
|
1248
|
+
|
1249
|
+
if to_exclusive is not None:
|
1250
|
+
assert to_exclusive.tzinfo is timezone.utc, (
|
1251
|
+
"to_exclusive must be a utc datetime:\n"
|
1252
|
+
"for example datetime.now(timezone.utc) or \n"
|
1253
|
+
"dt = datetime(2025, 4, 15, 12, 0, 0, tzinfo=timezone.utc)"
|
1254
|
+
)
|
1255
|
+
req = HistoricalFillsRequest(
|
1256
|
+
account=account,
|
1257
|
+
from_inclusive=from_inclusive,
|
1258
|
+
limit=limit,
|
1259
|
+
order_id=order_id,
|
1260
|
+
to_exclusive=to_exclusive,
|
1261
|
+
venue=venue,
|
1194
1262
|
)
|
1195
|
-
|
1263
|
+
res = await grpc_client.unary_unary(req)
|
1264
|
+
return res
|
1196
1265
|
|
1197
1266
|
async def orderflow(
|
1198
1267
|
self,
|
1199
1268
|
request_iterator: AsyncIterator[OrderflowRequest],
|
1200
|
-
) ->
|
1269
|
+
) -> AsyncGenerator[Orderflow, None]:
|
1201
1270
|
"""
|
1202
1271
|
A two-way channel for both order entry and listening to order updates (fills, acks, outs, etc.).
|
1203
1272
|
|
@@ -1210,12 +1279,12 @@ class AsyncClient:
|
|
1210
1279
|
"""
|
1211
1280
|
grpc_client = await self.core()
|
1212
1281
|
decoder = grpc_client.get_decoder(OrderflowRequestUnannotatedResponseType)
|
1213
|
-
stub = grpc_client.channel.stream_stream(
|
1282
|
+
stub: grpc.aio.StreamStreamMultiCallable = grpc_client.channel.stream_stream(
|
1214
1283
|
OrderflowRequest_route,
|
1215
1284
|
request_serializer=grpc_client.encoder().encode,
|
1216
1285
|
response_deserializer=decoder.decode,
|
1217
1286
|
)
|
1218
|
-
call = stub(
|
1287
|
+
call: grpc.aio._base_call.StreamStreamCall[OrderflowRequest, Orderflow] = stub(
|
1219
1288
|
request_iterator, metadata=(("authorization", f"Bearer {grpc_client.jwt}"),)
|
1220
1289
|
)
|
1221
1290
|
async for update in call:
|
@@ -1223,10 +1292,10 @@ class AsyncClient:
|
|
1223
1292
|
|
1224
1293
|
async def stream_orderflow(
|
1225
1294
|
self,
|
1226
|
-
account: Optional[
|
1295
|
+
account: Optional[AccountIdOrName] = None,
|
1227
1296
|
execution_venue: Optional[str] = None,
|
1228
|
-
trader: Optional[
|
1229
|
-
) ->
|
1297
|
+
trader: Optional[TraderIdOrEmail] = None,
|
1298
|
+
) -> AsyncGenerator[Orderflow, None]:
|
1230
1299
|
"""
|
1231
1300
|
A stream for listening to order updates (fills, acks, outs, etc.).
|
1232
1301
|
|
@@ -1245,12 +1314,16 @@ class AsyncClient:
|
|
1245
1314
|
)
|
1246
1315
|
grpc_client = await self.core()
|
1247
1316
|
decoder = grpc_client.get_decoder(SubscribeOrderflowRequest)
|
1248
|
-
stub
|
1317
|
+
stub: grpc.aio.UnaryStreamMultiCallable[
|
1318
|
+
SubscribeOrderflowRequest, Orderflow
|
1319
|
+
] = grpc_client.channel.unary_stream(
|
1249
1320
|
SubscribeOrderflowRequest.get_route(),
|
1250
1321
|
request_serializer=grpc_client.encoder().encode,
|
1251
1322
|
response_deserializer=decoder.decode,
|
1252
1323
|
)
|
1253
|
-
call
|
1324
|
+
call: grpc.aio._base_call.UnaryStreamCall[
|
1325
|
+
SubscribeOrderflowRequest, Orderflow
|
1326
|
+
] = stub(request, metadata=(("authorization", f"Bearer {grpc_client.jwt}"),))
|
1254
1327
|
async for update in call:
|
1255
1328
|
yield update
|
1256
1329
|
|
@@ -1258,39 +1331,49 @@ class AsyncClient:
|
|
1258
1331
|
# Order entry
|
1259
1332
|
# ------------------------------------------------------------
|
1260
1333
|
|
1334
|
+
async def send_limit_order(
|
1335
|
+
self,
|
1336
|
+
*args,
|
1337
|
+
**kwargs,
|
1338
|
+
) -> Order:
|
1339
|
+
"""
|
1340
|
+
@deprecated(reason="Use place_limit_order instead")
|
1341
|
+
"""
|
1342
|
+
return await self.place_limit_order(*args, **kwargs)
|
1343
|
+
|
1261
1344
|
async def place_limit_order(
|
1262
1345
|
self,
|
1263
1346
|
*,
|
1264
|
-
id: Optional[
|
1347
|
+
id: Optional[OrderId] = None,
|
1265
1348
|
symbol: TradableProduct | str,
|
1266
|
-
execution_venue: Optional[str],
|
1267
|
-
|
1349
|
+
execution_venue: Optional[str] = None,
|
1350
|
+
dir: Optional[OrderDir] = None,
|
1268
1351
|
quantity: Decimal,
|
1269
1352
|
limit_price: Decimal,
|
1270
1353
|
order_type: OrderType = OrderType.LIMIT,
|
1271
|
-
time_in_force: TimeInForce =
|
1272
|
-
good_til_date: Optional[datetime] = None,
|
1354
|
+
time_in_force: TimeInForce = TimeInForceEnum.DAY,
|
1273
1355
|
price_round_method: Optional[TickRoundMethod] = None,
|
1274
1356
|
account: Optional[str] = None,
|
1275
1357
|
trader: Optional[str] = None,
|
1276
1358
|
post_only: bool = False,
|
1277
1359
|
trigger_price: Optional[Decimal] = None,
|
1278
|
-
|
1360
|
+
**kwargs: Any,
|
1361
|
+
) -> Order:
|
1279
1362
|
"""
|
1280
1363
|
Sends a regular limit order.
|
1281
1364
|
|
1282
1365
|
Args:
|
1366
|
+
id: in case user wants to generate their own order id, otherwise it will be generated automatically
|
1283
1367
|
symbol: the symbol to send the order for
|
1284
1368
|
execution_venue: the execution venue to send the order to,
|
1285
1369
|
if execution_venue is set to None, the OMS will send the order to the primary_exchange
|
1286
1370
|
the primary_exchange can be deduced from `get_product_info`
|
1287
|
-
|
1371
|
+
dir: the direction of the order, BUY or SELL
|
1288
1372
|
quantity: the quantity of the order
|
1289
1373
|
limit_price: the limit price of the order
|
1290
1374
|
It is highly recommended to make this a Decimal object from the decimal module to avoid floating point errors
|
1291
1375
|
order_type: the type of the order
|
1292
1376
|
time_in_force: the time in force of the order
|
1293
|
-
good_til_date: the date the order is good until, only relevant for time_in_force = "GTD"
|
1294
1377
|
price_round_method: the method to round the price to the nearest tick, will not round if None
|
1295
1378
|
account: the account to send the order for
|
1296
1379
|
While technically optional, for most order types, the account is required
|
@@ -1299,13 +1382,21 @@ class AsyncClient:
|
|
1299
1382
|
post_only: whether the order should be post only, not supported by all exchanges
|
1300
1383
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
1301
1384
|
Returns:
|
1302
|
-
the
|
1385
|
+
the Order object for the order
|
1303
1386
|
The order.status should be "PENDING" until the order is "OPEN" / "REJECTED" / "OUT" / "CANCELED" / "STALE"
|
1304
1387
|
|
1305
1388
|
If the order is rejected, the order.reject_reason and order.reject_message will be set
|
1306
1389
|
"""
|
1390
|
+
grpc_client = await self.core()
|
1307
1391
|
assert quantity > 0, "quantity must be positive"
|
1308
1392
|
|
1393
|
+
if dir is None:
|
1394
|
+
if "odir" in kwargs and isinstance(kwargs["odir"], OrderDir):
|
1395
|
+
logging.warning("odir is deprecated, use dir instead")
|
1396
|
+
dir = kwargs["odir"]
|
1397
|
+
else:
|
1398
|
+
raise ValueError("dir is required")
|
1399
|
+
|
1309
1400
|
if price_round_method is not None:
|
1310
1401
|
if execution_venue is None:
|
1311
1402
|
product_info = await self.get_product_info(symbol)
|
@@ -1331,44 +1422,43 @@ class AsyncClient:
|
|
1331
1422
|
else:
|
1332
1423
|
raise ValueError(f"Could not find market information for {symbol}")
|
1333
1424
|
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
post_only,
|
1348
|
-
trigger_price,
|
1349
|
-
good_til_date,
|
1350
|
-
execution_venue,
|
1425
|
+
req: PlaceOrderRequest = PlaceOrderRequest.new(
|
1426
|
+
dir=dir,
|
1427
|
+
quantity=quantity,
|
1428
|
+
symbol=symbol,
|
1429
|
+
time_in_force=time_in_force,
|
1430
|
+
limit_price=limit_price,
|
1431
|
+
order_type=order_type,
|
1432
|
+
account=account,
|
1433
|
+
id=id,
|
1434
|
+
parent_id=None,
|
1435
|
+
source=OrderSource.API,
|
1436
|
+
trader=trader,
|
1437
|
+
execution_venue=execution_venue,
|
1438
|
+
post_only=post_only,
|
1439
|
+
trigger_price=trigger_price,
|
1351
1440
|
)
|
1352
|
-
|
1353
|
-
return
|
1441
|
+
res = await grpc_client.unary_unary(req)
|
1442
|
+
return res
|
1354
1443
|
|
1355
1444
|
async def send_market_pro_order(
|
1356
1445
|
self,
|
1357
1446
|
*,
|
1358
|
-
id: Optional[
|
1447
|
+
id: Optional[OrderId] = None,
|
1359
1448
|
symbol: TradableProduct | str,
|
1360
1449
|
execution_venue: str,
|
1361
1450
|
odir: OrderDir,
|
1362
1451
|
quantity: Decimal,
|
1363
|
-
time_in_force: TimeInForce =
|
1452
|
+
time_in_force: TimeInForce = TimeInForceEnum.DAY,
|
1364
1453
|
account: Optional[str] = None,
|
1365
1454
|
fraction_through_market: Decimal = Decimal("0.001"),
|
1366
|
-
) ->
|
1455
|
+
) -> Order:
|
1367
1456
|
"""
|
1368
1457
|
Sends a market-order like limit price based on the BBO.
|
1369
1458
|
Meant to behave as a market order but with more protections.
|
1370
1459
|
|
1371
1460
|
Args:
|
1461
|
+
id: in case user wants to generate their own order id, otherwise it will be generated automatically
|
1372
1462
|
symbol: the symbol to send the order for
|
1373
1463
|
execution_venue: the execution venue to send the order to
|
1374
1464
|
odir: the direction of the order
|
@@ -1440,7 +1530,7 @@ class AsyncClient:
|
|
1440
1530
|
time_in_force=time_in_force,
|
1441
1531
|
)
|
1442
1532
|
|
1443
|
-
async def cancel_order(self, order_id:
|
1533
|
+
async def cancel_order(self, order_id: OrderId) -> Cancel:
|
1444
1534
|
"""
|
1445
1535
|
Cancels an order by order id.
|
1446
1536
|
|
@@ -1449,10 +1539,17 @@ class AsyncClient:
|
|
1449
1539
|
Returns:
|
1450
1540
|
the CancelFields object
|
1451
1541
|
"""
|
1452
|
-
|
1453
|
-
|
1542
|
+
grpc_client = await self.core()
|
1543
|
+
req = CancelOrderRequest(id=order_id)
|
1544
|
+
res = await grpc_client.unary_unary(req)
|
1545
|
+
return res
|
1454
1546
|
|
1455
|
-
async def cancel_all_orders(
|
1547
|
+
async def cancel_all_orders(
|
1548
|
+
self,
|
1549
|
+
account: Optional[AccountIdOrName] = None,
|
1550
|
+
execution_venue: Optional[str] = None,
|
1551
|
+
trader: Optional[TraderIdOrEmail] = None,
|
1552
|
+
) -> bool:
|
1456
1553
|
"""
|
1457
1554
|
Cancels all open orders.
|
1458
1555
|
|
@@ -1460,5 +1557,25 @@ class AsyncClient:
|
|
1460
1557
|
True if all orders were cancelled successfully
|
1461
1558
|
False if there was an error
|
1462
1559
|
"""
|
1463
|
-
|
1464
|
-
|
1560
|
+
|
1561
|
+
open_orders = await self.get_open_orders(
|
1562
|
+
account=account,
|
1563
|
+
venue=execution_venue,
|
1564
|
+
trader=trader,
|
1565
|
+
)
|
1566
|
+
outputs = await asyncio.gather(
|
1567
|
+
*(self.cancel_order(order.id) for order in open_orders)
|
1568
|
+
)
|
1569
|
+
|
1570
|
+
for cancel in outputs:
|
1571
|
+
if cancel.reject_reason is not None:
|
1572
|
+
return False
|
1573
|
+
return True
|
1574
|
+
grpc_client = await self.core()
|
1575
|
+
req = CancelAllOrdersRequest(
|
1576
|
+
account=account,
|
1577
|
+
execution_venue=execution_venue,
|
1578
|
+
trader=trader,
|
1579
|
+
)
|
1580
|
+
res = await grpc_client.unary_unary(req)
|
1581
|
+
return res
|