ostium-python-sdk 0.2.107__tar.gz → 2.0.0__tar.gz

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.
Files changed (52) hide show
  1. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/PKG-INFO +37 -2
  2. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/README.md +31 -1
  3. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/constants.py +1 -0
  4. ostium_python_sdk-2.0.0/ostium_python_sdk/formulae.py +313 -0
  5. ostium_python_sdk-2.0.0/ostium_python_sdk/formulae_wrapper.py +204 -0
  6. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/scscript/funding.py +4 -2
  7. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/sdk.py +36 -78
  8. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/subgraph.py +11 -9
  9. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk.egg-info/PKG-INFO +37 -2
  10. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk.egg-info/SOURCES.txt +12 -0
  11. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/setup.py +1 -1
  12. ostium_python_sdk-2.0.0/tests/test_current_total_profit_p.py +37 -0
  13. ostium_python_sdk-2.0.0/tests/test_current_total_profit_raw.py +57 -0
  14. ostium_python_sdk-2.0.0/tests/test_current_trade_profit_p.py +111 -0
  15. ostium_python_sdk-2.0.0/tests/test_current_trade_profit_raw.py +29 -0
  16. ostium_python_sdk-2.0.0/tests/test_funding.py +518 -0
  17. ostium_python_sdk-2.0.0/tests/test_get_trade_funding_fee.py +25 -0
  18. ostium_python_sdk-2.0.0/tests/test_get_trade_rollover_fee.py +25 -0
  19. ostium_python_sdk-2.0.0/tests/test_remove_collateral_from_leverage.py +44 -0
  20. ostium_python_sdk-2.0.0/tests/test_remove_collateral_with_collateral.py +44 -0
  21. ostium_python_sdk-2.0.0/tests/test_top_up_with_collateral.py +52 -0
  22. ostium_python_sdk-2.0.0/tests/test_top_up_with_leverage.py +45 -0
  23. ostium_python_sdk-2.0.0/tests/test_trade_get_sl_price.py +47 -0
  24. ostium_python_sdk-2.0.0/tests/test_trade_get_tp_price.py +67 -0
  25. ostium_python_sdk-2.0.0/tests/test_trade_liquidation_price.py +88 -0
  26. ostium_python_sdk-0.2.107/ostium_python_sdk/formulae.py +0 -449
  27. ostium_python_sdk-0.2.107/ostium_python_sdk/formulae_wrapper.py +0 -316
  28. ostium_python_sdk-0.2.107/tests/test_trade_get_tp_price.py +0 -39
  29. ostium_python_sdk-0.2.107/tests/test_trade_liquidation_price.py +0 -32
  30. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/MANIFEST.in +0 -0
  31. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/__init__.py +0 -0
  32. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/abi/__init__.py +0 -0
  33. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/abi/abi.py +0 -0
  34. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/abi/faucet_abi.py +0 -0
  35. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/balance.py +0 -0
  36. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/config.py +0 -0
  37. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/exceptions.py +0 -0
  38. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/faucet.py +0 -0
  39. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/ostium.py +0 -0
  40. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/price.py +0 -0
  41. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/scscript/__init__.py +0 -0
  42. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk/utils.py +0 -0
  43. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk.egg-info/dependency_links.txt +0 -0
  44. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk.egg-info/requires.txt +0 -0
  45. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/ostium_python_sdk.egg-info/top_level.txt +0 -0
  46. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/pyproject.toml +0 -0
  47. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/requirements-dev.txt +0 -0
  48. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/requirements.txt +0 -0
  49. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/setup.cfg +0 -0
  50. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/tests/__init__.py +0 -0
  51. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/tests/test_get_price_impact.py +0 -0
  52. {ostium_python_sdk-0.2.107 → ostium_python_sdk-2.0.0}/tests/test_slippage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ostium-python-sdk
3
- Version: 0.2.107
3
+ Version: 2.0.0
4
4
  Summary: A python based SDK developed for interacting with Ostium, a leveraged trading application for trading currencies, commodities, indices, crypto and more.
