silhouette-python-sdk 0.3.0__tar.gz → 0.3.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.
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/PKG-INFO +13 -183
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/README.md +12 -182
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/pyproject.toml +8 -2
- silhouette_python_sdk-0.3.0/silhouette/twap/USAGE_GUIDE.md +0 -445
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/LICENSE.md +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/auth.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/base_model.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/client.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/generated/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/rfq_types.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/v1/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/api.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/exchange.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/info.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/constants.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/error.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/signing.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/types.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/websocket_manager.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/py.typed +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/authenticated_client.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/base_model.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/client.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/generated/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/interfaces.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/utils/__init__.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/utils/constants.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/utils/conversions.py +0 -0
- {silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/utils/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: silhouette-python-sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python SDK for trading on Silhouette - the shield exchange on Hyperliquid
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: silhouette,trading,privacy,exchange,hyperliquid,defi,crypto,sdk
|
|
@@ -61,9 +61,9 @@ This package provides:
|
|
|
61
61
|
pip install silhouette-python-sdk
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
## Quick
|
|
64
|
+
## Quick start
|
|
65
65
|
|
|
66
|
-
### Using
|
|
66
|
+
### Using the enhanced Hyperliquid SDK
|
|
67
67
|
|
|
68
68
|
```python
|
|
69
69
|
# IMPORTANT: Always import silhouette FIRST
|
|
@@ -86,7 +86,7 @@ usdc_balance = info.get_balance("0x1615330FAee0776a643CC0075AD2008418e067Db", "U
|
|
|
86
86
|
print(f"USDC Balance: {usdc_balance}")
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
### Using Silhouette API
|
|
89
|
+
### Using the Silhouette API
|
|
90
90
|
|
|
91
91
|
```python
|
|
92
92
|
from silhouette import SilhouetteApiClient
|
|
@@ -118,9 +118,9 @@ withdrawal = client.user.initiate_withdrawal("USDC", "100.0")
|
|
|
118
118
|
print(f"Withdrawal initiated: {withdrawal['withdrawalId']}")
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
## Enhanced
|
|
121
|
+
## Enhanced features
|
|
122
122
|
|
|
123
|
-
### Hyperliquid SDK
|
|
123
|
+
### Hyperliquid SDK enhancements
|
|
124
124
|
|
|
125
125
|
The enhanced Hyperliquid SDK includes these convenience methods:
|
|
126
126
|
|
|
@@ -133,28 +133,19 @@ The enhanced Hyperliquid SDK includes these convenience methods:
|
|
|
133
133
|
|
|
134
134
|
All other Hyperliquid SDK methods work exactly as documented in the [official Hyperliquid SDK](https://github.com/hyperliquid-dex/hyperliquid-python-sdk).
|
|
135
135
|
|
|
136
|
-
### Silhouette API
|
|
136
|
+
### Silhouette API client
|
|
137
137
|
|
|
138
138
|
The `SilhouetteApiClient` provides access to the Silhouette shielded exchange:
|
|
139
139
|
|
|
140
140
|
- **Dict-based API**: All methods return plain Python dicts with camelCase keys matching the API
|
|
141
141
|
- **No model imports needed**: Pydantic models are used internally for validation, but you work with simple dicts
|
|
142
|
-
- **User operations**: Balances, withdrawal initiation
|
|
142
|
+
- **User operations**: Balances, withdrawal initiation and status polling
|
|
143
143
|
- **Order management**: Create, cancel, query orders
|
|
144
144
|
- **Delegated orders**: List, get, and batch retrieve delegated orders
|
|
145
|
-
- **
|
|
145
|
+
- **Market data**: Query supported tokens and trading pairs
|
|
146
|
+
- **Referral management**: Register new users, set referrers, query referral details
|
|
146
147
|
- **Automatic authentication**: SIWE-based session management with automatic token refresh
|
|
147
148
|
|
|
148
|
-
API response structure:
|
|
149
|
-
```python
|
|
150
|
-
# All responses are dicts with camelCase keys
|
|
151
|
-
response = client.user.get_balances()
|
|
152
|
-
# {
|
|
153
|
-
# "responseMetadata": {"timestamp": 1234567890, "requestId": "..."},
|
|
154
|
-
# "balances": [{"token": "USDC", "available": "1000.0", ...}]
|
|
155
|
-
# }
|
|
156
|
-
```
|
|
157
|
-
|
|
158
149
|
### Delegated orders
|
|
159
150
|
|
|
160
151
|
Delegated orders are orders placed on Hyperliquid by Silhouette on behalf of a trader. Query them using the `delegated_order` operations:
|
|
@@ -178,43 +169,6 @@ batch = client.delegated_order.batch_get_delegated_orders(
|
|
|
178
169
|
print(f"Found: {len(batch['orders'])}, Not found: {batch['notFound']}")
|
|
179
170
|
```
|
|
180
171
|
|
|
181
|
-
## API Design
|
|
182
|
-
|
|
183
|
-
### Why Dicts Instead of Models?
|
|
184
|
-
|
|
185
|
-
The SDK uses a hybrid approach for optimal developer experience:
|
|
186
|
-
|
|
187
|
-
**Internal (validation)**:
|
|
188
|
-
- Pydantic models auto-generated from OpenAPI spec
|
|
189
|
-
- Runtime type validation of all requests and responses
|
|
190
|
-
- Models stay in sync with API via regeneration
|
|
191
|
-
|
|
192
|
-
**External (your code)**:
|
|
193
|
-
- Plain Python dicts with camelCase keys
|
|
194
|
-
- No need to import generated models
|
|
195
|
-
- Simple dict access: `response["withdrawalId"]`
|
|
196
|
-
- Clean, Pythonic API
|
|
197
|
-
|
|
198
|
-
### Regenerating models
|
|
199
|
-
|
|
200
|
-
Models are generated from the OpenAPI specifications using `datamodel-code-generator`. When the Silhouette API changes, regenerate the models to stay in sync:
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
# Generate from committed specs
|
|
204
|
-
make generate
|
|
205
|
-
|
|
206
|
-
# Or fetch fresh specs and regenerate in one step
|
|
207
|
-
make regenerate
|
|
208
|
-
|
|
209
|
-
# Fetch from a specific URL
|
|
210
|
-
make fetch-heimdall-v0-spec URL=https://api-staging.silhouette.exchange
|
|
211
|
-
make fetch-heimdall-v1-spec URL=https://api-staging.silhouette.exchange
|
|
212
|
-
make generate
|
|
213
|
-
|
|
214
|
-
# Run tests to catch any breaking changes
|
|
215
|
-
make test
|
|
216
|
-
```
|
|
217
|
-
|
|
218
172
|
## Configuration
|
|
219
173
|
|
|
220
174
|
Create `examples/config.json` from the example template:
|
|
@@ -228,133 +182,13 @@ Then configure:
|
|
|
228
182
|
- `secret_key`: Your wallet's private key (or use `keystore_path` for a keystore file)
|
|
229
183
|
- `use_testnet`: Set to `true` for testnet, `false` for mainnet
|
|
230
184
|
|
|
231
|
-
### [Optional] Using an API
|
|
185
|
+
### [Optional] Using an API wallet
|
|
232
186
|
|
|
233
187
|
Generate and authorise a new API private key on <https://app.hyperliquid.xyz/API>, and set the API wallet's private key as the `secret_key` in `examples/config.json`. Note that you must still set the public key of the main wallet (not the API wallet) as the `account_address`.
|
|
234
188
|
|
|
235
|
-
##
|
|
236
|
-
|
|
237
|
-
See [examples/](examples/) for complete examples:
|
|
238
|
-
|
|
239
|
-
- **[silhouette_full_workflow.py](examples/silhouette_full_workflow.py)** - Complete workflow: deposit, trade, withdraw
|
|
240
|
-
- **[basic_order.py](examples/basic_order.py)** - Place and manage orders on Hyperliquid
|
|
241
|
-
- **[basic_spot_order.py](examples/basic_spot_order.py)** - Spot trading examples
|
|
242
|
-
- **[basic_adding.py](examples/basic_adding.py)** - Deposit funds to Hyperliquid
|
|
243
|
-
|
|
244
|
-
Run any example after configuring your credentials:
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
python examples/silhouette_full_workflow.py
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
## Development
|
|
251
|
-
|
|
252
|
-
### Prerequisites
|
|
253
|
-
|
|
254
|
-
- Python 3.10 or higher
|
|
255
|
-
- [Poetry](https://python-poetry.org/) for dependency management
|
|
256
|
-
|
|
257
|
-
### Setup
|
|
189
|
+
## Contributing
|
|
258
190
|
|
|
259
|
-
|
|
260
|
-
# Install Poetry (if not already installed)
|
|
261
|
-
curl -sSL https://install.python-poetry.org | python3 -
|
|
262
|
-
|
|
263
|
-
# Install dependencies
|
|
264
|
-
make install
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### Development Workflow
|
|
268
|
-
|
|
269
|
-
#### Code Quality and Linting
|
|
270
|
-
|
|
271
|
-
This project uses [ruff](https://docs.astral.sh/ruff/) for linting and formatting, with pre-commit hooks for automated checks.
|
|
272
|
-
|
|
273
|
-
**Normal development workflow:**
|
|
274
|
-
1. Make your changes
|
|
275
|
-
2. Run `git add .` to stage changes
|
|
276
|
-
3. Run `git commit` - pre-commit hooks will run automatically
|
|
277
|
-
|
|
278
|
-
**If pre-commit hooks fail:**
|
|
279
|
-
1. `make check` - See all linting issues
|
|
280
|
-
2. `make fix` - Auto-fix safe issues
|
|
281
|
-
3. `make format` - Format code
|
|
282
|
-
4. `make test` - Run tests
|
|
283
|
-
5. Stage changes and commit again
|
|
284
|
-
|
|
285
|
-
#### Available Make Commands
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
make build # Builds as a tarball and a wheel
|
|
289
|
-
make check # Run ruff check without fixes
|
|
290
|
-
make check-safety # Run safety checks on dependencies
|
|
291
|
-
make cleanup # Cleanup project
|
|
292
|
-
make fix # Run ruff check with fixes
|
|
293
|
-
make fix-unsafe # Run ruff check with unsafe fixes
|
|
294
|
-
make format # Run ruff format
|
|
295
|
-
make install # Install dependencies from poetry.lock
|
|
296
|
-
make install-types # Find and install additional types for mypy
|
|
297
|
-
make lockfile-update # Update poetry.lock
|
|
298
|
-
make lockfile-update-full # Fully regenerate poetry.lock
|
|
299
|
-
make poetry-download # Download and install poetry
|
|
300
|
-
make pre-commit # Run all pre-commit hooks
|
|
301
|
-
make publish # Publish the package to PyPI
|
|
302
|
-
make test # Run tests with pytest
|
|
303
|
-
make update-dev-deps # Update development dependencies to latest versions
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
Run `make` without arguments to see this list of commands.
|
|
307
|
-
|
|
308
|
-
### Running Tests
|
|
309
|
-
|
|
310
|
-
```bash
|
|
311
|
-
# Run all tests
|
|
312
|
-
make test
|
|
313
|
-
|
|
314
|
-
# Run specific test file
|
|
315
|
-
poetry run pytest tests/hyperliquid/info_test.py -v
|
|
316
|
-
|
|
317
|
-
# Run with coverage report
|
|
318
|
-
poetry run pytest --cov=silhouette --cov-report=html
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
## Project Structure
|
|
322
|
-
|
|
323
|
-
```
|
|
324
|
-
silhouette-python-sdk/
|
|
325
|
-
├── silhouette/
|
|
326
|
-
│ ├── api/ # Silhouette API client
|
|
327
|
-
│ │ ├── client.py # Main API client (dict-based API)
|
|
328
|
-
│ │ ├── auth.py # SIWE authentication
|
|
329
|
-
│ │ └── generated/ # Generated Pydantic models from OpenAPI spec
|
|
330
|
-
│ │ └── models/ # Request/response models (internal use only)
|
|
331
|
-
│ ├── hyperliquid/ # Enhanced Hyperliquid SDK wrappers
|
|
332
|
-
│ │ ├── info.py # Enhanced Info class
|
|
333
|
-
│ │ ├── exchange.py # Enhanced Exchange class
|
|
334
|
-
│ │ └── utils/ # Re-exported utilities
|
|
335
|
-
│ └── utils/
|
|
336
|
-
│ └── conversions.py # Token conversion utilities
|
|
337
|
-
├── tests/ # Test suite
|
|
338
|
-
│ ├── api/ # API client tests
|
|
339
|
-
│ ├── hyperliquid/ # Hyperliquid wrapper tests
|
|
340
|
-
│ └── utils/ # Utility tests
|
|
341
|
-
└── examples/ # Usage examples
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
**Note**: The `generated/models/` directory contains Pydantic models auto-generated from the OpenAPI specification. These are used internally for validation but you don't need to import them - the API client returns plain dicts.
|
|
345
|
-
|
|
346
|
-
## Releases
|
|
347
|
-
|
|
348
|
-
See [GitHub Releases](https://github.com/silhouette-exchange/silhouette-python-sdk/releases) for available versions.
|
|
349
|
-
|
|
350
|
-
We follow [Semantic Versioning](https://semver.org/) and use [Release Drafter](https://github.com/marketplace/actions/release-drafter) for automated release notes.
|
|
351
|
-
|
|
352
|
-
### Building and Releasing
|
|
353
|
-
|
|
354
|
-
1. Bump version: `poetry version <major|minor|patch>`
|
|
355
|
-
2. Commit changes: `git commit -am "Bump version to X.Y.Z"`
|
|
356
|
-
3. Create GitHub release
|
|
357
|
-
4. Publish: `make publish`
|
|
191
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and project structure.
|
|
358
192
|
|
|
359
193
|
## Licence
|
|
360
194
|
|
|
@@ -371,7 +205,3 @@ This project is licensed under the terms of the MIT licence. See [LICENSE](LICEN
|
|
|
371
205
|
}
|
|
372
206
|
```
|
|
373
207
|
|
|
374
|
-
## Credits
|
|
375
|
-
|
|
376
|
-
This project was generated with [`python-package-template`](https://github.com/TezRomacH/python-package-template).
|
|
377
|
-
|
|
@@ -29,9 +29,9 @@ This package provides:
|
|
|
29
29
|
pip install silhouette-python-sdk
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
## Quick
|
|
32
|
+
## Quick start
|
|
33
33
|
|
|
34
|
-
### Using
|
|
34
|
+
### Using the enhanced Hyperliquid SDK
|
|
35
35
|
|
|
36
36
|
```python
|
|
37
37
|
# IMPORTANT: Always import silhouette FIRST
|
|
@@ -54,7 +54,7 @@ usdc_balance = info.get_balance("0x1615330FAee0776a643CC0075AD2008418e067Db", "U
|
|
|
54
54
|
print(f"USDC Balance: {usdc_balance}")
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
### Using Silhouette API
|
|
57
|
+
### Using the Silhouette API
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
60
|
from silhouette import SilhouetteApiClient
|
|
@@ -86,9 +86,9 @@ withdrawal = client.user.initiate_withdrawal("USDC", "100.0")
|
|
|
86
86
|
print(f"Withdrawal initiated: {withdrawal['withdrawalId']}")
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
## Enhanced
|
|
89
|
+
## Enhanced features
|
|
90
90
|
|
|
91
|
-
### Hyperliquid SDK
|
|
91
|
+
### Hyperliquid SDK enhancements
|
|
92
92
|
|
|
93
93
|
The enhanced Hyperliquid SDK includes these convenience methods:
|
|
94
94
|
|
|
@@ -101,28 +101,19 @@ The enhanced Hyperliquid SDK includes these convenience methods:
|
|
|
101
101
|
|
|
102
102
|
All other Hyperliquid SDK methods work exactly as documented in the [official Hyperliquid SDK](https://github.com/hyperliquid-dex/hyperliquid-python-sdk).
|
|
103
103
|
|
|
104
|
-
### Silhouette API
|
|
104
|
+
### Silhouette API client
|
|
105
105
|
|
|
106
106
|
The `SilhouetteApiClient` provides access to the Silhouette shielded exchange:
|
|
107
107
|
|
|
108
108
|
- **Dict-based API**: All methods return plain Python dicts with camelCase keys matching the API
|
|
109
109
|
- **No model imports needed**: Pydantic models are used internally for validation, but you work with simple dicts
|
|
110
|
-
- **User operations**: Balances, withdrawal initiation
|
|
110
|
+
- **User operations**: Balances, withdrawal initiation and status polling
|
|
111
111
|
- **Order management**: Create, cancel, query orders
|
|
112
112
|
- **Delegated orders**: List, get, and batch retrieve delegated orders
|
|
113
|
-
- **
|
|
113
|
+
- **Market data**: Query supported tokens and trading pairs
|
|
114
|
+
- **Referral management**: Register new users, set referrers, query referral details
|
|
114
115
|
- **Automatic authentication**: SIWE-based session management with automatic token refresh
|
|
115
116
|
|
|
116
|
-
API response structure:
|
|
117
|
-
```python
|
|
118
|
-
# All responses are dicts with camelCase keys
|
|
119
|
-
response = client.user.get_balances()
|
|
120
|
-
# {
|
|
121
|
-
# "responseMetadata": {"timestamp": 1234567890, "requestId": "..."},
|
|
122
|
-
# "balances": [{"token": "USDC", "available": "1000.0", ...}]
|
|
123
|
-
# }
|
|
124
|
-
```
|
|
125
|
-
|
|
126
117
|
### Delegated orders
|
|
127
118
|
|
|
128
119
|
Delegated orders are orders placed on Hyperliquid by Silhouette on behalf of a trader. Query them using the `delegated_order` operations:
|
|
@@ -146,43 +137,6 @@ batch = client.delegated_order.batch_get_delegated_orders(
|
|
|
146
137
|
print(f"Found: {len(batch['orders'])}, Not found: {batch['notFound']}")
|
|
147
138
|
```
|
|
148
139
|
|
|
149
|
-
## API Design
|
|
150
|
-
|
|
151
|
-
### Why Dicts Instead of Models?
|
|
152
|
-
|
|
153
|
-
The SDK uses a hybrid approach for optimal developer experience:
|
|
154
|
-
|
|
155
|
-
**Internal (validation)**:
|
|
156
|
-
- Pydantic models auto-generated from OpenAPI spec
|
|
157
|
-
- Runtime type validation of all requests and responses
|
|
158
|
-
- Models stay in sync with API via regeneration
|
|
159
|
-
|
|
160
|
-
**External (your code)**:
|
|
161
|
-
- Plain Python dicts with camelCase keys
|
|
162
|
-
- No need to import generated models
|
|
163
|
-
- Simple dict access: `response["withdrawalId"]`
|
|
164
|
-
- Clean, Pythonic API
|
|
165
|
-
|
|
166
|
-
### Regenerating models
|
|
167
|
-
|
|
168
|
-
Models are generated from the OpenAPI specifications using `datamodel-code-generator`. When the Silhouette API changes, regenerate the models to stay in sync:
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
# Generate from committed specs
|
|
172
|
-
make generate
|
|
173
|
-
|
|
174
|
-
# Or fetch fresh specs and regenerate in one step
|
|
175
|
-
make regenerate
|
|
176
|
-
|
|
177
|
-
# Fetch from a specific URL
|
|
178
|
-
make fetch-heimdall-v0-spec URL=https://api-staging.silhouette.exchange
|
|
179
|
-
make fetch-heimdall-v1-spec URL=https://api-staging.silhouette.exchange
|
|
180
|
-
make generate
|
|
181
|
-
|
|
182
|
-
# Run tests to catch any breaking changes
|
|
183
|
-
make test
|
|
184
|
-
```
|
|
185
|
-
|
|
186
140
|
## Configuration
|
|
187
141
|
|
|
188
142
|
Create `examples/config.json` from the example template:
|
|
@@ -196,133 +150,13 @@ Then configure:
|
|
|
196
150
|
- `secret_key`: Your wallet's private key (or use `keystore_path` for a keystore file)
|
|
197
151
|
- `use_testnet`: Set to `true` for testnet, `false` for mainnet
|
|
198
152
|
|
|
199
|
-
### [Optional] Using an API
|
|
153
|
+
### [Optional] Using an API wallet
|
|
200
154
|
|
|
201
155
|
Generate and authorise a new API private key on <https://app.hyperliquid.xyz/API>, and set the API wallet's private key as the `secret_key` in `examples/config.json`. Note that you must still set the public key of the main wallet (not the API wallet) as the `account_address`.
|
|
202
156
|
|
|
203
|
-
##
|
|
204
|
-
|
|
205
|
-
See [examples/](examples/) for complete examples:
|
|
206
|
-
|
|
207
|
-
- **[silhouette_full_workflow.py](examples/silhouette_full_workflow.py)** - Complete workflow: deposit, trade, withdraw
|
|
208
|
-
- **[basic_order.py](examples/basic_order.py)** - Place and manage orders on Hyperliquid
|
|
209
|
-
- **[basic_spot_order.py](examples/basic_spot_order.py)** - Spot trading examples
|
|
210
|
-
- **[basic_adding.py](examples/basic_adding.py)** - Deposit funds to Hyperliquid
|
|
211
|
-
|
|
212
|
-
Run any example after configuring your credentials:
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
python examples/silhouette_full_workflow.py
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Development
|
|
219
|
-
|
|
220
|
-
### Prerequisites
|
|
221
|
-
|
|
222
|
-
- Python 3.10 or higher
|
|
223
|
-
- [Poetry](https://python-poetry.org/) for dependency management
|
|
224
|
-
|
|
225
|
-
### Setup
|
|
157
|
+
## Contributing
|
|
226
158
|
|
|
227
|
-
|
|
228
|
-
# Install Poetry (if not already installed)
|
|
229
|
-
curl -sSL https://install.python-poetry.org | python3 -
|
|
230
|
-
|
|
231
|
-
# Install dependencies
|
|
232
|
-
make install
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Development Workflow
|
|
236
|
-
|
|
237
|
-
#### Code Quality and Linting
|
|
238
|
-
|
|
239
|
-
This project uses [ruff](https://docs.astral.sh/ruff/) for linting and formatting, with pre-commit hooks for automated checks.
|
|
240
|
-
|
|
241
|
-
**Normal development workflow:**
|
|
242
|
-
1. Make your changes
|
|
243
|
-
2. Run `git add .` to stage changes
|
|
244
|
-
3. Run `git commit` - pre-commit hooks will run automatically
|
|
245
|
-
|
|
246
|
-
**If pre-commit hooks fail:**
|
|
247
|
-
1. `make check` - See all linting issues
|
|
248
|
-
2. `make fix` - Auto-fix safe issues
|
|
249
|
-
3. `make format` - Format code
|
|
250
|
-
4. `make test` - Run tests
|
|
251
|
-
5. Stage changes and commit again
|
|
252
|
-
|
|
253
|
-
#### Available Make Commands
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
make build # Builds as a tarball and a wheel
|
|
257
|
-
make check # Run ruff check without fixes
|
|
258
|
-
make check-safety # Run safety checks on dependencies
|
|
259
|
-
make cleanup # Cleanup project
|
|
260
|
-
make fix # Run ruff check with fixes
|
|
261
|
-
make fix-unsafe # Run ruff check with unsafe fixes
|
|
262
|
-
make format # Run ruff format
|
|
263
|
-
make install # Install dependencies from poetry.lock
|
|
264
|
-
make install-types # Find and install additional types for mypy
|
|
265
|
-
make lockfile-update # Update poetry.lock
|
|
266
|
-
make lockfile-update-full # Fully regenerate poetry.lock
|
|
267
|
-
make poetry-download # Download and install poetry
|
|
268
|
-
make pre-commit # Run all pre-commit hooks
|
|
269
|
-
make publish # Publish the package to PyPI
|
|
270
|
-
make test # Run tests with pytest
|
|
271
|
-
make update-dev-deps # Update development dependencies to latest versions
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Run `make` without arguments to see this list of commands.
|
|
275
|
-
|
|
276
|
-
### Running Tests
|
|
277
|
-
|
|
278
|
-
```bash
|
|
279
|
-
# Run all tests
|
|
280
|
-
make test
|
|
281
|
-
|
|
282
|
-
# Run specific test file
|
|
283
|
-
poetry run pytest tests/hyperliquid/info_test.py -v
|
|
284
|
-
|
|
285
|
-
# Run with coverage report
|
|
286
|
-
poetry run pytest --cov=silhouette --cov-report=html
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Project Structure
|
|
290
|
-
|
|
291
|
-
```
|
|
292
|
-
silhouette-python-sdk/
|
|
293
|
-
├── silhouette/
|
|
294
|
-
│ ├── api/ # Silhouette API client
|
|
295
|
-
│ │ ├── client.py # Main API client (dict-based API)
|
|
296
|
-
│ │ ├── auth.py # SIWE authentication
|
|
297
|
-
│ │ └── generated/ # Generated Pydantic models from OpenAPI spec
|
|
298
|
-
│ │ └── models/ # Request/response models (internal use only)
|
|
299
|
-
│ ├── hyperliquid/ # Enhanced Hyperliquid SDK wrappers
|
|
300
|
-
│ │ ├── info.py # Enhanced Info class
|
|
301
|
-
│ │ ├── exchange.py # Enhanced Exchange class
|
|
302
|
-
│ │ └── utils/ # Re-exported utilities
|
|
303
|
-
│ └── utils/
|
|
304
|
-
│ └── conversions.py # Token conversion utilities
|
|
305
|
-
├── tests/ # Test suite
|
|
306
|
-
│ ├── api/ # API client tests
|
|
307
|
-
│ ├── hyperliquid/ # Hyperliquid wrapper tests
|
|
308
|
-
│ └── utils/ # Utility tests
|
|
309
|
-
└── examples/ # Usage examples
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Note**: The `generated/models/` directory contains Pydantic models auto-generated from the OpenAPI specification. These are used internally for validation but you don't need to import them - the API client returns plain dicts.
|
|
313
|
-
|
|
314
|
-
## Releases
|
|
315
|
-
|
|
316
|
-
See [GitHub Releases](https://github.com/silhouette-exchange/silhouette-python-sdk/releases) for available versions.
|
|
317
|
-
|
|
318
|
-
We follow [Semantic Versioning](https://semver.org/) and use [Release Drafter](https://github.com/marketplace/actions/release-drafter) for automated release notes.
|
|
319
|
-
|
|
320
|
-
### Building and Releasing
|
|
321
|
-
|
|
322
|
-
1. Bump version: `poetry version <major|minor|patch>`
|
|
323
|
-
2. Commit changes: `git commit -am "Bump version to X.Y.Z"`
|
|
324
|
-
3. Create GitHub release
|
|
325
|
-
4. Publish: `make publish`
|
|
159
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and project structure.
|
|
326
160
|
|
|
327
161
|
## Licence
|
|
328
162
|
|
|
@@ -338,7 +172,3 @@ This project is licensed under the terms of the MIT licence. See [LICENSE](LICEN
|
|
|
338
172
|
howpublished = {\url{https://github.com/silhouette-exchange/silhouette-python-sdk}}
|
|
339
173
|
}
|
|
340
174
|
```
|
|
341
|
-
|
|
342
|
-
## Credits
|
|
343
|
-
|
|
344
|
-
This project was generated with [`python-package-template`](https://github.com/TezRomacH/python-package-template).
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "silhouette-python-sdk"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "Python SDK for trading on Silhouette - the shield exchange on Hyperliquid"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -43,6 +43,12 @@ Repository = "https://github.com/silhouette-exchange/silhouette-python-sdk"
|
|
|
43
43
|
packages = [
|
|
44
44
|
{ include = "silhouette" },
|
|
45
45
|
]
|
|
46
|
+
exclude = [
|
|
47
|
+
"examples/",
|
|
48
|
+
"docs/",
|
|
49
|
+
"AGENTS.md",
|
|
50
|
+
"CONTRIBUTING.md",
|
|
51
|
+
]
|
|
46
52
|
include = [
|
|
47
53
|
"silhouette/py.typed",
|
|
48
54
|
{ path = "silhouette/api/generated/__init__.py", format = ["sdist", "wheel"] },
|
|
@@ -55,12 +61,12 @@ pytest = "^8.4"
|
|
|
55
61
|
mypy = "^1.18"
|
|
56
62
|
ruff = "^0.13"
|
|
57
63
|
pre-commit = "^4.3"
|
|
58
|
-
safety = "^3.6"
|
|
59
64
|
coverage = "^7.10"
|
|
60
65
|
pytest-cov = "^7"
|
|
61
66
|
pytest-socket = "^0.7.0"
|
|
62
67
|
types-requests = "^2.31"
|
|
63
68
|
datamodel-code-generator = {version = "^0.29", extras = ["http"]}
|
|
69
|
+
pip-audit = "^2.10.0"
|
|
64
70
|
|
|
65
71
|
[tool.ruff]
|
|
66
72
|
target-version = "py310"
|
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
# Silhouette TWAP Platform - Usage Guide
|
|
2
|
-
|
|
3
|
-
## Table of Contents
|
|
4
|
-
|
|
5
|
-
1. [Platform Overview](#platform-overview)
|
|
6
|
-
2. [Getting Started](#getting-started)
|
|
7
|
-
3. [Platform Features](#platform-features)
|
|
8
|
-
4. [Common Use Cases](#common-use-cases)
|
|
9
|
-
5. [How the Platform Works](#how-the-platform-works)
|
|
10
|
-
6. [Key Handling and Authentication](#key-handling-and-authentication)
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Platform Overview
|
|
15
|
-
|
|
16
|
-
Silhouette TWAP (Time-Weighted Average Price) is an algorithmic trading platform designed to execute large trading orders on the Hyperliquid exchange over extended time periods. The platform intelligently splits large orders into smaller, randomized lots distributed across time to minimize market impact while ensuring reliable execution.
|
|
17
|
-
|
|
18
|
-
### Key Benefits
|
|
19
|
-
|
|
20
|
-
- **Minimized Market Impact**: Large orders are broken down into smaller pieces spread over time
|
|
21
|
-
- **Anti-Detection**: Randomized timing and sizing prevent pattern recognition
|
|
22
|
-
- **Automated Execution**: Hands-off execution once an order is placed
|
|
23
|
-
- **Price Protection**: Configurable price bounds prevent unwanted executions
|
|
24
|
-
- **Secure**: API keys encrypted at rest, only decrypted during execution
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## Getting Started
|
|
29
|
-
|
|
30
|
-
### Prerequisites
|
|
31
|
-
|
|
32
|
-
1. **Hyperliquid Account**
|
|
33
|
-
- Create an account on Hyperliquid
|
|
34
|
-
- Generate an API key
|
|
35
|
-
- Register the API key as an "agent" for your wallet
|
|
36
|
-
|
|
37
|
-
2. **Python SDK**
|
|
38
|
-
- Install the Silhouette Python SDK
|
|
39
|
-
|
|
40
|
-
### Installation
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
pip install silhouette-sdk
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Basic Usage
|
|
47
|
-
|
|
48
|
-
The `AuthenticatedTwapClient` handles all authentication automatically - no manual setup required:
|
|
49
|
-
|
|
50
|
-
```python
|
|
51
|
-
from silhouette.twap.authenticated_client import AuthenticatedTwapClient
|
|
52
|
-
from datetime import datetime, timedelta
|
|
53
|
-
import time
|
|
54
|
-
|
|
55
|
-
# Initialize the client (registration happens automatically)
|
|
56
|
-
client = AuthenticatedTwapClient(
|
|
57
|
-
base_url="https://scheduler.silhouette.com",
|
|
58
|
-
private_key="0x...", # Your Ethereum private key (for SIWE signing, never sent to server)
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# Create a TWAP order
|
|
62
|
-
start_time = datetime.now()
|
|
63
|
-
end_time = start_time + timedelta(hours=2)
|
|
64
|
-
|
|
65
|
-
order = client.create_twap_order({
|
|
66
|
-
"asset_id": "BTC",
|
|
67
|
-
"amount": "1.0", # Total amount to execute
|
|
68
|
-
"lots": 10, # Number of sub-orders
|
|
69
|
-
"order_side": "buy", # "buy" or "sell"
|
|
70
|
-
"market_type": "spot", # "spot" or "perp"
|
|
71
|
-
"start_time": int(start_time.timestamp()),
|
|
72
|
-
"end_time": int(end_time.timestamp()),
|
|
73
|
-
"price_upper_bound": "50000", # Optional: max price
|
|
74
|
-
"price_lower_bound": "45000", # Optional: min price
|
|
75
|
-
"slippage": "0.001" # Optional: slippage tolerance (default 0.001)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
print(f"Order created: {order['id']}")
|
|
79
|
-
print(f"Status: {order['status']}")
|
|
80
|
-
|
|
81
|
-
# Monitor order status
|
|
82
|
-
order_data = order
|
|
83
|
-
while order_data['status'] == "active":
|
|
84
|
-
time.sleep(60) # Check every minute
|
|
85
|
-
order_data = client.get_order(order['id'])
|
|
86
|
-
print(f"Progress: {order_data['executedAmount']} / {order_data['totalAmount']}")
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Available Methods
|
|
90
|
-
|
|
91
|
-
```python
|
|
92
|
-
# Create a TWAP order
|
|
93
|
-
order = client.create_twap_order(order_data)
|
|
94
|
-
|
|
95
|
-
# Get order details
|
|
96
|
-
order = client.get_order(order_id)
|
|
97
|
-
|
|
98
|
-
# Cancel an order
|
|
99
|
-
result = client.cancel_order(order_id)
|
|
100
|
-
|
|
101
|
-
# Pause an active order
|
|
102
|
-
result = client.pause_order(order_id)
|
|
103
|
-
|
|
104
|
-
# Resume a paused order
|
|
105
|
-
result = client.resume_order(order_id)
|
|
106
|
-
|
|
107
|
-
# Get all orders for your wallet
|
|
108
|
-
orders = client.get_orders_by_user()
|
|
109
|
-
|
|
110
|
-
# Get your wallet address
|
|
111
|
-
wallet_address = client.get_wallet_address()
|
|
112
|
-
|
|
113
|
-
# Check if client is ready
|
|
114
|
-
is_ready = client.is_ready()
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Platform Features
|
|
120
|
-
|
|
121
|
-
### TWAP Order Execution
|
|
122
|
-
|
|
123
|
-
Execute large orders over time with intelligent splitting and randomization.
|
|
124
|
-
|
|
125
|
-
**Required Parameters:**
|
|
126
|
-
- `asset_id`: Trading pair (e.g., "BTC", "ETH")
|
|
127
|
-
- `amount`: Total quantity to execute (as string)
|
|
128
|
-
- `lots`: Number of sub-orders to split into
|
|
129
|
-
- `order_side`: "buy" or "sell"
|
|
130
|
-
- `market_type`: "spot" or "perp"
|
|
131
|
-
- `start_time`: Unix timestamp (seconds)
|
|
132
|
-
- `end_time`: Unix timestamp (seconds)
|
|
133
|
-
|
|
134
|
-
**Optional Parameters:**
|
|
135
|
-
- `price_upper_bound`: Maximum price for buys (string)
|
|
136
|
-
- `price_lower_bound`: Minimum price for buys (string)
|
|
137
|
-
- `slippage`: Slippage tolerance (default "0.001", i.e., 0.1%)
|
|
138
|
-
- `order_intent`: Required for perp orders - "open" or "close"
|
|
139
|
-
|
|
140
|
-
### Price Bounds Protection
|
|
141
|
-
|
|
142
|
-
Protect your orders with upper and/or lower price limits.
|
|
143
|
-
|
|
144
|
-
```python
|
|
145
|
-
order = client.create_twap_order({
|
|
146
|
-
"asset_id": "BTC",
|
|
147
|
-
"amount": "10.0",
|
|
148
|
-
"lots": 20,
|
|
149
|
-
"order_side": "buy",
|
|
150
|
-
"market_type": "spot",
|
|
151
|
-
"start_time": int(start_time.timestamp()),
|
|
152
|
-
"end_time": int(end_time.timestamp()),
|
|
153
|
-
"price_upper_bound": "52000", # Don't buy above $52,000
|
|
154
|
-
"price_lower_bound": "48000" # Don't buy below $48,000
|
|
155
|
-
})
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
- Price bounds are validated before each lot execution
|
|
159
|
-
- Orders automatically pause if bounds are breached
|
|
160
|
-
- Orders resume when price returns to acceptable range
|
|
161
|
-
|
|
162
|
-
### Randomized Execution
|
|
163
|
-
|
|
164
|
-
The platform automatically randomizes:
|
|
165
|
-
- **Timing**: ±20% variance in execution intervals
|
|
166
|
-
- **Size**: ±15% variance in individual lot sizes
|
|
167
|
-
|
|
168
|
-
This prevents market makers from detecting your order patterns.
|
|
169
|
-
|
|
170
|
-
### Perpetual Futures Support
|
|
171
|
-
|
|
172
|
-
For perpetual futures orders, you must specify `order_intent`:
|
|
173
|
-
|
|
174
|
-
```python
|
|
175
|
-
# Open a new position
|
|
176
|
-
order = client.create_twap_order({
|
|
177
|
-
"asset_id": "BTC",
|
|
178
|
-
"amount": "10.0",
|
|
179
|
-
"lots": 15,
|
|
180
|
-
"order_side": "buy",
|
|
181
|
-
"market_type": "perp",
|
|
182
|
-
"order_intent": "open", # Required for perp: "open" or "close"
|
|
183
|
-
"start_time": int(start_time.timestamp()),
|
|
184
|
-
"end_time": int(end_time.timestamp())
|
|
185
|
-
})
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Order Management
|
|
189
|
-
|
|
190
|
-
**Order States:**
|
|
191
|
-
- `pending`: Order created, waiting to start
|
|
192
|
-
- `active`: Order executing lots over time
|
|
193
|
-
- `paused`: Price bounds breached or manually paused
|
|
194
|
-
- `completed`: All lots executed successfully
|
|
195
|
-
- `cancelled`: Order cancelled by user
|
|
196
|
-
- `failed`: Critical error occurred
|
|
197
|
-
|
|
198
|
-
**Monitoring:**
|
|
199
|
-
```python
|
|
200
|
-
# Get order status
|
|
201
|
-
order = client.get_order(order_id)
|
|
202
|
-
print(f"Status: {order['status']}")
|
|
203
|
-
print(f"Executed: {order['executedAmount']} / {order['totalAmount']}")
|
|
204
|
-
|
|
205
|
-
# List all your orders
|
|
206
|
-
orders = client.get_orders_by_user()
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
## Common Use Cases
|
|
212
|
-
|
|
213
|
-
### Use Case 1: Large Order Execution
|
|
214
|
-
|
|
215
|
-
Execute a large order without moving the market.
|
|
216
|
-
|
|
217
|
-
```python
|
|
218
|
-
from silhouette.twap.authenticated_client import AuthenticatedTwapClient
|
|
219
|
-
from datetime import datetime, timedelta
|
|
220
|
-
|
|
221
|
-
client = AuthenticatedTwapClient(
|
|
222
|
-
base_url="https://scheduler.silhouette.com",
|
|
223
|
-
private_key="0x...",
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
start = datetime.now()
|
|
227
|
-
end = start + timedelta(hours=6)
|
|
228
|
-
|
|
229
|
-
order = client.create_twap_order({
|
|
230
|
-
"asset_id": "BTC",
|
|
231
|
-
"amount": "100.0",
|
|
232
|
-
"lots": 50, # ~2 BTC per lot
|
|
233
|
-
"order_side": "buy",
|
|
234
|
-
"market_type": "spot",
|
|
235
|
-
"start_time": int(start.timestamp()),
|
|
236
|
-
"end_time": int(end.timestamp()),
|
|
237
|
-
"price_upper_bound": "52000"
|
|
238
|
-
})
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Use Case 2: Dollar Cost Averaging (DCA)
|
|
242
|
-
|
|
243
|
-
Accumulate an asset over time with price protection.
|
|
244
|
-
|
|
245
|
-
```python
|
|
246
|
-
start = datetime.now()
|
|
247
|
-
end = start + timedelta(hours=24)
|
|
248
|
-
|
|
249
|
-
order = client.create_twap_order({
|
|
250
|
-
"asset_id": "ETH",
|
|
251
|
-
"amount": "50.0",
|
|
252
|
-
"lots": 20, # 20 purchases over 24 hours
|
|
253
|
-
"order_side": "buy",
|
|
254
|
-
"market_type": "spot",
|
|
255
|
-
"start_time": int(start.timestamp()),
|
|
256
|
-
"end_time": int(end.timestamp()),
|
|
257
|
-
"price_upper_bound": "3000",
|
|
258
|
-
"price_lower_bound": "2500"
|
|
259
|
-
})
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Use Case 3: Exit Strategy
|
|
263
|
-
|
|
264
|
-
Sell a large position gradually to minimize impact.
|
|
265
|
-
|
|
266
|
-
```python
|
|
267
|
-
start = datetime.now()
|
|
268
|
-
end = start + timedelta(hours=4)
|
|
269
|
-
|
|
270
|
-
order = client.create_twap_order({
|
|
271
|
-
"asset_id": "BTC",
|
|
272
|
-
"amount": "50.0",
|
|
273
|
-
"lots": 30,
|
|
274
|
-
"order_side": "sell",
|
|
275
|
-
"market_type": "spot",
|
|
276
|
-
"start_time": int(start.timestamp()),
|
|
277
|
-
"end_time": int(end.timestamp()),
|
|
278
|
-
"price_lower_bound": "48000" # Don't sell below $48k
|
|
279
|
-
})
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### Use Case 4: Perpetual Position Entry
|
|
283
|
-
|
|
284
|
-
Open a large perpetual position gradually.
|
|
285
|
-
|
|
286
|
-
```python
|
|
287
|
-
start = datetime.now()
|
|
288
|
-
end = start + timedelta(hours=3)
|
|
289
|
-
|
|
290
|
-
order = client.create_twap_order({
|
|
291
|
-
"asset_id": "BTC",
|
|
292
|
-
"amount": "25.0",
|
|
293
|
-
"lots": 15,
|
|
294
|
-
"order_side": "buy",
|
|
295
|
-
"market_type": "perp",
|
|
296
|
-
"order_intent": "open",
|
|
297
|
-
"start_time": int(start.timestamp()),
|
|
298
|
-
"end_time": int(end.timestamp()),
|
|
299
|
-
"price_upper_bound": "51000"
|
|
300
|
-
})
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## How the Platform Works
|
|
306
|
-
|
|
307
|
-
### Architecture Overview
|
|
308
|
-
|
|
309
|
-
The Silhouette TWAP platform uses a **split services architecture**:
|
|
310
|
-
|
|
311
|
-
1. **Scheduler Service (TypeScript/NestJS)**
|
|
312
|
-
- Handles order planning and TWAP computation
|
|
313
|
-
- Manages user authentication
|
|
314
|
-
- Splits orders into randomized lots
|
|
315
|
-
- Creates execution tasks
|
|
316
|
-
|
|
317
|
-
2. **Executor Service (Python/FastAPI)**
|
|
318
|
-
- Consumes tasks from the queue
|
|
319
|
-
- Validates price bounds before execution
|
|
320
|
-
- Executes trades on Hyperliquid
|
|
321
|
-
- Reports results back
|
|
322
|
-
|
|
323
|
-
Both services communicate through **Upstash Redis** for task queuing and state storage.
|
|
324
|
-
|
|
325
|
-
### Order Execution Flow
|
|
326
|
-
|
|
327
|
-
```
|
|
328
|
-
User → Scheduler → Redis → Executor → Hyperliquid
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
1. User creates a TWAP order via the SDK
|
|
332
|
-
2. Scheduler validates the order and computes execution plan
|
|
333
|
-
3. Scheduler creates execution tasks with randomized timing
|
|
334
|
-
4. Tasks are queued in Redis
|
|
335
|
-
5. Executor consumes tasks at scheduled times
|
|
336
|
-
6. Executor validates price bounds and executes trades
|
|
337
|
-
7. Results are reported back and stored
|
|
338
|
-
|
|
339
|
-
### TWAP Algorithm
|
|
340
|
-
|
|
341
|
-
When you create a TWAP order:
|
|
342
|
-
|
|
343
|
-
1. **Order Splitting**: Total amount divided into multiple lots
|
|
344
|
-
- ±15% size variation per lot to avoid patterns
|
|
345
|
-
- Example: 10 BTC / 20 lots → ~0.43-0.57 BTC per lot
|
|
346
|
-
|
|
347
|
-
2. **Time Distribution**: Executions spread across duration
|
|
348
|
-
- ±20% timing variance in execution intervals
|
|
349
|
-
- Example: 2-hour order → executions at 4.8min, 12.2min, 17.4min
|
|
350
|
-
|
|
351
|
-
3. **Price Validation**: Price bounds checked before each execution
|
|
352
|
-
- Real-time market price validation
|
|
353
|
-
- Order pauses if bounds are breached
|
|
354
|
-
|
|
355
|
-
4. **Execution Tracking**: Each lot execution is tracked individually
|
|
356
|
-
- Complete audit trail
|
|
357
|
-
- Status updates in real-time
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## Key Handling and Authentication
|
|
362
|
-
|
|
363
|
-
### Authentication Process
|
|
364
|
-
|
|
365
|
-
The `AuthenticatedTwapClient` handles all authentication automatically:
|
|
366
|
-
|
|
367
|
-
```python
|
|
368
|
-
client = AuthenticatedTwapClient(
|
|
369
|
-
base_url="https://scheduler.silhouette.com",
|
|
370
|
-
private_key="0x...",
|
|
371
|
-
)
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
**What happens during initialization:**
|
|
375
|
-
|
|
376
|
-
1. Health check - Verifies scheduler service is available
|
|
377
|
-
2. Registration check - Checks if your wallet is registered
|
|
378
|
-
3. Auto-registration - Registers your API key if needed
|
|
379
|
-
4. JWT generation - Creates authentication token
|
|
380
|
-
5. Ready to use - Client is immediately available
|
|
381
|
-
|
|
382
|
-
**Automatic token refresh:**
|
|
383
|
-
- If a request receives 401 (Unauthorized), the client automatically refreshes the token
|
|
384
|
-
- The failed request is automatically retried
|
|
385
|
-
- All happens transparently
|
|
386
|
-
|
|
387
|
-
### Security Architecture
|
|
388
|
-
|
|
389
|
-
**Key Components:**
|
|
390
|
-
|
|
391
|
-
1. **Hyperliquid API Key**
|
|
392
|
-
- Used for authentication and trade execution
|
|
393
|
-
- Must be registered as an "agent" for your wallet
|
|
394
|
-
- Cannot withdraw funds
|
|
395
|
-
- Sent over the wire only once during registration
|
|
396
|
-
- Encrypted at rest in storage
|
|
397
|
-
- Only decrypted at lot execution time by the executor service
|
|
398
|
-
|
|
399
|
-
2. **JWT Tokens**
|
|
400
|
-
- Client-signed using your Hyperliquid API key
|
|
401
|
-
- Algorithm: ES256K (ECDSA with secp256k1)
|
|
402
|
-
- Short-lived (1 hour max)
|
|
403
|
-
- Automatically refreshed
|
|
404
|
-
|
|
405
|
-
### Key Rotation
|
|
406
|
-
|
|
407
|
-
To rotate your API key, simply create a new client instance:
|
|
408
|
-
|
|
409
|
-
```python
|
|
410
|
-
client = AuthenticatedTwapClient(
|
|
411
|
-
base_url="https://scheduler.silhouette.com",
|
|
412
|
-
private_key="0x...", # Your Ethereum private key
|
|
413
|
-
)
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
The client automatically detects registration and updates your key.
|
|
417
|
-
|
|
418
|
-
### Security Best Practices
|
|
419
|
-
|
|
420
|
-
1. **Keep API Keys Secure**
|
|
421
|
-
- Store in environment variables or secrets manager
|
|
422
|
-
- Never commit to version control
|
|
423
|
-
- Use different keys for testnet and mainnet
|
|
424
|
-
|
|
425
|
-
2. **Key Permissions**
|
|
426
|
-
- Silhouette only uses your API key for signing trades
|
|
427
|
-
- Cannot withdraw funds or access other operations
|
|
428
|
-
- Revoke immediately if compromised
|
|
429
|
-
|
|
430
|
-
3. **System Protections**
|
|
431
|
-
- Anti-enumeration protection prevents key discovery
|
|
432
|
-
- Constant-time validation operations
|
|
433
|
-
- Generic error messages for security
|
|
434
|
-
|
|
435
|
-
---
|
|
436
|
-
|
|
437
|
-
## Additional Resources
|
|
438
|
-
|
|
439
|
-
You can interact with the scheduler server directly via API. The OpenAPI-compliant API documentation and architecture breakdown can be found at:
|
|
440
|
-
|
|
441
|
-
**https://silhouette-scheduler.fly.dev**
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
*Last Updated: 2025*
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/api/generated/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/exchange.py
RENAMED
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/error.py
RENAMED
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/signing.py
RENAMED
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/hyperliquid/utils/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/authenticated_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{silhouette_python_sdk-0.3.0 → silhouette_python_sdk-0.3.2}/silhouette/twap/generated/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|