architect-py 5.1.4rc1__py3-none-any.whl → 5.1.5__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 +56 -11
- architect_py/client.pyi +14 -3
- architect_py/grpc/models/Core/ConfigResponse.py +7 -2
- architect_py/grpc/models/Folio/AccountSummary.py +7 -1
- architect_py/grpc/models/Marketdata/Candle.py +6 -0
- architect_py/grpc/models/Marketdata/L1BookSnapshot.py +6 -0
- architect_py/grpc/models/Marketdata/L2BookSnapshot.py +6 -0
- architect_py/grpc/models/Marketdata/Liquidation.py +6 -0
- architect_py/grpc/models/Marketdata/Ticker.py +6 -0
- architect_py/grpc/models/Marketdata/Trade.py +6 -0
- architect_py/grpc/models/definitions.py +20 -0
- architect_py/tests/test_positions.py +173 -0
- architect_py/tests/test_rounding.py +28 -28
- architect_py/utils/pandas.py +50 -1
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.5.dist-info}/METADATA +1 -1
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.5.dist-info}/RECORD +20 -19
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.5.dist-info}/WHEEL +0 -0
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.5.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.1.4rc1.dist-info → architect_py-5.1.5.dist-info}/top_level.txt +0 -0
architect_py/__init__.py
CHANGED
architect_py/async_client.py
CHANGED
@@ -44,7 +44,7 @@ from architect_py.grpc.orderflow import OrderflowChannel
|
|
44
44
|
from architect_py.grpc.resolve_endpoint import PAPER_GRPC_PORT, resolve_endpoint
|
45
45
|
from architect_py.utils.nearest_tick import TickRoundMethod
|
46
46
|
from architect_py.utils.orderbook import update_orderbook_side
|
47
|
-
from architect_py.utils.pandas import candles_to_dataframe
|
47
|
+
from architect_py.utils.pandas import candles_to_dataframe, tickers_to_dataframe
|
48
48
|
from architect_py.utils.price_bands import price_band_pairs
|
49
49
|
from architect_py.utils.symbol_parsing import nominative_expiration
|
50
50
|
|
@@ -890,6 +890,37 @@ class AsyncClient:
|
|
890
890
|
res: Ticker = await grpc_client.unary_unary(req)
|
891
891
|
return res
|
892
892
|
|
893
|
+
async def get_tickers(
|
894
|
+
self,
|
895
|
+
*,
|
896
|
+
venue: Venue,
|
897
|
+
symbols: Optional[Sequence[TradableProduct | str]] = None,
|
898
|
+
include_options: bool = False,
|
899
|
+
sort_by: Optional[SortTickersBy | str] = None,
|
900
|
+
offset: Optional[int] = None,
|
901
|
+
limit: Optional[int] = None,
|
902
|
+
as_dataframe: bool = False,
|
903
|
+
) -> Union[Sequence[Ticker], pd.DataFrame]:
|
904
|
+
"""
|
905
|
+
Gets the tickers for a list of symbols.
|
906
|
+
"""
|
907
|
+
grpc_client = await self.marketdata(venue)
|
908
|
+
sort_by = SortTickersBy(sort_by) if sort_by else None
|
909
|
+
symbols = [str(symbol) for symbol in symbols] if symbols else None
|
910
|
+
req = TickersRequest.new(
|
911
|
+
offset=offset,
|
912
|
+
include_options=include_options,
|
913
|
+
sort_by=sort_by,
|
914
|
+
limit=limit,
|
915
|
+
symbols=symbols,
|
916
|
+
venue=venue,
|
917
|
+
)
|
918
|
+
res: TickersResponse = await grpc_client.unary_unary(req)
|
919
|
+
if as_dataframe:
|
920
|
+
return tickers_to_dataframe(res.tickers)
|
921
|
+
else:
|
922
|
+
return res.tickers
|
923
|
+
|
893
924
|
async def stream_l1_book_snapshots(
|
894
925
|
self,
|
895
926
|
symbols: Sequence[TradableProduct | str],
|
@@ -1151,6 +1182,27 @@ class AsyncClient:
|
|
1151
1182
|
res = await grpc_client.unary_unary(req)
|
1152
1183
|
return res
|
1153
1184
|
|
1185
|
+
async def get_positions(
|
1186
|
+
self,
|
1187
|
+
accounts: Optional[list[str]] = None,
|
1188
|
+
trader: Optional[str] = None,
|
1189
|
+
) -> dict[str, Decimal]:
|
1190
|
+
"""
|
1191
|
+
Get positions for the specified symbols.
|
1192
|
+
|
1193
|
+
Args:
|
1194
|
+
symbols: list of symbol strings
|
1195
|
+
"""
|
1196
|
+
account_summaries = await self.get_account_summaries(
|
1197
|
+
accounts=accounts, trader=trader
|
1198
|
+
)
|
1199
|
+
positions: dict[str, Decimal] = {}
|
1200
|
+
for summary in account_summaries:
|
1201
|
+
for symbol, summary in summary.positions.items():
|
1202
|
+
for pos in summary:
|
1203
|
+
positions[symbol] = positions.get(symbol, Decimal(0)) + pos.quantity
|
1204
|
+
return positions
|
1205
|
+
|
1154
1206
|
async def get_account_summaries(
|
1155
1207
|
self,
|
1156
1208
|
accounts: Optional[list[str]] = None,
|
@@ -1531,7 +1583,7 @@ class AsyncClient:
|
|
1531
1583
|
execution_venue: Optional[str] = None,
|
1532
1584
|
dir: OrderDir,
|
1533
1585
|
quantity: Decimal,
|
1534
|
-
limit_price: Decimal,
|
1586
|
+
limit_price: Optional[Decimal] = None,
|
1535
1587
|
order_type: OrderType = OrderType.LIMIT,
|
1536
1588
|
time_in_force: TimeInForce = TimeInForce.DAY,
|
1537
1589
|
price_round_method: Optional[TickRoundMethod] = None,
|
@@ -1563,7 +1615,7 @@ class AsyncClient:
|
|
1563
1615
|
While technically optional, for most order types, the account is required
|
1564
1616
|
trader: the trader to send the order for, defaults to the user's trader
|
1565
1617
|
for when sending order for another user, not relevant for vast majority of users
|
1566
|
-
post_only: whether the order should be post only,
|
1618
|
+
post_only: whether the order should be post only, NOT SUPPORTED BY ALL EXCHANGES (e.g. CME)
|
1567
1619
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
1568
1620
|
stop_loss_price: the stop loss price for a bracket order.
|
1569
1621
|
profit_price: the take profit price for a bracket order.
|
@@ -1576,14 +1628,7 @@ class AsyncClient:
|
|
1576
1628
|
grpc_client = await self.core()
|
1577
1629
|
assert quantity > 0, "quantity must be positive"
|
1578
1630
|
|
1579
|
-
if
|
1580
|
-
if "odir" in kwargs and isinstance(kwargs["odir"], OrderDir):
|
1581
|
-
logging.warning("odir is deprecated, use dir instead")
|
1582
|
-
dir = kwargs["odir"]
|
1583
|
-
else:
|
1584
|
-
raise ValueError("dir is required")
|
1585
|
-
|
1586
|
-
if price_round_method is not None:
|
1631
|
+
if limit_price is not None and price_round_method is not None:
|
1587
1632
|
if execution_venue is None:
|
1588
1633
|
product_info = await self.get_product_info(symbol)
|
1589
1634
|
if product_info is None:
|
architect_py/client.pyi
CHANGED
@@ -14,7 +14,7 @@ from architect_py.grpc.orderflow import OrderflowChannel as OrderflowChannel
|
|
14
14
|
from architect_py.grpc.resolve_endpoint import PAPER_GRPC_PORT as PAPER_GRPC_PORT, resolve_endpoint as resolve_endpoint
|
15
15
|
from architect_py.utils.nearest_tick import TickRoundMethod as TickRoundMethod
|
16
16
|
from architect_py.utils.orderbook import update_orderbook_side as update_orderbook_side
|
17
|
-
from architect_py.utils.pandas import candles_to_dataframe as candles_to_dataframe
|
17
|
+
from architect_py.utils.pandas import candles_to_dataframe as candles_to_dataframe, tickers_to_dataframe as tickers_to_dataframe
|
18
18
|
from architect_py.utils.price_bands import price_band_pairs as price_band_pairs
|
19
19
|
from architect_py.utils.symbol_parsing import nominative_expiration as nominative_expiration
|
20
20
|
from datetime import date, datetime
|
@@ -353,6 +353,10 @@ class Client:
|
|
353
353
|
"""
|
354
354
|
Gets the ticker for a symbol.
|
355
355
|
"""
|
356
|
+
def get_tickers(self, *, venue: Venue, symbols: Sequence[TradableProduct | str] | None = None, include_options: bool = False, sort_by: SortTickersBy | str | None = None, offset: int | None = None, limit: int | None = None, as_dataframe: bool = False) -> Sequence[Ticker] | pd.DataFrame:
|
357
|
+
"""
|
358
|
+
Gets the tickers for a list of symbols.
|
359
|
+
"""
|
356
360
|
def list_accounts(self) -> list[AccountWithPermissions]:
|
357
361
|
"""
|
358
362
|
List accounts for the user that the API key belongs to.
|
@@ -370,6 +374,13 @@ class Client:
|
|
370
374
|
account: account uuid or name
|
371
375
|
Examples: "00000000-0000-0000-0000-000000000000", "STONEX:000000/JDoe"
|
372
376
|
'''
|
377
|
+
def get_positions(self, accounts: list[str] | None = None, trader: str | None = None) -> dict[str, Decimal]:
|
378
|
+
"""
|
379
|
+
Get positions for the specified symbols.
|
380
|
+
|
381
|
+
Args:
|
382
|
+
symbols: list of symbol strings
|
383
|
+
"""
|
373
384
|
def get_account_summaries(self, accounts: list[str] | None = None, trader: str | None = None) -> list[AccountSummary]:
|
374
385
|
"""
|
375
386
|
Get account summaries for accounts matching the filters.
|
@@ -489,7 +500,7 @@ class Client:
|
|
489
500
|
trigger_price=trigger_price,
|
490
501
|
)
|
491
502
|
"""
|
492
|
-
def place_order(self, *, id: OrderId | None = None, symbol: TradableProduct | str, execution_venue: str | None = None, dir: OrderDir, quantity: Decimal, limit_price: Decimal, order_type: OrderType = ..., time_in_force: TimeInForce = ..., price_round_method: TickRoundMethod | None = None, account: str | None = None, trader: str | None = None, post_only: bool | None = None, trigger_price: Decimal | None = None, stop_loss: TriggerLimitOrderType | None = None, take_profit_price: Decimal | None = None, **kwargs: Any) -> Order:
|
503
|
+
def place_order(self, *, id: OrderId | None = None, symbol: TradableProduct | str, execution_venue: str | None = None, dir: OrderDir, quantity: Decimal, limit_price: Decimal | None = None, order_type: OrderType = ..., time_in_force: TimeInForce = ..., price_round_method: TickRoundMethod | None = None, account: str | None = None, trader: str | None = None, post_only: bool | None = None, trigger_price: Decimal | None = None, stop_loss: TriggerLimitOrderType | None = None, take_profit_price: Decimal | None = None, **kwargs: Any) -> Order:
|
493
504
|
'''
|
494
505
|
Sends a regular order.
|
495
506
|
|
@@ -510,7 +521,7 @@ class Client:
|
|
510
521
|
While technically optional, for most order types, the account is required
|
511
522
|
trader: the trader to send the order for, defaults to the user\'s trader
|
512
523
|
for when sending order for another user, not relevant for vast majority of users
|
513
|
-
post_only: whether the order should be post only,
|
524
|
+
post_only: whether the order should be post only, NOT SUPPORTED BY ALL EXCHANGES (e.g. CME)
|
514
525
|
trigger_price: the trigger price for the order, only relevant for stop / take_profit orders
|
515
526
|
stop_loss_price: the stop loss price for a bracket order.
|
516
527
|
profit_price: the take profit price for a bracket order.
|
@@ -3,23 +3,28 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import Dict
|
6
|
+
from typing import Dict, Optional
|
7
7
|
|
8
8
|
from msgspec import Struct
|
9
9
|
|
10
10
|
|
11
11
|
class ConfigResponse(Struct, omit_defaults=True):
|
12
12
|
marketdata: Dict[str, str]
|
13
|
+
symbology: Optional[str] = None
|
13
14
|
|
14
15
|
# Constructor that takes all field titles as arguments for convenience
|
15
16
|
@classmethod
|
16
17
|
def new(
|
17
18
|
cls,
|
18
19
|
marketdata: Dict[str, str],
|
20
|
+
symbology: Optional[str] = None,
|
19
21
|
):
|
20
22
|
return cls(
|
21
23
|
marketdata,
|
24
|
+
symbology,
|
22
25
|
)
|
23
26
|
|
24
27
|
def __str__(self) -> str:
|
25
|
-
return
|
28
|
+
return (
|
29
|
+
f"ConfigResponse(marketdata={self.marketdata},symbology={self.symbology})"
|
30
|
+
)
|
@@ -15,7 +15,13 @@ from .. import definitions
|
|
15
15
|
class AccountSummary(Struct, omit_defaults=True):
|
16
16
|
account: str
|
17
17
|
balances: Dict[str, Decimal]
|
18
|
-
positions:
|
18
|
+
positions: Annotated[
|
19
|
+
Dict[str, List[definitions.AccountPosition]],
|
20
|
+
Meta(description="map from TradableProduct to a list of AccountPosition"),
|
21
|
+
]
|
22
|
+
"""
|
23
|
+
map from TradableProduct to a list of AccountPosition
|
24
|
+
"""
|
19
25
|
timestamp: datetime
|
20
26
|
cash_excess: Optional[
|
21
27
|
Annotated[Optional[Decimal], Meta(description="Cash available to withdraw.")]
|
@@ -136,10 +136,16 @@ class Candle(Struct, omit_defaults=True):
|
|
136
136
|
|
137
137
|
@property
|
138
138
|
def datetime(self) -> datetime:
|
139
|
+
"""
|
140
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
141
|
+
"""
|
139
142
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
140
143
|
|
141
144
|
@property
|
142
145
|
def datetime_local(self) -> datetime:
|
146
|
+
"""
|
147
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
148
|
+
"""
|
143
149
|
return datetime.fromtimestamp(self.ts)
|
144
150
|
|
145
151
|
@property
|
@@ -103,10 +103,16 @@ class L1BookSnapshot(Struct, omit_defaults=True):
|
|
103
103
|
|
104
104
|
@property
|
105
105
|
def datetime(self) -> datetime:
|
106
|
+
"""
|
107
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
108
|
+
"""
|
106
109
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
107
110
|
|
108
111
|
@property
|
109
112
|
def datetime_local(self) -> datetime:
|
113
|
+
"""
|
114
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
115
|
+
"""
|
110
116
|
return datetime.fromtimestamp(self.ts)
|
111
117
|
|
112
118
|
@property
|
@@ -100,8 +100,14 @@ class L2BookSnapshot(Struct, omit_defaults=True):
|
|
100
100
|
|
101
101
|
@property
|
102
102
|
def datetime(self) -> datetime:
|
103
|
+
"""
|
104
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
105
|
+
"""
|
103
106
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
104
107
|
|
105
108
|
@property
|
106
109
|
def datetime_local(self) -> datetime:
|
110
|
+
"""
|
111
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
112
|
+
"""
|
107
113
|
return datetime.fromtimestamp(self.ts)
|
@@ -93,8 +93,14 @@ class Liquidation(Struct, omit_defaults=True):
|
|
93
93
|
|
94
94
|
@property
|
95
95
|
def datetime(self) -> datetime:
|
96
|
+
"""
|
97
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
98
|
+
"""
|
96
99
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
97
100
|
|
98
101
|
@property
|
99
102
|
def datetime_local(self) -> datetime:
|
103
|
+
"""
|
104
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
105
|
+
"""
|
100
106
|
return datetime.fromtimestamp(self.ts)
|
@@ -155,10 +155,16 @@ class Ticker(Struct, omit_defaults=True):
|
|
155
155
|
|
156
156
|
@property
|
157
157
|
def datetime(self) -> datetime:
|
158
|
+
"""
|
159
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
160
|
+
"""
|
158
161
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
159
162
|
|
160
163
|
@property
|
161
164
|
def datetime_local(self) -> datetime:
|
165
|
+
"""
|
166
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
167
|
+
"""
|
162
168
|
return datetime.fromtimestamp(self.ts)
|
163
169
|
|
164
170
|
@property
|
@@ -85,10 +85,16 @@ class Trade(Struct, omit_defaults=True):
|
|
85
85
|
|
86
86
|
@property
|
87
87
|
def datetime(self) -> datetime:
|
88
|
+
"""
|
89
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
90
|
+
"""
|
88
91
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
89
92
|
|
90
93
|
@property
|
91
94
|
def datetime_local(self) -> datetime:
|
95
|
+
"""
|
96
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
97
|
+
"""
|
92
98
|
return datetime.fromtimestamp(self.ts)
|
93
99
|
|
94
100
|
@property
|
@@ -422,10 +422,16 @@ class L2BookDiff(Struct, omit_defaults=True):
|
|
422
422
|
|
423
423
|
@property
|
424
424
|
def datetime(self) -> datetime:
|
425
|
+
"""
|
426
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
427
|
+
"""
|
425
428
|
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
426
429
|
|
427
430
|
@property
|
428
431
|
def datetime_local(self) -> datetime:
|
432
|
+
"""
|
433
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
434
|
+
"""
|
429
435
|
return datetime.fromtimestamp(self.ts)
|
430
436
|
|
431
437
|
|
@@ -1854,6 +1860,20 @@ class Fill(Struct, omit_defaults=True):
|
|
1854
1860
|
def trade_time(self, value: int) -> None:
|
1855
1861
|
self.ts = value
|
1856
1862
|
|
1863
|
+
@property
|
1864
|
+
def datetime(self) -> datetime:
|
1865
|
+
"""
|
1866
|
+
Convenience property to get the timestamp as a datetime object in UTC.
|
1867
|
+
"""
|
1868
|
+
return datetime.fromtimestamp(self.ts, tz=timezone.utc)
|
1869
|
+
|
1870
|
+
@property
|
1871
|
+
def datetime_local(self) -> datetime:
|
1872
|
+
"""
|
1873
|
+
Convenience property to get the timestamp as a datetime object in local time.
|
1874
|
+
"""
|
1875
|
+
return datetime.fromtimestamp(self.ts)
|
1876
|
+
|
1857
1877
|
@property
|
1858
1878
|
def execution_venue(self) -> str:
|
1859
1879
|
return self.x
|
@@ -0,0 +1,173 @@
|
|
1
|
+
import asyncio
|
2
|
+
from decimal import Decimal
|
3
|
+
|
4
|
+
import pytest
|
5
|
+
|
6
|
+
from architect_py.async_client import AsyncClient, OrderDir, OrderType
|
7
|
+
|
8
|
+
|
9
|
+
@pytest.mark.asyncio
|
10
|
+
@pytest.mark.timeout(10)
|
11
|
+
async def test_positions(async_client: AsyncClient):
|
12
|
+
if not async_client.paper_trading:
|
13
|
+
return
|
14
|
+
|
15
|
+
accounts = await async_client.list_accounts()
|
16
|
+
|
17
|
+
assert len(accounts) == 1, (
|
18
|
+
f"Expected exactly one account in paper trading mode, got {len(accounts)}"
|
19
|
+
)
|
20
|
+
account_id = accounts[0].account.id
|
21
|
+
front_ES_future = await async_client.get_front_future("ES CME Futures", "CME")
|
22
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
23
|
+
ES_position = positions.get(front_ES_future)
|
24
|
+
|
25
|
+
# flatten position
|
26
|
+
if ES_position is not None:
|
27
|
+
flatten_direction = OrderDir.SELL if ES_position > Decimal(0) else OrderDir.BUY
|
28
|
+
|
29
|
+
order = await async_client.place_order(
|
30
|
+
symbol=front_ES_future,
|
31
|
+
venue="CME",
|
32
|
+
dir=flatten_direction,
|
33
|
+
quantity=Decimal(value="1"),
|
34
|
+
account=account_id,
|
35
|
+
order_type=OrderType.MARKET,
|
36
|
+
)
|
37
|
+
while True:
|
38
|
+
open_orders = await async_client.get_open_orders(order_ids=[order.id])
|
39
|
+
if not open_orders:
|
40
|
+
break
|
41
|
+
await asyncio.sleep(0.2)
|
42
|
+
|
43
|
+
fills = await async_client.get_fills(order_id=order.id)
|
44
|
+
assert len(fills.fills) == 1, "Expected exactly one fill for the order"
|
45
|
+
assert fills.fills[0].dir == flatten_direction, (
|
46
|
+
"Fill direction does not match order direction"
|
47
|
+
)
|
48
|
+
|
49
|
+
# go long
|
50
|
+
order = await async_client.place_order(
|
51
|
+
symbol=front_ES_future,
|
52
|
+
venue="CME",
|
53
|
+
dir=OrderDir.BUY,
|
54
|
+
quantity=Decimal(value="5"),
|
55
|
+
account=account_id,
|
56
|
+
order_type=OrderType.MARKET,
|
57
|
+
)
|
58
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
59
|
+
assert positions.get(front_ES_future) == Decimal(5), (
|
60
|
+
f"Expected position in {front_ES_future} to be 5, got {positions.get(front_ES_future)}"
|
61
|
+
)
|
62
|
+
|
63
|
+
# go long to flat
|
64
|
+
order = await async_client.place_order(
|
65
|
+
symbol=front_ES_future,
|
66
|
+
venue="CME",
|
67
|
+
dir=OrderDir.SELL,
|
68
|
+
quantity=Decimal(value="5"),
|
69
|
+
account=account_id,
|
70
|
+
order_type=OrderType.MARKET,
|
71
|
+
)
|
72
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
73
|
+
assert positions.get(front_ES_future) is None, (
|
74
|
+
f"Expected position in {front_ES_future} to be 0, got {positions.get(front_ES_future)}"
|
75
|
+
)
|
76
|
+
|
77
|
+
# go long
|
78
|
+
order = await async_client.place_order(
|
79
|
+
symbol=front_ES_future,
|
80
|
+
venue="CME",
|
81
|
+
dir=OrderDir.BUY,
|
82
|
+
quantity=Decimal(value="8"),
|
83
|
+
account=account_id,
|
84
|
+
order_type=OrderType.MARKET,
|
85
|
+
)
|
86
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
87
|
+
assert positions.get(front_ES_future) == Decimal(8), (
|
88
|
+
f"Expected position in {front_ES_future} to be 8, got {positions.get(front_ES_future)}"
|
89
|
+
)
|
90
|
+
|
91
|
+
# go long to short
|
92
|
+
order = await async_client.place_order(
|
93
|
+
symbol=front_ES_future,
|
94
|
+
venue="CME",
|
95
|
+
dir=OrderDir.SELL,
|
96
|
+
quantity=Decimal(value="10"),
|
97
|
+
account=account_id,
|
98
|
+
order_type=OrderType.MARKET,
|
99
|
+
)
|
100
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
101
|
+
assert positions.get(front_ES_future) == Decimal(-2), (
|
102
|
+
f"Expected position in {front_ES_future} to be -2, got {positions.get(front_ES_future)}"
|
103
|
+
)
|
104
|
+
|
105
|
+
# go flat
|
106
|
+
order = await async_client.place_order(
|
107
|
+
symbol=front_ES_future,
|
108
|
+
venue="CME",
|
109
|
+
dir=OrderDir.BUY,
|
110
|
+
quantity=Decimal(value="2"),
|
111
|
+
account=account_id,
|
112
|
+
order_type=OrderType.MARKET,
|
113
|
+
)
|
114
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
115
|
+
assert positions.get(front_ES_future) is None, (
|
116
|
+
f"Expected position in {front_ES_future} to be 0, got {positions.get(front_ES_future)}"
|
117
|
+
)
|
118
|
+
|
119
|
+
# go short
|
120
|
+
order = await async_client.place_order(
|
121
|
+
symbol=front_ES_future,
|
122
|
+
venue="CME",
|
123
|
+
dir=OrderDir.SELL,
|
124
|
+
quantity=Decimal(value="5"),
|
125
|
+
account=account_id,
|
126
|
+
order_type=OrderType.MARKET,
|
127
|
+
)
|
128
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
129
|
+
assert positions.get(front_ES_future) == Decimal(-5), (
|
130
|
+
f"Expected position in {front_ES_future} to be -5, got {positions.get(front_ES_future)}"
|
131
|
+
)
|
132
|
+
|
133
|
+
# go short to flat
|
134
|
+
order = await async_client.place_order(
|
135
|
+
symbol=front_ES_future,
|
136
|
+
venue="CME",
|
137
|
+
dir=OrderDir.BUY,
|
138
|
+
quantity=Decimal(value="5"),
|
139
|
+
account=account_id,
|
140
|
+
order_type=OrderType.MARKET,
|
141
|
+
)
|
142
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
143
|
+
assert positions.get(front_ES_future) is None, (
|
144
|
+
f"Expected position in {front_ES_future} to be 0, got {positions.get(front_ES_future)}"
|
145
|
+
)
|
146
|
+
|
147
|
+
# go short
|
148
|
+
order = await async_client.place_order(
|
149
|
+
symbol=front_ES_future,
|
150
|
+
venue="CME",
|
151
|
+
dir=OrderDir.SELL,
|
152
|
+
quantity=Decimal(value="5"),
|
153
|
+
account=account_id,
|
154
|
+
order_type=OrderType.MARKET,
|
155
|
+
)
|
156
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
157
|
+
assert positions.get(front_ES_future) == Decimal(-5), (
|
158
|
+
f"Expected position in {front_ES_future} to be -5, got {positions.get(front_ES_future)}"
|
159
|
+
)
|
160
|
+
|
161
|
+
# go short to long
|
162
|
+
order = await async_client.place_order(
|
163
|
+
symbol=front_ES_future,
|
164
|
+
venue="CME",
|
165
|
+
dir=OrderDir.BUY,
|
166
|
+
quantity=Decimal(value="10"),
|
167
|
+
account=account_id,
|
168
|
+
order_type=OrderType.MARKET,
|
169
|
+
)
|
170
|
+
positions = await async_client.get_positions(accounts=[account_id])
|
171
|
+
assert positions.get(front_ES_future) == Decimal(5), (
|
172
|
+
f"Expected position in {front_ES_future} to be 5, got {positions.get(front_ES_future)}"
|
173
|
+
)
|
@@ -1,41 +1,41 @@
|
|
1
|
-
|
1
|
+
from decimal import Decimal
|
2
2
|
|
3
|
-
|
3
|
+
from architect_py.utils.nearest_tick import TickRoundMethod
|
4
4
|
|
5
5
|
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
6
|
+
def _test_rounding():
|
7
|
+
# Example usage
|
8
|
+
value = Decimal("123.454")
|
9
|
+
tick_size = Decimal("0.01")
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
rounded_value = TickRoundMethod.ROUND(value, tick_size=tick_size)
|
12
|
+
assert rounded_value == Decimal("123.45")
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
rounded_ceil = TickRoundMethod.CEIL(value, tick_size)
|
15
|
+
assert rounded_ceil == Decimal("123.46")
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
rounded_floor = TickRoundMethod.FLOOR(value, tick_size)
|
18
|
+
assert rounded_floor == Decimal("123.45")
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
rounded_floor = TickRoundMethod.FLOOR(Decimal("123.459"), tick_size)
|
21
|
+
assert rounded_floor == Decimal("123.45")
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
rounded_toward_zero_pos = TickRoundMethod.TOWARD_ZERO(value, tick_size)
|
24
|
+
assert rounded_toward_zero_pos == Decimal("123.45")
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
value_negative = Decimal("-123.456")
|
27
|
+
rounded_toward_zero_neg = TickRoundMethod.TOWARD_ZERO(value_negative, tick_size)
|
28
|
+
assert rounded_toward_zero_neg == Decimal("-123.45")
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
rounded_away_from_zero_pos = TickRoundMethod.AWAY_FROM_ZERO(value, tick_size)
|
31
|
+
assert rounded_away_from_zero_pos == Decimal("123.46")
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
rounded_away_from_zero_neg = TickRoundMethod.AWAY_FROM_ZERO(
|
34
|
+
value_negative, tick_size
|
35
|
+
)
|
36
|
+
assert rounded_away_from_zero_neg == Decimal("-123.46")
|
37
37
|
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
if __name__ == "__main__":
|
40
|
+
_test_rounding()
|
41
|
+
print("rounding.py: All tests passed!")
|
architect_py/utils/pandas.py
CHANGED
@@ -4,7 +4,7 @@ import msgspec
|
|
4
4
|
import pandas as pd
|
5
5
|
|
6
6
|
if TYPE_CHECKING:
|
7
|
-
from .. import Candle
|
7
|
+
from .. import Candle, Ticker
|
8
8
|
|
9
9
|
CANDLES_FIELD_MAP = {
|
10
10
|
"av": "sell_volume",
|
@@ -43,3 +43,52 @@ def candles_to_dataframe(candles: List["Candle"]) -> pd.DataFrame:
|
|
43
43
|
df.style.hide(["tn", "ts"], axis=1)
|
44
44
|
df.set_index("timestamp", inplace=True)
|
45
45
|
return df
|
46
|
+
|
47
|
+
|
48
|
+
def tickers_to_dataframe(tickers: List["Ticker"]) -> pd.DataFrame:
|
49
|
+
records = msgspec.to_builtins(tickers)
|
50
|
+
df = pd.DataFrame.from_records(records)
|
51
|
+
df.rename(
|
52
|
+
columns={
|
53
|
+
"s": "symbol",
|
54
|
+
"ve": "venue",
|
55
|
+
"ap": "ask_price",
|
56
|
+
"as": "ask_size",
|
57
|
+
"bp": "bid_price",
|
58
|
+
"bs": "bid_size",
|
59
|
+
"dividend": "dividend",
|
60
|
+
"dividend_yield": "dividend_yield",
|
61
|
+
"eps_adj": "eps_adj",
|
62
|
+
"fr": "funding_rate",
|
63
|
+
"ft": "next_funding_time",
|
64
|
+
"h": "high_24h",
|
65
|
+
"ip": "index_price",
|
66
|
+
"isp": "indicative_settlement_price",
|
67
|
+
"l": "low_24h",
|
68
|
+
"market_cap": "market_cap",
|
69
|
+
"mp": "mark_price",
|
70
|
+
"o": "open_24h",
|
71
|
+
"oi": "open_interest",
|
72
|
+
"p": "last_price",
|
73
|
+
"price_to_earnings": "price_to_earnings",
|
74
|
+
"q": "last_size",
|
75
|
+
"sd": "last_settlement_date",
|
76
|
+
"shares_outstanding_weighted_adj": "shares_outstanding_weighted_adj",
|
77
|
+
"sp": "last_settlement_price",
|
78
|
+
"v": "volume_24h",
|
79
|
+
"vm": "volume_30d",
|
80
|
+
"xh": "session_high",
|
81
|
+
"xl": "session_low",
|
82
|
+
"xo": "session_open",
|
83
|
+
"xv": "session_volume",
|
84
|
+
},
|
85
|
+
inplace=True,
|
86
|
+
)
|
87
|
+
df["timestamp"] = pd.to_datetime(
|
88
|
+
df["ts"] * 1_000_000_000 + df["tn"],
|
89
|
+
unit="ns",
|
90
|
+
utc=True,
|
91
|
+
)
|
92
|
+
df.style.hide(["tn", "ts"], axis=1)
|
93
|
+
df.set_index("symbol", inplace=True)
|
94
|
+
return df
|
@@ -1,7 +1,7 @@
|
|
1
|
-
architect_py/__init__.py,sha256=
|
2
|
-
architect_py/async_client.py,sha256=
|
1
|
+
architect_py/__init__.py,sha256=jrffx1fAChnV8djCoFdEmsTwyHTCkw0_P3RvSimjcx8,16666
|
2
|
+
architect_py/async_client.py,sha256=jU_P4McMXGsKhUIov0CEXG27qi4SdfIVZkU3uFc-md8,65827
|
3
3
|
architect_py/client.py,sha256=y8w17ZLo_Y2-knH-46qqVGlSJyQHB9qwOPodI9pzN-Q,5192
|
4
|
-
architect_py/client.pyi,sha256=
|
4
|
+
architect_py/client.pyi,sha256=w8yM9u2TQvm12DHoEunq0CKTQ0EVOqrkh_iuNMf1Dk8,26113
|
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
|
@@ -29,7 +29,7 @@ architect_py/grpc/resolve_endpoint.py,sha256=r_PBWANIJJ47N5uyPcnefZ21ZE1-mzgACfC
|
|
29
29
|
architect_py/grpc/server.py,sha256=Abmdfe1eYbctVgzoJYBBBLpd7UD70FbYQLtJImSyRzs,1934
|
30
30
|
architect_py/grpc/utils.py,sha256=5sykLExUNZbcQHcxLCCM9DdOOiJJZcpputGrDtaMifY,667
|
31
31
|
architect_py/grpc/models/__init__.py,sha256=DVsP-OURNPSlFKWxQGShF7ytvOUJc2_fQ-ng5kOh1X8,9366
|
32
|
-
architect_py/grpc/models/definitions.py,sha256=
|
32
|
+
architect_py/grpc/models/definitions.py,sha256=fWVidMJ4pEzP7Z6bLhyYlSYxGttfH40Vgki1P9b47ow,82836
|
33
33
|
architect_py/grpc/models/Accounts/AccountsRequest.py,sha256=1a88cltSebOb53EdJ0hKEGR7FlmBiibrCtGzLTKqDBY,1524
|
34
34
|
architect_py/grpc/models/Accounts/AccountsResponse.py,sha256=DlXbkd3UbRybblBAfokw-K6nRvLNZgqz7cc0EKiW1zI,636
|
35
35
|
architect_py/grpc/models/Accounts/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
@@ -64,7 +64,7 @@ architect_py/grpc/models/Boss/WithdrawalsRequest.py,sha256=876d2gsGbSTPZ74wCoe0n
|
|
64
64
|
architect_py/grpc/models/Boss/WithdrawalsResponse.py,sha256=th6r28rjNBUuMBs95lwf9pxaxFtrwKJ_VAq7egwMVM8,632
|
65
65
|
architect_py/grpc/models/Boss/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
66
66
|
architect_py/grpc/models/Core/ConfigRequest.py,sha256=9taH97J4b-_Co7d-o_zHOPg_vckc_InvnADXYpd_MlM,809
|
67
|
-
architect_py/grpc/models/Core/ConfigResponse.py,sha256=
|
67
|
+
architect_py/grpc/models/Core/ConfigResponse.py,sha256=fjOEuwTyawepSaVGfLXqhmo_1ssDsDbyYkxje_SwBlU,717
|
68
68
|
architect_py/grpc/models/Core/RestartCptyRequest.py,sha256=Hl_uSGkMFE9yPonClcNE24neeib8LP3fHH6UwpI_WSQ,916
|
69
69
|
architect_py/grpc/models/Core/RestartCptyResponse.py,sha256=aCyJfucfFGHieGURjEejeT9HPoaKJ2xCGPVqw5pcCJs,427
|
70
70
|
architect_py/grpc/models/Core/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
@@ -79,7 +79,7 @@ architect_py/grpc/models/Folio/AccountHistoryRequest.py,sha256=62zM93rALjckq8y5s
|
|
79
79
|
architect_py/grpc/models/Folio/AccountHistoryResponse.py,sha256=3CUKPrqbUpH1MRYFZi2Q4dfN-nzcM6OxM_FA5pA_OyQ,622
|
80
80
|
architect_py/grpc/models/Folio/AccountSummariesRequest.py,sha256=epYjLFc1cMblp04li_WSCIcl4bFJEjDedJNO9D2x1bg,1595
|
81
81
|
architect_py/grpc/models/Folio/AccountSummariesResponse.py,sha256=YoJddUl0TB1pkoI7C_avt94RSL9ZCf2u8_kOYpewRGI,678
|
82
|
-
architect_py/grpc/models/Folio/AccountSummary.py,sha256=
|
82
|
+
architect_py/grpc/models/Folio/AccountSummary.py,sha256=2upTyjDCpkxIXZ40DjUmZFaBBnmIbhF1htijOoCc2D4,3816
|
83
83
|
architect_py/grpc/models/Folio/AccountSummaryRequest.py,sha256=qu9f-liMEOqxq8LM2h9EosCj2vtTJwduUKjiwYO8GTo,1002
|
84
84
|
architect_py/grpc/models/Folio/HistoricalFillsRequest.py,sha256=ybd6vIO1xkiovUW9Q-Pl4K21kfmFX8uMOoE7LZqsOLU,2241
|
85
85
|
architect_py/grpc/models/Folio/HistoricalFillsResponse.py,sha256=MmHFvt-FuLgw93fHN8lfcyMsG2qHys1gUD0gq0QZGyM,775
|
@@ -90,16 +90,16 @@ architect_py/grpc/models/Health/HealthCheckRequest.py,sha256=uKxA8HbItw-MF-LfHk7
|
|
90
90
|
architect_py/grpc/models/Health/HealthCheckResponse.py,sha256=0yh75XgiyrJdNet4xx5_u7gyW6Qx8fwTPO9h6E_HVWU,755
|
91
91
|
architect_py/grpc/models/Health/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
92
92
|
architect_py/grpc/models/Marketdata/ArrayOfL1BookSnapshot.py,sha256=Os13kKncZgwoCqrorTspvcj8EO7u4Xr3fNQV8mWONFM,329
|
93
|
-
architect_py/grpc/models/Marketdata/Candle.py,sha256=
|
93
|
+
architect_py/grpc/models/Marketdata/Candle.py,sha256=GIidzpVm9CwxbkIS3cJiRB_WaWQ3vwoGr_g6dSaDl9I,8472
|
94
94
|
architect_py/grpc/models/Marketdata/HistoricalCandlesRequest.py,sha256=uJvsHOn2gXD9w4ybk1iXu4Z1LJ4g5g89y_DIwAMUChY,1587
|
95
95
|
architect_py/grpc/models/Marketdata/HistoricalCandlesResponse.py,sha256=_LGtTw6dVMtF0U6N7l68IbxDDMcooOEW7YsJaoLtniY,604
|
96
|
-
architect_py/grpc/models/Marketdata/L1BookSnapshot.py,sha256=
|
96
|
+
architect_py/grpc/models/Marketdata/L1BookSnapshot.py,sha256=tM-2KEhy3M8hxwfDpPLDmNYIh_cfblWZkRVk_A1k6Ww,3874
|
97
97
|
architect_py/grpc/models/Marketdata/L1BookSnapshotRequest.py,sha256=9TxfqAivsmZgmIuIemmX6A9bTvMvVU6rWYDGi86gZZg,1072
|
98
98
|
architect_py/grpc/models/Marketdata/L1BookSnapshotsRequest.py,sha256=TFGnuPfTcHMSO849WnEPj1a52RsVReAEWqQ9Fb3La1g,1189
|
99
|
-
architect_py/grpc/models/Marketdata/L2BookSnapshot.py,sha256=
|
99
|
+
architect_py/grpc/models/Marketdata/L2BookSnapshot.py,sha256=bvJJPfXMhS68J8M2U6Yb-yvLJuCLy_dUF_viG0udBWM,2785
|
100
100
|
architect_py/grpc/models/Marketdata/L2BookSnapshotRequest.py,sha256=9qRKbwY2KLtW2F-40XOvRfT73kVPTymL0Q3JCR2EbtU,1072
|
101
101
|
architect_py/grpc/models/Marketdata/L2BookUpdate.py,sha256=i-kWdJZvAoYEI280TfC3sTH46VIpMoj8N2UxWAkTDLs,2602
|
102
|
-
architect_py/grpc/models/Marketdata/Liquidation.py,sha256=
|
102
|
+
architect_py/grpc/models/Marketdata/Liquidation.py,sha256=QFco-zA3xUKstAbFkJ4qn_uluQ8XK6yDApvQULsSl3Y,2633
|
103
103
|
architect_py/grpc/models/Marketdata/MarketStatus.py,sha256=4Kt2z16t7dpjpiELWshJyyH1b-D07YdQchjGMvZkSRM,977
|
104
104
|
architect_py/grpc/models/Marketdata/MarketStatusRequest.py,sha256=ajyI4UlvFusyM0743dukT4KFZTlp9iUh0lTGWl6n7nw,1056
|
105
105
|
architect_py/grpc/models/Marketdata/SubscribeCandlesRequest.py,sha256=ck5pQx54uymlpR-jxFpxcW0LPDLU7R8GvqLqF-7GmoU,1508
|
@@ -110,12 +110,12 @@ architect_py/grpc/models/Marketdata/SubscribeLiquidationsRequest.py,sha256=6BhC4
|
|
110
110
|
architect_py/grpc/models/Marketdata/SubscribeManyCandlesRequest.py,sha256=pel2GGysDsJXjPY7rkyqqyGS3MPl13YezJS7apihiFc,1512
|
111
111
|
architect_py/grpc/models/Marketdata/SubscribeTickersRequest.py,sha256=7g2LBAYd97OJ9FrxpUvZKO7hSMng-K4KfnsN08O4XSM,1437
|
112
112
|
architect_py/grpc/models/Marketdata/SubscribeTradesRequest.py,sha256=7P8FyNx6wijNUBGry0vaMhaEKuG1ik8kTibJBvdol2k,1299
|
113
|
-
architect_py/grpc/models/Marketdata/Ticker.py,sha256=
|
113
|
+
architect_py/grpc/models/Marketdata/Ticker.py,sha256=ti8Z3HEePBGk66DUwgZjKMpBhHrimT_Rv4VYaC7f3rs,11805
|
114
114
|
architect_py/grpc/models/Marketdata/TickerRequest.py,sha256=Ay--5JKgCfdvlVWD2H6YSa_66NC3Dt6c-XK8JkbWhus,1008
|
115
115
|
architect_py/grpc/models/Marketdata/TickerUpdate.py,sha256=sJ4wvCeGckMV30HwAcAsEMQbCzjN31OxF19q70jdxok,437
|
116
116
|
architect_py/grpc/models/Marketdata/TickersRequest.py,sha256=x6UlQdAisnXgs3vbghQY3nuiFccSU3ueU0YJVAKaKUs,2359
|
117
117
|
architect_py/grpc/models/Marketdata/TickersResponse.py,sha256=CLzKx-ItwH9-Qq8YruFhXh7TmtHwzNRMEOPJ9LQD9co,574
|
118
|
-
architect_py/grpc/models/Marketdata/Trade.py,sha256=
|
118
|
+
architect_py/grpc/models/Marketdata/Trade.py,sha256=NZ-pM4MUNzQvq5RwYOS0_xgmDI17AxdM4t8NKdPnGu8,2689
|
119
119
|
architect_py/grpc/models/Marketdata/__init__.py,sha256=sIyaEvJdP-VmGTGPPqZuRjKn4bc7NUClJ76Gd5uq-5s,57
|
120
120
|
architect_py/grpc/models/Oms/Cancel.py,sha256=P550abgbBqVbC3UE7YaOaEytF__DsTYWsepNvkHaAQE,2357
|
121
121
|
architect_py/grpc/models/Oms/CancelAllOrdersRequest.py,sha256=oCRbluj6nyoDCHQszPDRIBt4ygFyO7QHZhCf8T8-fYM,1474
|
@@ -166,16 +166,17 @@ architect_py/tests/test_marketdata.py,sha256=W26OrL51ONAclBjBcm7trS1QPXtLLjdgnsb
|
|
166
166
|
architect_py/tests/test_order_entry.py,sha256=5HDjzNJOC7lSx4driP4mDJr9HuR2cFTwO8s1haGXl9E,1284
|
167
167
|
architect_py/tests/test_orderflow.py,sha256=b4iohhs7YUoJMevlUfLQyIoVqjam7pl0BPs0dSfZhqM,3951
|
168
168
|
architect_py/tests/test_portfolio_management.py,sha256=Q4pburTDJ53hrq2_aRbNAOG3nwbCEsgZQGbI_AMHLxE,709
|
169
|
-
architect_py/tests/
|
169
|
+
architect_py/tests/test_positions.py,sha256=zVO6qmYVn7heQt2C17deYUUCAmJ-u6cnekTmqKm8Vh0,5925
|
170
|
+
architect_py/tests/test_rounding.py,sha256=qjuPIdX6TbfPtfrzotZx6-Aodf4et7j3AswgQ7DQtm4,1363
|
170
171
|
architect_py/tests/test_symbology.py,sha256=74fbUgoycuViMHHnurE2Dnfao75wWu_cmQMyU5XQcdY,3436
|
171
172
|
architect_py/tests/test_sync_client.py,sha256=teaHrp-CMpKIDsGPdnyxvmuW_a3hgFftnsnPsFHz9Tw,946
|
172
173
|
architect_py/utils/nearest_tick.py,sha256=i1cCGMSi-sP4Grbp0RCwEsoLzMWN9iC6gPMBm2daDWM,4810
|
173
174
|
architect_py/utils/nearest_tick_2.py,sha256=f-o6b73Mo8epCIaOYBS9F0k_6UHUDSVG1N_VWg7iFBU,3641
|
174
175
|
architect_py/utils/orderbook.py,sha256=JM02NhHbmK3sNaS2Ara8FBY4TvKvtMIzJW1oVd8KC3s,1004
|
175
|
-
architect_py/utils/pandas.py,sha256=
|
176
|
+
architect_py/utils/pandas.py,sha256=Jyiimf6Y5FbTLotUhSIgOnRHMGz7ZvAqNSCHEwZ9eQU,2599
|
176
177
|
architect_py/utils/price_bands.py,sha256=j7ioSA3dx025CD5E2Vg7XQvmjPvxQb-gzQBfQTovpTw,21874
|
177
178
|
architect_py/utils/symbol_parsing.py,sha256=OjJzk2c6QU2s0aJMSyVEzlWD5Vy-RlakJVW7jNHVDJk,845
|
178
|
-
architect_py-5.1.
|
179
|
+
architect_py-5.1.5.dist-info/licenses/LICENSE,sha256=6P0_5gYN8iPWPZeqA9nxiO3tRQmcSA1ijAVR7C8j1SI,11362
|
179
180
|
examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
180
181
|
examples/book_subscription.py,sha256=1WFQN_QCE8cRS_CIv2k0NxqpK37fA9-Ja2Kfxs8vsb8,1461
|
181
182
|
examples/candles.py,sha256=T71TsxbfXCT6mrJZmTgdTKesJFdQhYP_4AsiNK-8KyQ,756
|
@@ -199,7 +200,7 @@ scripts/preprocess_grpc_schema.py,sha256=p9LdoMZzixBSsVx7Dy3_8uJzOy_QwCoVMkAABQK
|
|
199
200
|
scripts/prune_graphql_schema.py,sha256=hmfw5FD_iKGKMFkq6H1neZiXXtljFFrOwi2fiusTWE4,6210
|
200
201
|
templates/exceptions.py,sha256=tIHbiO5Q114h9nPwJXsgHvW_bERLwxuNp9Oj41p6t3A,2379
|
201
202
|
templates/juniper_base_client.py,sha256=B8QF4IFSwqBK5UY2aFPbSdYnX9bcwnlxLK4ojPRaW0E,12705
|
202
|
-
architect_py-5.1.
|
203
|
-
architect_py-5.1.
|
204
|
-
architect_py-5.1.
|
205
|
-
architect_py-5.1.
|
203
|
+
architect_py-5.1.5.dist-info/METADATA,sha256=mUUxF_AZbqF0dHqRcn1mivlye9rkUi1KMogf-Qqw9jQ,2638
|
204
|
+
architect_py-5.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
205
|
+
architect_py-5.1.5.dist-info/top_level.txt,sha256=UjtO97OACFQ9z5MzS-X2wBlt5Ovk1vxakQPKfokI454,40
|
206
|
+
architect_py-5.1.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|