architect-py 3.2.1__py3-none-any.whl → 5.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. architect_py/__init__.py +8 -2
  2. architect_py/async_client.py +887 -575
  3. architect_py/client.py +36 -33
  4. architect_py/client_interface.py +62 -0
  5. architect_py/common_types/__init__.py +6 -0
  6. architect_py/common_types/order_dir.py +85 -0
  7. architect_py/common_types/scalars.py +25 -0
  8. architect_py/common_types/tradable_product.py +59 -0
  9. architect_py/graphql_client/client.py +3 -6
  10. architect_py/graphql_client/fragments.py +3 -6
  11. architect_py/graphql_client/get_fills_query.py +2 -1
  12. architect_py/graphql_client/search_symbols_query.py +2 -1
  13. architect_py/graphql_client/subscribe_orderflow.py +2 -1
  14. architect_py/graphql_client/subscribe_trades.py +2 -1
  15. architect_py/grpc/__init__.py +125 -0
  16. architect_py/grpc/client.py +86 -0
  17. architect_py/{grpc_client → grpc/models}/Accounts/AccountsRequest.py +2 -2
  18. architect_py/{grpc_client → grpc/models}/Accounts/AccountsResponse.py +1 -1
  19. architect_py/{grpc_client → grpc/models}/Accounts/__init__.py +1 -1
  20. architect_py/{grpc_client → grpc/models}/Algo/AlgoOrderForTwapAlgo.py +1 -1
  21. architect_py/{grpc_client → grpc/models}/Algo/CreateAlgoOrderRequestForTwapAlgo.py +2 -2
  22. architect_py/{grpc_client → grpc/models}/Algo/ModifyAlgoOrderRequestForTwapAlgo.py +2 -2
  23. architect_py/{grpc_client → grpc/models}/Algo/__init__.py +1 -1
  24. architect_py/grpc/models/Auth/CreateJwtRequest.py +47 -0
  25. architect_py/grpc/models/Auth/CreateJwtResponse.py +23 -0
  26. architect_py/{grpc_client/Cpty → grpc/models/Auth}/__init__.py +1 -1
  27. architect_py/grpc/models/Core/ConfigRequest.py +37 -0
  28. architect_py/grpc/models/Core/ConfigResponse.py +25 -0
  29. architect_py/{grpc_client/Folio → grpc/models/Core}/__init__.py +1 -1
  30. architect_py/{grpc_client → grpc/models}/Cpty/CptyRequest.py +5 -4
  31. architect_py/{grpc_client → grpc/models}/Cpty/CptyResponse.py +6 -6
  32. architect_py/grpc/models/Cpty/CptyStatus.py +48 -0
  33. architect_py/grpc/models/Cpty/CptyStatusRequest.py +45 -0
  34. architect_py/grpc/models/Cpty/CptysRequest.py +37 -0
  35. architect_py/grpc/models/Cpty/CptysResponse.py +27 -0
  36. architect_py/grpc/models/Cpty/__init__.py +2 -0
  37. architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryRequest.py +2 -2
  38. architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryResponse.py +1 -1
  39. architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesRequest.py +2 -2
  40. architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesResponse.py +1 -1
  41. architect_py/{grpc_client → grpc/models}/Folio/AccountSummary.py +1 -1
  42. architect_py/{grpc_client → grpc/models}/Folio/AccountSummaryRequest.py +2 -2
  43. architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsRequest.py +3 -3
  44. architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsResponse.py +1 -1
  45. architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersRequest.py +3 -3
  46. architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersResponse.py +1 -1
  47. architect_py/grpc/models/Folio/__init__.py +2 -0
  48. architect_py/{grpc_client → grpc/models}/Health/HealthCheckRequest.py +2 -2
  49. architect_py/{grpc_client → grpc/models}/Health/HealthCheckResponse.py +1 -1
  50. architect_py/grpc/models/Health/__init__.py +2 -0
  51. architect_py/{grpc_client → grpc/models}/Marketdata/Candle.py +1 -1
  52. architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesRequest.py +11 -8
  53. architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesResponse.py +1 -1
  54. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshot.py +36 -3
  55. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotRequest.py +8 -3
  56. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotsRequest.py +6 -3
  57. architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshot.py +1 -1
  58. architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshotRequest.py +2 -2
  59. architect_py/{grpc_client → grpc/models}/Marketdata/Liquidation.py +2 -2
  60. architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatus.py +1 -1
  61. architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatusRequest.py +2 -2
  62. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCandlesRequest.py +2 -2
  63. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCurrentCandlesRequest.py +3 -4
  64. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL1BookSnapshotsRequest.py +6 -3
  65. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL2BookUpdatesRequest.py +2 -2
  66. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeLiquidationsRequest.py +2 -2
  67. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeManyCandlesRequest.py +2 -2
  68. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTickersRequest.py +2 -2
  69. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTradesRequest.py +2 -2
  70. architect_py/{grpc_client → grpc/models}/Marketdata/Ticker.py +14 -3
  71. architect_py/{grpc_client → grpc/models}/Marketdata/TickerRequest.py +2 -2
  72. architect_py/{grpc_client → grpc/models}/Marketdata/TickersRequest.py +2 -2
  73. architect_py/{grpc_client → grpc/models}/Marketdata/TickersResponse.py +1 -1
  74. architect_py/{grpc_client → grpc/models}/Marketdata/Trade.py +2 -2
  75. architect_py/grpc/models/Marketdata/__init__.py +2 -0
  76. architect_py/{grpc_client → grpc/models}/Oms/Cancel.py +1 -1
  77. architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersRequest.py +2 -2
  78. architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersResponse.py +1 -1
  79. architect_py/{grpc_client → grpc/models}/Oms/CancelOrderRequest.py +2 -2
  80. architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersRequest.py +2 -2
  81. architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersResponse.py +1 -1
  82. architect_py/{grpc_client → grpc/models}/Oms/Order.py +2 -2
  83. architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsRequest.py +2 -2
  84. architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsResponse.py +1 -1
  85. architect_py/{grpc_client → grpc/models}/Oms/PlaceOrderRequest.py +3 -3
  86. architect_py/grpc/models/Oms/__init__.py +2 -0
  87. architect_py/{grpc_client → grpc/models}/Orderflow/DropcopyRequest.py +2 -2
  88. architect_py/{grpc_client → grpc/models}/Orderflow/OrderflowRequest.py +2 -1
  89. architect_py/{grpc_client → grpc/models}/Orderflow/SubscribeOrderflowRequest.py +2 -2
  90. architect_py/grpc/models/Orderflow/__init__.py +2 -0
  91. architect_py/grpc/models/Symbology/DownloadProductCatalogRequest.py +42 -0
  92. architect_py/grpc/models/Symbology/DownloadProductCatalogResponse.py +27 -0
  93. architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsRequest.py +2 -2
  94. architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsResponse.py +1 -1
  95. architect_py/{grpc_client → grpc/models}/Symbology/SubscribeSymbology.py +1 -1
  96. architect_py/{grpc_client → grpc/models}/Symbology/SymbologyRequest.py +2 -2
  97. architect_py/{grpc_client → grpc/models}/Symbology/SymbologySnapshot.py +7 -2
  98. architect_py/{grpc_client → grpc/models}/Symbology/SymbologyUpdate.py +9 -2
  99. architect_py/{grpc_client → grpc/models}/Symbology/SymbolsRequest.py +2 -2
  100. architect_py/{grpc_client → grpc/models}/Symbology/SymbolsResponse.py +1 -1
  101. architect_py/grpc/models/Symbology/UploadProductCatalogRequest.py +49 -0
  102. architect_py/grpc/models/Symbology/UploadProductCatalogResponse.py +20 -0
  103. architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyRequest.py +2 -2
  104. architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyResponse.py +1 -1
  105. architect_py/grpc/models/Symbology/__init__.py +2 -0
  106. architect_py/grpc/models/__init__.py +2 -0
  107. architect_py/{grpc_client → grpc/models}/definitions.py +293 -223
  108. architect_py/grpc/resolve_endpoint.py +67 -0
  109. architect_py/{grpc_client/grpc_server.py → grpc/server.py} +13 -9
  110. architect_py/grpc/utils.py +32 -0
  111. architect_py/tests/conftest.py +86 -85
  112. architect_py/tests/test_book_building.py +49 -50
  113. architect_py/tests/test_marketdata.py +168 -0
  114. architect_py/tests/test_order_entry.py +37 -0
  115. architect_py/tests/test_orderflow.py +38 -0
  116. architect_py/tests/test_portfolio_management.py +23 -0
  117. architect_py/tests/test_rounding.py +28 -28
  118. architect_py/tests/test_symbology.py +37 -30
  119. architect_py/utils/nearest_tick.py +2 -5
  120. architect_py/utils/nearest_tick_2.py +1 -2
  121. architect_py/utils/orderbook.py +35 -0
  122. architect_py/utils/pandas.py +44 -0
  123. architect_py/utils/price_bands.py +0 -3
  124. architect_py/utils/symbol_parsing.py +29 -0
  125. architect_py-5.0.0b1.dist-info/METADATA +124 -0
  126. architect_py-5.0.0b1.dist-info/RECORD +184 -0
  127. {architect_py-3.2.1.dist-info → architect_py-5.0.0b1.dist-info}/WHEEL +2 -1
  128. architect_py-5.0.0b1.dist-info/top_level.txt +4 -0
  129. examples/__init__.py +0 -0
  130. examples/book_subscription.py +53 -0
  131. examples/candles.py +30 -0
  132. examples/common.py +107 -0
  133. examples/external_cpty.py +77 -0
  134. examples/funding_rate_mean_reversion_algo.py +192 -0
  135. examples/order_sending.py +92 -0
  136. examples/stream_l1_marketdata.py +25 -0
  137. examples/stream_l2_marketdata.py +40 -0
  138. examples/trades.py +21 -0
  139. examples/tutorial_async.py +84 -0
  140. examples/tutorial_sync.py +95 -0
  141. scripts/generate_functions_md.py +164 -0
  142. scripts/generate_sync_interface.py +207 -0
  143. scripts/postprocess_grpc.py +594 -0
  144. scripts/preprocess_grpc_schema.py +647 -0
  145. templates/exceptions.py +83 -0
  146. templates/juniper_base_client.py +371 -0
  147. architect_py/client_protocol.py +0 -52
  148. architect_py/grpc_client/Folio/AggregatedAccountSummariesRequest.py +0 -59
  149. architect_py/grpc_client/Folio/AggregatedAccountSummariesResponse.py +0 -27
  150. architect_py/grpc_client/Health/__init__.py +0 -2
  151. architect_py/grpc_client/Marketdata/__init__.py +0 -2
  152. architect_py/grpc_client/Oms/__init__.py +0 -2
  153. architect_py/grpc_client/Orderflow/__init__.py +0 -2
  154. architect_py/grpc_client/Symbology/__init__.py +0 -2
  155. architect_py/grpc_client/__init__.py +0 -2
  156. architect_py/grpc_client/grpc_client.py +0 -405
  157. architect_py/scalars.py +0 -172
  158. architect_py/tests/test_accounts.py +0 -31
  159. architect_py/tests/test_client.py +0 -29
  160. architect_py/tests/test_grpc_client.py +0 -30
  161. architect_py/tests/test_order_sending.py +0 -61
  162. architect_py/tests/test_snapshots.py +0 -52
  163. architect_py/tests/test_subscriptions.py +0 -129
  164. architect_py-3.2.1.dist-info/METADATA +0 -212
  165. architect_py-3.2.1.dist-info/RECORD +0 -146
  166. /architect_py/{grpc_client → grpc/models}/Marketdata/ArrayOfL1BookSnapshot.py +0 -0
  167. /architect_py/{grpc_client → grpc/models}/Marketdata/L2BookUpdate.py +0 -0
  168. /architect_py/{grpc_client → grpc/models}/Marketdata/TickerUpdate.py +0 -0
  169. /architect_py/{grpc_client → grpc/models}/Orderflow/Dropcopy.py +0 -0
  170. /architect_py/{grpc_client → grpc/models}/Orderflow/Orderflow.py +0 -0
  171. {architect_py-3.2.1.dist-info → architect_py-5.0.0b1.dist-info/licenses}/LICENSE +0 -0
