Metadata-Version: 2.1
Name: dexteritysdk
Version: 0.2.3
Summary: Client for Dexterity - a modular derivatives decentralized exchange reference implementation
Author: Joe Howarth
Author-email: josephehowarth@gmail.com
Requires-Python: >=3.9,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Requires-Dist: Jinja2 (>=3.0.3,<4.0.0)
Requires-Dist: MarkupSafe (>=2.0.1,<3.0.0)
Requires-Dist: OSlash (>=0.6.3,<0.7.0)
Requires-Dist: Pillow (>=9.0.1,<10.0.0)
Requires-Dist: PyNaCl (>=1.5.0,<2.0.0)
Requires-Dist: Pygments (>=2.11.2,<3.0.0)
Requires-Dist: QtPy (>=2.0.1,<3.0.0)
Requires-Dist: Send2Trash (>=1.8.0,<2.0.0)
Requires-Dist: aiodns (>=3.0.0,<4.0.0)
Requires-Dist: aiohttp (>=3.8.1,<4.0.0)
Requires-Dist: aiosignal (>=1.2.0,<2.0.0)
Requires-Dist: anyio (>=3.5.0,<4.0.0)
Requires-Dist: appnope (>=0.1.2,<0.2.0)
Requires-Dist: argon2-cffi (>=21.3.0,<22.0.0)
Requires-Dist: argparse (>=1.4.0,<2.0.0)
Requires-Dist: async-timeout (>=4.0.2,<5.0.0)
Requires-Dist: attrs (>=21.4.0,<22.0.0)
Requires-Dist: backcall (>=0.2.0,<0.3.0)
Requires-Dist: backoff (>=1.11.1,<2.0.0)
Requires-Dist: base58 (>=2.1.1,<3.0.0)
Requires-Dist: bleach (>=4.1.0,<5.0.0)
Requires-Dist: borsh-construct (>=0.1.0,<0.2.0)
Requires-Dist: certifi (>=2021.10.8,<2022.0.0)
Requires-Dist: cffi (>=1.15.0,<2.0.0)
Requires-Dist: charset-normalizer (>=2.0.12,<3.0.0)
Requires-Dist: construct (>=2.10.67,<3.0.0)
Requires-Dist: construct-typing (>=0.5.2,<0.6.0)
Requires-Dist: cryptography (>=36.0.1,<37.0.0)
Requires-Dist: cycler (>=0.11.0,<0.12.0)
Requires-Dist: debugpy (>=1.5.1,<2.0.0)
Requires-Dist: decorator (>=5.1.1,<6.0.0)
Requires-Dist: defusedxml (>=0.7.1,<0.8.0)
Requires-Dist: dnspython (>=2.2.0,<3.0.0)
Requires-Dist: entrypoints (>=0.4,<0.5)
Requires-Dist: flake8 (>=4.0.1,<5.0.0)
Requires-Dist: frozenlist (>=1.3.0,<2.0.0)
Requires-Dist: h11 (==0.12.0)
Requires-Dist: idna (>=3.3,<4.0)
Requires-Dist: ipykernel (>=6.9.0,<7.0.0)
Requires-Dist: ipython (>=8.0.1,<9.0.0)
Requires-Dist: ipython_genutils (>=0.2.0,<0.3.0)
Requires-Dist: ipywidgets (>=7.6.5,<8.0.0)
Requires-Dist: jedi (>=0.18.1,<0.19.0)
Requires-Dist: jsonrpcclient (>=4.0.2,<5.0.0)
Requires-Dist: jsonrpcserver (>=5.0.6,<6.0.0)
Requires-Dist: jsonschema (==3.2.0)
Requires-Dist: jupyter (>=1.0.0,<2.0.0)
Requires-Dist: jupyter-client (>=7.1.2,<8.0.0)
Requires-Dist: jupyter-console (>=6.4.0,<7.0.0)
Requires-Dist: jupyter-core (>=4.9.1,<5.0.0)
Requires-Dist: jupyterlab-pygments (>=0.1.2,<0.2.0)
Requires-Dist: jupyterlab-widgets (>=1.0.2,<2.0.0)
Requires-Dist: kiwisolver (>=1.3.2,<2.0.0)
Requires-Dist: loguru (>=0.6.0,<0.7.0)
Requires-Dist: matplotlib (>=3.5.1,<4.0.0)
Requires-Dist: matplotlib-inline (>=0.1.3,<0.2.0)
Requires-Dist: mccabe (==0.6.1)
Requires-Dist: mistune (==0.8.4)
Requires-Dist: multidict (>=6.0.2,<7.0.0)
Requires-Dist: nbclient (>=0.5.10,<0.6.0)
Requires-Dist: nbconvert (==6.2)
Requires-Dist: nbformat (>=5.1.3,<6.0.0)
Requires-Dist: nest-asyncio (>=1.5.4,<2.0.0)
Requires-Dist: notebook (>=6.4.8,<7.0.0)
Requires-Dist: numpy (>=1.22.2,<2.0.0)
Requires-Dist: packaging (>=21.3,<22.0)
Requires-Dist: pandas (>=1.4.1,<2.0.0)
Requires-Dist: pandocfilters (>=1.5.0,<2.0.0)
Requires-Dist: parso (>=0.8.3,<0.9.0)
Requires-Dist: pexpect (>=4.8.0,<5.0.0)
Requires-Dist: pickleshare (>=0.7.5,<0.8.0)
Requires-Dist: podite (==0.1.2)
Requires-Dist: prometheus-client (>=0.13.1,<0.14.0)
Requires-Dist: prompt-toolkit (>=3.0.28,<4.0.0)
Requires-Dist: ptyprocess (>=0.7.0,<0.8.0)
Requires-Dist: pycares (>=4.1.2,<5.0.0)
Requires-Dist: pycodestyle (>=2.8.0,<3.0.0)
Requires-Dist: pycparser (>=2.21,<3.0)
Requires-Dist: pyflakes (>=2.4.0,<3.0.0)
Requires-Dist: pyparsing (>=3.0.7,<4.0.0)
Requires-Dist: pyrsistent (>=0.18.1,<0.19.0)
Requires-Dist: pythclient (>=0.1.2,<0.2.0)
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
Requires-Dist: pytz (>=2022.1,<2023.0)
Requires-Dist: pyzmq (>=22.3.0,<23.0.0)
Requires-Dist: qtconsole (>=5.2.2,<6.0.0)
Requires-Dist: requests (>=2.27.1,<3.0.0)
Requires-Dist: rfc3986 (==1.5)
Requires-Dist: six (>=1.16.0,<2.0.0)
Requires-Dist: sniffio (>=1.2.0,<2.0.0)
Requires-Dist: solana (>=0.28.0,<0.29.0)
Requires-Dist: terminado (>=0.13.1,<0.14.0)
Requires-Dist: testpath (>=0.5.0,<0.6.0)
Requires-Dist: tornado (>=6.1,<7.0)
Requires-Dist: traitlets (>=5.1.1,<6.0.0)
Requires-Dist: types-cachetools (>=4.2.9,<5.0.0)
Requires-Dist: typing-extensions (==4.2.0)
Requires-Dist: urllib3 (>=1.26.8,<2.0.0)
Requires-Dist: wcwidth (>=0.2.5,<0.3.0)
Requires-Dist: webencodings (>=0.5.1,<0.6.0)
Requires-Dist: websockets (>=10.1,<11.0)
Requires-Dist: widgetsnbextension (>=3.5.2,<4.0.0)
Requires-Dist: yarl (>=1.7.2,<2.0.0)
Description-Content-Type: text/markdown

