nado-protocol 0.1.4__tar.gz → 0.1.5__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 (84) hide show
  1. nado_protocol-0.1.5/PKG-INFO +309 -0
  2. nado_protocol-0.1.5/README.md +284 -0
  3. nado_protocol-0.1.5/nado_protocol/client/apis/market/execute.py +322 -0
  4. nado_protocol-0.1.5/nado_protocol/trigger_client/execute.py +343 -0
  5. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/query.py +19 -0
  6. nado_protocol-0.1.5/nado_protocol/trigger_client/types/models.py +85 -0
  7. nado_protocol-0.1.5/nado_protocol/trigger_client/types/query.py +199 -0
  8. nado_protocol-0.1.5/nado_protocol/utils/twap.py +189 -0
  9. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/pyproject.toml +1 -1
  10. nado_protocol-0.1.4/PKG-INFO +0 -159
  11. nado_protocol-0.1.4/README.md +0 -135
  12. nado_protocol-0.1.4/nado_protocol/client/apis/market/execute.py +0 -176
  13. nado_protocol-0.1.4/nado_protocol/trigger_client/execute.py +0 -118
  14. nado_protocol-0.1.4/nado_protocol/trigger_client/types/models.py +0 -44
  15. nado_protocol-0.1.4/nado_protocol/trigger_client/types/query.py +0 -77
  16. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/__init__.py +0 -0
  17. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/__init__.py +0 -0
  18. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/__init__.py +0 -0
  19. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/base.py +0 -0
  20. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/market/__init__.py +0 -0
  21. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/market/query.py +0 -0
  22. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/perp/__init__.py +0 -0
  23. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/perp/query.py +0 -0
  24. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/__init__.py +0 -0
  25. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/execute.py +0 -0
  26. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/query.py +0 -0
  27. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/__init__.py +0 -0
  28. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/base.py +0 -0
  29. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/execute.py +0 -0
  30. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/query.py +0 -0
  31. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/__init__.py +0 -0
  32. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/execute.py +0 -0
  33. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/query.py +0 -0
  34. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/context.py +0 -0
  35. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/__init__.py +0 -0
  36. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/Endpoint.json +0 -0
  37. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/FQuerier.json +0 -0
  38. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IAirdrop.json +0 -0
  39. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IClearinghouse.json +0 -0
  40. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IEndpoint.json +0 -0
  41. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IFoundationRewardsAirdrop.json +0 -0
  42. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IPerpEngine.json +0 -0
  43. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IProductEngine.json +0 -0
  44. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/ISpotEngine.json +0 -0
  45. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IStaking.json +0 -0
  46. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/MockERC20.json +0 -0
  47. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/deployments/deployment.testing.json +0 -0
  48. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/deployments/deployment.testnet.json +0 -0
  49. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/__init__.py +0 -0
  50. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/domain.py +0 -0
  51. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/sign.py +0 -0
  52. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/types.py +0 -0
  53. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/loader.py +0 -0
  54. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/types.py +0 -0
  55. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/__init__.py +0 -0
  56. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/execute.py +0 -0
  57. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/query.py +0 -0
  58. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/__init__.py +0 -0
  59. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/execute.py +0 -0
  60. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/models.py +0 -0
  61. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/query.py +0 -0
  62. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/stream.py +0 -0
  63. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/__init__.py +0 -0
  64. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/query.py +0 -0
  65. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/__init__.py +0 -0
  66. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/models.py +0 -0
  67. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/query.py +0 -0
  68. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/__init__.py +0 -0
  69. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/types/__init__.py +0 -0
  70. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/types/execute.py +0 -0
  71. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/__init__.py +0 -0
  72. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/backend.py +0 -0
  73. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/bytes32.py +0 -0
  74. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/enum.py +0 -0
  75. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/exceptions.py +0 -0
  76. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/execute.py +0 -0
  77. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/expiration.py +0 -0
  78. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/interest.py +0 -0
  79. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/math.py +0 -0
  80. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/model.py +0 -0
  81. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/nonce.py +0 -0
  82. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/order.py +0 -0
  83. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/subaccount.py +0 -0
  84. {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/time.py +0 -0
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: nado-protocol
3
+ Version: 0.1.5
4
+ Summary: Nado Protocol SDK
5
+ Keywords: nado protocol,nado sdk,nado protocol api
6
+ Author: Jeury Mejia
7
+ Author-email: jeury@inkfnd.com
8
+ Maintainer: Frank Jia
9
+ Maintainer-email: frank@inkfnd.com
10
+ Requires-Python: >=3.9,<4.0
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Dist: eth-account (>=0.8.0,<0.9.0)
19
+ Requires-Dist: pydantic (>=1.10.7,<2.0.0)
20
+ Requires-Dist: web3 (>=6.4.0,<7.0.0)
21
+ Project-URL: Documentation, https://nadohq.github.io/nado-python-sdk/
22
+ Project-URL: Homepage, https://nado.xyz
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Nado Protocol Python SDK
26
+
27
+ This is the Python SDK for the [Nado Protocol API](TODO).
28
+
29
+ See [SDK docs](https://nadohq.github.io/nado-python-sdk/index.html) to get started.
30
+
31
+ ## Requirements
32
+
33
+ - Python 3.9 or above
34
+
35
+ ## Installation
36
+
37
+ You can install the SDK via pip:
38
+
39
+ ```bash
40
+ pip install nado-protocol
41
+ ```
42
+
43
+ ## Basic usage
44
+
45
+ ### Import the necessary utilities:
46
+
47
+ ```python
48
+ from nado_protocol.client import create_nado_client, NadoClientMode
49
+ from nado_protocol.contracts.types import DepositCollateralParams
50
+ from nado_protocol.engine_client.types.execute import (
51
+ OrderParams,
52
+ PlaceOrderParams,
53
+ SubaccountParams
54
+ )
55
+ from nado_protocol.utils.expiration import OrderType, get_expiration_timestamp
56
+ from nado_protocol.utils.math import to_pow_10, to_x18
57
+ from nado_protocol.utils.nonce import gen_order_nonce
58
+ from nado_protocol.utils.order import build_appendix
59
+ ```
60
+
61
+ ### Create the NadoClient providing your private key:
62
+
63
+ ```python
64
+ print("setting up nado client...")
65
+ private_key = "xxx"
66
+ client = create_nado_client(NadoClientMode.DEVNET, private_key)
67
+ ```
68
+
69
+ ### Perform basic operations:
70
+
71
+ ```python
72
+ # Depositing collaterals
73
+ print("approving allowance...")
74
+ approve_allowance_tx_hash = client.spot.approve_allowance(0, to_pow_10(100000, 6))
75
+ print("approve allowance tx hash:", approve_allowance_tx_hash)
76
+
77
+ print("querying my allowance...")
78
+ token_allowance = client.spot.get_token_allowance(0, client.context.signer.address)
79
+ print("token allowance:", token_allowance)
80
+
81
+ print("depositing collateral...")
82
+ deposit_tx_hash = client.spot.deposit(
83
+ DepositCollateralParams(
84
+ subaccount_name="default", product_id=0, amount=to_pow_10(100000, 6)
85
+ )
86
+ )
87
+ print("deposit collateral tx hash:", deposit_tx_hash)
88
+
89
+ # Placing orders
90
+ print("placing order...")
91
+ owner = client.context.engine_client.signer.address
92
+ product_id = 1
93
+ order = OrderParams(
94
+ sender=SubaccountParams(
95
+ subaccount_owner=owner,
96
+ subaccount_name="default",
97
+ ),
98
+ priceX18=to_x18(20000),
99
+ amount=to_pow_10(1, 17),
100
+ expiration=get_expiration_timestamp(40),
101
+ nonce=gen_order_nonce(),
102
+ appendix=build_appendix(order_type=OrderType.POST_ONLY)
103
+ )
104
+ res = client.market.place_order({"product_id": product_id, "order": order})
105
+ print("order result:", res.json(indent=2))
106
+ ```
107
+
108
+ ## TWAP and Trigger Orders
109
+
110
+ The SDK provides comprehensive support for Time-Weighted Average Price (TWAP) orders and price trigger orders through the Trigger Client.
111
+
112
+ ### TWAP Orders
113
+
114
+ TWAP orders allow you to execute large trades over time with controlled slippage:
115
+
116
+ ```python
117
+ from nado_protocol.trigger_client import TriggerClient
118
+ from nado_protocol.trigger_client.types import TriggerClientOpts
119
+ from nado_protocol.utils.math import to_x18
120
+ from nado_protocol.utils.expiration import get_expiration_timestamp
121
+
122
+ # Create trigger client
123
+ trigger_client = TriggerClient(
124
+ opts=TriggerClientOpts(url=TRIGGER_BACKEND_URL, signer=private_key)
125
+ )
126
+
127
+ # Place a TWAP order to buy 5 BTC over 2 hours
128
+ twap_result = trigger_client.place_twap_order(
129
+ product_id=1,
130
+ sender=client.signer.address,
131
+ price_x18=str(to_x18(50_000)), # Max $50k per execution
132
+ total_amount_x18=str(to_x18(5)), # Buy 5 BTC total
133
+ expiration=get_expiration_timestamp(60 * 24), # 24 hours
134
+ nonce=client.order_nonce(),
135
+ times=10, # Split into 10 executions
136
+ slippage_frac=0.005, # 0.5% slippage tolerance
137
+ interval_seconds=720, # 12 minutes between executions
138
+ )
139
+ ```
140
+
141
+ ### TWAP with Custom Amounts
142
+
143
+ For more sophisticated strategies, you can specify custom amounts for each execution:
144
+
145
+ ```python
146
+ # Decreasing size strategy: 2 BTC, 1.5 BTC, 1 BTC, 0.5 BTC
147
+ custom_amounts = [
148
+ str(to_x18(2)), # 2 BTC
149
+ str(to_x18(1.5)), # 1.5 BTC
150
+ str(to_x18(1)), # 1 BTC
151
+ str(to_x18(0.5)), # 0.5 BTC
152
+ ]
153
+
154
+ custom_twap_result = trigger_client.place_twap_order(
155
+ product_id=1,
156
+ sender=client.signer.address,
157
+ price_x18=str(to_x18(51_000)),
158
+ total_amount_x18=str(to_x18(5)), # 5 BTC total
159
+ expiration=get_expiration_timestamp(60 * 12),
160
+ nonce=client.order_nonce(),
161
+ times=4, # 4 executions
162
+ slippage_frac=0.01, # 1% slippage
163
+ interval_seconds=1800, # 30 minutes
164
+ custom_amounts_x18=custom_amounts,
165
+ )
166
+ ```
167
+
168
+ ### Price Trigger Orders
169
+
170
+ Create conditional orders that execute when price conditions are met:
171
+
172
+ ```python
173
+ # Stop-loss order (sell when price drops below $45k)
174
+ stop_loss = trigger_client.place_price_trigger_order(
175
+ product_id=1,
176
+ sender=client.signer.address,
177
+ price_x18=str(to_x18(44_000)), # Sell at $44k
178
+ amount_x18=str(-to_x18(1)), # Sell 1 BTC (negative for sell)
179
+ expiration=get_expiration_timestamp(60 * 24 * 7), # 1 week
180
+ nonce=client.order_nonce(),
181
+ trigger_price_x18=str(to_x18(45_000)), # Trigger below $45k
182
+ trigger_type="last_price_below",
183
+ reduce_only=True, # Only reduce position
184
+ )
185
+
186
+ # Take-profit order (sell when price rises above $55k)
187
+ take_profit = trigger_client.place_price_trigger_order(
188
+ product_id=1,
189
+ sender=client.signer.address,
190
+ price_x18=str(to_x18(56_000)), # Sell at $56k
191
+ amount_x18=str(-to_x18(1)), # Sell 1 BTC
192
+ expiration=get_expiration_timestamp(60 * 24 * 7),
193
+ nonce=client.order_nonce(),
194
+ trigger_price_x18=str(to_x18(55_000)), # Trigger above $55k
195
+ trigger_type="last_price_above",
196
+ reduce_only=True,
197
+ )
198
+ ```
199
+
200
+ ### Supported Trigger Types
201
+
202
+ The SDK supports six types of price triggers:
203
+
204
+ - `"last_price_above"`: Trigger when last traded price goes above threshold
205
+ - `"last_price_below"`: Trigger when last traded price goes below threshold
206
+ - `"oracle_price_above"`: Trigger when oracle price goes above threshold
207
+ - `"oracle_price_below"`: Trigger when oracle price goes below threshold
208
+ - `"mid_price_above"`: Trigger when mid price goes above threshold
209
+ - `"mid_price_below"`: Trigger when mid price goes below threshold
210
+
211
+ ### Complete Trading Strategy Example
212
+
213
+ Here's how to set up a complete trading strategy with stop-loss, take-profit, and DCA:
214
+
215
+ ```python
216
+ # 1. Stop-loss protection
217
+ stop_loss = trigger_client.place_price_trigger_order(
218
+ product_id=1,
219
+ sender=client.signer.address,
220
+ price_x18=str(to_x18(44_000)),
221
+ amount_x18=str(-to_x18(2)), # Close 2 BTC position
222
+ expiration=get_expiration_timestamp(60 * 24 * 30),
223
+ nonce=client.order_nonce(),
224
+ trigger_price_x18=str(to_x18(45_000)),
225
+ trigger_type="last_price_below",
226
+ reduce_only=True,
227
+ )
228
+
229
+ # 2. Take-profit target
230
+ take_profit = trigger_client.place_price_trigger_order(
231
+ product_id=1,
232
+ sender=client.signer.address,
233
+ price_x18=str(to_x18(58_000)),
234
+ amount_x18=str(-to_x18(2)), # Close 2 BTC position
235
+ expiration=get_expiration_timestamp(60 * 24 * 30),
236
+ nonce=client.order_nonce(),
237
+ trigger_price_x18=str(to_x18(57_000)),
238
+ trigger_type="last_price_above",
239
+ reduce_only=True,
240
+ )
241
+
242
+ # 3. DCA accumulation strategy
243
+ dca_strategy = trigger_client.place_twap_order(
244
+ product_id=1,
245
+ sender=client.signer.address,
246
+ price_x18=str(to_x18(52_000)), # Max $52k per buy
247
+ total_amount_x18=str(to_x18(10)), # Buy 10 BTC over time
248
+ expiration=get_expiration_timestamp(60 * 24 * 7),
249
+ nonce=client.order_nonce(),
250
+ times=20, # 20 executions
251
+ slippage_frac=0.005, # 0.5% slippage
252
+ interval_seconds=1800, # 30 minutes
253
+ )
254
+ ```
255
+
256
+ See [Getting Started](https://nadohq.github.io/nado-python-sdk/getting-started.html) for more.
257
+
258
+ ## Running locally
259
+
260
+ 1. Clone [github repo](https://github.com/nadohq/nado-python-sdk)
261
+
262
+ 2. Install poetry
263
+
264
+ ```
265
+
266
+ $ curl -sSL https://install.python-poetry.org | python3 -
267
+
268
+ ```
269
+
270
+ 3. Setup a virtual environment and activate it
271
+
272
+ ```
273
+
274
+ $ python3 -m venv venv
275
+ $ source ./venv/bin/activate
276
+
277
+ ```
278
+
279
+ 4. Install dependencies via `poetry install`
280
+ 5. Setup an `.env` file and set the following envvars
281
+
282
+ ```shell
283
+ CLIENT_MODE='devnet'
284
+ SIGNER_PRIVATE_KEY="0x..."
285
+ LINKED_SIGNER_PRIVATE_KEY="0x..." # not required
286
+ ```
287
+
288
+ ### Run tests
289
+
290
+ ```
291
+ $ poetry run test
292
+ ```
293
+
294
+ ### Run sanity checks
295
+
296
+ - `poetry run client-sanity`: runs sanity checks for the top-level client.
297
+ - `poetry run engine-sanity`: runs sanity checks for the `engine-client`.
298
+ - `poetry run indexer-sanity`: runs sanity checks for the `indexer-client`.
299
+ - `poetry run trigger-sanity`: runs sanity checks for the `trigger-client` including TWAP and price trigger examples.
300
+ - `poetry run contracts-sanity`: runs sanity checks for the contracts module.
301
+
302
+ ### Build Docs
303
+
304
+ To build the docs locally run:
305
+
306
+ ```
307
+ $ poetry run sphinx-build docs/source docs/build
308
+ ```
309
+
@@ -0,0 +1,284 @@
1
+ # Nado Protocol Python SDK
2
+
3
+ This is the Python SDK for the [Nado Protocol API](TODO).
4
+
5
+ See [SDK docs](https://nadohq.github.io/nado-python-sdk/index.html) to get started.
6
+
7
+ ## Requirements
8
+
9
+ - Python 3.9 or above
10
+
11
+ ## Installation
12
+
13
+ You can install the SDK via pip:
14
+
15
+ ```bash
16
+ pip install nado-protocol
17
+ ```
18
+
19
+ ## Basic usage
20
+
21
+ ### Import the necessary utilities:
22
+
23
+ ```python
24
+ from nado_protocol.client import create_nado_client, NadoClientMode
25
+ from nado_protocol.contracts.types import DepositCollateralParams
26
+ from nado_protocol.engine_client.types.execute import (
27
+ OrderParams,
28
+ PlaceOrderParams,
29
+ SubaccountParams
30
+ )
31
+ from nado_protocol.utils.expiration import OrderType, get_expiration_timestamp
32
+ from nado_protocol.utils.math import to_pow_10, to_x18
33
+ from nado_protocol.utils.nonce import gen_order_nonce
34
+ from nado_protocol.utils.order import build_appendix
35
+ ```
36
+
37
+ ### Create the NadoClient providing your private key:
38
+
39
+ ```python
40
+ print("setting up nado client...")
41
+ private_key = "xxx"
42
+ client = create_nado_client(NadoClientMode.DEVNET, private_key)
43
+ ```
44
+
45
+ ### Perform basic operations:
46
+
47
+ ```python
48
+ # Depositing collaterals
49
+ print("approving allowance...")
50
+ approve_allowance_tx_hash = client.spot.approve_allowance(0, to_pow_10(100000, 6))
51
+ print("approve allowance tx hash:", approve_allowance_tx_hash)
52
+
53
+ print("querying my allowance...")
54
+ token_allowance = client.spot.get_token_allowance(0, client.context.signer.address)
55
+ print("token allowance:", token_allowance)
56
+
57
+ print("depositing collateral...")
58
+ deposit_tx_hash = client.spot.deposit(
59
+ DepositCollateralParams(
60
+ subaccount_name="default", product_id=0, amount=to_pow_10(100000, 6)
61
+ )
62
+ )
63
+ print("deposit collateral tx hash:", deposit_tx_hash)
64
+
65
+ # Placing orders
66
+ print("placing order...")
67
+ owner = client.context.engine_client.signer.address
68
+ product_id = 1
69
+ order = OrderParams(
70
+ sender=SubaccountParams(
71
+ subaccount_owner=owner,
72
+ subaccount_name="default",
73
+ ),
74
+ priceX18=to_x18(20000),
75
+ amount=to_pow_10(1, 17),
76
+ expiration=get_expiration_timestamp(40),
77
+ nonce=gen_order_nonce(),
78
+ appendix=build_appendix(order_type=OrderType.POST_ONLY)
79
+ )
80
+ res = client.market.place_order({"product_id": product_id, "order": order})
81
+ print("order result:", res.json(indent=2))
82
+ ```
83
+
84
+ ## TWAP and Trigger Orders
85
+
86
+ The SDK provides comprehensive support for Time-Weighted Average Price (TWAP) orders and price trigger orders through the Trigger Client.
87
+
88
+ ### TWAP Orders
89
+
90
+ TWAP orders allow you to execute large trades over time with controlled slippage:
91
+
92
+ ```python
93
+ from nado_protocol.trigger_client import TriggerClient
94
+ from nado_protocol.trigger_client.types import TriggerClientOpts
95
+ from nado_protocol.utils.math import to_x18
96
+ from nado_protocol.utils.expiration import get_expiration_timestamp
97
+
98
+ # Create trigger client
99
+ trigger_client = TriggerClient(
100
+ opts=TriggerClientOpts(url=TRIGGER_BACKEND_URL, signer=private_key)
101
+ )
102
+
103
+ # Place a TWAP order to buy 5 BTC over 2 hours
104
+ twap_result = trigger_client.place_twap_order(
105
+ product_id=1,
106
+ sender=client.signer.address,
107
+ price_x18=str(to_x18(50_000)), # Max $50k per execution
108
+ total_amount_x18=str(to_x18(5)), # Buy 5 BTC total
109
+ expiration=get_expiration_timestamp(60 * 24), # 24 hours
110
+ nonce=client.order_nonce(),
111
+ times=10, # Split into 10 executions
112
+ slippage_frac=0.005, # 0.5% slippage tolerance
113
+ interval_seconds=720, # 12 minutes between executions
114
+ )
115
+ ```
116
+
117
+ ### TWAP with Custom Amounts
118
+
119
+ For more sophisticated strategies, you can specify custom amounts for each execution:
120
+
121
+ ```python
122
+ # Decreasing size strategy: 2 BTC, 1.5 BTC, 1 BTC, 0.5 BTC
123
+ custom_amounts = [
124
+ str(to_x18(2)), # 2 BTC
125
+ str(to_x18(1.5)), # 1.5 BTC
126
+ str(to_x18(1)), # 1 BTC
127
+ str(to_x18(0.5)), # 0.5 BTC
128
+ ]
129
+
130
+ custom_twap_result = trigger_client.place_twap_order(
131
+ product_id=1,
132
+ sender=client.signer.address,
133
+ price_x18=str(to_x18(51_000)),
134
+ total_amount_x18=str(to_x18(5)), # 5 BTC total
135
+ expiration=get_expiration_timestamp(60 * 12),
136
+ nonce=client.order_nonce(),
137
+ times=4, # 4 executions
138
+ slippage_frac=0.01, # 1% slippage
139
+ interval_seconds=1800, # 30 minutes
140
+ custom_amounts_x18=custom_amounts,
141
+ )
142
+ ```
143
+
144
+ ### Price Trigger Orders
145
+
146
+ Create conditional orders that execute when price conditions are met:
147
+
148
+ ```python
149
+ # Stop-loss order (sell when price drops below $45k)
150
+ stop_loss = trigger_client.place_price_trigger_order(
151
+ product_id=1,
152
+ sender=client.signer.address,
153
+ price_x18=str(to_x18(44_000)), # Sell at $44k
154
+ amount_x18=str(-to_x18(1)), # Sell 1 BTC (negative for sell)
155
+ expiration=get_expiration_timestamp(60 * 24 * 7), # 1 week
156
+ nonce=client.order_nonce(),
157
+ trigger_price_x18=str(to_x18(45_000)), # Trigger below $45k
158
+ trigger_type="last_price_below",
159
+ reduce_only=True, # Only reduce position
160
+ )
161
+
162
+ # Take-profit order (sell when price rises above $55k)
163
+ take_profit = trigger_client.place_price_trigger_order(
164
+ product_id=1,
165
+ sender=client.signer.address,
166
+ price_x18=str(to_x18(56_000)), # Sell at $56k
167
+ amount_x18=str(-to_x18(1)), # Sell 1 BTC
168
+ expiration=get_expiration_timestamp(60 * 24 * 7),
169
+ nonce=client.order_nonce(),
170
+ trigger_price_x18=str(to_x18(55_000)), # Trigger above $55k
171
+ trigger_type="last_price_above",
172
+ reduce_only=True,
173
+ )
174
+ ```
175
+
176
+ ### Supported Trigger Types
177
+
178
+ The SDK supports six types of price triggers:
179
+
180
+ - `"last_price_above"`: Trigger when last traded price goes above threshold
181
+ - `"last_price_below"`: Trigger when last traded price goes below threshold
182
+ - `"oracle_price_above"`: Trigger when oracle price goes above threshold
183
+ - `"oracle_price_below"`: Trigger when oracle price goes below threshold
184
+ - `"mid_price_above"`: Trigger when mid price goes above threshold
185
+ - `"mid_price_below"`: Trigger when mid price goes below threshold
186
+
187
+ ### Complete Trading Strategy Example
188
+
189
+ Here's how to set up a complete trading strategy with stop-loss, take-profit, and DCA:
190
+
191
+ ```python
192
+ # 1. Stop-loss protection
193
+ stop_loss = trigger_client.place_price_trigger_order(
194
+ product_id=1,
195
+ sender=client.signer.address,
196
+ price_x18=str(to_x18(44_000)),
197
+ amount_x18=str(-to_x18(2)), # Close 2 BTC position
198
+ expiration=get_expiration_timestamp(60 * 24 * 30),
199
+ nonce=client.order_nonce(),
200
+ trigger_price_x18=str(to_x18(45_000)),
201
+ trigger_type="last_price_below",
202
+ reduce_only=True,
203
+ )
204
+
205
+ # 2. Take-profit target
206
+ take_profit = trigger_client.place_price_trigger_order(
207
+ product_id=1,
208
+ sender=client.signer.address,
209
+ price_x18=str(to_x18(58_000)),
210
+ amount_x18=str(-to_x18(2)), # Close 2 BTC position
211
+ expiration=get_expiration_timestamp(60 * 24 * 30),
212
+ nonce=client.order_nonce(),
213
+ trigger_price_x18=str(to_x18(57_000)),
214
+ trigger_type="last_price_above",
215
+ reduce_only=True,
216
+ )
217
+
218
+ # 3. DCA accumulation strategy
219
+ dca_strategy = trigger_client.place_twap_order(
220
+ product_id=1,
221
+ sender=client.signer.address,
222
+ price_x18=str(to_x18(52_000)), # Max $52k per buy
223
+ total_amount_x18=str(to_x18(10)), # Buy 10 BTC over time
224
+ expiration=get_expiration_timestamp(60 * 24 * 7),
225
+ nonce=client.order_nonce(),
226
+ times=20, # 20 executions
227
+ slippage_frac=0.005, # 0.5% slippage
228
+ interval_seconds=1800, # 30 minutes
229
+ )
230
+ ```
231
+
232
+ See [Getting Started](https://nadohq.github.io/nado-python-sdk/getting-started.html) for more.
233
+
234
+ ## Running locally
235
+
236
+ 1. Clone [github repo](https://github.com/nadohq/nado-python-sdk)
237
+
238
+ 2. Install poetry
239
+
240
+ ```
241
+
242
+ $ curl -sSL https://install.python-poetry.org | python3 -
243
+
244
+ ```
245
+
246
+ 3. Setup a virtual environment and activate it
247
+
248
+ ```
249
+
250
+ $ python3 -m venv venv
251
+ $ source ./venv/bin/activate
252
+
253
+ ```
254
+
255
+ 4. Install dependencies via `poetry install`
256
+ 5. Setup an `.env` file and set the following envvars
257
+
258
+ ```shell
259
+ CLIENT_MODE='devnet'
260
+ SIGNER_PRIVATE_KEY="0x..."
261
+ LINKED_SIGNER_PRIVATE_KEY="0x..." # not required
262
+ ```
263
+
264
+ ### Run tests
265
+
266
+ ```
267
+ $ poetry run test
268
+ ```
269
+
270
+ ### Run sanity checks
271
+
272
+ - `poetry run client-sanity`: runs sanity checks for the top-level client.
273
+ - `poetry run engine-sanity`: runs sanity checks for the `engine-client`.
274
+ - `poetry run indexer-sanity`: runs sanity checks for the `indexer-client`.
275
+ - `poetry run trigger-sanity`: runs sanity checks for the `trigger-client` including TWAP and price trigger examples.
276
+ - `poetry run contracts-sanity`: runs sanity checks for the contracts module.
277
+
278
+ ### Build Docs
279
+
280
+ To build the docs locally run:
281
+
282
+ ```
283
+ $ poetry run sphinx-build docs/source docs/build
284
+ ```