avantis-trader-sdk 0.8.13__py3-none-any.whl → 0.8.15__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.
@@ -11,5 +11,7 @@ MAINNET_ADDRESSES = {
11
11
 
12
12
  AVANTIS_SOCKET_API = "https://socket-api-pub.avantisfi.com/socket-api/v1/data"
13
13
  AVANTIS_CORE_API_BASE_URL = "https://core.avantisfi.com"
14
+ AVANTIS_FEED_V3_URL = "https://feed-v3.avantisfi.com"
15
+ PYTH_LAZER_SSE_URL = "https://pyth-lazer-proxy-3.dourolabs.app/v1/stream"
14
16
 
15
17
  CONTRACT_ADDRESSES = MAINNET_ADDRESSES
@@ -1,12 +1,19 @@
1
1
  import json
2
2
  import websockets
3
- from ..types import PriceFeedResponse, PriceFeedUpdatesResponse, PairInfoFeed
4
- from typing import List, Callable
3
+ from ..types import (
4
+ PriceFeedResponse,
5
+ PriceFeedUpdatesResponse,
6
+ PairInfoFeed,
7
+ FeedV3PriceResponse,
8
+ LazerPriceFeedResponse,
9
+ )
10
+ from typing import List, Callable, Optional
5
11
  import requests
6
12
  from pydantic import ValidationError
7
- from ..config import AVANTIS_SOCKET_API
13
+ from ..config import AVANTIS_SOCKET_API, AVANTIS_FEED_V3_URL, PYTH_LAZER_SSE_URL
8
14
  import asyncio
9
15
  from concurrent.futures import ThreadPoolExecutor
16
+ import aiohttp
10
17
 
11
18
 
12
19
  class FeedClient:
@@ -22,14 +29,21 @@ class FeedClient:
22
29
  hermes_url="https://hermes.pyth.network/v2/updates/price/latest",
23
30
  socket_api: str = AVANTIS_SOCKET_API,
24
31
  pair_fetcher: Callable = None,
32
+ feed_v3_url: str = AVANTIS_FEED_V3_URL,
33
+ lazer_sse_url: str = PYTH_LAZER_SSE_URL,
25
34
  ):
26
35
  """
27
36
  Constructor for the FeedClient class.
28
37
 
29
38
  Args:
30
- ws_url: Optional - The websocket URL to connect to.
31
- on_error: Optional callback for handling websocket errors.
32
- on_close: Optional callback for handling websocket close events.
39
+ ws_url: Optional - The websocket URL to connect to (Pyth Hermes).
40
+ on_error: Optional callback for handling websocket/SSE errors.
41
+ on_close: Optional callback for handling websocket/SSE close events.
42
+ hermes_url: Optional - The Hermes HTTP API URL.
43
+ socket_api: Optional - The Avantis socket API URL.
44
+ pair_fetcher: Optional - Custom pair fetcher function.
45
+ feed_v3_url: Optional - The feed-v3 API URL for price update data.
46
+ lazer_sse_url: Optional - The Pyth Lazer SSE URL for real-time prices.
33
47
  """
