trd-utils 0.0.19__py3-none-any.whl → 0.0.20__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.

Potentially problematic release.


This version of trd-utils might be problematic. Click here for more details.

trd_utils/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- __version__ = "0.0.19"
2
+ __version__ = "0.0.20"
3
3
 
@@ -0,0 +1,26 @@
1
+ """
2
+ General usage wallet-related utils code.
3
+ """
4
+
5
+
6
+ def shorten_wallet_address(
7
+ address: str,
8
+ start_chars: int = 7,
9
+ end_chars: int = 6,
10
+ ):
11
+ """
12
+ Shortens an Ethereum address by keeping a specific number of characters
13
+ from the beginning and end, separated by '...'.
14
+
15
+ Args:
16
+ address (str): The Ethereum address to shorten
17
+ start_chars (int): Number of characters to keep from the beginning (default: 7)
18
+ end_chars (int): Number of characters to keep from the end (default: 6)
19
+
20
+ Returns:
21
+ str: The shortened address
22
+ """
23
+ if not address or len(address) <= start_chars + end_chars:
24
+ return address
25
+
26
+ return f"{address[:start_chars]}...{address[-end_chars:]}"
@@ -1,10 +1,9 @@
1
-
2
-
3
1
  from datetime import datetime
4
2
  from decimal import Decimal
5
3
 
6
4
  from trd_utils.types_helper.base_model import BaseModel
7
5
 
6
+
8
7
  class UnifiedPositionInfo(BaseModel):
9
8
  # The id of the position.
10
9
  position_id: str = None
@@ -40,20 +39,22 @@ class UnifiedPositionInfo(BaseModel):
40
39
 
41
40
  def __str__(self):
42
41
  parts = []
43
-
42
+
44
43
  # Add position pair and ID
45
- parts.append(f"Position: {self.position_pair or 'Unknown'} (ID: {self.position_id or 'N/A'})")
46
-
44
+ parts.append(
45
+ f"Position: {self.position_pair or 'Unknown'} (ID: {self.position_id or 'N/A'})"
46
+ )
47
+
47
48
  # Add side and leverage
48
49
  side_str = f"Side: {self.position_side or 'Unknown'}"
49
50
  if self.position_leverage is not None:
50
51
  side_str += f", {self.position_leverage}x"
51
52
  parts.append(side_str)
52
-
53
+
53
54
  # Add margin mode if available
54
55
  if self.margin_mode:
55
56
  parts.append(f"Margin: {self.margin_mode}")
56
-
57
+
57
58
  # Add open price if available
58
59
  price_str = "Open price: "
59
60
  if self.open_price is not None:
@@ -63,23 +64,25 @@ class UnifiedPositionInfo(BaseModel):
63
64
  else:
64
65
  price_str += "N/A"
65
66
  parts.append(price_str)
66
-
67
+
67
68
  # Add open time if available
68
69
  if self.open_time:
69
70
  parts.append(f"Opened: {self.open_time.strftime('%Y-%m-%d %H:%M:%S')}")
70
-
71
+
71
72
  # Add PNL if available
72
73
  if self.position_pnl is not None:
73
74
  parts.append(f"PNL: {self.position_pnl}")
74
-
75
+
75
76
  return " | ".join(parts)
76
77
 
77
78
  def __repr__(self):
78
79
  return self.__str__()
79
80
 
81
+
80
82
  class UnifiedTraderPositions(BaseModel):
81
83
  positions: list[UnifiedPositionInfo] = None
82
84
 
85
+
83
86
  class UnifiedTraderInfo(BaseModel):
84
87
  # Trader's id. Either int or str. In DEXes (such as HyperLiquid),
85
88
  # this might be wallet address of the trader.
@@ -94,13 +97,15 @@ class UnifiedTraderInfo(BaseModel):
94
97
  # Trader's win-rate. Not all exchanges might support this field.
95
98
  win_rate: Decimal = None
96
99
 
100
+ def get_win_rate_str(self) -> str:
101
+ return str(round(self.win_rate, 2)) if self.win_rate is not None else "N/A"
102
+
97
103
  def __str__(self):
98
104
  return (
99
- f"Trader: {self.trader_name} (ID: {self.trader_id})"
100
- f"{' | Win Rate: ' + str(round(self.win_rate, 2))}"
101
- f"{' | Profile: ' + self.trader_url}"
105
+ f"{self.trader_name} ({self.trader_id})"
106
+ f" | Win Rate: {self.get_win_rate_str()}"
107
+ f" | Profile: {self.trader_url}"
102
108
  )
103
-
109
+
104
110
  def __repr__(self):
105
111
  return self.__str__()
106
-
@@ -8,11 +8,15 @@ import httpx
8
8
  from pathlib import Path
9
9
 
10
10
  from trd_utils.cipher import AESCipher
