nado-protocol 0.2.8__tar.gz → 0.3.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 (81) hide show
  1. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/PKG-INFO +1 -1
  2. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/margin_manager.py +113 -17
  3. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/pyproject.toml +1 -1
  4. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/README.md +0 -0
  5. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/__init__.py +0 -0
  6. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/__init__.py +0 -0
  7. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/__init__.py +0 -0
  8. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/base.py +0 -0
  9. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/market/__init__.py +0 -0
  10. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/market/execute.py +0 -0
  11. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/market/query.py +0 -0
  12. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/perp/__init__.py +0 -0
  13. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/perp/query.py +0 -0
  14. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/rewards/__init__.py +0 -0
  15. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/rewards/execute.py +0 -0
  16. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/rewards/query.py +0 -0
  17. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/spot/__init__.py +0 -0
  18. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/spot/base.py +0 -0
  19. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/spot/execute.py +0 -0
  20. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/spot/query.py +0 -0
  21. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/subaccount/__init__.py +0 -0
  22. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/subaccount/execute.py +0 -0
  23. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/apis/subaccount/query.py +0 -0
  24. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/client/context.py +0 -0
  25. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/__init__.py +0 -0
  26. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/Endpoint.json +0 -0
  27. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/FQuerier.json +0 -0
  28. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IAirdrop.json +0 -0
  29. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IClearinghouse.json +0 -0
  30. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IEndpoint.json +0 -0
  31. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IFoundationRewardsAirdrop.json +0 -0
  32. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IPerpEngine.json +0 -0
  33. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IProductEngine.json +0 -0
  34. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/ISpotEngine.json +0 -0
  35. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/IStaking.json +0 -0
  36. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/abis/MockERC20.json +0 -0
  37. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/deployments/deployment.mainnet.json +0 -0
  38. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/deployments/deployment.testing.json +0 -0
  39. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/deployments/deployment.testnet.json +0 -0
  40. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/eip712/__init__.py +0 -0
  41. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/eip712/domain.py +0 -0
  42. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/eip712/sign.py +0 -0
  43. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/eip712/types.py +0 -0
  44. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/loader.py +0 -0
  45. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/contracts/types.py +0 -0
  46. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/__init__.py +0 -0
  47. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/execute.py +0 -0
  48. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/query.py +0 -0
  49. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/types/__init__.py +0 -0
  50. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/types/execute.py +0 -0
  51. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/types/models.py +0 -0
  52. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/types/query.py +0 -0
  53. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/engine_client/types/stream.py +0 -0
  54. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/indexer_client/__init__.py +0 -0
  55. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/indexer_client/query.py +0 -0
  56. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/indexer_client/types/__init__.py +0 -0
  57. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/indexer_client/types/models.py +0 -0
  58. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/indexer_client/types/query.py +0 -0
  59. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/__init__.py +0 -0
  60. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/execute.py +0 -0
  61. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/query.py +0 -0
  62. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/types/__init__.py +0 -0
  63. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/types/execute.py +0 -0
  64. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/types/models.py +0 -0
  65. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/trigger_client/types/query.py +0 -0
  66. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/__init__.py +0 -0
  67. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/backend.py +0 -0
  68. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/balance.py +0 -0
  69. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/bytes32.py +0 -0
  70. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/enum.py +0 -0
  71. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/exceptions.py +0 -0
  72. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/execute.py +0 -0
  73. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/expiration.py +0 -0
  74. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/interest.py +0 -0
  75. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/math.py +0 -0
  76. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/model.py +0 -0
  77. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/nonce.py +0 -0
  78. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/order.py +0 -0
  79. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/subaccount.py +0 -0
  80. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/time.py +0 -0
  81. {nado_protocol-0.2.8 → nado_protocol-0.3.0}/nado_protocol/utils/twap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nado-protocol
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: Nado Protocol SDK
5
5
  Keywords: nado protocol,nado sdk,nado protocol api
6
6
  Author: Jeury Mejia