34
48
  if (
35
49
  ws_url is not None
@@ -40,11 +54,15 @@ class FeedClient:
40
54
 
41
55
  self.ws_url = ws_url
42
56
  self.hermes_url = hermes_url
57
+ self.feed_v3_url = feed_v3_url
58
+ self.lazer_sse_url = lazer_sse_url
43
59
  self.pair_feeds = {}
44
60
  self.feed_pairs = {}
45
61
  self.price_feed_callbacks = {}
62
+ self.lazer_callbacks = {}
46
63
  self._socket = None
47
64
  self._connected = False
65
+ self._lazer_connected = False
48
66
  self._on_error = on_error
49
67
  self._on_close = on_close
50
68
  self.socket_api = socket_api
@@ -267,3 +285,97 @@ class FeedClient:
267
285
  return PriceFeedUpdatesResponse(**data)
268
286
  else:
269
287
  response.raise_for_status()
288
+
289
+ async def get_price_update_data(self, pair_index: int) -> FeedV3PriceResponse:
290
+ """
291
+ Retrieves price update data from the feed-v3 API for a specific pair.
292
+
293
+ This returns both core (Pyth Hermes) and pro (Pyth Lazer) price data,
294
+ including the priceUpdateData bytes needed for contract calls.
295
+
296
+ Args:
297
+ pair_index: The pair index to get price update data for.
298
+
299
+ Returns:
300
+ A FeedV3PriceResponse containing core and pro price data.
301
+
302
+ Raises:
303
+ requests.HTTPError: If the API request fails.
304
+ """
305
+ url = f"{self.feed_v3_url}/v2/pairs/{pair_index}/price-update-data"
306
+ response = requests.get(url, timeout=10)
307
+ response.raise_for_status()
308
+ data = response.json()
309
+ return FeedV3PriceResponse(**data)
310
+
311
+ async def get_latest_lazer_price(
312
+ self, lazer_feed_ids: List[int]
313
+ ) -> LazerPriceFeedResponse:
314
+ """
315
+ Retrieves the latest prices from the Pyth Lazer API.
316
+
317
+ Args:
318
+ lazer_feed_ids: List of Lazer feed IDs to get prices for.
319
+
320
+ Returns:
321
+ A LazerPriceFeedResponse containing the latest prices.
322
+
323
+ Raises:
324
+ requests.HTTPError: If the API request fails.
325
+ """
326
+ params = "&".join([f"price_feed_ids={fid}" for fid in lazer_feed_ids])
327
+ url = f"{self.lazer_sse_url.replace('/stream', '/latest_price')}?{params}"
328
+ response = requests.get(url, timeout=10)
329
+ response.raise_for_status()
330
+ data = response.json()
331
+ return LazerPriceFeedResponse(**data)
332
+
333
+ async def listen_for_lazer_price_updates(
334
+ self,
335
+ lazer_feed_ids: List[int],
336
+ callback: Callable[[LazerPriceFeedResponse], None],
337
+ ):
338
+ """
339
+ Listens for real-time price updates from the Pyth Lazer SSE stream.
340
+
341
+ This is the Pyth Pro alternative to the WebSocket-based listen_for_price_updates.
342
+
343
+ Args:
344
+ lazer_feed_ids: List of Lazer feed IDs to subscribe to.
345
+ callback: Callback function to handle price updates.
346
+
347
+ Raises:
348
+ Exception: If an error occurs while listening for price updates.
349
+ """
350
+ params = "&".join([f"price_feed_ids={fid}" for fid in lazer_feed_ids])
351
+ url = f"{self.lazer_sse_url}?{params}"
352
+
353
+ try:
354
+ async with aiohttp.ClientSession() as session:
355
+ async with session.get(url) as response:
356
+ self._lazer_connected = True
357
+ async for line in response.content:
358
+ line = line.decode("utf-8").strip()
359
+ if line.startswith("data:"):
360
+ try:
361
+ data = json.loads(line[5:].strip())
362
+ price_response = LazerPriceFeedResponse(**data)
363
+ callback(price_response)
364
+ except json.JSONDecodeError as e:
365
+ if self._on_error:
366
+ self._on_error(e)
367
+ except ValidationError as e:
368
+ if self._on_error:
369
+ self._on_error(e)
370
+ except aiohttp.ClientError as e:
371
+ self._lazer_connected = False
372
+ if self._on_error:
373
+ self._on_error(e)
374
+ else:
375
+ raise e
376
+ except Exception as e:
377
+ self._lazer_connected = False
378
+ if self._on_close:
379
+ self._on_close(e)
380
+ else:
381
+ raise e
@@ -187,3 +187,22 @@ class PairsCache:
187
187
  """
188
188
  pairs_info = await self.get_pairs_info()
189
189
  return pairs_info[pair_index].from_ + "/" + pairs_info[pair_index].to
190
+
191
+ async def get_lazer_feed_id(self, pair_index: int) -> int:
192
+ """
193
+ Retrieves the Pyth Lazer feed ID for a pair.
194
+
195
+ Args:
196
+ pair_index: The pair index.
197
+
198
+ Returns:
199
+ The Lazer feed ID as an integer.
200
+
201
+ Raises:
202
+ ValueError: If the pair does not have a Lazer feed configured.
203
+ """
204
+ pair_info = await self.get_pair_info_from_socket(pair_index)
205
+ lazer_feed = pair_info.get("lazerFeed")
206
+ if not lazer_feed:
207
+ raise ValueError(f"Pair {pair_index} does not have a Lazer feed configured")
208
+ return lazer_feed.get("feedId")
@@ -8,6 +8,7 @@ from ..types import (
8
8
  TradeInfo,
9
9
  PendingLimitOrderExtendedResponse,
10
10
  MarginUpdateType,
11
+ PriceSourcing,
11
12
  )
12
13
  from typing import Optional, List, Tuple
13
14
  import math
@@ -73,11 +74,15 @@ class TradeRPC:
73
74
  trade_input_order_type == TradeInputOrderType.MARKET
74
75
  or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
75
76
  ) and not trade_input.openPrice:
76
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(
77
+ lazer_feed_id = await self.client.pairs_cache.get_lazer_feed_id(
77
78
  trade_input.pairIndex
78
79
  )
79
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
80
- price = int(price_data.parsed[0].converted_price * 10**10)
80
+ price_data = await self.feed_client.get_latest_lazer_price([lazer_feed_id])
81
+ price_feed = next(
82
+ (f for f in price_data.price_feeds if f.price_feed_id == lazer_feed_id),
83
+ price_data.price_feeds[0],
84
+ )
85
+ price = int(price_feed.converted_price * 10**10)
81
86
  trade_input.openPrice = price
82
87
 
83
88
  if (
@@ -136,11 +141,15 @@ class TradeRPC:
136
141
  trade_input_order_type == TradeInputOrderType.MARKET
137
142
  or trade_input_order_type == TradeInputOrderType.MARKET_ZERO_FEE
138
143
  ) and not trade_input.openPrice:
139
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(
144
+ lazer_feed_id = await self.client.pairs_cache.get_lazer_feed_id(
140
145
  trade_input.pairIndex
141
146
  )
142
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
143
- price = int(price_data.parsed[0].converted_price * 10**10)
147
+ price_data = await self.feed_client.get_latest_lazer_price([lazer_feed_id])
148
+ price_feed = next(
149
+ (f for f in price_data.price_feeds if f.price_feed_id == lazer_feed_id),
150
+ price_data.price_feeds[0],
151
+ )
152
+ price = int(price_feed.converted_price * 10**10)
144
153
  trade_input.openPrice = price
145
154
 
146
155
  if (
@@ -162,8 +171,6 @@ class TradeRPC:
162
171
  }
163
172
  )
164
173
 
165
- print("transaction: ", trade_input.trader)
166
-
167
174
  delegate_transaction = await Trading.functions.delegatedAction(
168
175
  trade_input.trader, transaction["data"]
169
176
  ).build_transaction(
@@ -595,6 +602,7 @@ class TradeRPC:
595
602
  margin_update_type: MarginUpdateType,
596
603
  collateral_change: float,
597
604
  trader: Optional[str] = None,
605
+ price_sourcing: PriceSourcing = PriceSourcing.PRO,
598
606
  ):
599
607
  """
600
608
  Builds a transaction to update the margin of a trade.
@@ -605,6 +613,7 @@ class TradeRPC:
605
613
  margin_update_type: The margin update type.
606
614
  collateral_change: The collateral change.
607
615
  trader (optional): The trader's wallet address.
616
+ price_sourcing: The price sourcing to use. Defaults to PriceSourcing.PRO (Pyth Pro/Lazer).
608
617
  Returns:
609
618
  A transaction object.
610
619
  """
@@ -615,11 +624,15 @@ class TradeRPC:
615
624
 
616
625
  collateral_change = int(collateral_change * 10**6)
617
626
 
618
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
619
-
620
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
621
-
622
- price_update_data = "0x" + price_data.binary.data[0]
627
+ if price_sourcing == PriceSourcing.PRO:
628
+ price_data = await self.feed_client.get_price_update_data(pair_index)
629
+ price_update_data = price_data.pro.price_update_data
630
+ else:
631
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
632
+ pair_index
633
+ )
634
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
635
+ price_update_data = "0x" + price_data.binary.data[0]
623
636
 
624
637
  transaction = await Trading.functions.updateMargin(
625
638
  pair_index,
@@ -627,6 +640,7 @@ class TradeRPC:
627
640
  margin_update_type.value,
628
641
  collateral_change,
629
642
  [price_update_data],
643
+ price_sourcing.value,
630
644
  ).build_transaction(
631
645
  {
632
646
  "from": trader,
@@ -645,6 +659,7 @@ class TradeRPC:
645
659
  margin_update_type: MarginUpdateType,
646
660
  collateral_change: float,
647
661
  trader: Optional[str] = None,
662
+ price_sourcing: PriceSourcing = PriceSourcing.PRO,
648
663
  ):
649
664
  """
650
665
  Builds a transaction to update the margin of a trade.
@@ -655,6 +670,7 @@ class TradeRPC:
655
670
  margin_update_type: The margin update type.
656
671
  collateral_change: The collateral change.
657
672
  trader (optional): The trader's wallet address.
673
+ price_sourcing: The price sourcing to use. Defaults to PriceSourcing.PRO (Pyth Pro/Lazer).
658
674
  Returns:
659
675
  A transaction object.
660
676
  """
@@ -665,11 +681,15 @@ class TradeRPC:
665
681
 
666
682
  collateral_change = int(collateral_change * 10**6)
667
683
 
668
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
669
-
670
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
671
-
672
- price_update_data = "0x" + price_data.binary.data[0]
684
+ if price_sourcing == PriceSourcing.PRO:
685
+ price_data = await self.feed_client.get_price_update_data(pair_index)
686
+ price_update_data = price_data.pro.price_update_data
687
+ else:
688
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
689
+ pair_index
690
+ )
691
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
692
+ price_update_data = "0x" + price_data.binary.data[0]
673
693
 
674
694
  transaction = await Trading.functions.updateMargin(
675
695
  pair_index,
@@ -677,6 +697,7 @@ class TradeRPC:
677
697
  margin_update_type.value,
678
698
  collateral_change,
679
699
  [price_update_data],
700
+ price_sourcing.value,
680
701
  ).build_transaction(
681
702
  {
682
703
  "from": trader,
@@ -708,6 +729,7 @@ class TradeRPC:
708
729
  take_profit_price: float,
709
730
  stop_loss_price: float,
710
731
  trader: str = None,
732
+ price_sourcing: PriceSourcing = PriceSourcing.PRO,
711
733
  ):
712
734
  """
713
735
  Builds a transaction to update the stop loss and take profit of a trade.
@@ -718,6 +740,7 @@ class TradeRPC:
718
740
  take_profit_price: The take profit price.
719
741
  stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
720
742
  trader (optional): The trader's wallet address.
743
+ price_sourcing: The price sourcing to use. Defaults to PriceSourcing.PRO (Pyth Pro/Lazer).
721
744
  Returns:
722
745
  A transaction object.
723
746
  """
@@ -729,11 +752,15 @@ class TradeRPC:
729
752
  if trader is None:
730
753
  trader = self.client.get_signer().get_ethereum_address()
731
754
 
732
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
733
-
734
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
735
-
736
- price_update_data = "0x" + price_data.binary.data[0]
755
+ if price_sourcing == PriceSourcing.PRO:
756
+ price_data = await self.feed_client.get_price_update_data(pair_index)
757
+ price_update_data = price_data.pro.price_update_data
758
+ else:
759
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
760
+ pair_index
761
+ )
762
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
763
+ price_update_data = "0x" + price_data.binary.data[0]
737
764
 
738
765
  take_profit_price = int(take_profit_price * 10**10)
739
766
  stop_loss_price = int(stop_loss_price * 10**10)
@@ -744,6 +771,7 @@ class TradeRPC:
744
771
  stop_loss_price,
745
772
  take_profit_price,
746
773
  [price_update_data],
774
+ price_sourcing.value,
747
775
  ).build_transaction(
748
776
  {
749
777
  "from": trader,
@@ -763,6 +791,7 @@ class TradeRPC:
763
791
  take_profit_price: float,
764
792
  stop_loss_price: float,
765
793
  trader: str = None,
794
+ price_sourcing: PriceSourcing = PriceSourcing.PRO,
766
795
  ):
767
796
  """
768
797
  Builds a transaction to update the stop loss and take profit of a trade.
@@ -773,6 +802,7 @@ class TradeRPC:
773
802
  take_profit_price: The take profit price.
774
803
  stop_loss_price: The stop loss price. Pass 0 if you want to remove the stop loss.
775
804
  trader (optional): The trader's wallet address.
805
+ price_sourcing: The price sourcing to use. Defaults to PriceSourcing.PRO (Pyth Pro/Lazer).
776
806
  Returns:
777
807
  A transaction object.
778
808
  """
@@ -784,11 +814,15 @@ class TradeRPC:
784
814
  if trader is None:
785
815
  trader = self.client.get_signer().get_ethereum_address()
786
816
 
787
- pair_name = await self.client.pairs_cache.get_pair_name_from_index(pair_index)
788
-
789
- price_data = await self.feed_client.get_latest_price_updates([pair_name])
790
-
791
- price_update_data = "0x" + price_data.binary.data[0]
817
+ if price_sourcing == PriceSourcing.PRO:
818
+ price_data = await self.feed_client.get_price_update_data(pair_index)
819
+ price_update_data = price_data.pro.price_update_data
820
+ else:
821
+ pair_name = await self.client.pairs_cache.get_pair_name_from_index(
822
+ pair_index
823
+ )
824
+ price_data = await self.feed_client.get_latest_price_updates([pair_name])
825
+ price_update_data = "0x" + price_data.binary.data[0]
792
826
 
793
827
  take_profit_price = int(take_profit_price * 10**10)
794
828
  stop_loss_price = int(stop_loss_price * 10**10)
@@ -799,6 +833,7 @@ class TradeRPC:
799
833
  stop_loss_price,
800
834
  take_profit_price,
801
835
  [price_update_data],
836
+ price_sourcing.value,
802
837
  ).build_transaction(
803
838
  {
804
839
  "from": trader,
@@ -487,6 +487,78 @@ class MarginUpdateType(Enum):
487
487
  WITHDRAW = 1
488
488
 
489
489
 
490
+ class PriceSourcing(Enum):
491
+ """Price sourcing options for contract calls."""
492
+
493
+ HERMES = 0 # Pyth Hermes (legacy)
494
+ PRO = 1 # Pyth Pro / Lazer
495
+
496
+
497
+ class LazerPriceFeed(BaseModel):
498
+ """Single price feed from Pyth Lazer SSE stream."""
499
+
500
+ price_feed_id: int = Field(..., alias="priceFeedId")
501
+ price: str
502
+ best_bid_price: str = Field(..., alias="bestBidPrice")
503
+ best_ask_price: str = Field(..., alias="bestAskPrice")
504
+ publisher_count: int = Field(..., alias="publisherCount")
505
+ exponent: int
506
+ confidence: int
507
+
508
+ @property
509
+ def converted_price(self) -> float:
510
+ return int(self.price) / 10 ** -self.exponent
511
+
512
+ class Config:
513
+ populate_by_name = True
514
+
515
+
516
+ class LazerPriceFeedResponse(BaseModel):
517
+ """Response from Pyth Lazer SSE stream."""
518
+
519
+ timestamp_us: str = Field(..., alias="timestampUs")
520
+ price_feeds: List[LazerPriceFeed] = Field(..., alias="priceFeeds")
521
+
522
+ @property
523
+ def timestamp_ms(self) -> int:
524
+ return int(self.timestamp_us) // 1000
525
+
526
+ class Config:
527
+ populate_by_name = True
528
+
529
+
530
+ class FeedV3CorePriceData(BaseModel):
531
+ """Core price data from feed-v3 API (Pyth Hermes)."""
532
+
533
+ price_update_data: str = Field(..., alias="priceUpdateData")
534
+ price: float
535
+ publish_timestamp_ms: int = Field(..., alias="publishTimestampMs")
536
+
537
+ class Config:
538
+ populate_by_name = True
539
+
540
+
541
+ class FeedV3ProPriceData(BaseModel):
542
+ """Pro price data from feed-v3 API (Pyth Pro/Lazer)."""
543
+
544
+ price_update_data: str = Field(..., alias="priceUpdateData")
545
+ price: float
546
+ publish_timestamp_ms: int = Field(..., alias="publishTimestampMs")
547
+
548
+ class Config:
549
+ populate_by_name = True
550
+
551
+
552
+ class FeedV3PriceResponse(BaseModel):
553
+ """Response from feed-v3 API containing both core and pro price data."""
554
+
555
+ core: FeedV3CorePriceData
556
+ pro: FeedV3ProPriceData
557
+
558
+ class Config:
559
+ populate_by_name = True
560
+
561
+
490
562
  class LossProtectionInfo(BaseModel):
491
563
  percentage: float
492
564
  amount: float
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: avantis_trader_sdk
3
+ Version: 0.8.15
4
+ Summary: SDK for interacting with Avantis trading contracts.
5
+ Home-page: https://avantisfi.com/
6
+ Author: Avantis Labs
7
+ Author-email: yug@avantisfi.com
8
+ License: MIT
9
+ Keywords: trading sdk blockchain ethereum web3 avantis
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.6
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: web3<7,>=6.15.1
16
+ Requires-Dist: pydantic<3,>=2.8.2
17
+ Requires-Dist: websockets<14,>=12.0
18
+ Requires-Dist: boto3<2,>=1.35.44
19
+ Requires-Dist: eth_account<0.14,>=0.10.0
20
+ Requires-Dist: toolz<1,>=0.12.1
21
+ Requires-Dist: eth_utils<5,>=2.1.0
22
+ Requires-Dist: pyasn1<1,>=0.6.1
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license
31
+ Dynamic: requires-dist
32
+ Dynamic: requires-python
33
+ Dynamic: summary
34
+
35
+ # Avantis Trader SDK
36
+
37
+ Python SDK for trading on [Avantis](https://avantisfi.com/) - a perpetual trading platform on Base.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install avantis-trader-sdk
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ import asyncio
49
+ from avantis_trader_sdk import TraderClient
50
+ from avantis_trader_sdk.types import TradeInput, TradeInputOrderType
51
+
52
+ async def main():
53
+ # Initialize client
54
+ trader_client = TraderClient("https://mainnet.base.org")
55
+ trader_client.set_local_signer("0xYOUR_PRIVATE_KEY")
56
+
57
+ trader = trader_client.get_signer().get_ethereum_address()
58
+
59
+ # Check and approve USDC allowance
60
+ allowance = await trader_client.get_usdc_allowance_for_trading(trader)
61
+ if allowance < 100:
62
+ await trader_client.approve_usdc_for_trading(100)
63
+
64
+ # Open a 10x long ETH position with $100 collateral
65
+ trade_input = TradeInput(
66
+ trader=trader,
67
+ pair_index=1, # ETH/USD
68
+ collateral_in_trade=100,
69
+ is_long=True,
70
+ leverage=10,
71
+ tp=5000, # take profit
72
+ sl=2500, # stop loss
73
+ )
74
+
75
+ tx = await trader_client.trade.build_trade_open_tx(
76
+ trade_input, TradeInputOrderType.MARKET, slippage_percentage=1
77
+ )
78
+ receipt = await trader_client.sign_and_get_receipt(tx)
79
+ print("Trade opened!", receipt.transactionHash.hex())
80
+
81
+ asyncio.run(main())
82
+ ```
83
+
84
+ ## Get Open Trades
85
+
86
+ ```python
87
+ trades, pending_orders = await trader_client.trade.get_trades(trader)
88
+
89
+ for trade in trades:
90
+ print(f"Pair: {trade.trade.pair_index}, Leverage: {trade.trade.leverage}x")
91
+ print(f"Entry: {trade.trade.open_price}, Liq: {trade.liquidation_price}")
92
+ ```
93
+
94
+ ## Close a Trade
95
+
96
+ ```python
97
+ trade = trades[0]
98
+ close_tx = await trader_client.trade.build_trade_close_tx(
99
+ pair_index=trade.trade.pair_index,
100
+ trade_index=trade.trade.trade_index,
101
+ collateral_to_close=trade.trade.collateral_in_trade,
102
+ trader=trader,
103
+ )
104
+ await trader_client.sign_and_get_receipt(close_tx)
105
+ ```
106
+
107
+ ## AI-Assisted Development
108
+
109
+ Building with AI tools? We provide optimized documentation:
110
+
111
+ - [AGENT.md](./AGENT.md) - Comprehensive guide for AI agents. Copy to your project or paste into AI chat.
112
+ - [.cursorrules](./.cursorrules) - Auto-loaded by Cursor IDE.
113
+
114
+ ```bash
115
+ curl -o AGENT.md https://raw.githubusercontent.com/Avantis-Labs/avantis_trader_sdk/main/AGENT.md
116
+ ```
117
+
118
+ ## Resources
119
+
120
+ - [Documentation](https://sdk.avantisfi.com/)
121
+ - [Examples](https://github.com/Avantis-Labs/avantis_trader_sdk/tree/main/examples)
122
+ - [Avantis Docs](https://docs.avantisfi.com/)
123
+
124
+ ## License
125
+
126
+ MIT
@@ -1,7 +1,7 @@
1
- avantis_trader_sdk/__init__.py,sha256=yDgKgOYEOlq-pVM-QqjmrO_UFl0aObe5ZjcgtRf4y7w,135
1
+ avantis_trader_sdk/__init__.py,sha256=qpix2Zruoll9hF1RrY9b0Z2na5gVuibZalTuAHJX_04,168
2
2
  avantis_trader_sdk/client.py,sha256=M01uwXIdxJjmPEcFr1MsDuoxU9YGddxcGMTPucOOssA,10903
3
- avantis_trader_sdk/config.py,sha256=ffmArpqwoXEupCt5aG8Q22da58Eye3jV1-f-PegTjiw,710
4
- avantis_trader_sdk/types.py,sha256=8UjPERXxVJ-zthDHZ4YlYU3goaXzMbZenTB8nQDQGwA,15379
3
+ avantis_trader_sdk/config.py,sha256=sE9y9R1ql1UwpFSs-qTbNfvO5iffRRUdYtx_JVOaWyA,838
4
+ avantis_trader_sdk/types.py,sha256=spp3n7UedgVM-w9JyCzQuqi8JiJmSjm24j4cxg0-gx8,17274
5
5
  avantis_trader_sdk/utils.py,sha256=gTYgNVVd5rLZEUf2eyJftjKYxn55wRm09xAXIF_xjXM,2831
6
6
  avantis_trader_sdk/abis/AggregatorV3Interface.json,sha256=qUeDGZ55Akgu8zOv_Wzf21sTREEyZXF47K_TdPcliBM,26244
7
7
  avantis_trader_sdk/abis/Sanctions.json,sha256=Fsn67jEGW4GdS15icrtxN_sur4e8-06SoijL7K79vAE,3857
@@ -128,7 +128,7 @@ avantis_trader_sdk/abis/Timelock.t.sol/Timelock.json,sha256=N58EBp-LRYuIUvs5s0ze
128
128
  avantis_trader_sdk/abis/TimelockBase.t.sol/TimelockBase.json,sha256=Bx-U5If_X5Dd49-GBDQTst3gDp8hG1YptPxoDyw3auw,1111293
129
129
  avantis_trader_sdk/abis/TimelockController.sol/TimelockController.json,sha256=k6uk3eErrOFWCIaSBno0aqziOi744NEdxnK8vG-ohrA,333379
130
130
  avantis_trader_sdk/abis/TradeBase.t.sol/TradeBase.json,sha256=w3sGtHzPkd45TLRhRxQzlUPmwYfjay7_4rU6CyuFu9M,1328584
131
- avantis_trader_sdk/abis/Trading.sol/Trading.json,sha256=Gkqzgl2aZUABJDGvMzqoRLApwResZAt7mzusO6SK3iI,228389
131
+ avantis_trader_sdk/abis/Trading.sol/Trading.json,sha256=IM8Uv4SSXq23L8W-eJSzPtmz_h10WaRWao5ks0uiOLo,41789
132
132
  avantis_trader_sdk/abis/TradingCallbacks.sol/TradingCallbacks.json,sha256=m_tO-wHtc5hXMky0wbLj6lqFt12SgtjlBQZQnmShECU,199077
133
133
  avantis_trader_sdk/abis/TradingStorage.sol/TradingStorage.json,sha256=ImaFCa_a4htBOw99ITGzfuWlUeN3CvIROv0f4KH-hqw,313012
134
134
  avantis_trader_sdk/abis/Tranche.sol/Tranche.json,sha256=AZX5KxzyXI6ao93UrZsqQE9FpNZAArOqReJX0OzoT2E,392082
@@ -195,16 +195,16 @@ avantis_trader_sdk/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
195
195
  avantis_trader_sdk/crypto/spki.py,sha256=CNy7A8TTwBHiNSzIj7uqiHKAeLcn1Q9MbszW_2mdXgI,3080
196
196
  avantis_trader_sdk/feed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
197
  avantis_trader_sdk/feed/feedIds.json,sha256=T77nww3eRiQt8rqZBDpdxA49USGyfI0dQBPnzo-H1dE,6697
198
- avantis_trader_sdk/feed/feed_client.py,sha256=Qnx-RAFd9pzYK7GY6IKzon20_ioI3OuSvFWxlhMnzrY,9403
198
+ avantis_trader_sdk/feed/feed_client.py,sha256=fwdmS_9b6N-CAbmu2Lq_26uKahMLsYKNglg6XF8xZHQ,13755
199
199
  avantis_trader_sdk/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
200
200
  avantis_trader_sdk/rpc/asset_parameters.py,sha256=ESx4eg0K3W9EigsEmN0a7Pym2hL4iJgMWmzhHmmWXyY,19323
201
201
  avantis_trader_sdk/rpc/blended.py,sha256=tRWfO7XreY_YahL9ACpss7ylWz5fdk6G3bv4QpLpGms,2441
202
202
  avantis_trader_sdk/rpc/category_parameters.py,sha256=ofsKct23E8DThCKqP627ol-_YPIdN5HAn09eLqyf6WM,7965
203
203
  avantis_trader_sdk/rpc/fee_parameters.py,sha256=0UCf4FZQp26777o8aA75oOO-b3xFK88c-_glbqQ2-8M,9132
204
- avantis_trader_sdk/rpc/pairs_cache.py,sha256=Cts7EqblH6WQ2Gc2OwYGkLtxlzu33-T4cd7hQCuNkcw,6610
204
+ avantis_trader_sdk/rpc/pairs_cache.py,sha256=wtxkvaemVbJclCSiOcyelbBcQzwJbIOP0JF0rfyE56M,7234
205
205
  avantis_trader_sdk/rpc/rpc_helpers.py,sha256=Sywz6BIj4y2gkudkOhPEND2r2ILvtfq502A_pSEUDv8,284
206
206
  avantis_trader_sdk/rpc/snapshot.py,sha256=hfLRfCbOqnqcuZncaiTmm0BJ2pgLFOEHgsgQ-92Xlcs,5352
207
- avantis_trader_sdk/rpc/trade.py,sha256=Aw_YJ5WGAfpleTISl7xyZw_6sVj4EBRSXHLuG_qzPSk,30141
207
+ avantis_trader_sdk/rpc/trade.py,sha256=EB9JEAih2s0y3h2Y1VnYboc7-gQQe-aQa3RBoseAiwk,32220
208
208
  avantis_trader_sdk/rpc/trading_parameters.py,sha256=_tpzgyMO_I-XebVWtiWSlmedtbr66elUxCRgegd1aao,4626
209
209
  avantis_trader_sdk/signers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
210
210
  avantis_trader_sdk/signers/base.py,sha256=QaOu0CxFq60oR4LegCp1XwONMQx8ZShXyiLZvfcbCPM,260
@@ -212,7 +212,7 @@ avantis_trader_sdk/signers/kms_signer.py,sha256=lxK3f9KQsdCDAvOE1SHleKjI8zD_3PTv
212
212
  avantis_trader_sdk/signers/local_signer.py,sha256=kUx5vExiBfvFGmoMCFR6b7_4cXx2mvYOJNqZQDIEcG8,505
213
213
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
214
  tests/test_client.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
215
- avantis_trader_sdk-0.8.13.dist-info/METADATA,sha256=50-W4zc-CnQ5WxvF4WsTDNaRjPm0YIQuBV0ubMEqpFg,5032
216
- avantis_trader_sdk-0.8.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
217
- avantis_trader_sdk-0.8.13.dist-info/top_level.txt,sha256=XffaQJ68SGT1KUz2HHXSGSEsmNy8-AGjgtO127xhzQA,25
218
- avantis_trader_sdk-0.8.13.dist-info/RECORD,,
215
+ avantis_trader_sdk-0.8.15.dist-info/METADATA,sha256=1XhW8Ak1oBkrDgb2UBASGfWIV2et7Pnt6tAliqbnUUo,3514
216
+ avantis_trader_sdk-0.8.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
217
+ avantis_trader_sdk-0.8.15.dist-info/top_level.txt,sha256=XffaQJ68SGT1KUz2HHXSGSEsmNy8-AGjgtO127xhzQA,25
218
+ avantis_trader_sdk-0.8.15.dist-info/RECORD,,