architect_py/client.py CHANGED
@@ -1,14 +1,12 @@
1
1
  import asyncio
2
-
3
2
  import sys
4
3
  import threading
5
4
  from asyncio import AbstractEventLoop
6
5
  from functools import partial
7
6
  from typing import Any, Awaitable, Callable, Coroutine, Optional, TypeVar
8
7
 
9
- from architect_py.async_client import AsyncClient
10
- from .client_protocol import AsyncClientProtocol
11
-
8
+ from .async_client import AsyncClient
9
+ from .client_interface import ClientProtocol
12
10
 
13
11
  T = TypeVar("T")
14
12
 
@@ -19,11 +17,13 @@ def is_async_function(obj):
19
17
  return callable(obj) and hasattr(obj, "__code__") and obj.__code__.co_flags & 0x80
20
18
 
21
19
 
22
- class Client(AsyncClientProtocol):
20
+ class Client(ClientProtocol):
23
21
  """
24
22
  This class is a wrapper around the AsyncClient class that allows you to call async methods synchronously.
25
23
  This does not work for subscription based methods.
26
24
 
25
+ This Client takes control of the event loop, which you can pass in.
26
+
27
27
  One can find the function definition in the AsyncClient class.
28
28
 
29
29
  The AsyncClient is more performant and powerful, so it is recommended to use that class if possible.
@@ -34,39 +34,43 @@ class Client(AsyncClientProtocol):
34
34
  Instead, add them to the AsyncClient class.
35
35
  """