@@ -78,6 +78,8 @@ class CrossPositionMetrics(BaseModel):
78
78
  symbol: str
79
79
  position_size: Decimal
80
80
  notional_value: Decimal
81
+ avg_entry_price: Optional[Decimal] # Average entry price (requires indexer data)
82
+ est_liq_price: Optional[Decimal] # Estimated liquidation price
81
83
  est_pnl: Optional[Decimal] # Estimated PnL (requires indexer data)
82
84
  unsettled: Decimal # Unsettled quote (v_quote_balance)
83
85
  margin_used: Decimal
@@ -520,9 +522,9 @@ class MarginManager:
520
522
  # This represents the unrealized PnL
521
523
  unsettled = self.calculate_perp_balance_value(balance)
522
524
 
523
- # Calculate Est. PnL if indexer data is available
524
- # Formula: (amount × oracle_price) - netEntryUnrealized
525
- # where netEntryUnrealized excludes funding, fees, slippage
525
+ # Calculate metrics (requires indexer data for avg_entry_price and est_pnl)
526
+ avg_entry_price = self._calculate_avg_entry_price(balance)
527
+ est_liq_price = self._calculate_est_liq_price(balance)
526
528
  est_pnl = self._calculate_est_pnl(balance)
527
529
 
528
530
  return CrossPositionMetrics(
@@ -530,6 +532,8 @@ class MarginManager:
530
532
  symbol=f"Product_{balance.product_id}",
531
533
  position_size=balance.amount,
532
534
  notional_value=notional,
535
+ avg_entry_price=avg_entry_price,
536
+ est_liq_price=est_liq_price,
533
537
  est_pnl=est_pnl,
534
538
  unsettled=unsettled,
535
539
  margin_used=margin_used,
@@ -541,6 +545,24 @@ class MarginManager:
541
545
  short_weight_maintenance=balance.short_weight_maintenance,
542
546
  )
543
547
 
548
+ def _get_indexer_event_for_product(self, product_id: int) -> Optional[IndexerEvent]:
549
+ """
550
+ Get indexer event for a specific product (cross margin only).
551
+
552
+ Returns None if indexer data is not available or product not found.
553
+ """
554
+ if not self.indexer_events or product_id == self.QUOTE_PRODUCT_ID:
555
+ return None
556
+
557
+ for event in self.indexer_events:
558
+ if event.product_id != product_id:
559
+ continue
560
+ if event.isolated:
561
+ continue
562
+ return event
563
+
564
+ return None
565
+
544
566
  def _calculate_est_pnl(self, balance: BalanceWithProduct) -> Optional[Decimal]:
545
567
  """
546
568
  Calculate estimated PnL if indexer snapshot is available.
@@ -549,26 +571,90 @@ class MarginManager:
549
571
 
550
572
  Returns None if indexer data is not available.
551
573
  """
552
- if not self.indexer_events or balance.product_id == self.QUOTE_PRODUCT_ID:
574
+ event = self._get_indexer_event_for_product(balance.product_id)
575
+ if event is None:
553
576
  return None
554
577
 
555
- for event in self.indexer_events:
556
- if event.product_id != balance.product_id:
557
- continue
558
- if event.isolated:
559
- continue
578
+ try:
579
+ net_entry_int = int(event.net_entry_unrealized)
580
+ except (TypeError, ValueError):
581
+ return None
560
582
 
561
- try:
562
- net_entry_int = int(event.net_entry_unrealized)
563
- except (TypeError, ValueError):
564
- continue
583
+ net_entry_unrealized = Decimal(net_entry_int) / Decimal(10**18)
584
+ current_value = balance.amount * balance.oracle_price
585
+ return current_value - net_entry_unrealized
586
+
587
+ def _calculate_avg_entry_price(
588
+ self, balance: BalanceWithProduct
589
+ ) -> Optional[Decimal]:
590
+ """
591
+ Calculate average entry price if indexer snapshot is available.
565
592
 
566
- net_entry_unrealized = Decimal(net_entry_int) / Decimal(10**18)
593
+ Formula: abs(netEntryUnrealized / position_amount)
567
594
 
568
- current_value = balance.amount * balance.oracle_price
569
- return current_value - net_entry_unrealized
595
+ Returns None if indexer data is not available or position is zero.
596
+ """
597
+ if balance.amount == 0:
598
+ return None
570
599
 