5
5
  Home-page: https://github.com/0xOstium/ostium-python-sdk
6
6
  Author: ami@ostium.io
@@ -86,8 +86,38 @@ First, install the package with development dependencies:
86
86
  pip install -e ".[dev]"
87
87
  ```
88
88
 
89
- Then run the tests:
89
+ ## Running tests
90
+
91
+ ### Run specific tests
90
92
 
93
+ ```bash
94
+ pytest -v tests/test_trade_liquidation_price.py
95
+ pytest -v tests/test_funding.py
96
+ pytest -v tests/test_trade_get_tp_price.py
97
+ pytest -v tests/test_trade_get_sl_price.py
98
+ pytest -v tests/test_current_trade_profit_p.py
99
+ pytest -v tests/test_top_up_with_collateral.py
100
+ pytest -v tests/test_top_up_with_leverage.py
101
+ pytest -v tests/test_remove_collateral_with_collateral.py
102
+ pytest -v tests/test_remove_collateral_from_leverage.py
103
+ pytest -v tests/test_current_total_profit_p.py
104
+ pytest -v tests/test_current_trade_profit_raw.py
105
+ pytest -v tests/test_current_total_profit_raw.py
106
+ pytest -v tests/test_get_trade_funding_fee.py
107
+ pytest -v tests/test_get_trade_rollover_fee.py
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+ ```
119
+
120
+ ### Run ALL tests
91
121
  ```bash
92
122
  pytest
93
123
  ```
@@ -514,6 +544,11 @@ All notable changes to the Ostium Python SDK will be documented in this file.
514
544
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
515
545
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
516
546
 
547
+
548
+ ## [2.0.0] - 2025-03-04
549
+
550
+ Version 2.0
551
+
517
552
  ## [0.2.1] - 2025-02-21
518
553
 
519
554
  ### Added
@@ -47,8 +47,38 @@ First, install the package with development dependencies:
47
47
  pip install -e ".[dev]"
48
48
  ```
49
49
 
50
- Then run the tests:
50
+ ## Running tests
51
51
 
52
+ ### Run specific tests
53
+
54
+ ```bash
55
+ pytest -v tests/test_trade_liquidation_price.py
56
+ pytest -v tests/test_funding.py
57
+ pytest -v tests/test_trade_get_tp_price.py
58
+ pytest -v tests/test_trade_get_sl_price.py
59
+ pytest -v tests/test_current_trade_profit_p.py
60
+ pytest -v tests/test_top_up_with_collateral.py
61
+ pytest -v tests/test_top_up_with_leverage.py
62
+ pytest -v tests/test_remove_collateral_with_collateral.py
63
+ pytest -v tests/test_remove_collateral_from_leverage.py
64
+ pytest -v tests/test_current_total_profit_p.py
65
+ pytest -v tests/test_current_trade_profit_raw.py
66
+ pytest -v tests/test_current_total_profit_raw.py
67
+ pytest -v tests/test_get_trade_funding_fee.py
68
+ pytest -v tests/test_get_trade_rollover_fee.py
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+ ```
80
+
81
+ ### Run ALL tests
52
82
  ```bash
53
83
  pytest
54
84
  ```
@@ -5,6 +5,7 @@ from decimal import Decimal
5
5
 
6
6
  MAX_PROFIT_P = Decimal('900') # 900% * PRECISION_6
7
7
  MAX_STOP_LOSS_P = Decimal('85')
8
+ MIN_LOSS_P = Decimal("-100") # Adjust if you need a different minimum
8
9
 
9
10
  PRECISION_2 = Decimal('100')
10
11
  PRECISION_6 = Decimal('1000000')