36
36
 
37
- __slots__ = ("client", "_loop")
37
+ __slots__ = ("client", "_event_loop")
38
38
  client: AsyncClient
39
- _loop: AbstractEventLoop
39
+ _event_loop: AbstractEventLoop
40
40
 
41
41
  def __init__(
42
42
  self,
43
43
  *,
44
- api_key: str,
45
- api_secret: str,
46
- host: str = "app.architect.co",
47
- paper_trading: bool = True,
48
- loop: Optional[AbstractEventLoop] = None,
44
+ api_key: Optional[str] = None,
45
+ api_secret: Optional[str] = None,
46
+ paper_trading: bool,
47
+ endpoint: str = "https://app.architect.co",
48
+ graphql_port: Optional[int] = None,
49
+ event_loop: Optional[AbstractEventLoop] = None,
49
50
  **kwargs,
50
51
  ):
51
- super().__setattr__(
52
- "client",
53
- AsyncClient(
52
+ if event_loop is None:
53
+ try:
54
+ event_loop = asyncio.get_running_loop()
55
+ except RuntimeError:
56
+ event_loop = asyncio.new_event_loop()
57
+ asyncio.set_event_loop(event_loop)
58
+ super().__setattr__("_event_loop", event_loop)
59
+
60
+ async_client = self._event_loop.run_until_complete(
61
+ AsyncClient.connect(
54
62
  api_key=api_key,
55
63
  api_secret=api_secret,
56
- host=host,
57
64
  paper_trading=paper_trading,
58
- _i_know_what_i_am_doing=True,
65
+ endpoint=endpoint,
66
+ graphql_port=graphql_port,
59
67
  **kwargs,
60
- ),
68
+ )
69
+ )
70
+ super().__setattr__(
71
+ "client",
72
+ async_client,
61
73
  )
62
-
63
- if loop is None:
64
- try:
65
- loop = asyncio.get_running_loop()
66
- except RuntimeError:
67
- loop = asyncio.new_event_loop()
68
- asyncio.set_event_loop(loop)
69
- super().__setattr__("_loop", loop)
70
74
 
71
75
  if "ipykernel" in sys.modules:
72
76
  # for jupyter notebooks
@@ -124,19 +128,18 @@ class Client(AsyncClientProtocol):
124
128
  ) -> T:
125
129
  return (
126
130
  super()
127
- .__getattribute__("_loop")
131
+ .__getattribute__("_event_loop")
128
132
  .run_until_complete(async_method(*args, **kwargs))
129
133
  )
130
134
 
131
135
 
132
136
  class AsyncExecutor:
133
137
  def __init__(self):
