polynode 0.6.1__tar.gz → 0.6.2__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 (42) hide show
  1. {polynode-0.6.1 → polynode-0.6.2}/PKG-INFO +1 -1
  2. {polynode-0.6.1 → polynode-0.6.2}/polynode/short_form.py +1 -1
  3. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/__init__.py +4 -0
  4. polynode-0.6.2/polynode/trading/position_management.py +104 -0
  5. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/trader.py +24 -0
  6. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/types.py +42 -0
  7. {polynode-0.6.1 → polynode-0.6.2}/pyproject.toml +1 -1
  8. {polynode-0.6.1 → polynode-0.6.2}/.gitignore +0 -0
  9. {polynode-0.6.1 → polynode-0.6.2}/README.md +0 -0
  10. {polynode-0.6.1 → polynode-0.6.2}/polynode/__init__.py +0 -0
  11. {polynode-0.6.1 → polynode-0.6.2}/polynode/_version.py +0 -0
  12. {polynode-0.6.1 → polynode-0.6.2}/polynode/cache/__init__.py +0 -0
  13. {polynode-0.6.1 → polynode-0.6.2}/polynode/client.py +0 -0
  14. {polynode-0.6.1 → polynode-0.6.2}/polynode/engine.py +0 -0
  15. {polynode-0.6.1 → polynode-0.6.2}/polynode/errors.py +0 -0
  16. {polynode-0.6.1 → polynode-0.6.2}/polynode/orderbook.py +0 -0
  17. {polynode-0.6.1 → polynode-0.6.2}/polynode/orderbook_state.py +0 -0
  18. {polynode-0.6.1 → polynode-0.6.2}/polynode/redemption_watcher.py +0 -0
  19. {polynode-0.6.1 → polynode-0.6.2}/polynode/subscription.py +0 -0
  20. {polynode-0.6.1 → polynode-0.6.2}/polynode/testing.py +0 -0
  21. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/clob_api.py +0 -0
  22. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/constants.py +0 -0
  23. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/cosigner.py +0 -0
  24. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/eip712.py +0 -0
  25. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/onboarding.py +0 -0
  26. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/privy.py +0 -0
  27. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/signer.py +0 -0
  28. {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/sqlite_backend.py +0 -0
  29. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/__init__.py +0 -0
  30. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/enums.py +0 -0
  31. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/events.py +0 -0
  32. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/orderbook.py +0 -0
  33. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/rest.py +0 -0
  34. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/short_form.py +0 -0
  35. {polynode-0.6.1 → polynode-0.6.2}/polynode/types/ws.py +0 -0
  36. {polynode-0.6.1 → polynode-0.6.2}/polynode/ws.py +0 -0
  37. {polynode-0.6.1 → polynode-0.6.2}/tests/__init__.py +0 -0
  38. {polynode-0.6.1 → polynode-0.6.2}/tests/conftest.py +0 -0
  39. {polynode-0.6.1 → polynode-0.6.2}/tests/test_client.py +0 -0
  40. {polynode-0.6.1 → polynode-0.6.2}/tests/test_orderbook.py +0 -0
  41. {polynode-0.6.1 → polynode-0.6.2}/tests/test_trading.py +0 -0
  42. {polynode-0.6.1 → polynode-0.6.2}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polynode
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: Python SDK for the PolyNode real-time prediction market data platform
5
5
  Project-URL: Homepage, https://polynode.dev
6
6
  Project-URL: Documentation, https://docs.polynode.dev
@@ -37,7 +37,7 @@ COIN_SYMBOLS: dict[ShortFormCoin, str] = {
37
37
  }
38
38
 
39
39
  INTERVAL_VARIANT: dict[ShortFormInterval, str] = {
40
- "5m": "five", "15m": "fifteen", "1h": "sixty",
40
+ "5m": "fiveminute", "15m": "fifteen", "1h": "hourly",
41
41
  }
42
42
 
43
43
  WINDOW_SECONDS: dict[ShortFormInterval, int] = {
@@ -5,6 +5,7 @@ from .constants import * # noqa: F401, F403
5
5
  from .signer import NormalizedSigner, normalize_signer
6
6
  from .cosigner import build_l2_headers, send_via_cosigner
7
7
  from .onboarding import derive_safe_address, derive_proxy_address, detect_wallet_type
8
+ from .position_management import build_split_txn, build_merge_txn, build_convert_txn
8
9
  from .trader import PolyNodeTrader
9
10
  from .privy import PrivySigner, PrivyConfig
10
11
 
@@ -20,4 +21,7 @@ __all__ = [
20
21
  "derive_safe_address",
21
22
  "derive_proxy_address",
22
23
  "detect_wallet_type",
24
+ "build_split_txn",
25
+ "build_merge_txn",
26
+ "build_convert_txn",
23
27
  ]
@@ -0,0 +1,104 @@
1
+ """
2
+ Position management — build transactions for split, merge, and convert on Polymarket.
3
+
4
+ These functions return TransactionRequest objects containing the contract address
5
+ and ABI-encoded calldata. Submit them via the Polymarket relayer (gasless for
6
+ Safe wallets) or directly on-chain.
7
+
8
+ from polynode.trading.position_management import build_split_txn, build_convert_txn
9
+
10
+ # Split $100 into YES + NO tokens
11
+ tx = build_split_txn("0xabc...conditionId", 100.0, neg_risk=True)
12
+
13
+ # Convert NO positions on outcomes 0 and 1
14
+ tx = build_convert_txn("0xdef...marketId", [0, 1], 50.0)
15
+ """
16
+
17
+ from .constants import CTF, NEG_RISK_ADAPTER, USDC
18
+ from .types import TransactionRequest
19
+
20
+
21
+ def build_split_txn(condition_id: str, amount: float, neg_risk: bool = True) -> TransactionRequest:
22
+ """Build a split transaction: USDC -> YES + NO outcome tokens.
23
+
24
+ Routes to NegRiskAdapter for neg-risk markets, CTF for standard markets.
25
+ Amount is in USDC (e.g. 100.0 = $100).
26
+ """
27
+ amount_raw = int(amount * 1_000_000)
28
+
29
+ if neg_risk:
30
+ # NegRiskAdapter.splitPosition(bytes32 conditionId, uint256 amount)
31
+ data = "0xa3d7da1d" + _encode_bytes32(condition_id) + _encode_uint256(amount_raw)
32
+ return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
33
+ else:
34
+ # CTF.splitPosition(address, bytes32, bytes32, uint256[], uint256)
35
+ data = (
36
+ "0x72108503"
37
+ + _encode_address(USDC)
38
+ + "00" * 32 # parentCollectionId = bytes32(0)
39
+ + _encode_bytes32(condition_id)
40
+ + _encode_uint256(160) # offset to partition array
41
+ + _encode_uint256(amount_raw)
42
+ + _encode_uint256(2) # partition length
43
+ + _encode_uint256(1)
44
+ + _encode_uint256(2)
45
+ )
46
+ return TransactionRequest(to=CTF, data=data)
47
+
48
+
49
+ def build_merge_txn(condition_id: str, amount: float, neg_risk: bool = True) -> TransactionRequest:
50
+ """Build a merge transaction: YES + NO outcome tokens -> USDC."""
51
+ amount_raw = int(amount * 1_000_000)
52
+
53
+ if neg_risk:
54
+ # NegRiskAdapter.mergePositions(bytes32 conditionId, uint256 amount)
55
+ data = "0x5d03f453" + _encode_bytes32(condition_id) + _encode_uint256(amount_raw)
56
+ return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
57
+ else:
58
+ # CTF.mergePositions(address, bytes32, bytes32, uint256[], uint256)
59
+ data = (
60
+ "0xcad9440e"
61
+ + _encode_address(USDC)
62
+ + "00" * 32
63
+ + _encode_bytes32(condition_id)
64
+ + _encode_uint256(160)
65
+ + _encode_uint256(amount_raw)
66
+ + _encode_uint256(2)
67
+ + _encode_uint256(1)
68
+ + _encode_uint256(2)
69
+ )
70
+ return TransactionRequest(to=CTF, data=data)
71
+
72
+
73
+ def build_convert_txn(market_id: str, outcome_indices: list[int], amount: float) -> TransactionRequest:
74
+ """Build a convert transaction: NO positions -> USDC + YES on complementary outcomes.
75
+
76
+ Only works on neg-risk multi-outcome markets.
77
+ outcome_indices: which outcomes' NOs to convert (e.g. [0, 1]).
78
+ """
79
+ amount_raw = int(amount * 1_000_000)
80
+
81
+ # Compute indexSet bitmask
82
+ index_set = 0
83
+ for idx in outcome_indices:
84
+ index_set |= 1 << idx
85
+
86
+ # NegRiskAdapter.convertPositions(bytes32 marketId, uint256 indexSet, uint256 amount)
87
+ data = "0xc64748c4" + _encode_bytes32(market_id) + _encode_uint256(index_set) + _encode_uint256(amount_raw)
88
+ return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
89
+
90
+
91
+ # ── Encoding helpers ──
92
+
93
+ def _encode_bytes32(hex_str: str) -> str:
94
+ s = hex_str.removeprefix("0x")
95
+ return s.zfill(64)[:64]
96
+
97
+
98
+ def _encode_address(addr: str) -> str:
99
+ s = addr.removeprefix("0x")
100
+ return s.lower().zfill(64)
101
+
102
+
103
+ def _encode_uint256(val: int) -> str:
104
+ return hex(val)[2:].zfill(64)
@@ -478,6 +478,30 @@ class PolyNodeTrader:
478
478
  db.upsert_market_meta(meta)
479
479
  return meta
480
480
 
481
+ # ── Position Management (split/merge/convert) ──
482
+
483
+ def split(self, params: "SplitParams") -> "TransactionRequest":
484
+ """Build a split transaction: USDC -> YES + NO outcome tokens.
485
+
486
+ Returns a TransactionRequest to submit via the Polymarket relayer or on-chain.
487
+ For gasless execution, use the TypeScript SDK's trader.split().
488
+ """
489
+ from .position_management import build_split_txn
490
+ return build_split_txn(params.condition_id, params.amount, neg_risk=True)
491
+
492
+ def merge(self, params: "MergeParams") -> "TransactionRequest":
493
+ """Build a merge transaction: YES + NO outcome tokens -> USDC."""
494
+ from .position_management import build_merge_txn
495
+ return build_merge_txn(params.condition_id, params.amount, neg_risk=True)
496
+
497
+ def convert(self, params: "ConvertParams") -> "TransactionRequest":
498
+ """Build a convert transaction: NO positions -> USDC + YES on complementary outcomes.
499
+
500
+ Only works on neg-risk multi-outcome markets.
501
+ """
502
+ from .position_management import build_convert_txn
503
+ return build_convert_txn(params.market_id, params.outcome_indices, params.amount)
504
+
481
505
  # ── History ──
482
506
 
483
507
  def get_order_history(self, params: HistoryParams | None = None) -> list[OrderHistoryRow]:
@@ -153,6 +153,48 @@ class OpenOrder:
153
153
  order_type: str
154
154
 
155
155
 
156
+ # ── Position Management (split/merge/convert) ──
157
+
158
+
159
+ @dataclass
160
+ class SplitParams:
161
+ """Parameters for splitting USDC into YES + NO outcome tokens."""
162
+ condition_id: str
163
+ amount: float # USDC amount (e.g. 100.0 = $100)
164
+
165
+
166
+ @dataclass
167
+ class MergeParams:
168
+ """Parameters for merging YES + NO outcome tokens back into USDC."""
169
+ condition_id: str
170
+ amount: float
171
+
172
+
173
+ @dataclass
174
+ class ConvertParams:
175
+ """Parameters for converting NO positions on selected outcomes.
176
+ Only works on neg-risk multi-outcome markets."""
177
+ market_id: str
178
+ outcome_indices: list[int] # e.g. [0, 1]
179
+ amount: float
180
+
181
+
182
+ @dataclass
183
+ class TransactionRequest:
184
+ """A pre-built transaction ready for submission."""
185
+ to: str
186
+ data: str # hex-encoded calldata
187
+ value: str = "0"
188
+
189
+
190
+ @dataclass
191
+ class PositionResult:
192
+ """Result of a position management operation."""
193
+ success: bool
194
+ tx_hash: str | None = None
195
+ error: str | None = None
196
+
197
+
156
198
  @dataclass
157
199
  class MarketMeta:
158
200
  token_id: str
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "polynode"
7
- version = "0.6.1"
7
+ version = "0.6.2"
8
8
  description = "Python SDK for the PolyNode real-time prediction market data platform"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes