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.
- nado_protocol-0.1.5/PKG-INFO +309 -0
- nado_protocol-0.1.5/README.md +284 -0
- nado_protocol-0.1.5/nado_protocol/client/apis/market/execute.py +322 -0
- nado_protocol-0.1.5/nado_protocol/trigger_client/execute.py +343 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/query.py +19 -0
- nado_protocol-0.1.5/nado_protocol/trigger_client/types/models.py +85 -0
- nado_protocol-0.1.5/nado_protocol/trigger_client/types/query.py +199 -0
- nado_protocol-0.1.5/nado_protocol/utils/twap.py +189 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/pyproject.toml +1 -1
- nado_protocol-0.1.4/PKG-INFO +0 -159
- nado_protocol-0.1.4/README.md +0 -135
- nado_protocol-0.1.4/nado_protocol/client/apis/market/execute.py +0 -176
- nado_protocol-0.1.4/nado_protocol/trigger_client/execute.py +0 -118
- nado_protocol-0.1.4/nado_protocol/trigger_client/types/models.py +0 -44
- nado_protocol-0.1.4/nado_protocol/trigger_client/types/query.py +0 -77
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/base.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/market/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/market/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/perp/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/perp/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/rewards/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/base.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/spot/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/apis/subaccount/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/client/context.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/Endpoint.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/FQuerier.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IAirdrop.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IClearinghouse.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IEndpoint.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IFoundationRewardsAirdrop.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IPerpEngine.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IProductEngine.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/ISpotEngine.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/IStaking.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/abis/MockERC20.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/deployments/deployment.testing.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/deployments/deployment.testnet.json +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/domain.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/sign.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/eip712/types.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/loader.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/contracts/types.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/models.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/engine_client/types/stream.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/models.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/indexer_client/types/query.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/types/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/trigger_client/types/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/__init__.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/backend.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/bytes32.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/enum.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/exceptions.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/execute.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/expiration.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/interest.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/math.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/model.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/nonce.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/order.py +0 -0
- {nado_protocol-0.1.4 → nado_protocol-0.1.5}/nado_protocol/utils/subaccount.py +0 -0
- {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
|
+
```
|