11
+ from trd_utils.common_utils.wallet_utils import shorten_wallet_address
12
+ from trd_utils.exchanges.base_types import UnifiedPositionInfo, UnifiedTraderInfo, UnifiedTraderPositions
11
13
  from trd_utils.exchanges.exchange_base import ExchangeBase
12
14
  from trd_utils.exchanges.hyperliquid.hyperliquid_types import HyperLiquidApiResponse, TraderPositionsInfoResponse
13
15
 
14
16
  logger = logging.getLogger(__name__)
15
17
 
18
+ BASE_PROFILE_URL = "https://hypurrscan.io/address/"
19
+
16
20
 
17
21
  class HyperLiquidClient(ExchangeBase):
18
22
  ###########################################################
@@ -63,7 +67,7 @@ class HyperLiquidClient(ExchangeBase):
63
67
  f"{self.hyperliquid_api_base_host}/info",
64
68
  headers=headers,
65
69
  content=payload,
66
- model=TraderPositionsInfoResponse,
70
+ model_type=TraderPositionsInfoResponse,
67
71
  )
68
72
 
69
73
  #endregion
@@ -78,7 +82,7 @@ class HyperLiquidClient(ExchangeBase):
78
82
  # f"{self.hyperliquid_api_base_url}/another-thing/info",
79
83
  # headers=headers,
80
84
  # content=payload,
81
- # model=CopyTraderInfoResponse,
85
+ # model_type=CopyTraderInfoResponse,
82
86
  # )
83
87
 
84
88
  # endregion
@@ -138,3 +142,48 @@ class HyperLiquidClient(ExchangeBase):
138
142
 
139
143
  # endregion
140
144
  ###########################################################
145
+ # region unified methods
146
+ async def get_unified_trader_positions(
147
+ self,
148
+ uid: int | str,
149
+ ) -> UnifiedTraderPositions:
150
+ result = await self.get_trader_positions_info(
151
+ uid=uid,
152
+ )
153
+ unified_result = UnifiedTraderPositions()
154
+ unified_result.positions = []
155
+ for position_container in result.asset_positions:
156
+ position = position_container.position
157
+ unified_pos = UnifiedPositionInfo()
158
+ unified_pos.position_id = position.get_position_id()
159
+ unified_pos.position_pnl = round(position.unrealized_pnl, 3)
160
+ unified_pos.position_side = position.get_side()
161
+ unified_pos.margin_mode = position.leverage.type
162
+ unified_pos.position_leverage = Decimal(position.leverage.value)
163
+ unified_pos.position_pair = f"{position.coin}/USDT"
164
+ unified_pos.open_time = None # hyperliquid doesn't provide this...
165
+ unified_pos.open_price = position.entry_px
166
+ unified_pos.open_price_unit = "USDT"
167
+ unified_result.positions.append(unified_pos)
168
+
169
+ return unified_result
170
+
171
+ async def get_unified_trader_info(
172
+ self,
173
+ uid: int | str,
174
+ ) -> UnifiedTraderInfo:
175
+ if not isinstance(uid, str):
176
+ uid = str(uid)
177
+ # sadly hyperliquid doesn't really have an endpoint to fetch information
178
+ # so we have to somehow *fake* these...
179
+ # maybe in future try to find a better way?
180
+ unified_info = UnifiedTraderInfo()
181
+ unified_info.trader_id = uid
182
+ unified_info.trader_name = shorten_wallet_address(uid)
183
+ unified_info.trader_url = f"{BASE_PROFILE_URL}{uid}"
184
+ unified_info.win_rate = None
185
+
186
+ return unified_info
187
+
188
+ # endregion
189
+ ###########################################################
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: trd_utils
3
- Version: 0.0.19
3
+ Version: 0.0.20
4
4
  Summary: Common Basic Utils for Python3. By ALiwoto.
5
5
  Keywords: utils,trd_utils,basic-utils,common-utils
6
6
  Author: ALiwoto
@@ -1,11 +1,12 @@
1
- trd_utils/__init__.py,sha256=5VsjvbcZt1tZKEb5CSJ0arTPA63xHY8ibWQ5EXVRXvY,25
1
+ trd_utils/__init__.py,sha256=zuFTqIXT51Hc1FEjtDNWqv0BXlPgdEGVKQ_5Z4W4oZs,25
2
2
  trd_utils/cipher/__init__.py,sha256=V05KNuzQwCic-ihMVHlC8sENaJGc3I8MCb4pg4849X8,1765
3
3
  trd_utils/common_utils/float_utils.py,sha256=W-jv7nzjl88xwGB6gsEXmDDhF6DseOrrVT2qx7OvyCo,266
4
+ trd_utils/common_utils/wallet_utils.py,sha256=OX9q2fymP0VfIWTRIRBP8W33cfyjLXimxMgPOsZe-3g,727
4
5
  trd_utils/date_utils/__init__.py,sha256=Erg_E1TfKWNpiuZFm_NXRjCwoRMfxpPS2-mJK6V4lFM,77