# Dexterity client SDK
**Dexterity** is a derivatives decentralized exchange running on Solana.
This package provides the basic blocks in order to integrate and trade on Dexterity.

You can learn more about Dexterity [here](https://docs.hxro.network/market-protocols/derivatives-protocol/dexterity).

## Prerequisites
* [Solana.py](https://pypi.org/project/solana/)

## Creating the client
First, an instance of a Solana client is required.
```python
from dexteritysdk.dex.sdk_context import SDKContext, SDKTrader
from solana.rpc.api import Client
from solana.keypair import Keypair
from solana.publickey import PublicKey

def main():
	# use "https://api.mainnet-beta.solana.com" for mainnet
	network = "https://api.devnet.solana.com"
	client = Client(network)
```

A Keypair for the payer has to also be provided.
```python
keypair = Keypair.from_secret_key(keypair_bytes)
```
The SDK also requires the **Market Product Group (MPG)** that we're going to trade on.

The public key of the default MPG is **`HiCy6vzuN3yLXD3z35D6nV7bzNLcyrvGLf3uSKuutSLo`** for mainnet or **`HyWxreWnng9ZBDPYpuYugAfpCMkRkJ1oz93oyoybDFLB`** for devnet.
```python
# mainnet MPG
mpg = PublicKey("HiCy6vzuN3yLXD3z35D6nV7bzNLcyrvGLf3uSKuutSLo")

# ** OR **
# devnet MPG
mpg = PublicKey("HyWxreWnng9ZBDPYpuYugAfpCMkRkJ1oz93oyoybDFLB")
```
Now, we're ready to get an instance of `SDKContext` for this MPG.
```python
ctx = SDKContext.connect(
	client=client,
	market_product_group_key=mpg,
	payer=keypair,
	raise_on_error=True
)
```

## Registering new trader / TRG
If you're a new trader, creation of a trading account is required.
```python
trader = ctx.register_trader(keypair)
trg_key = trader.account
```

The **Trader Risk Group (TRG)** is your trading account, that you can now use.

## Using an existing TRG
If you already have a trader set up, you need to provide the TRG public key for it.
The SDK allows you to list all your registered TRGs.
```python
# this will return a list of your all your TRG public keys
# for example: [HeykeQWRh6DC2Tz5X3WBuWdMHicyECDEFGMjomV6LBye, HeyZNJ9gQVAEqHeCFFQ781E53d66DATKXHeynwnCFBye]
trg_keys = ctx.list_trader_risk_groups()
```

After finding your TRG, you can initialise the `SDKTrader` instance.
```python
from dexteritysdk.codegen.dex.types import TraderRiskGroup
from dexteritysdk.program_ids import *
from dexteritysdk.utils.solana import explore

# ...
trader = SDKTrader.connect(ctx, trg_pubkey, keypair)
```

## Funding the TRG
To start trading, you need to deposit funds.
The tokens deposited have to be MPG vault mint tokens (e.g. USDC).
The wallet you provided will be debited.
```python
# this will deposit 733.1 USDC
trader.deposit(ctx, 733.1)
```

You can also withdraw in a similar fashion.
```python
# this will withdraw 0.1 USDC back to your wallet
trader.withdraw(ctx, 0.1)
```

You can check your balance at any time.
```python
trader.get_trader_risk_group().cash_balance
```

## Trading on Dexterity

### Listing trading products and order books
The `products` field of a `SDKContext` instance, is a list of the available trading products (`SDKProduct`).
Every `SDKProduct` has a `name` and a `get_orderbook(ctx)` function that will return its order book (`SDKOrderBook`).
The `SDKOrderBook` contains all `SDKOrders` on each side of the book.

Here's an example:
```python
for product in ctx.products:
	book = product.get_orderbook(ctx, refresh=True)
	print(f"Printing the order book of {product.name}")
	for order in book.bids:
		print(f"Bid of size {order.qty} at {order.price}")
	for order in book.asks:
		print(f"Ask of size {order.qty} at {order.price}")
```

### Placing an order

Placing an order is straightforward.
```python
from dexteritysdk.utils.aob import Side
# ...
order_summary = trader.place_order(ctx, product, Side.ASK, size, price)
```
The returned `SDKOrderSummary` contains the `order_id` of the new order, as well as the `remaining_qty` and `filled_qty` if your order has been filled. If the order is immediately fully filled, `order_id` will be `None`.

If there's any error, an exception will be raised.

### Cancelling orders
To cancel a previous order you can call `trader.cancel(ctx, product, order_id)`.
Following the previous example:
```python
trader.cancel(ctx, product, order_summary.order_id)
```

You can also cancel all your open orders for multiple products.
```python
# products is a list of SDKProduct
# if products list is empty or None, then all your open orders will be cancelled
products = [ctx.products[0], ctx.products[2]]
trader.cancel_all_orders(ctx, products)
```
If any cancel fails, an exception will be raised.

### Positions
Positions can also be listed, by iterating the `trader_positions` array:
```python
trader.get_trader_risk_group().trader_positions
```