134
- """
135
- one consideration is to enforce this class to be a singleton
136
- however, this is not necessary as the class is only used in the Client class
137
- when it is used in a jupyter notebook, so unlikely to be a problem
138
- """
139
-
138
+ # NB: one consideration is to enforce this class to be a singleton.
139
+ #
140
+ # However, this is not necessary as the class is only used in the
141
+ # Client class when it is used in a jupyter notebook, so its unlikely
142
+ # to be a problem.
140
143
  self.loop = asyncio.new_event_loop()
141
144
  self.thread = threading.Thread(target=self._run_loop, daemon=True)
142
145
  self.thread.start()
@@ -0,0 +1,62 @@
1
+ # fmt: off
2
+
3
+ # mypy: ignore-errors
4
+
5
+ # Autogenerated from generate_sync_interface.py
6
+
7
+ # If you are here for function definitions, please refer to architect_py/async_client.py
8
+ # This file is so that the sync client has good type hinting
9
+ # It is not used for anything else
10
+ # For maintainers: ensure that the types in this file are correct for correct type hinting
11
+
12
+
13
+ from typing import Any, Union
14
+ from .graphql_client import *
15
+ from .async_client import *
16
+
17
+
18
+ class ClientProtocol:
19
+ def cancel_all_orders(self) -> bool: ...
20
+ def cancel_order(self, order_id: str) -> CancelFields: ...
21
+ def core(self) -> GrpcClient: ...
22
+ def discover_marketdata(self) -> Any: ...
23
+ def get_account_history(self, account: str, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None) -> Sequence[AccountSummaryFields]: ...
24
+ def get_account_summaries(self, accounts: Optional[list[str]] = None, trader: Optional[str] = None) -> Sequence[AccountSummaryFields]: ...
25
+ def get_account_summary(self, account: str) -> AccountSummaryFields: ...
26
+ def get_all_open_orders(self) -> Sequence[OrderFields]: ...
27
+ def get_cme_first_notice_date(self, symbol: str) -> Optional[date]: ...
28
+ def get_cme_future_from_root_month_year(self, root: str, month: int, year: int) -> str: ...
29
+ def get_cme_futures_series(self, series: str) -> list[tuple[date, str]]: ...
30
+ def get_execution_info(self, symbol: Union[TradableProduct, str], execution_venue: str) -> Optional[ExecutionInfoFields]: ...
31
+ def get_execution_infos(self, symbols: Optional[list[TradableProduct]], execution_venue: Optional[str] = None) -> Sequence[ExecutionInfoFields]: ...
32
+ @staticmethod
33
+ def get_expiration_from_CME_name(name: str) -> Optional[date]: ...
34
+ def get_fills(self, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None, venue: Optional[str] = None, account: Optional[str] = None, order_id: Optional[str] = None) -> GetFillsQueryFolioHistoricalFills: ...
35
+ def get_futures_series(self, series_symbol: str) -> list[str]: ...
36
+ def get_historical_candles(self, symbol: Union[TradableProduct, str], venue: str, candle_width: CandleWidth, start: datetime, end: datetime, *, as_dataframe: bool = False) -> Union[list[Candle], pd.DataFrame]: ...
37
+ def get_historical_orders(self, order_ids: Optional[list[str]] = None, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None, venue: Optional[str] = None, account: Optional[str] = None, parent_order_id: Optional[str] = None) -> Sequence[OrderFields]: ...
38
+ def get_l1_book_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L1BookSnapshot: ...
39
+ def get_l1_book_snapshots(self, symbols: list[Union[TradableProduct, str]], venue: str) -> Sequence[L1BookSnapshot]: ...
40
+ def get_l2_book_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L2BookSnapshot: ...
41
+ def get_market_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L1BookSnapshot: ...
42
+ def get_market_snapshots(self, symbols: list[Union[TradableProduct, str]], venue: str) -> Sequence[L1BookSnapshot]: ...
43
+ def get_market_status(self, symbol: Union[TradableProduct, str], venue: str) -> MarketStatus: ...
44
+ def get_open_orders(self, order_ids: Optional[list[str]] = None, venue: Optional[str] = None, account: Optional[str] = None, trader: Optional[str] = None, symbol: Optional[str] = None, parent_order_id: Optional[str] = None) -> Sequence[OrderFields]: ...
45
+ def get_order(self, order_id: str) -> Optional[OrderFields]: ...
46
+ def get_orders(self, order_ids: list[str]) -> list[Optional[OrderFields]]: ...
47
+ def get_product_info(self, symbol: str) -> Optional[ProductInfoFields]: ...
48
+ def get_product_infos(self, symbols: Optional[list[str]]) -> Sequence[ProductInfoFields]: ...
49
+ def get_ticker(self, symbol: Union[TradableProduct, str], venue: str) -> Ticker: ...
50
+ def hmart(self) -> GrpcClient: ...
51
+ def list_accounts(self) -> Sequence[AccountWithPermissionsFields]: ...
52
+ def list_symbols(self, *, marketdata: Optional[str] = None) -> list[str]: ...
53
+ def marketdata(self, venue: str) -> GrpcClient: ...
54
+ def orderflow(self, request_iterator: AsyncIterator) -> AsyncIterator: ...
55
+ def place_limit_order(self, *, id: Optional[str] = None, symbol: Union[TradableProduct, str], execution_venue: Optional[str], odir: OrderDir, quantity: Decimal, limit_price: Decimal, order_type: OrderType = OrderType.LIMIT, time_in_force: TimeInForce = TimeInForce.DAY, good_til_date: Optional[datetime] = None, price_round_method: Optional[TickRoundMethod] = None, account: Optional[str] = None, trader: Optional[str] = None, post_only: bool = False, trigger_price: Optional[Decimal] = None) -> OrderFields: ...
56
+ def refresh_jwt(self, force: bool = False) -> Any: ...
57
+ def search_symbols(self, search_string: Optional[str] = None, execution_venue: Optional[str] = None, offset: int = 0, limit: int = 20) -> list[TradableProduct]: ...
58
+ def send_market_pro_order(self, *, id: Optional[str] = None, symbol: Union[TradableProduct, str], execution_venue: str, odir: OrderDir, quantity: Decimal, time_in_force: TimeInForce = TimeInForce.DAY, account: Optional[str] = None, fraction_through_market: Decimal = Decimal('0.001')) -> OrderFields: ...
59
+ def set_hmart(self, endpoint: str) -> Any: ...
60
+ def set_jwt(self, jwt: Optional[str], jwt_expiration: Optional[datetime] = None) -> Any: ...
61
+ def set_marketdata(self, venue: str, endpoint: str) -> Any: ...
62
+ def who_am_i(self) -> tuple[str, str]: ...
@@ -0,0 +1,6 @@
1
+ from .order_dir import OrderDir
2
+ from .tradable_product import TradableProduct
3
+
4
+ Venue = str
5
+
6
+ __all__ = ["OrderDir", "TradableProduct", "Venue"]
@@ -0,0 +1,85 @@
1
+ from enum import Enum
2
+ from typing import Literal
3
+
4
+
5
+ class OrderDir(str, Enum):
6
+ BUY = "BUY"
7
+ SELL = "SELL"
8
+
9
+ def __int__(self):
10
+ if self == OrderDir.BUY:
11
+ return 1
12
+ elif self == OrderDir.SELL:
13
+ return -1
14
+ else:
15
+ raise ValueError(f"Unknown Dir: {self}")
16
+
17
+ def get_opposite(self) -> "OrderDir":
18
+ """
19
+ NOTE: ENUMS ARE IMMUTABLE SO THIS DOES NOT MUTATE THE STATE OF THE ENUM
20
+ """
21
+ if self == OrderDir.BUY:
22
+ return OrderDir.SELL
23
+ elif self == OrderDir.SELL:
24
+ return OrderDir.BUY
25
+ else:
26
+ raise ValueError(f"Unknown Dir: {self}")
27
+
28
+ def __str__(self) -> str:
29
+ return self.value
30
+
31
+ def lower(self) -> str:
32
+ return self.value.lower()
33
+
34
+ @classmethod
35
+ def from_string(cls, value: str) -> "OrderDir":
36
+ lower = value.lower()
37
+ if lower == "buy":
38
+ return cls.BUY
39
+ elif lower == "sell":
40
+ return cls.SELL
41
+ elif lower == "bid":
42
+ return cls.BUY
43
+ elif lower == "ask":
44
+ return cls.SELL
45
+ elif lower == "b":
46
+ return cls.BUY
47
+ elif lower == "a" or lower == "s":
48
+ return cls.SELL
49
+ else:
50
+ raise ValueError(f"Unknown Dir: {value}")
51
+
52
+ @classmethod
53
+ def from_unit(cls, value: Literal[1, -1]) -> "OrderDir":
54
+ if value == 1:
55
+ return cls.BUY
56
+ elif value == -1:
57
+ return cls.SELL
58
+ else:
59
+ raise ValueError(f"Unknown Dir: {value}")
60
+
61
+ @classmethod
62
+ def from_sign(cls, value: int) -> "OrderDir":
63
+ if value > 0:
64
+ return cls.BUY
65
+ elif value < 0:
66
+ return cls.SELL
67
+ else:
68
+ raise ValueError(f"Unknown Dir: {value}")
69
+
70
+
71
+ def graphql_serialize_order_dir(value: OrderDir) -> str:
72
+ """
73
+ For ariadne-codegen
74
+ """
75
+ return value.lower()
76
+
77
+
78
+ def graphql_parse_order_dir(value: str) -> OrderDir:
79
+ """
80
+ For ariadne-codegen
81
+ """
82
+ if value == "buy":
83
+ return OrderDir.BUY
84
+ else:
85
+ return OrderDir.SELL
@@ -0,0 +1,25 @@
1
+ from datetime import datetime, timezone
2
+ from typing import TYPE_CHECKING, Optional
3
+
4
+ if TYPE_CHECKING:
5
+ from architect_py.graphql_client.base_model import UnsetType
6
+
7
+
8
+ def convert_datetime_to_utc_str(dt: "Optional[datetime] | UnsetType") -> Optional[str]:
9
+ if not isinstance(dt, datetime):
10
+ return None
11
+
12
+ if dt.tzinfo is None:
13
+ raise ValueError(
14
+ "in a datetime sent to the backend, the good_til_date must be timezone-aware. Try \n"
15
+ "from zoneinfo import ZoneInfo\n"
16
+ "datetime(..., tzinfo={your_local_timezone}) or "
17
+ "datetime.now(tz=ZoneInfo('UTC'))\n"
18
+ "# examples of local timezones:\n"
19
+ "ZoneInfo('America/New_York'), "
20
+ "ZoneInfo('America/Los_Angeles'), ZoneInfo('America/Chicago')"
21
+ )
22
+ utc_str = dt.astimezone(timezone.utc).isoformat()[:-6]
23
+ # [:-6] removes the utc offset
24
+
25
+ return f"{utc_str}Z"
@@ -0,0 +1,59 @@
1
+ from typing import Optional
2
+
3
+
4
+ class TradableProduct(str):
5
+ """
6
+ Example instantiations:
7
+ TradableProduct("ES 20250321 CME Future", "USD")
8
+ TradableProduct("ES 20250321 CME Future/USD")
9
+ (these are equivalent)
10
+
11
+ This type exists to enforce the
12
+ {base}/{quote} format for strings
13
+
14
+ A base is the product that is being priced in terms of the quote.
15
+ For example,
16
+ "ES 20250321 CME Future/USD" means that the ES 20250321 CME Future is priced in USD.
17
+ "ES 20250321 CME Future/EUR" means that the ES 20250321 CME Future is priced in EUR.
18
+ "ES 20250321 CME Future/BTC" means that the ES 20250321 CME Future is priced in BTC
19
+ (such a product does not exist on any exchange though).
20
+
21
+ For example in a currency pair, the base is the first currency and the quote is the second currency.
22
+ In the currency pair USD/EUR, USD is the base and EUR is the quote.
23
+ USD/EUR = 1.1234 means that 1 USD = 1.1234 EUR
24
+ EUR/USD = 0.8901 means that 1 EUR = 0.8901 USD
25
+ """
26
+
27
+ def __new__(
28
+ cls, base_or_value: str, quote: Optional[str] = None
29
+ ) -> "TradableProduct":
30
+ """
31
+ These are equivalent:
32
+ TradableProduct("ES 20250321 CME Future", "USD")
33
+ TradableProduct("ES 20250321 CME Future/USD")
34
+ """
35
+ if quote is None:
36
+ value = base_or_value
37
+ else:
38
+ value = f"{base_or_value}/{quote}"
39
+
40
+ assert "/" in value, (
41
+ f"TradableProduct must be in the form of 'base/quote'. Got: {base_or_value}"
42
+ )
43
+ return super().__new__(cls, value)
44
+
45
+ def base_quote(self) -> list[str]:
46
+ return self.split("/")
47
+
48
+ def base(self) -> str:
49
+ return self.split("/", 1)[0]
50
+
51
+ def quote(self) -> str:
52
+ return self.split("/", 1)[1]
53
+
54
+
55
+ def parse_tradable_product(value: str) -> TradableProduct:
56
+ """
57
+ For ariadne-codegen
58
+ """
59
+ return TradableProduct(value)
@@ -6,12 +6,9 @@ from decimal import Decimal
6
6
  from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Optional, Union
