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
@@ -0,0 +1,186 @@
1
+ """
2
+ Do *NOT* run this script in production. This script is for educational purposes only.
3
+ """
4
+
5
+ import asyncio
6
+ from decimal import Decimal
7
+ from typing import AsyncIterator, Optional
8
+
9
+ from architect_py.async_client import AsyncClient
10
+ from architect_py.common_types.order_dir import OrderDir
11
+ from architect_py.common_types.tradable_product import TradableProduct
12
+ from architect_py.graphql_client.exceptions import GraphQLClientHttpError
13
+ from architect_py.grpc.models.definitions import OrderType, TimeInForceEnum
14
+ from architect_py.grpc.models.Orderflow.Orderflow import (
15
+ TaggedOrderAck,
16
+ TaggedOrderOut,
17
+ TaggedOrderReject,
18
+ )
19
+ from architect_py.grpc.models.Orderflow.OrderflowRequest import (
20
+ OrderflowRequest,
21
+ PlaceOrder,
22
+ )
23
+
24
+ from .common import connect_async_client
25
+
26
+ venue = "BINANCE"
27
+ product = "BTC-USDT Perpetual"
28
+ tradable_product = TradableProduct(product, "USDT Crypto")
29
+ best_bid_price: Optional[Decimal] = None
30
+ best_ask_price: Optional[Decimal] = None
31
+ current_funding_rate: Optional[Decimal] = None # as fraction, e.g. 0.0001 = 1 bp
32
+ target_position = 0
33
+ current_position = 0
34
+
35
+
36
+ class OrderflowRequester:
37
+ def __init__(self):
38
+ self.queue: asyncio.Queue[OrderflowRequest] = asyncio.Queue()
39
+
40
+ async def __aiter__(self) -> AsyncIterator[OrderflowRequest]:
41
+ while True:
42
+ value = await self.queue.get() # Wait for a value
43
+ yield value # Yield it when available
44
+
45
+ async def __anext__(self) -> OrderflowRequest:
46
+ return await self.queue.get()
47
+
48
+ async def put(self, value: OrderflowRequest) -> None:
49
+ # OrderflowRequest contains: PlaceOrder, CancelOrder, CancelAllOrders
50
+ await self.queue.put(value) # Put value into the queue
51
+
52
+
53
+ async def update_marketdata(c: AsyncClient):
54
+ while True:
55
+ ticker = await c.get_ticker(tradable_product, venue)
56
+ if ticker.funding_rate:
57
+ global current_funding_rate
58
+ global target_position
59
+ current_funding_rate = ticker.funding_rate
60
+ # set target_position based on funding rate
61
+ if current_funding_rate >= 0.1:
62
+ target_position = -10
63
+ elif current_funding_rate >= 0.05:
64
+ target_position = -5
65
+ elif current_funding_rate >= 0.0001:
66
+ target_position = 1
67
+ elif current_funding_rate >= -0.05:
68
+ target_position = 5
69
+ else:
70
+ target_position = 10
71
+ if ticker.bid_price:
72
+ global best_bid_price
73
+ best_bid_price = ticker.bid_price
74
+ if ticker.ask_price:
75
+ global best_ask_price
76
+ best_ask_price = ticker.ask_price
77
+ await asyncio.sleep(1)
78
+
79
+
80
+ async def subscribe_and_print_orderflow(
81
+ c: AsyncClient, orderflow_requester: OrderflowRequester
82
+ ):
83
+ try:
84
+ stream = c.orderflow(orderflow_requester)
85
+ """
86
+ subscribe_orderflow_stream is a duplex_stream meaning that it is a stream that can be read from and written to.
87
+ This is a stream that will be used to send orders to the Architect and receive order updates from the Architect.
88
+ """
89
+ async for orderflow in stream:
90
+ if isinstance(orderflow, TaggedOrderAck):
91
+ print(f"<!> ACK {orderflow.order_id}")
92
+ if isinstance(orderflow, TaggedOrderReject):
93
+ print(f"<!> REJECT {orderflow.id} {orderflow.r}: {orderflow.rm}")
94
+ # reject reason, reject message
95
+ elif isinstance(orderflow, TaggedOrderOut):
96
+ print(f"<!> OUT {orderflow.id}")
97
+ except GraphQLClientHttpError as e:
98
+ print(e.status_code)
99
+ print(e.response.json())
100
+
101
+
102
+ async def step_to_target_position(
103
+ c: AsyncClient, orderflow_requester: OrderflowRequester
104
+ ):
105
+ while True:
106
+ await asyncio.sleep(10)
107
+ # check open orders
108
+ open_orders = await c.get_open_orders()
109
+ n = len(open_orders)
110
+ if n > 0:
111
+ print("there are {n} open orders, skipping step")
112
+ continue
113
+
114
+ order = None
115
+ # send orders to step to target position
116
+ if current_position < target_position:
117
+ if best_ask_price is not None:
118
+ # buy 1 contract
119
+
120
+ # make sure to import the correct PlaceOrder from architect_py.grpc_client.Orderflow.OrderflowRequest
121
+ order = PlaceOrder.new(
122
+ symbol=tradable_product,
123
+ dir=OrderDir.BUY,
124
+ quantity=Decimal(1),
125
+ execution_venue=None,
126
+ limit_price=best_ask_price,
127
+ time_in_force=TimeInForceEnum.DAY,
128
+ order_type=OrderType.LIMIT,
129
+ )
130
+
131
+ elif current_position > target_position:
132
+ if best_bid_price is not None:
133
+ # sell 1 contract
134
+
135
+ # make sure to import the correct PlaceOrder from architect_py.grpc_client.Orderflow.OrderflowRequest
136
+ order = PlaceOrder.new(
137
+ symbol=tradable_product,
138
+ dir=OrderDir.SELL,
139
+ quantity=Decimal(1),
140
+ execution_venue=None,
141
+ limit_price=best_bid_price,
142
+ time_in_force=TimeInForceEnum.DAY,
143
+ order_type=OrderType.LIMIT,
144
+ )
145
+
146
+ if order is not None:
147
+ await orderflow_requester.put(
148
+ order
149
+ ) # this will add the order to the queue to send over
150
+
151
+
152
+ async def print_info(c: AsyncClient):
153
+ accounts = await c.list_accounts()
154
+ while True:
155
+ await asyncio.sleep(3)
156
+ account_summaries = await c.get_account_summaries(
157
+ accounts=[account.account.name for account in accounts]
158
+ )
159
+ pos = Decimal(0)
160
+ for account in account_summaries:
161
+ for name, balance in account.balances.items():
162
+ print(f"balance for {name}: {balance}")
163
+ pos += balance
164
+ global current_position
165
+ current_position = pos
166
+ print("---")
167
+ print(f"info : funding_rate: {current_funding_rate}")
168
+ print(f"info : bbo: {best_bid_price} {best_ask_price}")
169
+ print(f"info : current_position: {current_position}")
170
+ print(f"info : target_position: {target_position}")
171
+
172
+
173
+ async def main():
174
+ c = await connect_async_client()
175
+
176
+ orderflow_requester = OrderflowRequester()
177
+
178
+ await asyncio.gather(
179
+ update_marketdata(c),
180
+ step_to_target_position(c, orderflow_requester),
181
+ print_info(c),
182
+ subscribe_and_print_orderflow(c, orderflow_requester),
183
+ )
184
+
185
+
186
+ asyncio.run(main())
@@ -0,0 +1,91 @@
1
+ import asyncio
2
+ import logging
3
+ from datetime import datetime, timedelta, timezone
4
+ from decimal import Decimal
5
+
6
+ from architect_py.async_client import AsyncClient
7
+ from architect_py.common_types.order_dir import OrderDir
8
+ from architect_py.common_types.tradable_product import TradableProduct
9
+ from architect_py.grpc.models.definitions import GoodTilDate, OrderType, TimeInForceEnum
10
+ from examples.common import connect_async_client
11
+
12
+ LOGGER = logging.getLogger(__name__)
13
+
14
+
15
+ async def search_symbol(c: AsyncClient) -> tuple[str, TradableProduct]:
16
+ venue = "CME"
17
+ markets = await c.search_symbols(
18
+ search_string="ES",
19
+ execution_venue=venue,
20
+ )
21
+ market = markets[0]
22
+ return venue, market
23
+
24
+
25
+ async def test_send_order(client: AsyncClient, account: str):
26
+ venue, symbol = await search_symbol(client)
27
+
28
+ snapshot = await client.get_market_snapshot(symbol=symbol, venue=venue)
29
+ if snapshot is None:
30
+ return ValueError(f"Market snapshot for {symbol} is None")
31
+
32
+ if snapshot.best_ask is None or snapshot.best_bid is None:
33
+ return ValueError(f"Market snapshot for {symbol} is None")
34
+
35
+ best_bid_price, best_bid_quantity = snapshot.best_bid
36
+
37
+ d = datetime.now(tz=timezone.utc) + timedelta(days=1)
38
+ gtd = GoodTilDate(d)
39
+
40
+ order = await client.place_limit_order(
41
+ symbol=symbol,
42
+ odir=OrderDir.BUY,
43
+ quantity=best_bid_quantity,
44
+ order_type=OrderType.LIMIT,
45
+ execution_venue="CME",
46
+ post_only=True,
47
+ limit_price=best_bid_price
48
+ - (snapshot.best_ask[0] - best_bid_price) * Decimal(10),
49
+ account=account,
50
+ time_in_force=gtd,
51
+ )
52
+ logging.critical(f"ORDER TEST: {order}")
53
+
54
+ assert order is not None
55
+
56
+ cancel = await client.cancel_order(order.id)
57
+
58
+ return cancel
59
+
60
+
61
+ async def test_cancel_all_orders(client: AsyncClient):
62
+ await client.cancel_all_orders()
63
+
64
+
65
+ async def test_send_market_pro_order(client: AsyncClient, account: str):
66
+ venue, symbol = await search_symbol(client)
67
+ print(symbol)
68
+
69
+ await client.send_market_pro_order(
70
+ symbol=symbol,
71
+ execution_venue=venue,
72
+ odir=OrderDir.BUY,
73
+ quantity=Decimal(1),
74
+ account=account,
75
+ time_in_force=TimeInForceEnum.IOC,
76
+ )
77
+
78
+
79
+ async def main():
80
+ client: AsyncClient = await connect_async_client()
81
+ accounts = await client.list_accounts()
82
+ account: str = accounts[0].account.name
83
+
84
+ await test_send_order(client, account)
85
+ await test_send_market_pro_order(client, account)
86
+
87
+
88
+ if __name__ == "__main__":
89
+ loop = asyncio.new_event_loop()
90
+ asyncio.set_event_loop(loop)
91
+ loop.run_until_complete(main())
@@ -0,0 +1,25 @@
1
+ import asyncio
2
+
3
+ from architect_py.async_client import AsyncClient
4
+ from architect_py.common_types.tradable_product import TradableProduct
5
+
6
+ from .common import connect_async_client
7
+
8
+
9
+ async def main():
10
+ c: AsyncClient = await connect_async_client()
11
+
12
+ async for snap in c.stream_l1_book_snapshots(
13
+ symbols=[TradableProduct("ES 20250620 CME Future/USD")],
14
+ venue="CME",
15
+ ):
16
+ best_bid_s = "<no bid>"
17
+ best_ask_s = "<no ask>"
18
+ if snap.best_bid:
19
+ best_bid_s = f"{snap.best_bid[1]} x {snap.best_bid[0]}" # size x price
20
+ if snap.best_ask:
21
+ best_ask_s = f"{snap.best_ask[0]} x {snap.best_ask[1]}" # price x size
22
+ print(f"{snap.symbol} {snap.timestamp} {best_bid_s} {best_ask_s}")
23
+
24
+
25
+ asyncio.run(main())
@@ -0,0 +1,38 @@
1
+ import asyncio
2
+
3
+ from architect_py.async_client import AsyncClient
4
+ from architect_py.common_types.tradable_product import TradableProduct
5
+
6
+ from .common import connect_async_client
7
+
8
+ buy_columns = "{:>15} {:>15}"
9
+ sell_columns = "{:<15} {:<15}"
10
+ green = "\033[32m"
11
+ red = "\033[31m"
12
+ normal = "\033[0m"
13
+
14
+
15
+ async def print_l2_book(c: AsyncClient, symbol: TradableProduct, venue: str):
16
+ book = await c.subscribe_l2_book(symbol, venue)
17
+ while True:
18
+ print(f"book timestamp: {book.timestamp}")
19
+ print((buy_columns + " " + sell_columns).format("Size", "Bid", "Ask", "Size"))
20
+ for i in range(min(20, len(book.bids), len(book.asks))):
21
+ b = book.bids[i]
22
+ s = book.asks[i]
23
+ print(
24
+ (green + buy_columns).format(b[1], b[0]),
25
+ (red + sell_columns).format(s[0], s[1]),
26
+ )
27
+ print(normal)
28
+ await asyncio.sleep(1)
29
+
30
+
31
+ async def main():
32
+ c: AsyncClient = await connect_async_client()
33
+ market_symbol = TradableProduct("ES 20250620 CME Future/USD")
34
+ venue = "CME"
35
+ await print_l2_book(c, market_symbol, venue=venue)
36
+
37
+
38
+ asyncio.run(main())
examples/trades.py ADDED
@@ -0,0 +1,21 @@
1
+ import asyncio
2
+
3
+ from architect_py.async_client import AsyncClient
4
+ from architect_py.common_types.tradable_product import TradableProduct
5
+ from architect_py.graphql_client.exceptions import GraphQLClientHttpError
6
+
7
+ from .common import connect_async_client
8
+
9
+
10
+ async def main():
11
+ c: AsyncClient = await connect_async_client()
12
+ market_id = TradableProduct("BTC Crypto", "USD")
13
+ try:
14
+ async for trade in c.stream_trades(market_id, venue="COINBASE"):
15
+ print(trade)
16
+ except GraphQLClientHttpError as e:
17
+ print(e.status_code)
18
+ print(e.response.json())
19
+
20
+
21
+ asyncio.run(main())
@@ -0,0 +1,86 @@
1
+ import asyncio
2
+ from decimal import Decimal
3
+
4
+ from architect_py.async_client import OrderDir
5
+ from architect_py.common_types.tradable_product import TradableProduct
6
+ from architect_py.graphql_client.enums import OrderStatus
7
+ from examples.common import connect_async_client
8
+
9
+
10
+ async def main():
11
+ c = await connect_async_client()
12
+
13
+ market = TradableProduct("ES 20281215 CME Future/US")
14
+ execution_venue = "CME"
15
+
16
+ # Get market snapshot for a single market
17
+ # Market snapshots tell you the current best bid, best ask,
18
+ # and other ticker info for the given symbol.
19
+ print()
20
+ print(f"Market snapshot for {market}")
21
+ market_snapshot = await c.get_market_snapshot(symbol=market, venue=execution_venue)
22
+ print(f"Best bid: {market_snapshot.best_bid}")
23
+ print(f"Best ask: {market_snapshot.best_ask}")
24
+
25
+ # List your FCM accounts
26
+ print()
27
+ print("Your FCM accounts:")
28
+ accounts = await c.list_accounts()
29
+ for account in accounts:
30
+ print(f"{account.account.name}")
31
+
32
+ account_id = accounts[0].account.id
33
+
34
+ # Place a limit order $100 below the best bid
35
+ if (best_bid := market_snapshot.best_bid) is not None:
36
+ bid_px = best_bid[0]
37
+ else:
38
+ raise ValueError("No bid price available")
39
+
40
+ limit_price = bid_px - Decimal(100)
41
+ quantity = Decimal(1)
42
+ account = accounts[0]
43
+ order = None
44
+ print()
45
+ if (
46
+ input(
47
+ f"Place a limit order to BUY 1 LIMIT {limit_price} on account {account.account.name}? [y/N]"
48
+ )
49
+ == "y"
50
+ ):
51
+ order = await c.place_limit_order(
52
+ symbol=market,
53
+ execution_venue=execution_venue,
54
+ odir=OrderDir.BUY,
55
+ quantity=quantity,
56
+ limit_price=limit_price,
57
+ account=str(account_id),
58
+ )
59
+ else:
60
+ raise ValueError("Order was not placed")
61
+ print(f"Order placed with ID: {order.id}")
62
+
63
+ # Poll order status until rejected or fully executed
64
+ # After 5 seconds, cancel the order
65
+ i = 0
66
+ while order.status is OrderStatus.OPEN:
67
+ await asyncio.sleep(1)
68
+ print(f"...order state: {order.status}")
69
+ order = await c.get_order(order.id)
70
+ assert order is not None
71
+ i += 1
72
+ if i == 5:
73
+ print("Canceling order")
74
+ await c.cancel_order(order.id)
75
+
76
+ if order.status is OrderStatus.REJECTED:
77
+ print(f"Order was rejected: {order.reject_reason}")
78
+ elif order.status is OrderStatus.CANCELED:
79
+ print("Order was canceled")
80
+ elif order.status is OrderStatus.OUT:
81
+ print(f"Order was filled for qty: {order.filled_quantity}")
82
+ print(f"Average execution price: {order.average_fill_price}")
83
+
84
+
85
+ if __name__ == "__main__":
86
+ asyncio.run(main())
@@ -0,0 +1,95 @@
1
+ import pprint
2
+ import time
3
+ from decimal import Decimal
4
+
5
+ from architect_py.common_types.order_dir import OrderDir
6
+ from architect_py.graphql_client.enums import OrderStatus
7
+ from architect_py.utils.nearest_tick import TickRoundMethod
8
+
9
+ from .common import confirm, connect_client, print_book, print_open_orders
10
+
11
+ c = connect_client()
12
+
13
+ venue = "CME"
14
+
15
+ # find ES markets
16
+ symbols = c.search_symbols(execution_venue=venue, search_string="ES")
17
+ print("\nFound markets:")
18
+
19
+ for s in symbols:
20
+ print(f" • {s}")
21
+
22
+ symbol = symbols[0]
23
+
24
+ # Lookup information about a single market
25
+ print(f"\nDetails for {symbols[0]}:")
26
+ product_info = c.get_product_info(symbol)
27
+ assert product_info is not None
28
+ pprint.pp(product_info)
29
+
30
+ # Get market snapshot for a single market
31
+ # Market snapshots tell you the current best bid, best ask,
32
+ # and other ticker info for the given symbol.
33
+ # this function is an alias for get_l1_book_snapshot
34
+ print(f"\nMarket snapshot for {product_info.symbol}:")
35
+ market_snapshot = c.get_market_snapshot(symbol=symbol, venue=venue)
36
+
37
+ pprint.pp(market_snapshot)
38
+
39
+ # Get L2 snapshot for a single market
40
+ print(f"\nL2 snapshot for {product_info.symbol}:")
41
+ start = time.perf_counter()
42
+ book = c.get_l2_book_snapshot(symbol=symbol, venue=venue)
43
+ elapsed = time.perf_counter() - start
44
+ print(f"Got book snapshot in {elapsed:.4f} seconds\n")
45
+ print_book(book)
46
+
47
+ # Get your accounts
48
+ print("\nYour accounts:")
49
+ accounts = c.list_accounts()
50
+ for account in accounts:
51
+ print(f" • {account.account.name}")
52
+
53
+ # Check your open orders
54
+ print("\nCurrent open orders:")
55
+ orders = c.get_open_orders()
56
+ print_open_orders(orders)
57
+
58
+ # Place a limit order 20% below the best bid
59
+ best_bid = market_snapshot.best_bid
60
+ assert best_bid is not None
61
+ best_bid_price, best_bid_quantity = best_bid
62
+ limit_price = best_bid_price * Decimal(0.8)
63
+ account = accounts[0]
64
+ order = None
65
+
66
+ if confirm(
67
+ f"Place a limit order to BUY 1 {symbol} LIMIT {limit_price} on account {account.account.name}?"
68
+ ):
69
+ order = c.send_limit_order(
70
+ symbol=symbol,
71
+ execution_venue=venue,
72
+ odir=OrderDir.BUY,
73
+ quantity=best_bid_quantity,
74
+ limit_price=limit_price,
75
+ account=account.account.name,
76
+ price_round_method=TickRoundMethod.ROUND,
77
+ )
78
+ assert order is not None
79
+ print(f"\nOrder placed with ID: {order.id}")
80
+
81
+ # Poll order status until rejected or fully executed
82
+ while order.status is OrderStatus.OPEN:
83
+ time.sleep(1)
84
+ print(f"...order state: {order.status}")
85
+ order = c.get_order(order.id)
86
+ assert order is not None
87
+
88
+ # Print final order state
89
+ if order.status is OrderStatus.REJECTED:
90
+ print(f"Order was rejected: {order.reject_reason}")
91
+ elif order.status is OrderStatus.CANCELED:
92
+ print("Order was canceled")
93
+ elif order.status is OrderStatus.OUT:
94
+ print(f"Order was filled for qty: {order.filled_quantity}")
95
+ print(f"Average execution price: {order.average_fill_price}")