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.
- architect_py/__init__.py +18 -2
- architect_py/async_client.py +1089 -658
- architect_py/client.py +36 -33
- architect_py/client_interface.py +63 -0
- architect_py/common_types/__init__.py +6 -0
- architect_py/common_types/order_dir.py +91 -0
- architect_py/common_types/scalars.py +25 -0
- architect_py/common_types/tradable_product.py +59 -0
- architect_py/graphql_client/__init__.py +2 -0
- architect_py/graphql_client/client.py +3 -6
- architect_py/graphql_client/enums.py +5 -0
- architect_py/graphql_client/fragments.py +3 -6
- architect_py/graphql_client/get_fills_query.py +2 -1
- architect_py/graphql_client/search_symbols_query.py +2 -1
- architect_py/graphql_client/subscribe_orderflow.py +2 -1
- architect_py/graphql_client/subscribe_trades.py +2 -1
- architect_py/grpc/__init__.py +145 -0
- architect_py/grpc/client.py +94 -0
- architect_py/{grpc_client → grpc/models}/Accounts/AccountsRequest.py +6 -3
- architect_py/{grpc_client → grpc/models}/Accounts/AccountsResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Accounts/__init__.py +1 -1
- architect_py/grpc/models/Algo/AlgoOrder.py +114 -0
- architect_py/grpc/models/Algo/AlgoOrderRequest.py +46 -0
- architect_py/grpc/models/Algo/AlgoOrdersRequest.py +72 -0
- architect_py/grpc/models/Algo/AlgoOrdersResponse.py +27 -0
- architect_py/grpc/models/Algo/CreateAlgoOrderRequest.py +56 -0
- architect_py/grpc/models/Algo/PauseAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/PauseAlgoResponse.py +20 -0
- architect_py/grpc/models/Algo/StartAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/StartAlgoResponse.py +20 -0
- architect_py/grpc/models/Algo/StopAlgoRequest.py +42 -0
- architect_py/grpc/models/Algo/StopAlgoResponse.py +20 -0
- architect_py/{grpc_client → grpc/models}/Algo/__init__.py +1 -1
- architect_py/grpc/models/Auth/CreateJwtRequest.py +47 -0
- architect_py/grpc/models/Auth/CreateJwtResponse.py +23 -0
- architect_py/{grpc_client/Cpty → grpc/models/Auth}/__init__.py +1 -1
- architect_py/grpc/models/Boss/DepositsRequest.py +40 -0
- architect_py/grpc/models/Boss/DepositsResponse.py +27 -0
- architect_py/grpc/models/Boss/RqdAccountStatisticsRequest.py +42 -0
- architect_py/grpc/models/Boss/RqdAccountStatisticsResponse.py +25 -0
- architect_py/grpc/models/Boss/StatementUrlRequest.py +40 -0
- architect_py/grpc/models/Boss/StatementUrlResponse.py +23 -0
- architect_py/grpc/models/Boss/StatementsRequest.py +40 -0
- architect_py/grpc/models/Boss/StatementsResponse.py +27 -0
- architect_py/grpc/models/Boss/WithdrawalsRequest.py +40 -0
- architect_py/grpc/models/Boss/WithdrawalsResponse.py +27 -0
- architect_py/{grpc_client/Folio → grpc/models/Boss}/__init__.py +1 -1
- architect_py/grpc/models/Core/ConfigRequest.py +37 -0
- architect_py/grpc/models/Core/ConfigResponse.py +25 -0
- architect_py/grpc/models/Core/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/Cpty/CptyRequest.py +5 -4
- architect_py/{grpc_client → grpc/models}/Cpty/CptyResponse.py +6 -6
- architect_py/grpc/models/Cpty/CptyStatus.py +48 -0
- architect_py/grpc/models/Cpty/CptyStatusRequest.py +45 -0
- architect_py/grpc/models/Cpty/CptysRequest.py +37 -0
- architect_py/grpc/models/Cpty/CptysResponse.py +27 -0
- architect_py/grpc/models/Cpty/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Folio/AccountHistoryResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Folio/AccountSummariesResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Folio/AccountSummary.py +1 -1
- architect_py/{grpc_client → grpc/models}/Folio/AccountSummaryRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsRequest.py +7 -4
- architect_py/{grpc_client → grpc/models}/Folio/HistoricalFillsResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersRequest.py +3 -3
- architect_py/{grpc_client → grpc/models}/Folio/HistoricalOrdersResponse.py +1 -1
- architect_py/grpc/models/Folio/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/Health/HealthCheckRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Health/HealthCheckResponse.py +1 -1
- architect_py/grpc/models/Health/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/Marketdata/Candle.py +1 -1
- architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesRequest.py +11 -8
- architect_py/{grpc_client → grpc/models}/Marketdata/HistoricalCandlesResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshot.py +52 -5
- architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotRequest.py +8 -3
- architect_py/{grpc_client → grpc/models}/Marketdata/L1BookSnapshotsRequest.py +6 -3
- architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshot.py +1 -1
- architect_py/{grpc_client → grpc/models}/Marketdata/L2BookSnapshotRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/Liquidation.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatus.py +1 -1
- architect_py/{grpc_client → grpc/models}/Marketdata/MarketStatusRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCandlesRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeCurrentCandlesRequest.py +3 -4
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL1BookSnapshotsRequest.py +6 -3
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeL2BookUpdatesRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeLiquidationsRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeManyCandlesRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTickersRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/SubscribeTradesRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/Ticker.py +14 -3
- architect_py/{grpc_client → grpc/models}/Marketdata/TickerRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/TickersRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Marketdata/TickersResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Marketdata/Trade.py +2 -2
- architect_py/grpc/models/Marketdata/__init__.py +2 -0
- architect_py/grpc/models/Oms/Cancel.py +90 -0
- architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Oms/CancelAllOrdersResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Oms/CancelOrderRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Oms/OpenOrdersResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Oms/Order.py +6 -13
- architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Oms/PendingCancelsResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Oms/PlaceOrderRequest.py +16 -23
- architect_py/grpc/models/Oms/__init__.py +2 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChain.py +30 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeks.py +30 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainGreeksRequest.py +47 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsChainRequest.py +45 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirations.py +29 -0
- architect_py/grpc/models/OptionsMarketdata/OptionsExpirationsRequest.py +42 -0
- architect_py/grpc/models/OptionsMarketdata/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/Orderflow/DropcopyRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Orderflow/OrderflowRequest.py +2 -1
- architect_py/{grpc_client → grpc/models}/Orderflow/SubscribeOrderflowRequest.py +2 -2
- architect_py/grpc/models/Orderflow/__init__.py +2 -0
- architect_py/grpc/models/Symbology/DownloadProductCatalogRequest.py +42 -0
- architect_py/grpc/models/Symbology/DownloadProductCatalogResponse.py +27 -0
- architect_py/grpc/models/Symbology/ExecutionInfoRequest.py +47 -0
- architect_py/grpc/models/Symbology/ExecutionInfoResponse.py +27 -0
- architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Symbology/PruneExpiredSymbolsResponse.py +1 -1
- architect_py/{grpc_client → grpc/models}/Symbology/SubscribeSymbology.py +1 -1
- architect_py/{grpc_client → grpc/models}/Symbology/SymbologyRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Symbology/SymbologySnapshot.py +7 -2
- architect_py/{grpc_client → grpc/models}/Symbology/SymbologyUpdate.py +9 -2
- architect_py/{grpc_client → grpc/models}/Symbology/SymbolsRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Symbology/SymbolsResponse.py +1 -1
- architect_py/grpc/models/Symbology/UploadProductCatalogRequest.py +49 -0
- architect_py/grpc/models/Symbology/UploadProductCatalogResponse.py +20 -0
- architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyRequest.py +2 -2
- architect_py/{grpc_client → grpc/models}/Symbology/UploadSymbologyResponse.py +1 -1
- architect_py/grpc/models/Symbology/__init__.py +2 -0
- architect_py/grpc/models/__init__.py +2 -0
- architect_py/{grpc_client → grpc/models}/definitions.py +671 -934
- architect_py/grpc/resolve_endpoint.py +70 -0
- architect_py/{grpc_client/grpc_server.py → grpc/server.py} +13 -9
- architect_py/grpc/utils.py +32 -0
- architect_py/internal_utils/__init__.py +0 -0
- architect_py/internal_utils/no_pandas.py +3 -0
- architect_py/tests/conftest.py +91 -85
- architect_py/tests/test_book_building.py +49 -50
- architect_py/tests/test_marketdata.py +168 -0
- architect_py/tests/test_order_entry.py +37 -0
- architect_py/tests/test_orderflow.py +41 -0
- architect_py/tests/test_portfolio_management.py +23 -0
- architect_py/tests/test_rounding.py +28 -28
- architect_py/tests/test_symbology.py +37 -30
- architect_py/utils/nearest_tick.py +2 -5
- architect_py/utils/nearest_tick_2.py +1 -2
- architect_py/utils/orderbook.py +35 -0
- architect_py/utils/pandas.py +44 -0
- architect_py/utils/price_bands.py +0 -3
- architect_py/utils/symbol_parsing.py +29 -0
- architect_py-5.0.0.dist-info/METADATA +54 -0
- architect_py-5.0.0.dist-info/RECORD +214 -0
- {architect_py-3.2.1.dist-info → architect_py-5.0.0.dist-info}/WHEEL +2 -1
- architect_py-5.0.0.dist-info/top_level.txt +4 -0
- examples/__init__.py +0 -0
- examples/book_subscription.py +52 -0
- examples/candles.py +30 -0
- examples/common.py +116 -0
- examples/external_cpty.py +77 -0
- examples/funding_rate_mean_reversion_algo.py +186 -0
- examples/order_sending.py +91 -0
- examples/stream_l1_marketdata.py +25 -0
- examples/stream_l2_marketdata.py +38 -0
- examples/trades.py +21 -0
- examples/tutorial_async.py +86 -0
- examples/tutorial_sync.py +95 -0
- scripts/generate_functions_md.py +166 -0
- scripts/generate_sync_interface.py +226 -0
- scripts/postprocess_grpc.py +604 -0
- scripts/preprocess_grpc_schema.py +708 -0
- templates/exceptions.py +83 -0
- templates/juniper_base_client.py +371 -0
- architect_py/client_protocol.py +0 -52
- architect_py/grpc_client/Algo/AlgoOrderForTwapAlgo.py +0 -61
- architect_py/grpc_client/Algo/CreateAlgoOrderRequestForTwapAlgo.py +0 -59
- architect_py/grpc_client/Algo/ModifyAlgoOrderRequestForTwapAlgo.py +0 -45
- architect_py/grpc_client/Folio/AggregatedAccountSummariesRequest.py +0 -59
- architect_py/grpc_client/Folio/AggregatedAccountSummariesResponse.py +0 -27
- architect_py/grpc_client/Health/__init__.py +0 -2
- architect_py/grpc_client/Marketdata/__init__.py +0 -2
- architect_py/grpc_client/Oms/Cancel.py +0 -42
- architect_py/grpc_client/Oms/__init__.py +0 -2
- architect_py/grpc_client/Orderflow/__init__.py +0 -2
- architect_py/grpc_client/Symbology/__init__.py +0 -2
- architect_py/grpc_client/__init__.py +0 -2
- architect_py/grpc_client/grpc_client.py +0 -405
- architect_py/scalars.py +0 -172
- architect_py/tests/test_accounts.py +0 -31
- architect_py/tests/test_client.py +0 -29
- architect_py/tests/test_grpc_client.py +0 -30
- architect_py/tests/test_order_sending.py +0 -61
- architect_py/tests/test_snapshots.py +0 -52
- architect_py/tests/test_subscriptions.py +0 -129
- architect_py-3.2.1.dist-info/METADATA +0 -212
- architect_py-3.2.1.dist-info/RECORD +0 -146
- /architect_py/{grpc_client → grpc/models}/Marketdata/ArrayOfL1BookSnapshot.py +0 -0
- /architect_py/{grpc_client → grpc/models}/Marketdata/L2BookUpdate.py +0 -0
- /architect_py/{grpc_client → grpc/models}/Marketdata/TickerUpdate.py +0 -0
- /architect_py/{grpc_client → grpc/models}/Orderflow/Dropcopy.py +0 -0
- /architect_py/{grpc_client → grpc/models}/Orderflow/Orderflow.py +0 -0
- {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
|