architect-py 5.1.2__py3-none-any.whl → 5.1.4b1__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 +1 -1
- architect_py/async_client.py +45 -22
- architect_py/client.py +11 -1
- architect_py/client.pyi +6 -1
- architect_py/grpc/client.py +13 -4
- architect_py/grpc/models/Marketdata/SubscribeL1BookSnapshotsRequest.py +14 -1
- architect_py/grpc/models/Marketdata/TickersRequest.py +4 -1
- architect_py/grpc/models/definitions.py +1 -0
- {architect_py-5.1.2.dist-info → architect_py-5.1.4b1.dist-info}/METADATA +3 -3
- {architect_py-5.1.2.dist-info → architect_py-5.1.4b1.dist-info}/RECORD +27 -24
- examples/book_subscription.py +1 -1
- examples/candles.py +1 -1
- examples/{common.py → config.py} +4 -48
- examples/funding_rate_mean_reversion_algo.py +1 -1
- examples/order_sending.py +1 -1
- examples/orderflow_channel.py +56 -0
- examples/orderflow_streaming.py +47 -0
- examples/stream_l1_marketdata.py +1 -1
- examples/stream_l2_marketdata.py +1 -1
- examples/termutils.py +44 -0
- examples/trades.py +1 -1
- examples/tutorial_async.py +2 -1
- examples/tutorial_sync.py +2 -1
- scripts/correct_sync_interface.py +5 -2
- {architect_py-5.1.2.dist-info → architect_py-5.1.4b1.dist-info}/WHEEL +0 -0
- {architect_py-5.1.2.dist-info → architect_py-5.1.4b1.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.1.2.dist-info → architect_py-5.1.4b1.dist-info}/top_level.txt +0 -0
architect_py/__init__.py
CHANGED
architect_py/async_client.py
CHANGED
@@ -11,6 +11,7 @@ from typing import (
|
|
11
11
|
Literal,
|
12
12
|
Optional,
|
13
13
|
Sequence,
|
14
|
+
Tuple,
|
14
15
|
Union,
|
15
16
|
overload,
|
16
17
|
)
|
@@ -56,6 +57,7 @@ class AsyncClient:
|
|
56
57
|
api_secret: Optional[str] = None
|
57
58
|
paper_trading: bool
|
58
59
|
graphql_client: GraphQLClient
|
60
|
+
grpc_options: Sequence[Tuple[str, Any]] | None = None
|
59
61
|
grpc_core: Optional[GrpcClient] = None
|
60
62
|
grpc_marketdata: dict[Venue, GrpcClient] = {}
|
61
63
|
grpc_hmart: Optional[GrpcClient] = None
|
@@ -77,14 +79,22 @@ class AsyncClient:
|
|
77
79
|
paper_trading: bool,
|
78
80
|
endpoint: str = "https://app.architect.co",
|
79
81
|
graphql_port: Optional[int] = None,
|
82
|
+
grpc_options: Sequence[Tuple[str, Any]] | None = None,
|
80
83
|
**kwargs: Any,
|
81
84
|
) -> "AsyncClient":
|
82
85
|
"""
|
83
86
|
Connect to an Architect installation.
|
84
87
|
|
85
|
-
An `api_key` and `api_secret` can be created at https://app.architect.co/api-keys
|
88
|
+
An `api_key` and `api_secret` can be created at https://app.architect.co/api-keys.
|
86
89
|
|
87
90
|
Raises ValueError if the API key and secret are not the correct length or contain invalid characters.
|
91
|
+
|
92
|
+
## Advanced configuration
|
93
|
+
|
94
|
+
### gRPC channel options
|
95
|
+
|
96
|
+
Use `grpc_options` to configure gRPC channels created by this client.
|
97
|
+
See https://grpc.github.io/grpc/python/glossary.html#term-channel_arguments for reference.
|
88
98
|
"""
|
89
99
|
if paper_trading:
|
90
100
|
COLOR = "\033[30;43m"
|
@@ -123,6 +133,7 @@ class AsyncClient:
|
|
123
133
|
paper_trading=paper_trading,
|
124
134
|
grpc_host=grpc_host,
|
125
135
|
grpc_port=grpc_port,
|
136
|
+
grpc_options=grpc_options,
|
126
137
|
graphql_port=graphql_port,
|
127
138
|
use_ssl=use_ssl,
|
128
139
|
_i_know_what_i_am_doing=True,
|
@@ -144,6 +155,7 @@ class AsyncClient:
|
|
144
155
|
paper_trading: bool,
|
145
156
|
grpc_host: str = "app.architect.co",
|
146
157
|
grpc_port: int,
|
158
|
+
grpc_options: Sequence[Tuple[str, Any]] | None = None,
|
147
159
|
graphql_port: Optional[int] = None,
|
148
160
|
use_ssl: bool = True,
|
149
161
|
_i_know_what_i_am_doing: bool = False,
|
@@ -179,7 +191,10 @@ class AsyncClient:
|
|
179
191
|
api_key=api_key,
|
180
192
|
api_secret=api_secret,
|
181
193
|
)
|
182
|
-
self.
|
194
|
+
self.grpc_options = grpc_options
|
195
|
+
self.grpc_core = GrpcClient(
|
196
|
+
host=grpc_host, port=grpc_port, use_ssl=use_ssl, options=grpc_options
|
197
|
+
)
|
183
198
|
|
184
199
|
async def close(self):
|
185
200
|
"""
|
@@ -268,7 +283,10 @@ class AsyncClient:
|
|
268
283
|
use_ssl,
|
269
284
|
)
|
270
285
|
self.grpc_marketdata[venue] = GrpcClient(
|
271
|
-
host=grpc_host,
|
286
|
+
host=grpc_host,
|
287
|
+
port=grpc_port,
|
288
|
+
use_ssl=use_ssl,
|
289
|
+
options=self.grpc_options,
|
272
290
|
)
|
273
291
|
except Exception as e:
|
274
292
|
logging.error("Failed to set marketdata endpoint: %s", e)
|
@@ -282,7 +300,10 @@ class AsyncClient:
|
|
282
300
|
try:
|
283
301
|
grpc_host, grpc_port, use_ssl = await resolve_endpoint(endpoint)
|
284
302
|
self.grpc_marketdata[venue] = GrpcClient(
|
285
|
-
host=grpc_host,
|
303
|
+
host=grpc_host,
|
304
|
+
port=grpc_port,
|
305
|
+
use_ssl=use_ssl,
|
306
|
+
options=self.grpc_options,
|
286
307
|
)
|
287
308
|
logging.debug(
|
288
309
|
f"Setting marketdata endpoint for {venue}: {grpc_host}:{grpc_port} use_ssl={use_ssl}"
|
@@ -315,7 +336,10 @@ class AsyncClient:
|
|
315
336
|
use_ssl,
|
316
337
|
)
|
317
338
|
self.grpc_hmart = GrpcClient(
|
318
|
-
host=grpc_host,
|
339
|
+
host=grpc_host,
|
340
|
+
port=grpc_port,
|
341
|
+
use_ssl=use_ssl,
|
342
|
+
options=self.grpc_options,
|
319
343
|
)
|
320
344
|
except Exception as e:
|
321
345
|
logging.error("Failed to set hmart endpoint: %s", e)
|
@@ -364,6 +388,17 @@ class AsyncClient:
|
|
364
388
|
"as of v5.0.0: enable_orderflow is deprecated; orderflow is enabled by default"
|
365
389
|
)
|
366
390
|
|
391
|
+
async def cpty_status(
|
392
|
+
self, kind: str, instance: Optional[str] = None
|
393
|
+
) -> CptyStatus:
|
394
|
+
"""
|
395
|
+
Get cpty status.
|
396
|
+
"""
|
397
|
+
grpc_client = await self.core()
|
398
|
+
req = CptyStatusRequest(kind=kind, instance=instance)
|
399
|
+
res: CptyStatus = await grpc_client.unary_unary(req)
|
400
|
+
return res
|
401
|
+
|
367
402
|
# ------------------------------------------------------------
|
368
403
|
# Symbology
|
369
404
|
# ------------------------------------------------------------
|
@@ -1382,28 +1417,16 @@ class AsyncClient:
|
|
1382
1417
|
|
1383
1418
|
Example:
|
1384
1419
|
```python
|
1385
|
-
async for
|
1386
|
-
print(
|
1420
|
+
async for event in client.stream_orderflow(account, execution_venue, trader):
|
1421
|
+
print(event)
|
1387
1422
|
```
|
1388
1423
|
"""
|
1389
1424
|
grpc_client = await self.core()
|
1390
|
-
|
1425
|
+
req: SubscribeOrderflowRequest = SubscribeOrderflowRequest(
|
1391
1426
|
account=account, execution_venue=execution_venue, trader=trader
|
1392
1427
|
)
|
1393
|
-
|
1394
|
-
|
1395
|
-
stub: grpc.aio.UnaryStreamMultiCallable[
|
1396
|
-
SubscribeOrderflowRequest, Orderflow
|
1397
|
-
] = grpc_client.channel.unary_stream(
|
1398
|
-
SubscribeOrderflowRequest.get_route(),
|
1399
|
-
request_serializer=grpc_client.encoder().encode,
|
1400
|
-
response_deserializer=decoder.decode,
|
1401
|
-
)
|
1402
|
-
call: grpc.aio._base_call.UnaryStreamCall[
|
1403
|
-
SubscribeOrderflowRequest, Orderflow
|
1404
|
-
] = stub(request, metadata=(("authorization", f"Bearer {grpc_client.jwt}"),))
|
1405
|
-
async for update in call:
|
1406
|
-
yield update
|
1428
|
+
async for res in grpc_client.unary_stream(req): # type: ignore
|
1429
|
+
yield res
|
1407
1430
|
|
1408
1431
|
# ------------------------------------------------------------
|
1409
1432
|
# Order entry
|
architect_py/client.py
CHANGED
@@ -4,7 +4,15 @@ import threading
|
|
4
4
|
from asyncio import AbstractEventLoop
|
5
5
|
from collections.abc import Callable
|
6
6
|
from functools import partial
|
7
|
-
from typing import
|
7
|
+
from typing import (
|
8
|
+
Any,
|
9
|
+
Concatenate,
|
10
|
+
Coroutine,
|
11
|
+
Optional,
|
12
|
+
ParamSpec,
|
13
|
+
Sequence,
|
14
|
+
TypeVar,
|
15
|
+
)
|
8
16
|
|
9
17
|
from .async_client import AsyncClient
|
10
18
|
|
@@ -50,6 +58,7 @@ class Client:
|
|
50
58
|
paper_trading: bool,
|
51
59
|
endpoint: str = "https://app.architect.co",
|
52
60
|
graphql_port: Optional[int] = None,
|
61
|
+
grpc_options: Sequence[tuple[str, Any]] | None = None,
|
53
62
|
event_loop: Optional[AbstractEventLoop] = None,
|
54
63
|
**kwargs,
|
55
64
|
):
|
@@ -78,6 +87,7 @@ class Client:
|
|
78
87
|
paper_trading=paper_trading,
|
79
88
|
endpoint=endpoint,
|
80
89
|
graphql_port=graphql_port,
|
90
|
+
grpc_options=grpc_options,
|
81
91
|
**kwargs,
|
82
92
|
)
|
83
93
|
|
architect_py/client.pyi
CHANGED
@@ -38,13 +38,14 @@ class Client:
|
|
38
38
|
api_secret: str | None
|
39
39
|
paper_trading: bool
|
40
40
|
graphql_client: GraphQLClient
|
41
|
+
grpc_options: Sequence[tuple[str, Any]] | None
|
41
42
|
grpc_core: GrpcClient | None
|
42
43
|
grpc_marketdata: dict[Venue, GrpcClient]
|
43
44
|
grpc_hmart: GrpcClient | None
|
44
45
|
jwt: str | None
|
45
46
|
jwt_expiration: datetime | None
|
46
47
|
l1_books: dict[Venue, dict[TradableProduct, tuple[L1BookSnapshot, asyncio.Task]]]
|
47
|
-
def __init__(self, *, api_key: str, api_secret: str, paper_trading: bool, endpoint: str = 'https://app.architect.co', graphql_port: int | None = None, event_loop: asyncio.events.AbstractEventLoop | None = None) -> None:
|
48
|
+
def __init__(self, *, api_key: str, api_secret: str, paper_trading: bool, endpoint: str = 'https://app.architect.co', graphql_port: int | None = None, grpc_options: Sequence[tuple[str, Any]] | None = None, event_loop: asyncio.events.AbstractEventLoop | None = None) -> None:
|
48
49
|
"""
|
49
50
|
Create a new Client instance.
|
50
51
|
|
@@ -118,6 +119,10 @@ class Client:
|
|
118
119
|
Returns:
|
119
120
|
(user_id, user_email)
|
120
121
|
"""
|
122
|
+
def cpty_status(self, kind: str, instance: str | None = None) -> CptyStatus:
|
123
|
+
"""
|
124
|
+
Get cpty status.
|
125
|
+
"""
|
121
126
|
def list_symbols(self, *, marketdata: Venue | None = None) -> list[str]:
|
122
127
|
"""
|
123
128
|
List all symbols.
|
architect_py/grpc/client.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from types import UnionType
|
2
|
-
from typing import AsyncIterator
|
2
|
+
from typing import Any, AsyncIterator, Sequence, Tuple
|
3
3
|
|
4
4
|
import grpc
|
5
5
|
import msgspec
|
@@ -18,14 +18,23 @@ class GrpcClient:
|
|
18
18
|
channel: grpc.aio.Channel
|
19
19
|
jwt: str | None = None
|
20
20
|
|
21
|
-
def __init__(
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
*,
|
24
|
+
host: str,
|
25
|
+
port: int,
|
26
|
+
use_ssl: bool = False,
|
27
|
+
options: Sequence[Tuple[str, Any]] | None = None,
|
28
|
+
):
|
22
29
|
scheme = "https" if use_ssl else "http"
|
23
30
|
self.endpoint = f"{scheme}://{host}:{port}"
|
24
31
|
if use_ssl:
|
25
32
|
credentials = grpc.ssl_channel_credentials()
|
26
|
-
self.channel = grpc.aio.secure_channel(
|
33
|
+
self.channel = grpc.aio.secure_channel(
|
34
|
+
f"{host}:{port}", credentials, options=options
|
35
|
+
)
|
27
36
|
else:
|
28
|
-
self.channel = grpc.aio.insecure_channel(f"{host}:{port}")
|
37
|
+
self.channel = grpc.aio.insecure_channel(f"{host}:{port}", options=options)
|
29
38
|
|
30
39
|
def set_jwt(self, jwt: str | None):
|
31
40
|
self.jwt = jwt
|
@@ -10,6 +10,17 @@ from msgspec import Meta, Struct
|
|
10
10
|
|
11
11
|
|
12
12
|
class SubscribeL1BookSnapshotsRequest(Struct, omit_defaults=True):
|
13
|
+
send_initial_snapshots: Optional[
|
14
|
+
Annotated[
|
15
|
+
bool,
|
16
|
+
Meta(
|
17
|
+
description="If true, send an initial snapshot to subscribers on symbol subscription"
|
18
|
+
),
|
19
|
+
]
|
20
|
+
] = False
|
21
|
+
"""
|
22
|
+
If true, send an initial snapshot to subscribers on symbol subscription
|
23
|
+
"""
|
13
24
|
symbols: Optional[
|
14
25
|
Annotated[
|
15
26
|
List[str],
|
@@ -25,16 +36,18 @@ class SubscribeL1BookSnapshotsRequest(Struct, omit_defaults=True):
|
|
25
36
|
@classmethod
|
26
37
|
def new(
|
27
38
|
cls,
|
39
|
+
send_initial_snapshots: Optional[bool] = False,
|
28
40
|
symbols: Optional[List[str]] = None,
|
29
41
|
venue: Optional[str] = None,
|
30
42
|
):
|
31
43
|
return cls(
|
44
|
+
send_initial_snapshots,
|
32
45
|
symbols,
|
33
46
|
venue,
|
34
47
|
)
|
35
48
|
|
36
49
|
def __str__(self) -> str:
|
37
|
-
return f"SubscribeL1BookSnapshotsRequest(symbols={self.symbols},venue={self.venue})"
|
50
|
+
return f"SubscribeL1BookSnapshotsRequest(send_initial_snapshots={self.send_initial_snapshots},symbols={self.symbols},venue={self.venue})"
|
38
51
|
|
39
52
|
@staticmethod
|
40
53
|
def get_response_type():
|
@@ -13,6 +13,7 @@ from .. import definitions
|
|
13
13
|
|
14
14
|
class TickersRequest(Struct, omit_defaults=True):
|
15
15
|
i: Optional[Annotated[Optional[int], Meta(title="offset")]] = None
|
16
|
+
include_options: Optional[bool] = None
|
16
17
|
k: Optional[
|
17
18
|
Annotated[Optional[definitions.SortTickersBy], Meta(title="sort_by")]
|
18
19
|
] = None
|
@@ -25,6 +26,7 @@ class TickersRequest(Struct, omit_defaults=True):
|
|
25
26
|
def new(
|
26
27
|
cls,
|
27
28
|
offset: Optional[int] = None,
|
29
|
+
include_options: Optional[bool] = None,
|
28
30
|
sort_by: Optional[definitions.SortTickersBy] = None,
|
29
31
|
limit: Optional[int] = None,
|
30
32
|
symbols: Optional[List[str]] = None,
|
@@ -32,6 +34,7 @@ class TickersRequest(Struct, omit_defaults=True):
|
|
32
34
|
):
|
33
35
|
return cls(
|
34
36
|
offset,
|
37
|
+
include_options,
|
35
38
|
sort_by,
|
36
39
|
limit,
|
37
40
|
symbols,
|
@@ -39,7 +42,7 @@ class TickersRequest(Struct, omit_defaults=True):
|
|
39
42
|
)
|
40
43
|
|
41
44
|
def __str__(self) -> str:
|
42
|
-
return f"TickersRequest(offset={self.i},sort_by={self.k},limit={self.n},symbols={self.symbols},venue={self.venue})"
|
45
|
+
return f"TickersRequest(offset={self.i},include_options={self.include_options},sort_by={self.k},limit={self.n},symbols={self.symbols},venue={self.venue})"
|
43
46
|
|
44
47
|
@property
|
45
48
|
def offset(self) -> Optional[int]:
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: architect-py
|
3
|
-
Version: 5.1.
|
3
|
+
Version: 5.1.4b1
|
4
4
|
Summary: Python SDK for the Architect trading platform and brokerage.
|
5
5
|
Author-email: "Architect Financial Technologies, Inc." <hello@architect.co>
|
6
6
|
License-Expression: Apache-2.0
|
7
|
-
Project-URL: Homepage, https://www.architect.co/brokerage/overview
|
8
7
|
Project-URL: Documentation, https://docs.architect.co
|
8
|
+
Project-URL: Homepage, https://www.architect.co/brokerage/overview
|
9
9
|
Project-URL: Repository, https://github.com/architect-xyz/architect-py
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
11
|
Classifier: Operating System :: OS Independent
|
@@ -48,7 +48,7 @@ Go to [FUNCTIONS.md](FUNCTIONS.md) file to see a catalog of methods.
|
|
48
48
|
|
49
49
|
## Examples
|
50
50
|
|
51
|
-
Go to the [Examples](./examples) to see examples of a variety of common use cases.
|
51
|
+
Go to the [Examples](./examples) to see examples of a variety of common use cases. To run a specific example, use e.g. `python -m examples.orderflow_streaming`.
|
52
52
|
|
53
53
|
## Documentation
|
54
54
|
|
@@ -1,7 +1,7 @@
|
|
1
|
-
architect_py/__init__.py,sha256=
|
2
|
-
architect_py/async_client.py,sha256=
|
3
|
-
architect_py/client.py,sha256=
|
4
|
-
architect_py/client.pyi,sha256=
|
1
|
+
architect_py/__init__.py,sha256=8CrccOPnPzBy9EjbeXrvHImwdFvNofKqInTPsDz-9Fw,16123
|
2
|
+
architect_py/async_client.py,sha256=k6bGfqkan0sdlKI2LOYTRwwT-UZLPDgKagxo_IUqhxU,62227
|
3
|
+
architect_py/client.py,sha256=S9FsNoRJGB2xiE6H1nPPIg_-oAPZ5qPOBWy_4Hw0UuI,5056
|
4
|
+
architect_py/client.pyi,sha256=bXd7pjtc1lDCB0l6tRkHr8tydz7n65TUpsyUeYaqV_4,24801
|
5
5
|
architect_py/common_types/__init__.py,sha256=fzOdIlKGWVN9V2Onc5z1v2bpvtZ4H9RSFA9ymJcBi3k,197
|
6
6
|
architect_py/common_types/order_dir.py,sha256=ebyWTcXzJWrotkc2D9wNGc6JXbE5I3NLLuAz3I7FTZ8,2191
|
7
7
|
architect_py/common_types/time_in_force.py,sha256=gEDYcNp014Eeb98zJDytiV0hGxHu_QsQndeM6Hk0Wa8,3132
|
@@ -23,12 +23,12 @@ architect_py/graphql_client/juniper_base_client.py,sha256=0kbAihyRgEP3n28zRumoST
|
|
23
23
|
architect_py/graphql_client/search_symbols_query.py,sha256=hbGa6gF-gMWtRYQm2vlCTPDex8RWrJ4Yn4nT0VRQnCQ,614
|
24
24
|
architect_py/graphql_client/user_id_query.py,sha256=tWKJJLgEINzd8e7rYlGklQCnwcwHzYFpCGQvhxQGX20,334
|
25
25
|
architect_py/grpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
|
-
architect_py/grpc/client.py,sha256=
|
26
|
+
architect_py/grpc/client.py,sha256=qApYInm_eEhSFKYZRQ_EJyrV-PMA1AOhJ1PoArzGGvM,3597
|
27
27
|
architect_py/grpc/resolve_endpoint.py,sha256=r_PBWANIJJ47N5uyPcnefZ21ZE1-mzgACfCBfQpekg8,2621
|
28
28
|
architect_py/grpc/server.py,sha256=Abmdfe1eYbctVgzoJYBBBLpd7UD70FbYQLtJImSyRzs,1934
|
29
29
|
architect_py/grpc/utils.py,sha256=5sykLExUNZbcQHcxLCCM9DdOOiJJZcpputGrDtaMifY,667
|
30
30
|
architect_py/grpc/models/__init__.py,sha256=RrTLZvU7mNykDNp1oOm4-dekzab9ugIXd_my7Sm0Vx4,9153
|
31
|
-
architect_py/grpc/models/definitions.py,sha256=
|
31
|
+
architect_py/grpc/models/definitions.py,sha256=UB2-xXjoAM6ZTkNrsa1Q2-W_t6XUWHykP_R5tqzDcbc,77048
|
32
32
|
architect_py/grpc/models/Accounts/AccountsRequest.py,sha256=1a88cltSebOb53EdJ0hKEGR7FlmBiibrCtGzLTKqDBY,1524
|
33
33
|
architect_py/grpc/models/Accounts/AccountsResponse.py,sha256=DlXbkd3UbRybblBAfokw-K6nRvLNZgqz7cc0EKiW1zI,636
|
34
34
|
architect_py/grpc/models/Accounts/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
@@ -99,7 +99,7 @@ architect_py/grpc/models/Marketdata/MarketStatus.py,sha256=4Kt2z16t7dpjpiELWshJy
|
|
99
99
|
architect_py/grpc/models/Marketdata/MarketStatusRequest.py,sha256=ajyI4UlvFusyM0743dukT4KFZTlp9iUh0lTGWl6n7nw,1056
|
100
100
|
architect_py/grpc/models/Marketdata/SubscribeCandlesRequest.py,sha256=ck5pQx54uymlpR-jxFpxcW0LPDLU7R8GvqLqF-7GmoU,1508
|
101
101
|
architect_py/grpc/models/Marketdata/SubscribeCurrentCandlesRequest.py,sha256=QuSNIXARFT--djk_Kl3SUWHfUwAfaasqzZ0cyZfzeN0,1930
|
102
|
-
architect_py/grpc/models/Marketdata/SubscribeL1BookSnapshotsRequest.py,sha256=
|
102
|
+
architect_py/grpc/models/Marketdata/SubscribeL1BookSnapshotsRequest.py,sha256=Pq8tqLBHLwGbcJwWqKvurvRT3ARXVktLYWhyQtIeHX0,1855
|
103
103
|
architect_py/grpc/models/Marketdata/SubscribeL2BookUpdatesRequest.py,sha256=8olH2zWguzq1RnmIAZ59tFTmGIBLAYuGanbiI3kamm0,1133
|
104
104
|
architect_py/grpc/models/Marketdata/SubscribeLiquidationsRequest.py,sha256=6BhC4FJvHxm4yq9l_TmEioegdu8ZMFaoEA-bRC8WY7A,1039
|
105
105
|
architect_py/grpc/models/Marketdata/SubscribeManyCandlesRequest.py,sha256=pel2GGysDsJXjPY7rkyqqyGS3MPl13YezJS7apihiFc,1512
|
@@ -108,7 +108,7 @@ architect_py/grpc/models/Marketdata/SubscribeTradesRequest.py,sha256=7P8FyNx6wij
|
|
108
108
|
architect_py/grpc/models/Marketdata/Ticker.py,sha256=O4kJK1RyThYgfpvIr9mgRWAAkYgwwAKgOhEhbfDo9b4,11592
|
109
109
|
architect_py/grpc/models/Marketdata/TickerRequest.py,sha256=Ay--5JKgCfdvlVWD2H6YSa_66NC3Dt6c-XK8JkbWhus,1008
|
110
110
|
architect_py/grpc/models/Marketdata/TickerUpdate.py,sha256=sJ4wvCeGckMV30HwAcAsEMQbCzjN31OxF19q70jdxok,437
|
111
|
-
architect_py/grpc/models/Marketdata/TickersRequest.py,sha256=
|
111
|
+
architect_py/grpc/models/Marketdata/TickersRequest.py,sha256=x6UlQdAisnXgs3vbghQY3nuiFccSU3ueU0YJVAKaKUs,2359
|
112
112
|
architect_py/grpc/models/Marketdata/TickersResponse.py,sha256=CLzKx-ItwH9-Qq8YruFhXh7TmtHwzNRMEOPJ9LQD9co,574
|
113
113
|
architect_py/grpc/models/Marketdata/Trade.py,sha256=RKZq_HUDLxIE41caDrwf99V0c48kH2pm3XRCn5RLcEQ,2476
|
114
114
|
architect_py/grpc/models/Marketdata/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
@@ -170,28 +170,31 @@ architect_py/utils/orderbook.py,sha256=JM02NhHbmK3sNaS2Ara8FBY4TvKvtMIzJW1oVd8KC
|
|
170
170
|
architect_py/utils/pandas.py,sha256=QHz2ynj4T92FobuzRaNoH3ypArHoSDCiGtZ3PVXJ2vo,1017
|
171
171
|
architect_py/utils/price_bands.py,sha256=j7ioSA3dx025CD5E2Vg7XQvmjPvxQb-gzQBfQTovpTw,21874
|
172
172
|
architect_py/utils/symbol_parsing.py,sha256=OjJzk2c6QU2s0aJMSyVEzlWD5Vy-RlakJVW7jNHVDJk,845
|
173
|
-
architect_py-5.1.
|
173
|
+
architect_py-5.1.4b1.dist-info/licenses/LICENSE,sha256=6P0_5gYN8iPWPZeqA9nxiO3tRQmcSA1ijAVR7C8j1SI,11362
|
174
174
|
examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
175
|
-
examples/book_subscription.py,sha256=
|
176
|
-
examples/candles.py,sha256=
|
177
|
-
examples/
|
175
|
+
examples/book_subscription.py,sha256=1WFQN_QCE8cRS_CIv2k0NxqpK37fA9-Ja2Kfxs8vsb8,1461
|
176
|
+
examples/candles.py,sha256=T71TsxbfXCT6mrJZmTgdTKesJFdQhYP_4AsiNK-8KyQ,756
|
177
|
+
examples/config.py,sha256=rv6x7QYJO6ckvpRcwghyJbkL_lTBPnK0u6nKgkYTvxQ,1858
|
178
178
|
examples/external_cpty.py,sha256=xxGXONXwoWIS8ys0SgxHLSmntAi1BlwV2NR9WD1kvpc,2527
|
179
|
-
examples/funding_rate_mean_reversion_algo.py,sha256=
|
180
|
-
examples/order_sending.py,sha256=
|
181
|
-
examples/
|
182
|
-
examples/
|
183
|
-
examples/
|
184
|
-
examples/
|
185
|
-
examples/
|
179
|
+
examples/funding_rate_mean_reversion_algo.py,sha256=Y9zJ7N4TEm36TH3jIHMbDxucKOOlD2VHe5oNcLai11o,6502
|
180
|
+
examples/order_sending.py,sha256=0M5eK20nDO5KXJZV-yidC7HR_RHP3uJL9f-q9FF0BIs,3313
|
181
|
+
examples/orderflow_channel.py,sha256=L6W9aZS95Xmjl1IvrKA1Cp06r9-QOERsBETLOg3EImk,1891
|
182
|
+
examples/orderflow_streaming.py,sha256=BtVwCYWBCpytaAFN9u2WPgGCugyNMsGa6nA1dPWuVLs,1300
|
183
|
+
examples/stream_l1_marketdata.py,sha256=ZkXcm5XOpG6epPn3EhmqlVJyYBwh87I0QHtuOmKjRpg,728
|
184
|
+
examples/stream_l2_marketdata.py,sha256=AeVOBBLdg-0OQE0gouHiLaUfGAAmUoVxif9XBrRo1tQ,1091
|
185
|
+
examples/termutils.py,sha256=ZZrky5Ftn4UoLPKGffGvUl1Z8CtvDoNjEtUH4S1a_KY,1133
|
186
|
+
examples/trades.py,sha256=0OzWQVTuIrC0KlisY0Tc-3pmWNP0m0-eCSntCV6Qdh8,561
|
187
|
+
examples/tutorial_async.py,sha256=FNMjP2WmszRB0OXoMbshJ775LoPDzm55UZICa9ztr5w,2639
|
188
|
+
examples/tutorial_sync.py,sha256=w5Sqa0YFh0XnpoXuhD3WsKRKpR5cuTTNb7pCp-Aqnz0,2846
|
186
189
|
scripts/add_imports_to_inits.py,sha256=bryhz6RpKAJsSieVMnXnRyLp8evNkpOsNUkBUPkk1WQ,4518
|
187
|
-
scripts/correct_sync_interface.py,sha256=
|
190
|
+
scripts/correct_sync_interface.py,sha256=gTSJLDAT8s-ayN_JqgKbeM6c3DYZOapduS_GIqrvD-A,4134
|
188
191
|
scripts/generate_functions_md.py,sha256=-rVRhbHlDodGH2a32UCsMLIpgXtDvOhBmkHa0RqDpCA,6232
|
189
192
|
scripts/postprocess_grpc.py,sha256=QqFZdOLH6hLPRCLUkf7qvuGooLsXulcpMghCpleHc-A,23198
|
190
193
|
scripts/preprocess_grpc_schema.py,sha256=p9LdoMZzixBSsVx7Dy3_8uJzOy_QwCoVMkAABQKUsBA,22894
|
191
194
|
scripts/prune_graphql_schema.py,sha256=hmfw5FD_iKGKMFkq6H1neZiXXtljFFrOwi2fiusTWE4,6210
|
192
195
|
templates/exceptions.py,sha256=tIHbiO5Q114h9nPwJXsgHvW_bERLwxuNp9Oj41p6t3A,2379
|
193
196
|
templates/juniper_base_client.py,sha256=B8QF4IFSwqBK5UY2aFPbSdYnX9bcwnlxLK4ojPRaW0E,12705
|
194
|
-
architect_py-5.1.
|
195
|
-
architect_py-5.1.
|
196
|
-
architect_py-5.1.
|
197
|
-
architect_py-5.1.
|
197
|
+
architect_py-5.1.4b1.dist-info/METADATA,sha256=T9t4zgT065VEpW9f1WGsCXkUNK_O1UQimeeqfrem1uY,2640
|
198
|
+
architect_py-5.1.4b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
199
|
+
architect_py-5.1.4b1.dist-info/top_level.txt,sha256=UjtO97OACFQ9z5MzS-X2wBlt5Ovk1vxakQPKfokI454,40
|
200
|
+
architect_py-5.1.4b1.dist-info/RECORD,,
|
examples/book_subscription.py
CHANGED
@@ -6,7 +6,7 @@ from pydantic import ValidationError
|
|
6
6
|
from architect_py import AsyncClient, TradableProduct
|
7
7
|
from architect_py.graphql_client.exceptions import GraphQLClientHttpError
|
8
8
|
|
9
|
-
from .
|
9
|
+
from .config import connect_async_client
|
10
10
|
|
11
11
|
buy_columns = "{:>15} {:>15} {:>15}"
|
12
12
|
sell_columns = "{:<15} {:<15} {:<15}"
|
examples/candles.py
CHANGED
@@ -3,7 +3,7 @@ import asyncio
|
|
3
3
|
from architect_py import AsyncClient, CandleWidth, TradableProduct
|
4
4
|
from architect_py.graphql_client.exceptions import GraphQLClientHttpError
|
5
5
|
|
6
|
-
from .
|
6
|
+
from .config import connect_async_client
|
7
7
|
|
8
8
|
|
9
9
|
async def main():
|
examples/{common.py → config.py}
RENAMED
@@ -16,15 +16,17 @@ class Config:
|
|
16
16
|
|
17
17
|
def load_config() -> Config:
|
18
18
|
loaded = load_dotenv()
|
19
|
+
|
19
20
|
if not loaded:
|
20
21
|
raise ValueError(
|
21
|
-
"⚠️ .env file not found or had no new variables\n"
|
22
|
-
"Please create a .env file with the following variables:\n"
|
22
|
+
"⚠️ .env file not found or had no new variables\n\n"
|
23
|
+
"Please create a .env file with the following variables:\n\n"
|
23
24
|
"ARCHITECT_ENDPOINT=your_endpoint (e.g. app.architect.co)\n"
|
24
25
|
"ARCHITECT_API_KEY=your_api_key (get from https://app.architect.co/user/account)\n"
|
25
26
|
"ARCHITECT_API_SECRET=your_api_secret\n"
|
26
27
|
"ARCHITECT_PAPER_TRADING=true/false\n"
|
27
28
|
)
|
29
|
+
|
28
30
|
endpoint = os.environ["ARCHITECT_ENDPOINT"]
|
29
31
|
api_key = os.getenv("ARCHITECT_API_KEY")
|
30
32
|
api_secret = os.getenv("ARCHITECT_API_SECRET")
|
@@ -49,7 +51,6 @@ def load_config() -> Config:
|
|
49
51
|
|
50
52
|
def connect_client():
|
51
53
|
config = load_config()
|
52
|
-
|
53
54
|
c = Client(
|
54
55
|
endpoint=config.endpoint,
|
55
56
|
api_key=config.api_key,
|
@@ -68,48 +69,3 @@ async def connect_async_client():
|
|
68
69
|
paper_trading=config.paper_trading,
|
69
70
|
)
|
70
71
|
return c
|
71
|
-
|
72
|
-
|
73
|
-
buy_columns = "{:>15} {:>15} {:>15}"
|
74
|
-
sell_columns = "{:<15} {:<15} {:<15}"
|
75
|
-
green = "\033[32m"
|
76
|
-
red = "\033[31m"
|
77
|
-
normal = "\033[0m"
|
78
|
-
|
79
|
-
|
80
|
-
def print_book(book):
|
81
|
-
print(
|
82
|
-
(buy_columns + " " + sell_columns).format(
|
83
|
-
"Total", "Size", "Bid", "Ask", "Size", "Total"
|
84
|
-
)
|
85
|
-
)
|
86
|
-
for i in range(min(20, len(book.bids), len(book.asks))):
|
87
|
-
b = book.bids[i]
|
88
|
-
s = book.asks[i]
|
89
|
-
print(
|
90
|
-
(green + buy_columns).format(b.total, b.amount, b.price),
|
91
|
-
(red + sell_columns).format(s.price, s.amount, s.total),
|
92
|
-
)
|
93
|
-
print(normal)
|
94
|
-
|
95
|
-
|
96
|
-
def print_open_orders(orders):
|
97
|
-
if len(orders) == 0:
|
98
|
-
print("No open orders")
|
99
|
-
else:
|
100
|
-
for o in orders:
|
101
|
-
print(
|
102
|
-
f" • {o.order.market.name} {o.order.dir} {o.order.quantity} {o.order.order_type.limit_price}"
|
103
|
-
)
|
104
|
-
|
105
|
-
|
106
|
-
def confirm(prompt: str):
|
107
|
-
"""
|
108
|
-
Ask user to enter Y or N (case-insensitive).
|
109
|
-
:return: True if the answer is Y.
|
110
|
-
:rtype: bool
|
111
|
-
"""
|
112
|
-
answer = ""
|
113
|
-
while answer not in ["y", "n"]:
|
114
|
-
answer = input(f"{prompt} [Y/N]? ").lower()
|
115
|
-
return answer == "y"
|
examples/order_sending.py
CHANGED
@@ -4,7 +4,7 @@ from datetime import datetime, timedelta, timezone
|
|
4
4
|
from decimal import Decimal
|
5
5
|
|
6
6
|
from architect_py import AsyncClient, OrderDir, OrderType, TimeInForce, TradableProduct
|
7
|
-
from examples.
|
7
|
+
from examples.config import connect_async_client
|
8
8
|
|
9
9
|
LOGGER = logging.getLogger(__name__)
|
10
10
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# """
|
2
|
+
# Example of using a bidirectional orderflow channel with the Architect OEMS.
|
3
|
+
|
4
|
+
# This connection style is ~equivalent to having a websocket.
|
5
|
+
|
6
|
+
# This code example sends a series of orders to Architect while concurrently
|
7
|
+
# listening to orderflow events. Compare to `examples/orderflow_streaming.py`,
|
8
|
+
# which accomplishes the same thing but using a separate asyncio task.
|
9
|
+
# """
|
10
|
+
|
11
|
+
# import asyncio
|
12
|
+
# from decimal import Decimal
|
13
|
+
|
14
|
+
# from architect_py import AsyncClient, OrderDir, PlaceOrderRequest
|
15
|
+
# from architect_py.grpc.models.Orderflow.OrderflowRequest import PlaceOrder
|
16
|
+
|
17
|
+
# from .config import connect_async_client
|
18
|
+
|
19
|
+
|
20
|
+
# async def send_orders(client: AsyncClient):
|
21
|
+
# symbol = await client.get_front_future("ES CME Futures")
|
22
|
+
# print(f"symbol={symbol}")
|
23
|
+
|
24
|
+
# while True:
|
25
|
+
# await asyncio.sleep(1)
|
26
|
+
# snap = await client.get_l1_book_snapshot(symbol, "CME")
|
27
|
+
# if snap.best_ask is not None:
|
28
|
+
# limit_price = snap.best_ask[0]
|
29
|
+
# print(f"\nPlacing buy order at {limit_price}\n")
|
30
|
+
# try:
|
31
|
+
# req = PlaceOrderRequest.new(
|
32
|
+
# symbol=symbol,
|
33
|
+
# execution_venue="CME",
|
34
|
+
# dir=OrderDir.BUY,
|
35
|
+
# quantity=Decimal(1),
|
36
|
+
# limit_price=limit_price,
|
37
|
+
# post_only=True,
|
38
|
+
# time_in_force="DAY",
|
39
|
+
# order_type="LIMIT",
|
40
|
+
# )
|
41
|
+
# print(f"req={req}")
|
42
|
+
# yield PlaceOrder(req)
|
43
|
+
# except Exception as e:
|
44
|
+
# print(f"Error placing order: {e}")
|
45
|
+
# else:
|
46
|
+
# print("\nNo ask price from snapshot, doing nothing\n")
|
47
|
+
|
48
|
+
|
49
|
+
# async def main():
|
50
|
+
# client = await connect_async_client()
|
51
|
+
|
52
|
+
# async for event in client.orderflow(send_orders(client)):
|
53
|
+
# print(f" --> {event}")
|
54
|
+
|
55
|
+
|
56
|
+
# asyncio.run(main())
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"""
|
2
|
+
Example of streaming orderflow events from the Architect OEMS.
|
3
|
+
|
4
|
+
This code example sends a series of orders to Architect in one asyncio
|
5
|
+
task, while concurrently listening to orderflow events in another.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
from decimal import Decimal
|
10
|
+
|
11
|
+
from architect_py import AsyncClient, OrderDir
|
12
|
+
|
13
|
+
from .config import connect_async_client
|
14
|
+
|
15
|
+
|
16
|
+
async def send_orders(client: AsyncClient):
|
17
|
+
symbol = await client.get_front_future("ES CME Futures")
|
18
|
+
print(f"symbol={symbol}")
|
19
|
+
|
20
|
+
while True:
|
21
|
+
await asyncio.sleep(1)
|
22
|
+
snap = await client.get_l1_book_snapshot(symbol, "CME")
|
23
|
+
if snap.best_ask is not None:
|
24
|
+
limit_price = snap.best_ask[0]
|
25
|
+
print(f"\nPlacing buy order at {limit_price}\n")
|
26
|
+
await client.place_limit_order(
|
27
|
+
symbol=symbol,
|
28
|
+
execution_venue="CME",
|
29
|
+
dir=OrderDir.BUY,
|
30
|
+
quantity=Decimal(1),
|
31
|
+
limit_price=limit_price,
|
32
|
+
post_only=True,
|
33
|
+
)
|
34
|
+
else:
|
35
|
+
print("\nNo ask price from snapshot, doing nothing\n")
|
36
|
+
|
37
|
+
|
38
|
+
async def main():
|
39
|
+
client = await connect_async_client()
|
40
|
+
|
41
|
+
asyncio.create_task(send_orders(client))
|
42
|
+
|
43
|
+
async for event in client.stream_orderflow():
|
44
|
+
print(f" --> {event}")
|
45
|
+
|
46
|
+
|
47
|
+
asyncio.run(main())
|
examples/stream_l1_marketdata.py
CHANGED
examples/stream_l2_marketdata.py
CHANGED
examples/termutils.py
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
buy_columns = "{:>15} {:>15} {:>15}"
|
2
|
+
sell_columns = "{:<15} {:<15} {:<15}"
|
3
|
+
green = "\033[32m"
|
4
|
+
red = "\033[31m"
|
5
|
+
normal = "\033[0m"
|
6
|
+
|
7
|
+
|
8
|
+
def print_book(book):
|
9
|
+
print(
|
10
|
+
(buy_columns + " " + sell_columns).format(
|
11
|
+
"Total", "Size", "Bid", "Ask", "Size", "Total"
|
12
|
+
)
|
13
|
+
)
|
14
|
+
for i in range(min(20, len(book.bids), len(book.asks))):
|
15
|
+
b = book.bids[i]
|
16
|
+
s = book.asks[i]
|
17
|
+
print(
|
18
|
+
(green + buy_columns).format(b.total, b.amount, b.price),
|
19
|
+
(red + sell_columns).format(s.price, s.amount, s.total),
|
20
|
+
)
|
21
|
+
print(normal)
|
22
|
+
|
23
|
+
|
24
|
+
def print_open_orders(orders):
|
25
|
+
if len(orders) == 0:
|
26
|
+
print("No open orders")
|
27
|
+
else:
|
28
|
+
for o in orders:
|
29
|
+
print(
|
30
|
+
f" • {o.order.market.name} {o.order.dir} {o.order.quantity} {o.order.order_type.limit_price}"
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
def confirm(prompt: str):
|
35
|
+
"""
|
36
|
+
Ask user to enter Y or N (case-insensitive).
|
37
|
+
|
38
|
+
:return: True if the answer is Y.
|
39
|
+
:rtype: bool
|
40
|
+
"""
|
41
|
+
answer = ""
|
42
|
+
while answer not in ["y", "n"]:
|
43
|
+
answer = input(f"{prompt} [Y/N]? ").lower()
|
44
|
+
return answer == "y"
|
examples/trades.py
CHANGED
examples/tutorial_async.py
CHANGED
examples/tutorial_sync.py
CHANGED
@@ -5,7 +5,8 @@ from decimal import Decimal
|
|
5
5
|
from architect_py import OrderDir, OrderStatus
|
6
6
|
from architect_py.utils.nearest_tick import TickRoundMethod
|
7
7
|
|
8
|
-
from .
|
8
|
+
from .config import connect_client
|
9
|
+
from .termutils import confirm, print_book, print_open_orders
|
9
10
|
|
10
11
|
c = connect_client()
|
11
12
|
|
@@ -65,8 +65,11 @@ def add_correct_docstring_and_correct_the_init(content: str):
|
|
65
65
|
param_parts = [str(p) for p in pos_params]
|
66
66
|
|
67
67
|
# turn Optional[Type] into Type | None
|
68
|
-
opt_re = re.compile(r"\b(?:Optional|Option)\[(
|
69
|
-
param_parts = [
|
68
|
+
opt_re = re.compile(r"\b(?:Optional|Option)\[(.+)]", re.DOTALL)
|
69
|
+
param_parts = [
|
70
|
+
opt_re.sub(lambda m: f"{m.group(1)} | None", s) # Optional[T] → T | None
|
71
|
+
for s in param_parts
|
72
|
+
]
|
70
73
|
|
71
74
|
param_str = ", ".join(param_parts)
|
72
75
|
|
File without changes
|
File without changes
|
File without changes
|