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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. architect_py/__init__.py +18 -2
  2. architect_py/async_client.py +1089 -658
  3. architect_py/client.py +36 -33
  4. architect_py/client_interface.py +63 -0
  5. architect_py/common_types/__init__.py +6 -0
  6. architect_py/common_types/order_dir.py +91 -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/__init__.py +2 -0
  10. architect_py/graphql_client/client.py +3 -6
  11. architect_py/graphql_client/enums.py +5 -0
  12. architect_py/graphql_client/fragments.py +3 -6
  13. architect_py/graphql_client/get_fills_query.py +2 -1
  14. architect_py/graphql_client/search_symbols_query.py +2 -1
  15. architect_py/graphql_client/subscribe_orderflow.py +2 -1
  16. architect_py/graphql_client/subscribe_trades.py +2 -1
  17. architect_py/grpc/__init__.py +145 -0
  18. architect_py/grpc/client.py +94 -0
  19. architect_py/{grpc_client → grpc/models}/Accounts/AccountsRequest.py +6 -3
  20. architect_py/{grpc_client → grpc/models}/Accounts/AccountsResponse.py +1 -1
  21. architect_py/{grpc_client → grpc/models}/Accounts/__init__.py +1 -1
  22. architect_py/grpc/models/Algo/AlgoOrder.py +114 -0
  23. architect_py/grpc/models/Algo/AlgoOrderRequest.py +46 -0
  24. architect_py/grpc/models/Algo/AlgoOrdersRequest.py +72 -0
  25. architect_py/grpc/models/Algo/AlgoOrdersResponse.py +27 -0
  26. architect_py/grpc/models/Algo/CreateAlgoOrderRequest.py +56 -0
  27. architect_py/grpc/models/Algo/PauseAlgoRequest.py +42 -0
  28. architect_py/grpc/models/Algo/PauseAlgoResponse.py +20 -0
  29. architect_py/grpc/models/Algo/StartAlgoRequest.py +42 -0
  30. architect_py/grpc/models/Algo/StartAlgoResponse.py +20 -0
  31. architect_py/grpc/models/Algo/StopAlgoRequest.py +42 -0
  32. architect_py/grpc/models/Algo/StopAlgoResponse.py +20 -0
  33. architect_py/{grpc_client → grpc/models}/Algo/__init__.py +1 -1
  34. architect_py/grpc/models/Auth/CreateJwtRequest.py +47 -0
  35. architect_py/grpc/models/Auth/CreateJwtResponse.py +23 -0
  36. architect_py/{grpc_client/Cpty → grpc/models/Auth}/__init__.py +1 -1
  37. architect_py/grpc/models/Boss/DepositsRequest.py +40 -0
  38. architect_py/grpc/models/Boss/DepositsResponse.py +27 -0
  39. architect_py/grpc/models/Boss/RqdAccountStatisticsRequest.py +42 -0
  40. architect_py/grpc/models/Boss/RqdAccountStatisticsResponse.py +25 -0
  41. architect_py/grpc/models/Boss/StatementUrlRequest.py +40 -0
  42. architect_py/grpc/models/Boss/StatementUrlResponse.py +23 -0
  43. architect_py/grpc/models/Boss/StatementsRequest.py +40 -0
  44. architect_py/grpc/models/Boss/StatementsResponse.py +27 -0
  45. architect_py/grpc/models/Boss/WithdrawalsRequest.py +40 -0
  46. architect_py/grpc/models/Boss/WithdrawalsResponse.py +27 -0
  47. architect_py/{grpc_client/Folio → grpc/models/Boss}/__init__.py +1 -1
  48. architect_py/grpc/models/Core/ConfigRequest.py +37 -0
  49. architect_py/grpc/models/Core/ConfigResponse.py +25 -0
  50. architect_py/grpc/models/Core/__init__.py +2 -0
  51. architect_py/{grpc_client → grpc/models}/Cpty/CptyRequest.py +5 -4
  52. architect_py/{grpc_client → grpc/models}/Cpty/CptyResponse.py +6 -6
  53. architect_py/grpc/models/Cpty/CptyStatus.py +48 -0
  54. architect_py/grpc/models/Cpty/CptyStatusRequest.py +45 -0
  55. architect_py/grpc/models/Cpty/CptysRequest.py +37 -0
  56. architect_py/grpc/models/Cpty/CptysResponse.py +27 -0
  57. architect_py/grpc/models/Cpty/__init__.py +2 -0
  58. architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryRequest.py +2 -2
  59. architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryResponse.py +1 -1
  60. architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesRequest.py +2 -2
  61. architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesResponse.py +1 -1
  62. architect_py/{grpc_client → grpc/models}/Folio/AccountSummary.py +1 -1
  63. architect_py/{grpc_client → grpc/models}/Folio/AccountSummaryRequest.py +2 -2
  64. architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsRequest.py +7 -4
  65. architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsResponse.py +1 -1
  66. architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersRequest.py +3 -3
  67. architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersResponse.py +1 -1
  68. architect_py/grpc/models/Folio/__init__.py +2 -0
  69. architect_py/{grpc_client → grpc/models}/Health/HealthCheckRequest.py +2 -2
  70. architect_py/{grpc_client → grpc/models}/Health/HealthCheckResponse.py +1 -1
  71. architect_py/grpc/models/Health/__init__.py +2 -0
  72. architect_py/{grpc_client → grpc/models}/Marketdata/Candle.py +1 -1
  73. architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesRequest.py +11 -8
  74. architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesResponse.py +1 -1
  75. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshot.py +52 -5
  76. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotRequest.py +8 -3
  77. architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotsRequest.py +6 -3
  78. architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshot.py +1 -1
  79. architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshotRequest.py +2 -2
  80. architect_py/{grpc_client → grpc/models}/Marketdata/Liquidation.py +2 -2
  81. architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatus.py +1 -1
  82. architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatusRequest.py +2 -2
  83. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCandlesRequest.py +2 -2
  84. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCurrentCandlesRequest.py +3 -4
  85. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL1BookSnapshotsRequest.py +6 -3
  86. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL2BookUpdatesRequest.py +2 -2
  87. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeLiquidationsRequest.py +2 -2
  88. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeManyCandlesRequest.py +2 -2
  89. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTickersRequest.py +2 -2
  90. architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTradesRequest.py +2 -2
  91. architect_py/{grpc_client → grpc/models}/Marketdata/Ticker.py +14 -3
  92. architect_py/{grpc_client → grpc/models}/Marketdata/TickerRequest.py +2 -2
  93. architect_py/{grpc_client → grpc/models}/Marketdata/TickersRequest.py +2 -2
  94. architect_py/{grpc_client → grpc/models}/Marketdata/TickersResponse.py +1 -1
  95. architect_py/{grpc_client → grpc/models}/Marketdata/Trade.py +2 -2
  96. architect_py/grpc/models/Marketdata/__init__.py +2 -0
  97. architect_py/grpc/models/Oms/Cancel.py +90 -0
  98. architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersRequest.py +2 -2
  99. architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersResponse.py +1 -1
  100. architect_py/{grpc_client → grpc/models}/Oms/CancelOrderRequest.py +2 -2
  101. architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersRequest.py +2 -2
  102. architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersResponse.py +1 -1
  103. architect_py/{grpc_client → grpc/models}/Oms/Order.py +6 -13
  104. architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsRequest.py +2 -2
  105. architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsResponse.py +1 -1
  106. architect_py/{grpc_client → grpc/models}/Oms/PlaceOrderRequest.py +16 -23
  107. architect_py/grpc/models/Oms/__init__.py +2 -0
  108. architect_py/grpc/models/OptionsMarketdata/OptionsChain.py +30 -0
  109. architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeks.py +30 -0
  110. architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeksRequest.py +47 -0
  111. architect_py/grpc/models/OptionsMarketdata/OptionsChainRequest.py +45 -0
  112. architect_py/grpc/models/OptionsMarketdata/OptionsExpirations.py +29 -0
  113. architect_py/grpc/models/OptionsMarketdata/OptionsExpirationsRequest.py +42 -0
  114. architect_py/grpc/models/OptionsMarketdata/__init__.py +2 -0
  115. architect_py/{grpc_client → grpc/models}/Orderflow/DropcopyRequest.py +2 -2
  116. architect_py/{grpc_client → grpc/models}/Orderflow/OrderflowRequest.py +2 -1
  117. architect_py/{grpc_client → grpc/models}/Orderflow/SubscribeOrderflowRequest.py +2 -2
  118. architect_py/grpc/models/Orderflow/__init__.py +2 -0
  119. architect_py/grpc/models/Symbology/DownloadProductCatalogRequest.py +42 -0
  120. architect_py/grpc/models/Symbology/DownloadProductCatalogResponse.py +27 -0
  121. architect_py/grpc/models/Symbology/ExecutionInfoRequest.py +47 -0
  122. architect_py/grpc/models/Symbology/ExecutionInfoResponse.py +27 -0
  123. architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsRequest.py +2 -2
  124. architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsResponse.py +1 -1
  125. architect_py/{grpc_client → grpc/models}/Symbology/SubscribeSymbology.py +1 -1
  126. architect_py/{grpc_client → grpc/models}/Symbology/SymbologyRequest.py +2 -2
  127. architect_py/{grpc_client → grpc/models}/Symbology/SymbologySnapshot.py +7 -2
  128. architect_py/{grpc_client → grpc/models}/Symbology/SymbologyUpdate.py +9 -2
  129. architect_py/{grpc_client → grpc/models}/Symbology/SymbolsRequest.py +2 -2
  130. architect_py/{grpc_client → grpc/models}/Symbology/SymbolsResponse.py +1 -1
  131. architect_py/grpc/models/Symbology/UploadProductCatalogRequest.py +49 -0
  132. architect_py/grpc/models/Symbology/UploadProductCatalogResponse.py +20 -0
  133. architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyRequest.py +2 -2
  134. architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyResponse.py +1 -1
  135. architect_py/grpc/models/Symbology/__init__.py +2 -0
  136. architect_py/grpc/models/__init__.py +2 -0
  137. architect_py/{grpc_client → grpc/models}/definitions.py +671 -934
  138. architect_py/grpc/resolve_endpoint.py +70 -0
  139. architect_py/{grpc_client/grpc_server.py → grpc/server.py} +13 -9
  140. architect_py/grpc/utils.py +32 -0
  141. architect_py/internal_utils/__init__.py +0 -0
  142. architect_py/internal_utils/no_pandas.py +3 -0
  143. architect_py/tests/conftest.py +91 -85
  144. architect_py/tests/test_book_building.py +49 -50
  145. architect_py/tests/test_marketdata.py +168 -0
  146. architect_py/tests/test_order_entry.py +37 -0
  147. architect_py/tests/test_orderflow.py +41 -0
  148. architect_py/tests/test_portfolio_management.py +23 -0
  149. architect_py/tests/test_rounding.py +28 -28
  150. architect_py/tests/test_symbology.py +37 -30
  151. architect_py/utils/nearest_tick.py +2 -5
  152. architect_py/utils/nearest_tick_2.py +1 -2
  153. architect_py/utils/orderbook.py +35 -0
  154. architect_py/utils/pandas.py +44 -0
  155. architect_py/utils/price_bands.py +0 -3
  156. architect_py/utils/symbol_parsing.py +29 -0
  157. architect_py-5.0.0.dist-info/METADATA +54 -0
  158. architect_py-5.0.0.dist-info/RECORD +214 -0
  159. {architect_py-3.2.1.dist-info → architect_py-5.0.0.dist-info}/WHEEL +2 -1
  160. architect_py-5.0.0.dist-info/top_level.txt +4 -0
  161. examples/__init__.py +0 -0
  162. examples/book_subscription.py +52 -0
  163. examples/candles.py +30 -0
  164. examples/common.py +116 -0
  165. examples/external_cpty.py +77 -0
  166. examples/funding_rate_mean_reversion_algo.py +186 -0
  167. examples/order_sending.py +91 -0
  168. examples/stream_l1_marketdata.py +25 -0
  169. examples/stream_l2_marketdata.py +38 -0
  170. examples/trades.py +21 -0
  171. examples/tutorial_async.py +86 -0
  172. examples/tutorial_sync.py +95 -0
  173. scripts/generate_functions_md.py +166 -0
  174. scripts/generate_sync_interface.py +226 -0
  175. scripts/postprocess_grpc.py +604 -0
  176. scripts/preprocess_grpc_schema.py +708 -0
  177. templates/exceptions.py +83 -0
  178. templates/juniper_base_client.py +371 -0
  179. architect_py/client_protocol.py +0 -52
  180. architect_py/grpc_client/Algo/AlgoOrderForTwapAlgo.py +0 -61
  181. architect_py/grpc_client/Algo/CreateAlgoOrderRequestForTwapAlgo.py +0 -59
  182. architect_py/grpc_client/Algo/ModifyAlgoOrderRequestForTwapAlgo.py +0 -45
  183. architect_py/grpc_client/Folio/AggregatedAccountSummariesRequest.py +0 -59
  184. architect_py/grpc_client/Folio/AggregatedAccountSummariesResponse.py +0 -27
  185. architect_py/grpc_client/Health/__init__.py +0 -2
  186. architect_py/grpc_client/Marketdata/__init__.py +0 -2
  187. architect_py/grpc_client/Oms/Cancel.py +0 -42
  188. architect_py/grpc_client/Oms/__init__.py +0 -2
  189. architect_py/grpc_client/Orderflow/__init__.py +0 -2
  190. architect_py/grpc_client/Symbology/__init__.py +0 -2
  191. architect_py/grpc_client/__init__.py +0 -2
  192. architect_py/grpc_client/grpc_client.py +0 -405
  193. architect_py/scalars.py +0 -172
  194. architect_py/tests/test_accounts.py +0 -31
  195. architect_py/tests/test_client.py +0 -29
  196. architect_py/tests/test_grpc_client.py +0 -30
  197. architect_py/tests/test_order_sending.py +0 -61
  198. architect_py/tests/test_snapshots.py +0 -52
  199. architect_py/tests/test_subscriptions.py +0 -129
  200. architect_py-3.2.1.dist-info/METADATA +0 -212
  201. architect_py-3.2.1.dist-info/RECORD +0 -146
  202. /architect_py/{grpc_client → grpc/models}/Marketdata/ArrayOfL1BookSnapshot.py +0 -0
  203. /architect_py/{grpc_client → grpc/models}/Marketdata/L2BookUpdate.py +0 -0
  204. /architect_py/{grpc_client → grpc/models}/Marketdata/TickerUpdate.py +0 -0
  205. /architect_py/{grpc_client → grpc/models}/Orderflow/Dropcopy.py +0 -0
  206. /architect_py/{grpc_client → grpc/models}/Orderflow/Orderflow.py +0 -0
  207. {architect_py-3.2.1.dist-info → architect_py-5.0.0.dist-info/licenses}/LICENSE +0 -0