571
- return None
600
+ event = self._get_indexer_event_for_product(balance.product_id)
601
+ if event is None:
602
+ return None
603
+
604
+ try:
605
+ net_entry_int = int(event.net_entry_unrealized)
606
+ except (TypeError, ValueError):
607
+ return None
608
+
609
+ net_entry_unrealized = Decimal(net_entry_int) / Decimal(10**18)
610
+ return abs(net_entry_unrealized / balance.amount)
611
+
612
+ def _calculate_est_liq_price(
613
+ self, balance: BalanceWithProduct
614
+ ) -> Optional[Decimal]:
615
+ """
616
+ Calculate estimated liquidation price.
617
+
618
+ Formula:
619
+ - If long: oracle_price - (maint_health / amount / long_weight)
620
+ - If short: oracle_price + (maint_health / abs(amount) * short_weight)
621
+
622
+ Returns None if:
623
+ - Position is zero
624
+ - Long liq price <= 0 (prevents -infinity)
625
+ - Short liq price >= 10x oracle price (prevents +infinity)
626
+ """
627
+ if balance.amount == 0:
628
+ return None
629
+
630
+ # Get maintenance health from subaccount info
631
+ maint_health = self._parse_health(self.subaccount_info.healths[1])
632
+
633
+ is_long = balance.amount > 0
634
+
635
+ if is_long:
636
+ # Long: oracle_price - (maint_health / amount / long_weight)
637
+ if balance.long_weight_maintenance == 0:
638
+ return None
639
+
640
+ liq_price = balance.oracle_price - (
641
+ maint_health / balance.amount / balance.long_weight_maintenance
642
+ )
643
+
644
+ # If liquidation price is 0 or less, return None (prevents -infinity)
645
+ if liq_price <= 0:
646
+ return None
647
+ else:
648
+ # Short: oracle_price + (maint_health / abs(amount) * short_weight)
649
+ liq_price = balance.oracle_price + (
650
+ maint_health / abs(balance.amount) * balance.short_weight_maintenance
651
+ )
652
+
653
+ # If liquidation price is 10x oracle price, return None (prevents +infinity)
654
+ if liq_price >= balance.oracle_price * 10:
655
+ return None
656
+
657
+ return liq_price
572
658
 
573
659
  def calculate_isolated_position_metrics(
574
660
  self, iso_pos: IsolatedPosition
@@ -783,6 +869,16 @@ def print_account_summary(summary: AccountSummary) -> None:
783
869
  print(f"│ Position: {cross_pos.position_size:,.3f}")
784
870
  print(f"│ Notional: ${cross_pos.notional_value:,.2f}")
785
871
 
872
+ if cross_pos.avg_entry_price is not None:
873
+ print(f"│ Avg Entry Price: ${cross_pos.avg_entry_price:,.2f}")
874
+ else:
875
+ print(f"│ Avg Entry Price: N/A")
876
+
877
+ if cross_pos.est_liq_price is not None:
878
+ print(f"│ Est. Liq Price: ${cross_pos.est_liq_price:,.2f}")
879
+ else:
880
+ print(f"│ Est. Liq Price: N/A")
881
+
786
882
  if cross_pos.est_pnl is not None:
787
883
  pnl_sign = "+" if cross_pos.est_pnl >= 0 else ""
788
884
  print(f"│ Est. PnL: {pnl_sign}${cross_pos.est_pnl:,.2f}")
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "nado-protocol"
3
- version = "0.2.8"
3
+ version = "0.3.0"
4
4
  description = "Nado Protocol SDK"
5
5
  authors = ["Jeury Mejia <jeury@inkfnd.com>"]
6
6
  homepage = "https://nado.xyz"
File without changes