7
7
  from uuid import UUID
8
8
 
9
- from architect_py.scalars import (
10
- OrderDir,
11
- TradableProduct,
12
- convert_datetime_to_utc_str,
13
- graphql_serialize_order_dir,
14
- )
9
+ from architect_py.common_types import OrderDir, TradableProduct
10
+ from architect_py.common_types.order_dir import graphql_serialize_order_dir
11
+ from architect_py.common_types.scalars import convert_datetime_to_utc_str
15
12
 
16
13
  from .base_model import UNSET
17
14
  from .juniper_base_client import JuniperBaseClient
@@ -8,12 +8,9 @@ from uuid import UUID
8
8
 
9
9
  from pydantic import BeforeValidator, Field
10
10
 
11
- from architect_py.scalars import (
12
- OrderDir,
13
- TradableProduct,
14
- graphql_parse_order_dir,
15
- parse_tradable_product,
16
- )
11
+ from architect_py.common_types import OrderDir, TradableProduct
12
+ from architect_py.common_types.order_dir import graphql_parse_order_dir
13
+ from architect_py.common_types.tradable_product import parse_tradable_product
17
14
 
18
15
  from .base_model import BaseModel
19
16
  from .enums import (
@@ -8,7 +8,8 @@ from uuid import UUID
8
8
 
9
9
  from pydantic import BeforeValidator, Field
10
10
 
11
- from architect_py.scalars import OrderDir, graphql_parse_order_dir
11
+ from architect_py.common_types import OrderDir
12
+ from architect_py.common_types.order_dir import graphql_parse_order_dir
12
13
 
13
14
  from .base_model import BaseModel
14
15
  from .enums import FillKind
@@ -5,7 +5,8 @@ from typing import Annotated, List
5
5
 
6
6
  from pydantic import BeforeValidator, Field
7
7
 
8
- from architect_py.scalars import TradableProduct, parse_tradable_product
8
+ from architect_py.common_types import TradableProduct
9
+ from architect_py.common_types.tradable_product import parse_tradable_product
9
10
 
10
11
  from .base_model import BaseModel
11
12
 
@@ -8,7 +8,8 @@ from uuid import UUID
8
8
 
9
9
  from pydantic import BeforeValidator, Field
10
10
 
11
- from architect_py.scalars import OrderDir, graphql_parse_order_dir
11
+ from architect_py.common_types import OrderDir
12
+ from architect_py.common_types.order_dir import graphql_parse_order_dir
12
13
 
13
14
  from .base_model import BaseModel
14
15
  from .enums import FillKind
@@ -7,7 +7,8 @@ from typing import Annotated, Optional
7
7
 
8
8
  from pydantic import BeforeValidator
9
9
 
10
- from architect_py.scalars import OrderDir, graphql_parse_order_dir
10
+ from architect_py.common_types import OrderDir
11
+ from architect_py.common_types.order_dir import graphql_parse_order_dir
11
12
 
12
13
  from .base_model import BaseModel
13
14
 
@@ -0,0 +1,125 @@
1
+ from .models.Accounts.AccountsRequest import AccountsRequest
2
+ from .models.Accounts.AccountsResponse import AccountsResponse
3
+ from .models.Auth.CreateJwtRequest import CreateJwtRequest
4
+ from .models.Auth.CreateJwtResponse import CreateJwtResponse
5
+ from .models.Core.ConfigRequest import ConfigRequest
6
+ from .models.Core.ConfigResponse import ConfigResponse
7
+ from .models.Cpty.CptyRequest import CptyRequest
8
+ from .models.Cpty.CptyResponse import CptyResponse
9
+ from .models.Cpty.CptysRequest import CptysRequest
10
+ from .models.Cpty.CptysResponse import CptysResponse
11
+ from .models.Cpty.CptyStatus import CptyStatus
12
+ from .models.Cpty.CptyStatusRequest import CptyStatusRequest
13
+ from .models.definitions import (
14
+ Account,
15
+ AccountPosition,
16
+ AccountStatistics,
17
+ CandleWidth,
18
+ L2BookDiff,
19
+ )
20
+ from .models.Folio.AccountHistoryRequest import AccountHistoryRequest
21
+ from .models.Folio.AccountHistoryResponse import AccountHistoryResponse
22
+ from .models.Folio.AccountSummariesRequest import AccountSummariesRequest
23
+ from .models.Folio.AccountSummariesResponse import AccountSummariesResponse
24
+ from .models.Folio.AccountSummary import AccountSummary
25
+ from .models.Folio.AccountSummaryRequest import AccountSummaryRequest
26
+ from .models.Folio.HistoricalFillsRequest import HistoricalFillsRequest
27
+ from .models.Folio.HistoricalFillsResponse import HistoricalFillsResponse
28
+ from .models.Folio.HistoricalOrdersRequest import HistoricalOrdersRequest
29
+ from .models.Folio.HistoricalOrdersResponse import HistoricalOrdersResponse
30
+ from .models.Marketdata.ArrayOfL1BookSnapshot import ArrayOfL1BookSnapshot
31
+ from .models.Marketdata.Candle import Candle
32
+ from .models.Marketdata.HistoricalCandlesRequest import HistoricalCandlesRequest
33
+ from .models.Marketdata.HistoricalCandlesResponse import HistoricalCandlesResponse
34
+ from .models.Marketdata.L1BookSnapshot import L1BookSnapshot
35
+ from .models.Marketdata.L1BookSnapshotRequest import L1BookSnapshotRequest
36
+ from .models.Marketdata.L1BookSnapshotsRequest import L1BookSnapshotsRequest
37
+ from .models.Marketdata.L2BookSnapshot import L2BookSnapshot
38
+ from .models.Marketdata.L2BookSnapshotRequest import L2BookSnapshotRequest
39
+ from .models.Marketdata.L2BookUpdate import L2BookUpdate
40
+ from .models.Marketdata.Liquidation import Liquidation
41
+ from .models.Marketdata.MarketStatus import MarketStatus
42
+ from .models.Marketdata.MarketStatusRequest import MarketStatusRequest
43
+ from .models.Marketdata.SubscribeCandlesRequest import SubscribeCandlesRequest
44
+ from .models.Marketdata.SubscribeCurrentCandlesRequest import (
45
+ SubscribeCurrentCandlesRequest,
46
+ )
47
+ from .models.Marketdata.SubscribeL1BookSnapshotsRequest import (
48
+ SubscribeL1BookSnapshotsRequest,
49
+ )
50
+ from .models.Marketdata.SubscribeL2BookUpdatesRequest import (
51
+ SubscribeL2BookUpdatesRequest,
52
+ )
53
+ from .models.Marketdata.SubscribeLiquidationsRequest import SubscribeLiquidationsRequest
54
+ from .models.Marketdata.SubscribeManyCandlesRequest import SubscribeManyCandlesRequest
55
+ from .models.Marketdata.SubscribeTickersRequest import SubscribeTickersRequest
56
+ from .models.Marketdata.SubscribeTradesRequest import SubscribeTradesRequest
57
+ from .models.Marketdata.Ticker import Ticker
58
+ from .models.Marketdata.TickerRequest import TickerRequest
59
+ from .models.Marketdata.TickersRequest import TickersRequest
60
+ from .models.Marketdata.TickersResponse import TickersResponse
61
+ from .models.Marketdata.TickerUpdate import TickerUpdate
62
+ from .models.Marketdata.Trade import Trade
63
+ from .models.Symbology.SymbolsRequest import SymbolsRequest
64
+ from .models.Symbology.SymbolsResponse import SymbolsResponse
65
+ from .resolve_endpoint import resolve_endpoint
66
+
67
+ __all__ = [
68
+ "Account",
69
+ "AccountPosition",
70
+ "AccountStatistics",
71
+ "AccountsRequest",
72
+ "AccountsResponse",
73
+ "ArrayOfL1BookSnapshot",
74
+ "CandleWidth",
75
+ "CreateJwtRequest",
76
+ "CreateJwtResponse",
77
+ "ConfigRequest",
78
+ "ConfigResponse",
79
+ "CptyRequest",
80
+ "CptyResponse",
81
+ "CptysRequest",
82
+ "CptysResponse",
83
+ "CptyStatus",
84
+ "CptyStatusRequest",
85
+ "AccountHistoryRequest",
86
+ "AccountHistoryResponse",
87
+ "AccountSummaryRequest",
88
+ "AccountSummary",
89
+ "AccountSummariesRequest",
90
+ "AccountSummariesResponse",
91
+ "HistoricalFillsRequest",
92
+ "HistoricalFillsResponse",
93
+ "HistoricalOrdersRequest",
94
+ "HistoricalOrdersResponse",
95
+ "Candle",
96
+ "HistoricalCandlesRequest",
97
+ "HistoricalCandlesResponse",
98
+ "L1BookSnapshot",
99
+ "L1BookSnapshotRequest",
100
+ "L1BookSnapshotsRequest",
101
+ "L2BookSnapshot",
102
+ "L2BookSnapshotRequest",
103
+ "L2BookUpdate",
104
+ "L2BookDiff",
105
+ "Liquidation",
106
+ "MarketStatus",
107
+ "MarketStatusRequest",
108
+ "SubscribeCandlesRequest",
109
+ "SubscribeCurrentCandlesRequest",
110
+ "SubscribeL1BookSnapshotsRequest",
111
+ "SubscribeL2BookUpdatesRequest",
112
+ "SubscribeLiquidationsRequest",
113
+ "SubscribeManyCandlesRequest",
114
+ "SubscribeTickersRequest",
115
+ "SubscribeTradesRequest",
116
+ "Ticker",
117
+ "TickerRequest",
118
+ "TickersRequest",
119
+ "TickersResponse",
120
+ "TickerUpdate",
121
+ "Trade",
122
+ "resolve_endpoint",
123
+ "SymbolsRequest",
124
+ "SymbolsResponse",
125
+ ]
@@ -0,0 +1,86 @@
1
+ from types import UnionType
2
+ from typing import AsyncIterator
3
+
4
+ import grpc
5
+ import msgspec
6
+
7
+ from . import *
8
+ from .utils import RequestType, ResponseTypeGeneric, decoders, encoder
9
+
10
+
11
+ class GrpcClient:
12
+ endpoint: str
13
+ channel: grpc.aio.Channel
14
+ jwt: str | None = None
15
+
16
+ def __init__(self, *, host: str, port: int, use_ssl: bool = False):
17
+ scheme = "https" if use_ssl else "http"
18
+ self.endpoint = f"{scheme}://{host}:{port}"
19
+ if use_ssl:
20
+ credentials = grpc.ssl_channel_credentials()
21
+ self.channel = grpc.aio.secure_channel(f"{host}:{port}", credentials)
22
+ else:
23
+ self.channel = grpc.aio.insecure_channel(f"{host}:{port}")
24
+
25
+ def set_jwt(self, jwt: str | None):
26
+ self.jwt = jwt
27
+
28
+ @staticmethod
29
+ def encoder() -> msgspec.json.Encoder:
30
+ return encoder
31
+
32
+ def get_decoder(
33
+ self, response_type: type[ResponseTypeGeneric] | UnionType
34
+ ) -> msgspec.json.Decoder:
35
+ try:
36
+ return decoders[response_type]
37
+ except KeyError:
38
+ decoder = msgspec.json.Decoder(type=response_type)
39
+ decoders[response_type] = decoder
40
+ return decoder
41
+
42
+ async def unary_unary(
43
+ self,
44
+ request: RequestType[ResponseTypeGeneric],
45
+ ) -> ResponseTypeGeneric:
46
+ """
47
+ Generic function for making a unary RPC call to the gRPC server.
48
+
49
+ NB: request_type and ResponseTypeGeneric *cannot* be union types
50
+ """
51
+ decoder: msgspec.json.Decoder[ResponseTypeGeneric] = self.get_decoder(
52
+ request.get_unannotated_response_type()
53
+ )
54
+ stub = self.channel.unary_unary(
55
+ request.get_route(),
56
+ request_serializer=encoder.encode,
57
+ response_deserializer=decoder.decode,
58
+ )
59
+ metadata = ()
60
+ if self.jwt is not None:
61
+ metadata = (("authorization", f"Bearer {self.jwt}"),)
62
+ return await stub(request, metadata=metadata)
63
+
64
+ async def unary_stream(
65
+ self,
66
+ request: RequestType[ResponseTypeGeneric],
67
+ ) -> AsyncIterator[ResponseTypeGeneric]:
68
+ """
69
+ Generic function for subscribing to a stream of updates from the gRPC server.
70
+
71
+ NB: request_type and ResponseTypeGeneric *cannot* be union types
72
+ """
73
+ decoder: msgspec.json.Decoder[ResponseTypeGeneric] = self.get_decoder(
74
+ request.get_unannotated_response_type()
75
+ )
76
+ stub = self.channel.unary_stream(
77
+ request.get_route(),
78
+ request_serializer=encoder.encode,
79
+ response_deserializer=decoder.decode,
80
+ )
81
+ metadata = ()
82
+ if self.jwt is not None:
83
+ metadata = (("authorization", f"Bearer {self.jwt}"),)
84
+ call = stub(request, metadata=metadata)
85
+ async for update in call:
86
+ yield update
@@ -2,7 +2,7 @@
2
2
  # filename: Accounts/AccountsRequest.json
3
3
 
4
4
  from __future__ import annotations
5
- from architect_py.grpc_client.Accounts.AccountsResponse import AccountsResponse
5
+ from architect_py.grpc.models.Accounts.AccountsResponse import AccountsResponse
6
6
 
7
7
  from typing import Annotated, Optional
8
8
 
@@ -24,7 +24,7 @@ class AccountsRequest(Struct, omit_defaults=True):
24
24
  Request accounts from the perspective of this trader; if not specified, defaults to the caller user.
25
25
  """
26
26
 
27
- # below is a constructor that takes all field titles as arguments for convenience
27
+ # Constructor that takes all field titles as arguments for convenience
28
28
  @classmethod
29
29
  def new(
30
30
  cls,