@@ -0,0 +1,313 @@
1
+ from decimal import Decimal, getcontext, ROUND_DOWN
2
+ from .constants import MAX_PROFIT_P, MIN_LOSS_P, MAX_STOP_LOSS_P, PRECISION_16, PRECISION_2, PRECISION_6, PRECISION_12, PRECISION_18, LIQ_THRESHOLD_P
3
+ from typing import Dict
4
+ from .scscript.funding import getPendingAccFundingFees, getTargetFundingRate
5
+
6
+ quantization_6 = Decimal('0.000001')
7
+ quantization_18 = Decimal('0.000000000000000001')
8
+
9
+ # v2 (formulae v1.3.3)
10
+
11
+
12
+ def GetTakeProfitPrice(open_price: Decimal, profit_p: Decimal, leverage: Decimal, is_long: bool) -> Decimal:
13
+ open_price = Decimal(open_price)
14
+ profit_p = Decimal(profit_p)
15
+ leverage = Decimal(leverage)
16
+
17
+ price_diff = (open_price * profit_p) / (leverage * Decimal('100'))
18
+
19
+ if (is_long):
20
+ tp_price = open_price + price_diff
21
+ else:
22
+ tp_price = open_price - price_diff
23
+
24
+ return Decimal(tp_price if tp_price > 0 else '0')
25
+
26
+ # v2 (formulae v1.3.3)
27
+
28
+
29
+ def GetStopLossPrice(open_price: Decimal, loss_p: Decimal, leverage: Decimal, is_long: bool) -> Decimal:
30
+ open_price = Decimal(open_price)
31
+ loss_p = Decimal(loss_p)
32
+ leverage = Decimal(leverage)
33
+
34
+ # price_diff matches your existing TP logic style, except using 'loss_p'
35
+ price_diff = (open_price * loss_p) / (leverage * Decimal('100'))
36
+
37
+ sl_price = open_price - price_diff if is_long else open_price + price_diff
38
+ return sl_price if sl_price > 0 else Decimal('0')
39
+
40
+ # v2 (formulae v1.3.3)
41
+
42
+
43
+ def CurrentTradeProfitP(
44
+ open_price: Decimal,
45
+ current_price: Decimal,
46
+ long: bool,
47
+ leverage: Decimal,
48
+ highest_leverage: Decimal
49
+ ) -> Decimal:
50
+ leverage_to_use = leverage if leverage > highest_leverage else highest_leverage
51
+ if long:
52
+ price_diff = current_price - open_price
53
+ else:
54
+ price_diff = open_price - current_price
55
+
56
+ profit_p = (price_diff / open_price) * leverage_to_use * Decimal("100")
57
+
58
+ if profit_p >= MAX_PROFIT_P:
59
+ profit_p = MAX_PROFIT_P
60
+
61
+ profit_p *= (leverage / leverage_to_use)
62
+
63
+ return profit_p
64
+
65
+ # v2 (formulae v1.3.3)
66
+
67
+
68
+ def TopUpWithCollateral(
69
+ leverage: Decimal,
70
+ collateral: Decimal,
71
+ added_collateral: Decimal
72
+ ) -> Decimal:
73
+ new_leverage = (collateral * leverage) / (collateral + added_collateral)
74
+ return new_leverage
75
+
76
+ # v2 (formulae v1.3.3)
77
+
78
+
79
+ def TopUpWithLeverage(
80
+ leverage: Decimal,
81
+ desired_leverage: Decimal,
82
+ collateral: Decimal
83
+ ) -> Decimal:
84
+ added_c = (collateral * leverage) / desired_leverage - collateral
85
+ return added_c
86
+
87
+ # v2 (formulae v1.3.3)
88
+
89
+
90
+ def RemoveCollateralWithCollateral(
91
+ leverage: Decimal,
92
+ collateral: Decimal,
93
+ removed_collateral: Decimal
94
+ ) -> Decimal:
95
+ new_leverage = (collateral * leverage) / (collateral - removed_collateral)
96
+ return new_leverage
97
+
98
+ # v2 (formulae v1.3.3)
99
+
100
+
101
+ def RemoveCollateralFromLeverage(
102
+ leverage: Decimal,
103
+ desired_leverage: Decimal,
104
+ collateral: Decimal
105
+ ) -> Decimal:
106
+ added_c = collateral - (collateral * leverage / desired_leverage)
107
+ return added_c
108
+
109
+ # tbd - used by SDK
110
+ # v2 (formulae v1.3.3)
111
+
112
+
113
+ def GetTradeLiquidationPrice(
114
+ open_price: Decimal,
115
+ long: bool,
116
+ collateral: Decimal,
117
+ leverage: Decimal,
118
+ rollover_fee: Decimal,
119
+ funding_fee: Decimal
120
+ ) -> Decimal:
121
+ print(
122
+ f"***** GetTradeLiquidationPrice: open_price: {open_price}, long: {long}, collateral: {collateral}, leverage: {leverage}, rollover_fee: {rollover_fee}, funding_fee: {funding_fee}")
123
+
124
+ liq_price_distance = (
125
+ open_price *
126
+ (collateral * (LIQ_THRESHOLD_P) / Decimal(100) - rollover_fee - funding_fee) /
127
+ collateral /
128
+ leverage
129
+ )
130
+
131
+ liq_price = open_price - liq_price_distance if long else open_price + liq_price_distance
132
+ liq_price = liq_price if liq_price > 0 else 0
133
+ return liq_price
134
+
135
+
136
+ # ???
137
+ def GetCurrentRolloverFee(
138
+ acc_rollover: str,
139
+ last_rollover_block: str,
140
+ rollover_fee_per_block: str,
141
+ latest_block: str
142
+ ) -> Decimal:
143
+ try:
144
+ acc_rollover = Decimal(acc_rollover)
145
+ last_rollover_block = Decimal(last_rollover_block)
146
+ rollover_fee_per_block = Decimal(rollover_fee_per_block)
147
+ latest_block = Decimal(latest_block)
148
+ current_fee = acc_rollover + \
149
+ (latest_block - last_rollover_block) * rollover_fee_per_block
150
+ return current_fee
151
+
152
+ except Exception as error:
153
+ raise Exception(f"Unable to compute Current Rollover Fee: {error}")
154
+
155
+
156
+ # v2 (formulae v1.3.3)
157
+ def GetTradeRolloverFee(
158
+ trade_rollover: Decimal,
159
+ current_rollover: Decimal,
160
+ collateral: Decimal,
161
+ leverage: Decimal
162
+ ) -> Decimal:
163
+ rollover_fee = (current_rollover - trade_rollover) * collateral * leverage
164
+ return rollover_fee
165
+
166
+
167
+ # Gets the funding fee (abs) for an open trade (up to this block, aka based on current_funding up till this block)
168
+ # v2 (formulae v1.3.3)
169
+ def GetTradeFundingFee(
170
+ trade_funding: Decimal,
171
+ current_funding: Decimal,
172
+ collateral: Decimal,
173
+ leverage: Decimal
174
+ ) -> Decimal:
175
+ print(
176
+ f"======> GetTradeFundingFee: trade_funding: {trade_funding}, current_funding: {current_funding}, collateral: {collateral}, leverage: {leverage}")
177
+ funding_fee = (current_funding - trade_funding) * collateral * leverage
178
+ return funding_fee
179
+
180
+
181
+ def GetPriceImpact(
182
+ mid_price: str,
183
+ bid_price: str,
184
+ ask_price: str,
185
+ is_open: bool,
186
+ is_long: bool,
187
+ ) -> dict:
188
+ try:
189
+ mid_price = Decimal(mid_price)
190
+ bid_price = Decimal(bid_price)
191
+ ask_price = Decimal(ask_price)
192
+
193
+ if (mid_price == 0):
194
+ return {
195
+ 'priceImpactP': str(0),
196
+ 'priceAfterImpact': str(0)
197
+ }
198
+
199
+ above_spot = is_open == is_long
200
+ used_price = ask_price if above_spot else bid_price
201
+ priceImpactP = 100 * (abs(mid_price - used_price) / mid_price)
202
+
203
+ return {
204
+ 'priceImpactP': str(priceImpactP),
205
+ 'priceAfterImpact': str(used_price)
206
+ }
207
+
208
+ except Exception as error:
209
+ raise Exception(f"Unable to compute Price Impact: {error}")
210
+
211
+
212
+ # calculates the gross (without fees) profit (abs) of an open trade
213
+
214
+ # calculates the net profit (after fees) of an open trade (abs)
215
+ # v2 (formulae v1.3.3)
216
+ def CurrentTradeProfitRaw(
217
+ open_price: Decimal,
218
+ current_price: Decimal,
219
+ long: bool,
220
+ leverage: Decimal,
221
+ highest_leverage: Decimal,
222
+ collateral: Decimal
223
+ ) -> Decimal:
224
+ profit_p = CurrentTradeProfitP(
225
+ open_price,
226
+ current_price,
227
+ long,
228
+ leverage,
229
+ highest_leverage
230
+ )
231
+ profit = (collateral * profit_p) / Decimal("100")
232
+ return profit
233
+
234
+ # v2 (formulae v1.3.3)
235
+
236
+
237
+ def CurrentTotalProfitRaw(
238
+ open_price: Decimal,
239
+ current_price: Decimal,
240
+ long: bool,
241
+ leverage: Decimal,
242
+ highest_leverage: Decimal,
243
+ collateral: Decimal,
244
+ rollover_fee: Decimal,
245
+ funding_fee: Decimal
246
+ ) -> Decimal:
247
+ # Get trade profit
248
+ trade_profit = CurrentTradeProfitRaw(
249
+ open_price,
250
+ current_price,
251
+ long,
252
+ leverage,
253
+ highest_leverage,
254
+ collateral
255
+ )
256
+
257
+ # Subtract fees
258
+ total_profit = trade_profit - \
259
+ rollover_fee - funding_fee
260
+
261
+ return total_profit
262
+
263
+
264
+ # v2 (formulae v1.3.3)
265
+ def CurrentTotalProfitP(total_profit: Decimal, collateral: Decimal) -> Decimal:
266
+ profit_p = (total_profit * Decimal("100")) / collateral
267
+ if profit_p <= MIN_LOSS_P:
268
+ profit_p = MIN_LOSS_P
269
+ return profit_p
270
+
271
+
272
+ def GetFundingRate(
273
+ accPerOiLong: str,
274
+ accPerOiShort: str,
275
+ lastFundingRate: str,
276
+ maxFundingFeePerBlock: str,
277
+ lastUpdateBlock: str,
278
+ latestBlock: str,
279
+ oiLong: str,
280
+ oiShort: str,
281
+ oiCap: str,
282
+ hillInflectionPoint: str,
283
+ hillPosScale: str,
284
+ hillNegScale: str,
285
+ springFactor: str,
286
+ sFactorUpScaleP: str,
287
+ sFactorDownScaleP: str,
288
+ verbose: bool = False
289
+ ):
290
+ acc_funding_long, acc_funding_short, latest_funding_rate, target_fr = getPendingAccFundingFees(
291
+ blockNumber=Decimal(latestBlock),
292
+ lastUpdateBlock=Decimal(lastUpdateBlock),
293
+ valueLong=Decimal(accPerOiLong) / PRECISION_18,
294
+ valueShort=Decimal(accPerOiShort) / PRECISION_18,
295
+ openInterestUsdcLong=Decimal(oiLong) / PRECISION_6,
296
+ openInterestUsdcShort=Decimal(oiShort) / PRECISION_6,
297
+ OiCap=Decimal(oiCap) / PRECISION_6,
298
+ maxFundingFeePerBlock=Decimal(maxFundingFeePerBlock) / PRECISION_18,
299
+ lastFundingRate=Decimal(lastFundingRate) / PRECISION_18,
300
+ hillInflectionPoint=Decimal(hillInflectionPoint) / PRECISION_18,
301
+ hillPosScale=Decimal(hillPosScale) / PRECISION_2,
302
+ hillNegScale=Decimal(hillNegScale) / PRECISION_2,
303
+ springFactor=Decimal(springFactor) / PRECISION_18,
304
+ sFactorUpScale=Decimal(sFactorUpScaleP) / PRECISION_2,
305
+ sFactorDownScaleP=Decimal(sFactorDownScaleP) / PRECISION_2
306
+ )
307
+
308
+ return {
309
+ 'accFundingLong': acc_funding_long,
310
+ 'accFundingShort': acc_funding_short,
311
+ 'latestFundingRate': latest_funding_rate,
312
+ 'targetFundingRate': target_fr
313
+ }
@@ -0,0 +1,204 @@
1
+ from decimal import Decimal
2
+ from .formulae import (PRECISION_18, PRECISION_2, PRECISION_6, GetCurrentRolloverFee, GetFundingRate,
3
+ GetTradeFundingFee, GetTradeLiquidationPrice, GetTradeRolloverFee,
4
+ GetPriceImpact, CurrentTradeProfitRaw,
5
+ CurrentTotalProfitRaw, CurrentTotalProfitP)
6
+
7
+
8
+ # TBD - used by SDK
9
+ # returns the funding_fee_long_per_block, funding_fee_short_per_block
10
+
11
+
12
+ def get_funding_fee_long_short(pair_info, block_number, verbose=False):
13
+ funding_rate_raw = GetFundingRate(
14
+ pair_info['accFundingLong'],
15
+ pair_info['accFundingShort'],
16
+ pair_info['lastFundingRate'],
17
+ pair_info['maxFundingFeePerBlock'],
18
+ pair_info['lastFundingBlock'],
19
+ str(block_number),
20
+ pair_info['longOI'],
21
+ pair_info['shortOI'],
22
+ pair_info['maxOI'],
23
+ pair_info['hillInflectionPoint'],
24
+ pair_info['hillPosScale'],
25
+ pair_info['hillNegScale'],
26
+ pair_info['springFactor'],
27
+ pair_info['sFactorUpScaleP'],
28
+ pair_info['sFactorDownScaleP'],
29
+ verbose
30
+ )
31
+
32
+ # Convert latest funding rate to decimal
33
+ latest_rate = Decimal(
34
+ funding_rate_raw['latestFundingRate']) / PRECISION_18 # Fixed key name
35
+
36
+ # Convert OI values to decimal
37
+ long_oi = Decimal(pair_info['longOI']) / PRECISION_18
38
+ short_oi = Decimal(pair_info['shortOI']) / PRECISION_18
39
+
40
+ if funding_rate_raw['longsPay']:
41
+ # If longs pay, they get negative rate
42
+ long_rate = -latest_rate
43
+ # Shorts receive proportional to OI ratio
44
+ short_rate = latest_rate * long_oi / \
45
+ short_oi if short_oi > 0 else Decimal('0')
46
+ else:
47
+ # If shorts pay, they get negative rate
48
+ short_rate = -latest_rate
49
+ # Longs receive proportional to OI ratio
50
+ long_rate = latest_rate * short_oi / \
51
+ long_oi if long_oi > 0 else Decimal('0')
52
+
53
+ return float(long_rate), float(short_rate)
54
+
55
+ # TBD - used by SDK
56
+ # Gets an open trade metrics: such as the open pnl, rollover, funding, liquidation price, price impact, etc.
57
+
58
+
59
+ def get_trade_metrics(trade_details, price_data, block_number, verbose=False):
60
+ """
61
+ Calculate PNL and related metrics for a trade.
62
+ """
63
+ if not trade_details or not price_data or not block_number:
64
+ return {
65
+ 'pnl': 0,
66
+ 'pnl_percent': 0,
67
+ 'rollover': 0,
68
+ 'funding': 0,
69
+ 'total_profit': 0,
70
+ 'net_pnl': 0,
71
+ 'net_value': 0,
72
+ 'liquidation_price': 0
73
+ }
74
+
75
+ pair_info = trade_details['pair']
76
+ # Calculate current rollover fee
77
+ current_rollover_raw = GetCurrentRolloverFee(
78
+ pair_info['accRollover'],
79
+ pair_info['lastRolloverBlock'],
80
+ pair_info['rolloverFeePerBlock'],
81
+ str(block_number)
82
+ )
83
+
84
+ if verbose:
85
+ print(f"Current rollover fee: {current_rollover_raw}")
86
+
87
+ trade_rollover_fee = GetTradeRolloverFee(
88
+ Decimal(trade_details['rollover']) / PRECISION_18,
89
+ Decimal(current_rollover_raw) / PRECISION_18,
90
+ Decimal(trade_details['collateral']) / PRECISION_6,
91
+ Decimal(trade_details['leverage']) / PRECISION_2
92
+ )
93
+
94
+ if verbose:
95
+ print(f"Trade Rollover fee: {trade_rollover_fee}")
96
+ if (trade_rollover_fee != 0):
97
+ print(f"***** Trade Rollover fee is not 0: {trade_rollover_fee}")
98
+ # Get funding rate
99
+ funding_rate_raw = GetFundingRate(
100
+ pair_info['accFundingLong'],
101
+ pair_info['accFundingShort'],
102
+ pair_info['lastFundingRate'],
103
+ pair_info['maxFundingFeePerBlock'],
104
+ pair_info['lastFundingBlock'],
105
+ str(block_number),
106
+ pair_info['longOI'],
107
+ pair_info['shortOI'],
108
+ pair_info['maxOI'],
109
+ pair_info['hillInflectionPoint'],
110
+ pair_info['hillPosScale'],
111
+ pair_info['hillNegScale'],
112
+ pair_info['springFactor'],
113
+ pair_info['sFactorUpScaleP'],
114
+ pair_info['sFactorDownScaleP'],
115
+ verbose
116
+ )
117
+
118
+ if verbose:
119
+ print(f"Funding rate: {funding_rate_raw}")
120
+
121
+ # Calculate funding fee
122
+ trade_funding_fee = GetTradeFundingFee(
123
+ Decimal(trade_details['funding']) / PRECISION_18,
124
+ Decimal(funding_rate_raw['accFundingLong']) if trade_details['isBuy'] else Decimal(
125
+ funding_rate_raw['accFundingShort']),
126
+ Decimal(trade_details['collateral']) / PRECISION_6,
127
+ Decimal(trade_details['leverage']) / PRECISION_2
128
+ )
129
+
130
+ if verbose:
131
+ print(f"trade_funding_fee: {trade_funding_fee}")
132
+
133
+ # Calculate liquidation price
134
+ trade_liquidation_price = GetTradeLiquidationPrice(
135
+ Decimal(trade_details['openPrice']) / PRECISION_18,
136
+ trade_details['isBuy'],
137
+ Decimal(trade_details['collateral']) / PRECISION_6,
138
+ Decimal(trade_details['leverage']) / PRECISION_2,
139
+ Decimal(trade_rollover_fee),
140
+ Decimal(trade_funding_fee)
141
+ )
142
+
143
+ if verbose:
144
+ print(f"trade_liquidation_price: {trade_liquidation_price}")
145
+
146
+ # Calculate price impact
147
+ is_open = False # Get the price assuming a close
148
+
149
+ price_impact_raw = GetPriceImpact(
150
+ str(int(Decimal(str(price_data['mid'])) * PRECISION_18)),
151
+ str(int(Decimal(str(price_data['bid'])) * PRECISION_18)),
152
+ str(int(Decimal(str(price_data['ask'])) * PRECISION_18)),
153
+ is_open,
154
+ trade_details['isBuy']
155
+ )
156
+ price_after_impact = price_impact_raw['priceAfterImpact']
157
+
158
+ # Calculate PNL (abs)
159
+ pnl_raw = CurrentTradeProfitRaw(
160
+ Decimal(trade_details['openPrice']) / PRECISION_18,
161
+ Decimal(price_after_impact) / PRECISION_18,
162
+ Decimal(trade_details['isBuy']),
163
+ Decimal(trade_details['leverage']) / PRECISION_2,
164
+ Decimal(trade_details['highestLeverage']) / PRECISION_2,
165
+ Decimal(trade_details['collateral']) / PRECISION_6
166
+ )
167
+
168
+ # Calculate total profit (abs)
169
+ total_profit_raw = CurrentTotalProfitRaw(
170
+ Decimal(trade_details['openPrice']) / PRECISION_18,
171
+ Decimal(price_after_impact) / PRECISION_18,
172
+ Decimal(trade_details['isBuy']),
173
+ Decimal(trade_details['leverage']) / PRECISION_2,
174
+ Decimal(trade_details['highestLeverage']) / PRECISION_2,
175
+ Decimal(trade_details['collateral']) / PRECISION_6,
176
+ Decimal(trade_rollover_fee),
177
+ Decimal(trade_funding_fee)
178
+ )
179
+
180
+ # Calculate PNL percentage
181
+ pnl_percent_raw = CurrentTotalProfitP(
182
+ Decimal(total_profit_raw), Decimal(trade_details['collateral']) / PRECISION_6)
183
+
184
+ # Convert values to proper decimals
185
+ pnl = Decimal(pnl_raw)
186
+ pnl_percent = Decimal(pnl_percent_raw)
187
+ net_pnl = Decimal(total_profit_raw)
188
+ total_profit = Decimal(total_profit_raw)
189
+ funding = Decimal(trade_funding_fee)
190
+ rollover = Decimal(trade_rollover_fee)
191
+ net_value = net_pnl + (Decimal(trade_details['collateral']) / PRECISION_6)
192
+ price_impact = Decimal(price_after_impact) / PRECISION_18
193
+
194
+ return {
195
+ 'pnl': float(pnl),
196
+ 'pnl_percent': float(pnl_percent),
197
+ 'rollover': float(rollover),
198
+ 'funding': float(funding),
199
+ 'total_profit': float(total_profit), # same as net_pnl
200
+ 'net_pnl': float(net_pnl), # same as total_profit
201
+ 'net_value': float(net_value),
202
+ 'liquidation_price': float(trade_liquidation_price),
203
+ 'price_impact': float(price_impact)
204
+ }
@@ -30,7 +30,9 @@ def getTargetFundingRate(normalizedOiDelta, hillInflectionPoint, maxFundingFeePe
30
30
 
31
31
  return (maxFundingFeePerBlock * targetFr).quantize(quantization_18, rounding=ROUND_DOWN)
32
32
 
33
-
33
+ #
34
+ # returns the accFundingLong, accFundingShort, latestFundingRate (per block), targetFr (per block)
35
+ #
34
36
  def getPendingAccFundingFees(
35
37
  blockNumber: Decimal,
36
38
  lastUpdateBlock: Decimal,
@@ -48,7 +50,7 @@ def getPendingAccFundingFees(
48
50
  sFactorUpScale: Decimal,
49
51
  sFactorDownScaleP: Decimal,
50
52
  ):
51
-
53
+ # print(f"********* getPendingAccFundingFees *********")
52
54
  numBlocks = blockNumber - lastUpdateBlock
53
55
  openInterestMax = max(openInterestUsdcLong, openInterestUsdcShort)
54
56
  normalizedOiDelta = ((openInterestUsdcLong - openInterestUsdcShort).quantize(quantization_6, rounding=ROUND_DOWN) / max(OiCap, openInterestMax).quantize(quantization_6, rounding=ROUND_DOWN)).quantize(quantization_6, rounding=ROUND_DOWN)