architect_py/scalars.py DELETED
@@ -1,172 +0,0 @@
1
- from enum import Enum
2
- from typing import Literal, Optional
3
-
4
- from datetime import datetime, timezone
5
-
6
-
7
- from typing import TYPE_CHECKING
8
-
9
- if TYPE_CHECKING:
10
- from architect_py.graphql_client.base_model import UnsetType
11
-
12
-
13
- """
14
- Custom Serialize / Deserializing functions for the scalars
15
- """
16
-
17
-
18
- def serialize(value) -> str:
19
- return value.serialize()
20
-
21
-
22
- class TradableProduct(str):
23
- """
24
- Example instantiations:
25
- TradableProduct("ES 20250321 CME Future", "USD")
26
- TradableProduct("ES 20250321 CME Future/USD")
27
- (these are equivalent)
28
-
29
- This type exists to enforce the
30
- {base}/{quote} format for strings
31
-
32
- A base is the product that is being priced in terms of the quote.
33
- For example,
34
- "ES 20250321 CME Future/USD" means that the ES 20250321 CME Future is priced in USD.
35
- "ES 20250321 CME Future/EUR" means that the ES 20250321 CME Future is priced in EUR.
36
- "ES 20250321 CME Future/BTC" means that the ES 20250321 CME Future is priced in BTC
37
- (such a product does not exist on any exchange though).
38
-
39
- For example in a currency pair, the base is the first currency and the quote is the second currency.
40
- In the currency pair USD/EUR, USD is the base and EUR is the quote.
41
- USD/EUR = 1.1234 means that 1 USD = 1.1234 EUR
42
- EUR/USD = 0.8901 means that 1 EUR = 0.8901 USD
43
- """
44
-
45
- def __new__(
46
- cls, base_or_value: str, quote: Optional[str] = None
47
- ) -> "TradableProduct":
48
- """
49
- These are equivalent:
50
- TradableProduct("ES 20250321 CME Future", "USD")
51
- TradableProduct("ES 20250321 CME Future/USD")
52
- """
53
- if quote is None:
54
- value = base_or_value
55
- else:
56
- value = f"{base_or_value}/{quote}"
57
-
58
- assert (
59
- "/" in value
60
- ), f"TradableProduct must be in the form of 'base/quote'. Got: {base_or_value}"
61
- return super().__new__(cls, value)
62
-
63
- def base_quote(self) -> list[str]:
64
- return self.split("/")
65
-
66
- def base(self) -> str:
67
- return self.split("/", 1)[0]
68
-
69
- def quote(self) -> str:
70
- return self.split("/", 1)[1]
71
-
72
-
73
- def parse_tradable_product(value: str) -> TradableProduct:
74
- # for ariadne
75
- return TradableProduct(value)
76
-
77
-
78
- class OrderDir(str, Enum):
79
- BUY = "BUY"
80
- SELL = "SELL"
81
-
82
- def __int__(self):
83
- if self == OrderDir.BUY:
84
- return 1
85
- elif self == OrderDir.SELL:
86
- return -1
87
- else:
88
- raise ValueError(f"Unknown Dir: {self}")
89
-
90
- def get_opposite(self) -> "OrderDir":
91
- """
92
- NOTE: ENUMS ARE IMMUTABLE SO THIS DOES NOT MUTATE THE STATE OF THE ENUM
93
- """
94
- if self == OrderDir.BUY:
95
- return OrderDir.SELL
96
- elif self == OrderDir.SELL:
97
- return OrderDir.BUY
98
- else:
99
- raise ValueError(f"Unknown Dir: {self}")
100
-
101
- def __str__(self) -> str:
102
- return self.value
103
-
104
- def lower(self) -> str:
105
- return self.value.lower()
106
-
107
- @classmethod
108
- def from_string(cls, value: str) -> "OrderDir":
109
- lower = value.lower()
110
- if lower == "buy":
111
- return cls.BUY
112
- elif lower == "sell":
113
- return cls.SELL
114
- elif lower == "bid":
115
- return cls.BUY
116
- elif lower == "ask":
117
- return cls.SELL
118
- elif lower == "b":
119
- return cls.BUY
120
- elif lower == "a" or lower == "s":
121
- return cls.SELL
122
- else:
123
- raise ValueError(f"Unknown Dir: {value}")
124
-
125
- @classmethod
126
- def from_unit(cls, value: Literal[1, -1]) -> "OrderDir":
127
- if value == 1:
128
- return cls.BUY
129
- elif value == -1:
130
- return cls.SELL
131
- else:
132
- raise ValueError(f"Unknown Dir: {value}")
133
-
134
- @classmethod
135
- def from_sign(cls, value: int) -> "OrderDir":
136
- if value > 0:
137
- return cls.BUY
138
- elif value < 0:
139
- return cls.SELL
140
- else:
141
- raise ValueError(f"Unknown Dir: {value}")
142
-
143
-
144
- def graphql_serialize_order_dir(value: OrderDir) -> str:
145
- return value.lower()
146
-
147
-
148
- def graphql_parse_order_dir(value: str) -> OrderDir:
149
- if value == "buy":
150
- return OrderDir.BUY
151
- else:
152
- return OrderDir.SELL
153
-
154
-
155
- def convert_datetime_to_utc_str(dt: "Optional[datetime] | UnsetType") -> Optional[str]:
156
- if not isinstance(dt, datetime):
157
- return None
158
-
159
- if dt.tzinfo is None:
160
- raise ValueError(
161
- "in a datetime sent to the backend, the good_til_date must be timezone-aware. Try \n"
162
- "from zoneinfo import ZoneInfo\n"
163
- "datetime(..., tzinfo={your_local_timezone}) or "
164
- "datetime.now(tz=ZoneInfo('UTC'))\n"
165
- "# examples of local timezones:\n"
166
- "ZoneInfo('America/New_York'), "
167
- "ZoneInfo('America/Los_Angeles'), ZoneInfo('America/Chicago')"
168
- )
169
- utc_str = dt.astimezone(timezone.utc).isoformat()[:-6]
170
- # [:-6] removes the utc offset
171
-
172
- return f"{utc_str}Z"
@@ -1,31 +0,0 @@
1
- from decimal import Decimal
2
- import pytest
3
-
4
- from architect_py.async_client import AsyncClient
5
-
6
- from collections import defaultdict
7
-
8
-
9
- @pytest.mark.asyncio
10
- async def test_account(async_client: AsyncClient):
11
- return
12
-
13
- accounts = await async_client.list_accounts()
14
- assert accounts is not None
15
- assert len(accounts) > 0
16
-
17
- unaggregated_summary = await async_client.get_account_summary(
18
- account=accounts[0].account.id
19
- )
20
-
21
- symbol_to_position = defaultdict(Decimal)
22
- for symbol, positions in unaggregated_summary.positions.items():
23
- for position in positions:
24
- symbol_to_position[symbol] += position.quantity
25
-
26
- aggregated_summary = await async_client.get_account_summary(
27
- account=accounts[0].account.id
28
- )
29
-
30
- assert unaggregated_summary is not None
31
- assert aggregated_summary is not None
@@ -1,29 +0,0 @@
1
- import pytest
2
- from architect_py.async_client import AsyncClient
3
- from architect_py.client import Client
4
-
5
-
6
- @pytest.mark.asyncio
7
- async def test_client_init():
8
- with pytest.raises(ValueError):
9
- client = AsyncClient(host="localhost", port=4567, api_key=" ", api_secret=" ")
10
- with pytest.raises(ValueError):
11
- client = AsyncClient(
12
- host="localhost", port=4567, api_key="something", api_secret='"alskjdf"'
13
- )
14
-
15
-
16
- @pytest.mark.asyncio
17
- async def test_client_jwt(async_client: AsyncClient):
18
- jwt = await async_client.graphql_client.create_jwt()
19
- assert jwt is not None, "jwt should not be None"
20
-
21
-
22
- def test_sync_client(sync_client: Client):
23
- sync_result = sync_client.search_symbols(execution_venue="CME", search_string="ES")
24
- assert len(sync_result) > 5
25
-
26
- ES_future = sync_result[0]
27
-
28
- sync_result = sync_client.search_symbols(ES_future)
29
- assert sync_result is not None
@@ -1,30 +0,0 @@
1
- import pytest
2
-
3
- from architect_py.async_client import AsyncClient
4
- from architect_py.scalars import TradableProduct
5
-
6
-
7
- @pytest.mark.asyncio
8
- async def test_grpc(async_client: AsyncClient, front_ES_future: str):
9
-
10
- endpoint = "binance.marketdata.architect.co"
11
- endpoint = "bybit.marketdata.architect.co"
12
- endpoint = "binance-futures-usd-m.marketdata.architect.co"
13
- endpoint = "cme.marketdata.architect.co"
14
-
15
- tp = TradableProduct(front_ES_future, "USD")
16
- snapshot = await async_client.grpc_client.request_l2_book_snapshot("CME", tp)
17
- assert snapshot is not None
18
-
19
- snapshot = await async_client.grpc_client.request_l1_book_snapshot(tp)
20
- assert snapshot is not None
21
-
22
- i = 0
23
- async for update in await async_client.grpc_client.subscribe_l1_books_stream(
24
- [front_ES_future]
25
- ):
26
- assert update is not None
27
- if i == 100:
28
- break
29
- i += 1
30
- return True
@@ -1,61 +0,0 @@
1
- from decimal import Decimal
2
-
3
- import pytest
4
-
5
- from architect_py.async_client import AsyncClient, OrderDir
6
- from architect_py.scalars import TradableProduct
7
- from architect_py.utils.nearest_tick_2 import TickRoundMethod
8
-
9
-
10
- @pytest.mark.asyncio
11
- @pytest.mark.timeout(3)
12
- async def test_live_far_order_cancel(async_client: AsyncClient, front_ES_future: str):
13
- """
14
- Places a bid order far below best bid, waits for placement, then should successfully cancel order
15
- """
16
- venue = "CME"
17
- tp = TradableProduct(front_ES_future, "USD")
18
-
19
- # Get snapshot
20
- execution_info = await async_client.get_execution_info(tp, venue)
21
- assert (
22
- execution_info is not None
23
- ), f"execution_info does not exist for {tp}, {venue}"
24
-
25
- assert execution_info.min_order_quantity is not None
26
- assert execution_info.tick_size is not None
27
-
28
- snapshot = await async_client.get_market_snapshot(tp, venue)
29
- assert snapshot is not None, f"Snapshot does not exist for {tp} at venue {venue}"
30
-
31
- min_qty = Decimal(execution_info.min_order_quantity)
32
-
33
- if bid_price := snapshot.bid_price:
34
- far_price = bid_price * Decimal("0.8")
35
- else:
36
- raise ValueError(f"No bid price in snapshot for {tp} at venue {venue}")
37
- limit_price = TickRoundMethod.FLOOR(far_price, execution_info.tick_size)
38
-
39
- accounts = await async_client.list_accounts()
40
-
41
- account = accounts[0]
42
- print(account)
43
-
44
- # Make a very cheap bid
45
- order = await async_client.send_limit_order(
46
- symbol=tp,
47
- odir=OrderDir.BUY,
48
- execution_venue=venue,
49
- quantity=min_qty,
50
- limit_price=limit_price,
51
- account=str(account.account.id),
52
- )
53
-
54
- assert order is not None
55
-
56
- order_query = await async_client.get_order(order.id)
57
- if order_query is None:
58
- raise ValueError("Order is None")
59
- else:
60
- cancel = await async_client.cancel_order(order.id)
61
- assert cancel
@@ -1,52 +0,0 @@
1
- import pytest
2
-
3
- from architect_py.async_client import AsyncClient
4
- from architect_py.scalars import TradableProduct
5
-
6
- from pytest_lazy_fixtures import lf
7
-
8
-
9
- @pytest.mark.asyncio
10
- @pytest.mark.parametrize(
11
- "symbol,venue",
12
- [
13
- (lf("front_ES_future"), "CME"),
14
- # (
15
- # "BTC-USDT BINANCE Perpetual/USDT Crypto*BINANCE-FUTURES-USD-M/DIRECT",
16
- # "BINANCE",
17
- # ),
18
- # (
19
- # "BTC-USDT BYBIT Perpetual/USDT Crypto*BYBIT/DIRECT",
20
- # "BYBIT",
21
- # ),
22
- ],
23
- )
24
- async def test_l2_snapshot(async_client: AsyncClient, symbol: str, venue: str):
25
- tp = TradableProduct(symbol, "USD")
26
-
27
- market_status = await async_client.get_market_status(tp, venue)
28
- if not market_status.is_trading:
29
- pytest.skip("market is not trading")
30
-
31
- snap = await async_client.get_l2_book_snapshot(
32
- tp,
33
- venue,
34
- )
35
- assert snap is not None, "snapshot should not be None"
36
-
37
-
38
- @pytest.mark.asyncio
39
- @pytest.mark.timeout(3)
40
- async def test_marketdata_snapshots(async_client: AsyncClient, front_ES_future: str):
41
- venue = "CME"
42
-
43
- market = TradableProduct(front_ES_future, "USD")
44
- market_status = await async_client.get_market_status(market, venue)
45
-
46
- if not market_status.is_trading:
47
- pytest.skip("market is not trading")
48
-
49
- snap = await async_client.get_market_snapshot(
50
- symbol=TradableProduct(market), venue="CME"
51
- )
52
- assert snap is not None, "snapshot should not be None"
@@ -1,129 +0,0 @@
1
- import asyncio
2
- from datetime import datetime
3
- import pytest
4
- from architect_py.async_client import AsyncClient
5
- from architect_py.scalars import TradableProduct
6
-
7
- from zoneinfo import ZoneInfo
8
-
9
- from pytest_lazy_fixtures import lf
10
-
11
-
12
- @pytest.mark.asyncio
13
- @pytest.mark.timeout(10)
14
- @pytest.mark.parametrize(
15
- "endpoint,symbol,venue",
16
- [
17
- ("cme.marketdata.architect.co", lf("front_ES_future_tp"), "CME"),
18
- # (
19
- # "https://usdm.binance.marketdata.architect.co",
20
- # "BTC-USDT BINANCE Perpetual/USDT Crypto",
21
- # "BINANCE",
22
- # ),
23
- # (
24
- # "https://bybit.marketdata.architect.co",
25
- # "BTC-USDT BYBIT Perpetual/USDT Crypto",
26
- # "BYBIT",
27
- # ),
28
- ],
29
- )
30
- @pytest.mark.asyncio
31
- async def test_subscribe_l1_stream(
32
- async_client: AsyncClient,
33
- endpoint: str,
34
- symbol: str,
35
- venue: str,
36
- ):
37
- tp = TradableProduct(symbol)
38
-
39
- await async_client.grpc_client.change_channel(endpoint)
40
-
41
- market_status = await async_client.get_market_status(tp, venue)
42
- if not market_status.is_trading:
43
- pytest.skip("market is not trading")
44
-
45
- symbols = [tp]
46
-
47
- [l1_book] = await async_client.subscribe_l1_book(symbols)
48
-
49
- i = 0
50
- async for snap in async_client.subscribe_l1_book_stream(symbols, venue):
51
- assert snap.best_bid is not None, f"{symbol} should always be bid"
52
- assert snap.best_ask is not None, f"{symbol} should always be offered"
53
- assert snap.best_bid[0] > 1_000, f"{symbol} should be > $1000"
54
- assert snap.best_ask[0] < 10_000_000, f"{symbol} should be < $10000000"
55
- i += 1
56
- if i > 5:
57
- break
58
-
59
- if l1_book.timestamp == 0:
60
- raise ValueError(f"Timestamp should be increasing {l1_book}")
61
-
62
-
63
- @pytest.mark.asyncio
64
- @pytest.mark.timeout(10)
65
- @pytest.mark.parametrize(
66
- "endpoint,symbol,venue",
67
- [
68
- ("cme.marketdata.architect.co", lf("front_ES_future_tp"), "CME"),
69
- # (
70
- # "https://usdm.binance.marketdata.architect.co",
71
- # "BTC-USDT BINANCE Perpetual/USDT Crypto",
72
- # "BINANCE",
73
- # ),
74
- # (
75
- # "https://bybit.marketdata.architect.co",
76
- # "BTC-USDT BYBIT Perpetual/USDT Crypto",
77
- # "BYBIT",
78
- # ),
79
- ],
80
- )
81
- @pytest.mark.asyncio
82
- @pytest.mark.timeout(10)
83
- async def test_subscribe_l2_stream(
84
- async_client: AsyncClient, endpoint: str, symbol: str, venue: str
85
- ):
86
- tp = TradableProduct(symbol)
87
-
88
- market_status = await async_client.get_market_status(tp, venue)
89
- if not market_status.is_trading:
90
- pytest.skip("market is not trading")
91
-
92
- l2_book = await async_client.subscribe_l2_book(tp, venue)
93
- ts = l2_book.timestamp
94
-
95
- i = 0
96
- async for snap in async_client.grpc_client.subscribe_l2_books_stream(
97
- symbol=tp, venue=venue
98
- ):
99
- assert snap is not None
100
- if i > 5:
101
- break
102
- i += 1
103
- await asyncio.sleep(1)
104
-
105
- if ts >= l2_book.timestamp:
106
- raise ValueError(f"Timestamp should be increasing {l2_book}")
107
-
108
-
109
- @pytest.mark.asyncio
110
- @pytest.mark.timeout(15)
111
- async def test_subscribe_cme_trades(async_client: AsyncClient):
112
- venue = "CME"
113
- markets = await async_client.get_cme_futures_series("ES CME Futures")
114
- _, market = markets[0]
115
-
116
- market = TradableProduct(market, "USD")
117
- market_status = await async_client.get_market_status(market, venue)
118
-
119
- if not market_status.is_trading:
120
- pytest.skip("market is not trading")
121
- elif not 9 <= datetime.now(ZoneInfo("America/Chicago")).hour < 17:
122
- pytest.skip("market is not liquid")
123
-
124
- i = 0
125
- async for trade in async_client.subscribe_trades_stream(market, venue):
126
- assert trade is not None, "trade from stream was None"
127
- if i > 3:
128
- break
129
- i += 1