5
6
  trd_utils/date_utils/datetime_helpers.py,sha256=euIJBr-6PfJzLScOC9xVXd8Re_Gw5CSBPwtHX9_Il4A,596
6
7
  trd_utils/exchanges/README.md,sha256=UwkpsfcoLCJaMvJe4yBsFkDpf8P6DOLYhtybb6xWMLc,6738
7
8
  trd_utils/exchanges/__init__.py,sha256=x74_8-P7ktZyL-1AuAU_SDQD8eKZMPh1gfkLzPuS1xY,440
8
- trd_utils/exchanges/base_types.py,sha256=bPsRUetQIHdW7ESMAQcjvX-Z2uixtCC93Vb-XnX6FFs,3229
9
+ trd_utils/exchanges/base_types.py,sha256=9sjXwGaUlUgdYg2NJz64AIalPxKc2aGvjVZdt6aM63I,3284
9
10
  trd_utils/exchanges/blofin/__init__.py,sha256=X4r9o4Nyjla4UeOBG8lrgtnGYO2aErFMKaJ7yQrFasE,76
10
11
  trd_utils/exchanges/blofin/blofin_client.py,sha256=x0CU75_wWRA6RmVfm2wh7y-jNjohpcMG6HJ1tqkD1ok,12342
11
12
  trd_utils/exchanges/blofin/blofin_types.py,sha256=LnK3LEVlqU3Vg0Cg1jNmb5GGHQImwI6LCKaDw-aQa6A,4059
@@ -16,7 +17,7 @@ trd_utils/exchanges/bx_ultra/bx_utils.py,sha256=PwapomwDW33arVmKIDj6cL-aP0ptu4BY
16
17
  trd_utils/exchanges/exchange_base.py,sha256=ZY_9vL9LXtAbAmlWygdVyy0wC-QDla-JGWZ8HMRlkk8,4266
17
18
  trd_utils/exchanges/hyperliquid/README.md,sha256=-qaxmDt_9NTus2xRuzyFGkKgYDWgWk7ufHVTSkyn3t4,105
18
19
  trd_utils/exchanges/hyperliquid/__init__.py,sha256=QhwGRcneGFHREM-MMdYpbcx-aWdsWsu2WznHzx7LaUM,92
19
- trd_utils/exchanges/hyperliquid/hyperliquid_client.py,sha256=xLSZWTwjm2i0Paa8x8csdCahE16GN0yaP2b7wpV_S0w,4764
20
+ trd_utils/exchanges/hyperliquid/hyperliquid_client.py,sha256=rqR5AG3aLV6vcho2lvYSgl8SCz-cFTNwag8dNLLDcn4,6852
20
21
  trd_utils/exchanges/hyperliquid/hyperliquid_types.py,sha256=ueL7Q4yOAK4orlUqeLVNRk6u1AG83pDeGJasTeT3774,2666
21
22
  trd_utils/html_utils/__init__.py,sha256=1WWs8C7JszRjTkmzIRLHpxWECHur_DrulTPGIeX88oM,426
22
23
  trd_utils/html_utils/html_formats.py,sha256=unKsvOiiDmYTTaM0DYZEUNLEUzWQKKrqASJXvY54kvU,2299
@@ -25,7 +26,7 @@ trd_utils/tradingview/tradingview_client.py,sha256=g_eWYaCRQAL8Kvd-r6AnAdbH7Jha6
25
26
  trd_utils/tradingview/tradingview_types.py,sha256=z21MXPVdWHAduEl3gSeMIRhxtBN9yK-jPYHfZSMIbSA,6144
26
27
  trd_utils/types_helper/__init__.py,sha256=lLbUiW1jUV1gjzTMFLthwkvF0hwauH-F_J2JZq--1U0,67
27
28
  trd_utils/types_helper/base_model.py,sha256=zehCrDH-9OhWtdKVu05yfcKP52oBD303aMEhs_nytSg,10892
28
- trd_utils-0.0.19.dist-info/LICENSE,sha256=J1EP2xt87RjjmsTV1jTjHDQMLIM9FjdwEftTpw8hyv4,1067
29
- trd_utils-0.0.19.dist-info/METADATA,sha256=GB_FuAcnnuw3a6HaRWIlEZeeF2IR1u5f4zFIYaXvqbg,1095
30
- trd_utils-0.0.19.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
31
- trd_utils-0.0.19.dist-info/RECORD,,
29
+ trd_utils-0.0.20.dist-info/LICENSE,sha256=J1EP2xt87RjjmsTV1jTjHDQMLIM9FjdwEftTpw8hyv4,1067
30
+ trd_utils-0.0.20.dist-info/METADATA,sha256=9p1L_6c3sR9uN8UR0_hBQ-aFNMvuD4dj9E1GiVGKbFY,1095
31
+ trd_utils-0.0.20.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ trd_utils-0.0.20.dist-info/RECORD,,