-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5d482e6
Showing
83 changed files
with
10,107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Sphinx build info version 1 | ||
# This file records the configuration used when building these files. When it is not found, a full rebuild will be done. | ||
config: 2ac667eb7d02dbdc96f2f0377386981f | ||
tags: 645f666f9bcd5a90fca523b33c5a78b7 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
# Advanced Perps Trading | ||
|
||
## Introduction | ||
|
||
This guide will help you understand more advanced concepts related to trading Synthetix Perps using the `synthetix` library. Check the sidebar for the various topics covered in this guide. If you're just getting started, it is recommended to read the [Trade Perps](trade_perps.md) guide first. | ||
|
||
## Managing Multiple Accounts | ||
|
||
Synthetix V3 allows you to hold multiple accounts which each maintain their own balances and positions. Since all positions inside an account use the same collateral, it can be useful to manage multiple accounts to separate different trading strategies or risk profiles. A trader can even simulate "isolated margin" by using separate accounts for each position. | ||
|
||
Your accounts are stored in the `account_ids` attribute, and can be refreshed using `get_accounts()`. | ||
```python | ||
# view all accounts | ||
print(snx.perps.account_ids) | ||
|
||
# refresh accounts | ||
snx.perps.get_accounts() | ||
|
||
# create an account | ||
snx.perps.create_account(submit=True) | ||
``` | ||
|
||
The default account is set at `snx.perps.default_account_id`. If no account is specified during some function calls, the default account will be used. | ||
```python | ||
>>> print(snx.perps.account_ids) | ||
[1, 2] | ||
|
||
>>> print(snx.perps.default_account_id) | ||
1 | ||
|
||
>>> snx.perps.get_margin_info() # this will use account 1 | ||
>>> snx.perps.get_margin_info(account_id=2) # this will use account 2 | ||
``` | ||
|
||
To replicate isolated margin, you can use separate accounts for each position. This way, the margin and pnl of each position are isolated from each other. In this example, we will deposit 500 snxUSD to account 1 and 2, and open a position on different markets using different accounts. If one position fails to meet the margin requirements and gets liquidated, the other position will not be affected. | ||
```python | ||
snx.perps.modify_collateral(500, account_id=1, submit=True) | ||
snx.perps.modify_collateral(500, account_id=2, submit=True) | ||
|
||
snx.perps.commit_order(1, market_name="ETH", account_id=1, submit=True) | ||
snx.perps.commit_order(0.1, market_name="BTC", account_id=2, submit=True) | ||
``` | ||
|
||
## Fetching Order Quotes | ||
|
||
Synthetix perps using a vAMM model, where orders are subject to price impact based on the size of the order. A premium or discount is applied to the index price based on the current skew of the market. For example, if a market is skewed long, there will be a premium applied to the index price, and vice versa. | ||
|
||
When placing an order, you can fetch a quote to see the estimated fill price of the order. This fill price is an estimate based on the current index price, current skew, and the size of the order. The quote will also show exchange and settlement fees, and the estimated margin required for a position of that size. | ||
```python | ||
>>> snx.perps.get_quote(1, market_name="ETH") | ||
{ | ||
'order_size': 1, | ||
'index_price': 2995.72, | ||
'fill_price': 2995.75, | ||
'required_margin': 116.49, | ||
'order_fees': 0.11649, | ||
'settlement_reward_cost': 1.00137346 | ||
} | ||
``` | ||
|
||
## Liquidations | ||
|
||
Liquidations occur when an account fails to meet the margin requirements given the size of their positions. When an account is liquidated, their positions are all closed and their collateral is lost. Liquidations will usually be triggered by keepers who are incentivized to liquidate accounts that fall below the maintenance margin requirement. You can check your margin balance and requirements using `get_margin_info()`. | ||
```python | ||
>>> snx.perps.get_margin_info() | ||
{ | ||
'total_collateral_value': 98.38, | ||
'available_margin': 98.39, | ||
'withdrawable_margin': 12.804, | ||
'initial_margin_requirement': 85.59, | ||
'maintenance_margin_requirement': 64.02, | ||
'max_liquidation_reward': 5.634 | ||
} | ||
``` | ||
|
||
If your `available_margin` falls below the `maintenance_margin_requirement`, your account is at risk of liquidation. You can also check the status of an account using `can_liquidate` and `can_liquidates`. | ||
```python | ||
>>> snx.perps.can_liquidate(1) | ||
False | ||
|
||
>>> snx.perps.can_liquidates([1, 2]) | ||
[(1, False), (2, False)] | ||
``` | ||
|
||
## Order Settlement | ||
|
||
Orders are usually settled onchain by a keeper, but you can also ensure your orders are settled by calling `settle_order`. This will check your order and settle it if it is ready to be settled. This function checks the order status before submission, so if an order has been settled by someone else, it will log this and not attempt to settle the order. | ||
|
||
```python | ||
>>> snx.perps.settle_order() # settle order for the default account | ||
INFO synthetix.synthetix:perps.py:1038 Waiting 0.3958 seconds to settle order | ||
INFO synthetix.synthetix:pyth.py:99 Fetching Pyth data for 1 markets | ||
INFO synthetix.synthetix:perps.py:1064 Settling order for account 1701411834604692328273631687329873105994 | ||
INFO synthetix.synthetix:perps.py:1065 settle tx: 0xB9153dbd4160f48f3259d0567fd75508afe8fcaa53ff328313a9654f10182742 | ||
INFO synthetix.synthetix:perps.py:1073 Order settlement successful for account 1701411834604692328273631687329873105994 | ||
|
||
>>> snx.perps.settle_order() # keeper settles order | ||
INFO synthetix.synthetix:perps.py:1038 Order is ready to be settled | ||
INFO synthetix.synthetix:pyth.py:99 Fetching Pyth data for 1 markets | ||
INFO synthetix.synthetix:perps.py:1064 Settling order for account 1701411834604692328273631687329873105994 | ||
INFO synthetix.synthetix:perps.py:1073 Keeper settled ETH order committed by 1701411834604692328273631687329873105994 | ||
|
||
>>> snx.perps.settle_order(max_tx_tries=10, tx_delay=5) # increase retries and delay | ||
``` | ||
|
||
Keep in mind the following: | ||
- In some cases a decentralized keeper will submit their transaction in the same block as you. If this happens, your transaction will fail but your order will be settled. | ||
- You may see some `ERROR` logs during order settlement. Since the order requires data from an offchain provider, sometimes this data is not available in time for the transaction to be submitted. This is normal and the order will be retried. You can use the `max_tx_tries` and `tx_delay` parameters to increase the number of retries and delay between retries. | ||
- Orders expire after a specified duration. The function will throw an error if an order is part the expiration, or if the order has already been settled. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Advanced Usage | ||
|
||
## Introduction | ||
|
||
This guide will help you understand more advanced concepts for interacting with Synthetix V3 using the `synthetix` library. Check the sidebar for the various topics covered in this guide. If you're just getting started, it is recommended to read the [quickstart](quickstart.md) guide first. | ||
|
||
## Contracts | ||
|
||
The `synthetix` library provides functions with more simple inputs for interacting with Synthetix V3 contracts. However, you can also interact with the contracts directly using the `web3.py` library. This can be useful for more advanced use cases, debugging, or to access functions that haven't been implemented in a module yet. | ||
|
||
The `contracts` module stores contract addresses and ABIs: | ||
```python | ||
# look up the PerpsMarketProxy contract | ||
>>> snx.contracts['PerpsMarketProxy'] | ||
{ | ||
'address': '0xf53Ca60F031FAf0E347D44FbaA4870da68250c8d', | ||
'abi': {...}, | ||
'contract': <web3 contract object> | ||
} | ||
|
||
# call a function on the contract | ||
>>> perps_market_proxy = snx.contracts['PerpsMarketProxy']['contract'] | ||
>>> perps_market_proxy.functions.getMarkets().call() | ||
(100, 200, ...) | ||
``` | ||
|
||
## Fetching Cannon Deployments | ||
|
||
Synthetix manages smart contract deployments using [Cannon](https://usecannon.com/). During the deployment process, new contract ABIs and addresses will be published to Cannon, however the "hard-coded" versions in the `synthetix` library will not be updated. Note that the `synthetix` library only includes the most commonly used contracts. For other contracts, fetch the addresses and ABIs from Cannon. This can be done during initialization by providing a `cannon_config`: | ||
```python | ||
>>> snx = Synthetix( | ||
provider_url=provider_url, | ||
cannon_config={ | ||
'package': 'synthetix-omnibus', | ||
'version': '12', | ||
'preset': 'andromeda' | ||
}) | ||
``` | ||
|
||
This will connect to the Cannon registry onchain and IPFS to fetch the contracts for the specified package, version, and preset. You can then access the contracts for all imported packages using the `contracts` attribute: | ||
```python | ||
>>> snx.contracts["packages"].keys() | ||
dict_keys(['perps_gas_oracle_node', 'pyth_erc7412_wrapper', 'system', ...]) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Oracle Data | ||
|
||
Synthetix V3 uses pull oracles from [Pyth](https://pyth.network/) to fetch the latest prices for assets using the [ERC-7412](https://erc7412.vercel.app/) pattern. The SDK helps handle the process of fetching the required price data for you, however this guide will help understand how the process works. | ||
|
||
## ERC-7412 Overview | ||
|
||
ERC-7412 is a standard that defines how a smart contract can prompt the user to fetch some offchain data and provide it in their transaction. The flow looks like this: | ||
1. The user calls a function on the smart contract (e.g. `getMarketSummary`) | ||
1. The call fails, providing the user with information about what data they need to provide | ||
1. The user fetches the data from an offchain source and creates a multicall transaction: `[fullfillOracleQuery, getMarketSummary]` | ||
1. The call succeeds after updating the oracle data, then calling the smart contract function again | ||
|
||
## ERC-7412 in Synthetix | ||
|
||
Synthetix V3 uses the ERC-7412 pattern to ensure that transactions only succeed when the contracts have access to price data within a certain tolerance. For example, some view functions require that prices are under 60 minutes old, otherwise they are considered stale. For more critical operations like order settlement on the perps markets, the contracts may require a price for a specific timestamp. | ||
|
||
For the best user experience, it is recommended that users fetch this data "optimistically" before calling a smart contract function. This will ensure that the transaction uses the most recent data and avoids running into reverts during transaction simulation. | ||
|
||
## SDK Integration | ||
|
||
The `synthetix` library will handle this logic for you, including optimistic fetching of oracle data. When you call a function that is expected to require some oracle data, the SDK will automatically fetch the required data and include it in a multicall. If the contract requires additional oracle data, the ERC-7412 pattern will be used to fetch the data and prepare a transaction. | ||
|
||
To better understand this process, we can look at the `snx.perps.get_market_summaries()` function. This function will fetch information about all of the available perps markets, including the open interest, funding rate, price, skew, and more. The function will optimistically fetch prices for all markets before requesting the market summary. You can see this in action by calling the function and inspecting the logs. | ||
|
||
```python | ||
>>> _, markets_by_name = snx.perps.get_markets() | ||
2024-05-01 15:55:10,714 - INFO - Fetching Pyth data for 32 markets | ||
|
||
>>> print(markets_by_name) | ||
{ | ||
'ETH': { | ||
'market_id': 100, | ||
'feed_id': '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', | ||
... | ||
}, | ||
'BTC': { | ||
... | ||
}, | ||
} | ||
``` | ||
|
||
As you can see from the logs, the SDK fetched prices for all available markets from a Pyth node before requesting the market summaries. | ||
|
||
## Caching Oracle Data | ||
|
||
For situations that require fresh prices but not a specific timestamp, the SDK will cache price data and reuse it for subsequent calls. This is useful for reducing the number of calls made to Pyth nodes. There is a "time to live" setting that determines how long the data is cached before it is considered stale. If you want to always fetch fresh data, you can set the `pyth_cache_ttl` setting to `0`. Otherwise, it represents the number of seconds that the data is considered fresh. | ||
|
||
```python | ||
>>> snx = Synthetix( | ||
provider_url=provider_url, | ||
pyth_cache_ttl=0, # Always fetch fresh data | ||
) | ||
|
||
>>> snx = Synthetix( | ||
provider_url=provider_url, | ||
pyth_cache_ttl=5, # Cache price data for 5 seconds | ||
) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Quickstart | ||
|
||
This library offers a way to interact with the [Synthetix](https://synthetix.io/) protocol using Python. This guide will teach you the basics: how to set up the client and use some of its functions. | ||
|
||
If your use case requires a more in-depth understanding of the protocol, please refer to the [Synthetix documentation](https://docs.synthetix.io/). | ||
|
||
## Requirements | ||
|
||
This library requires Python 3.8 or higher. It makes heavy use of the [web3.py](https://github.com/ethereum/web3.py) library for interacting with smart contracts. | ||
|
||
It is recommended to use a virtual environment to install the library and its dependencies. Use [venv](https://docs.python.org/3/library/venv.html) to create and manage this virtual environment: | ||
|
||
```bash | ||
python3 -m venv env | ||
source env/bin/activate | ||
|
||
# optionally upgrade pip | ||
pip install --upgrade pip | ||
``` | ||
|
||
## Installation | ||
|
||
The library is available from the PyPI package repository and can be installed using `pip`: | ||
|
||
```bash | ||
pip install synthetix | ||
``` | ||
|
||
## Initializing the client | ||
|
||
To use the library, initialize the `Synthetix` object that can be used to interact with the protocol. At minimum, you must provide an RPC endpoint. | ||
|
||
```python | ||
from synthetix import Synthetix | ||
|
||
# Base Mainnet | ||
snx = Synthetix( | ||
provider_url="https://base.llamarpc.com", | ||
) | ||
``` | ||
|
||
This creates an `snx` object that helps you interact with the protocol smart contracts. At minimum you need to provide the `provider_url` parameter, which is the RPC endpoint of the node you want to connect to. If there are any warnings or errors during initialization, they are logged to the console. | ||
|
||
## Basic usage | ||
|
||
Once set up, you can use the `snx` object to interact with the different modules in the protocol. Here are some common functions you may want to use: | ||
|
||
```python | ||
# basic functions | ||
snx.get_susd_balance() # fetch the balance of sUSD | ||
snx.get_eth_balance() # fetch the balance of ETH and WETH | ||
|
||
# perps markets | ||
snx.perps.get_markets() # fetch all perps market summaries | ||
snx.perps.get_account_ids() # fetch all perps accounts for the specified address | ||
snx.perps.get_margin_info(1) # get the margin balances for account_id 1 | ||
``` | ||
|
||
Let's see how to use the get_markets function with a sample output: | ||
```python | ||
>>> markets_by_id, markets_by_name = snx.perps.get_markets() | ||
>>> markets_by_name | ||
{ | ||
'ETH': { | ||
'market_id': 100, | ||
'market_name': 'ETH', | ||
'skew': -3308.71, | ||
'size': 14786.42 | ||
'max_open_interest': 100000, | ||
'current_funding_rate': 0.00196 | ||
'current_funding_velocity': -0.02977 | ||
'index_price': 1560.37 | ||
}, | ||
'BTC': { | ||
... | ||
}, | ||
... | ||
} | ||
``` |
Oops, something went wrong.