# Python SDK

Python SDK: <https://pypi.org/project/gfx-perp-sdk/>\
\
This SDK contains 3 classes to interact with the GooseFX on-chain perpetual futures.

* `Perp`
* `Product`
* `Trader`

### Perp

The `Perp` class is required to initialize the connection and wallet that is going to be used for subsequent interaction.&#x20;

**Constructor**

{% code overflow="wrap" %}

```python
perp = Perp(connection, network_type, wallet, mpg=None, mpgBytes=None)
```

{% endcode %}

| Parameters                           | Description                                                                                                 |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `connection` (Client)                | An instance of the `Client` class from `solana.rpc.api` to communicate with the Solana blockchain.          |
| `network_type` (NETWORK\_TYPE)       | An enum value indicating the network type (either `NETWORK_TYPE.mainnet` or `NETWORK_TYPE.devnet`).         |
| `wallet` (Keypair)                   | An instance of the `Keypair` class representing the user's wallet.                                          |
| `mpg` (MarketProductGroup, optional) | Optional. An instance of the `MarketProductGroup` class for initializing the market product group directly. |
| `mpgBytes` (bytes, optional)         | Optional. Raw bytes data for the market product group.                                                      |

**Methods**

**init()**

Initializes the Perp instance by setting up the market product group and related data.

```python
perp.init()
```

Returns: `None` (Can raise exceptions for error handling)

**place\_order(product, order\_type, trade\_side, size, price)**

Places an order in the perpetual market.

{% code overflow="wrap" %}

```python
perp.place_order(product, order_type, trade_side, size, price)
```

{% endcode %}

| Parameters               | Description                                                      |
| ------------------------ | ---------------------------------------------------------------- |
| `product` (Product)      | The product instance for which the order is being placed.        |
| `order_type` (OrderType) | The type of order (e.g., `OrderType.limit`, `OrderType.market`). |
| `trade_side` (TradeSide) | The side of the trade (`TradeSide.buy` or `TradeSide.sell`).     |
| `size` (int)             | The size of the order.                                           |
| `price` (float)          | The price at which the order is to be executed.                  |

Returns: `None` (Implementation-dependent, can return order details or raise exceptions)

| Properties           | Description                                                                        |
| -------------------- | ---------------------------------------------------------------------------------- |
| `marketProductGroup` | A `MarketProductGroup` instance containing market product group details.           |
| `mpgBytes`           | Raw bytes data representing the market product group.                              |
| `connection`         | The `Client` instance for Solana network communication.                            |
| `wallet`             | The `Keypair` instance representing the user's wallet.                             |
| `networkType`        | The network type (`NETWORK_TYPE.mainnet` or `NETWORK_TYPE.devnet`).                |
| `ADDRESSES`          | A `ConstantIDs` instance containing various constant IDs for the perpetual market. |

Initializing the `Perp` class should be the first step irrespective of the type of operation in the following manner:

```python
perp = Perp(rpc_client, 'devnet', wallet)
perp.init()
```

### Product

An instance of the `product` class signifies one of the perp product we offer to trade.&#x20;

**Constructor**

{% code overflow="wrap" %}

```python
product = Product(name, PRODUCT_ID, ORDERBOOK_ID, BIDS, ASKS, EVENT_QUEUE, tick_size, decimals)
```

{% endcode %}

| Parameters                 | Description                                                                                  |
| -------------------------- | -------------------------------------------------------------------------------------------- |
| `name` (str)               | A string representing the name of the product.                                               |
| `PRODUCT_ID` (PublicKey)   | An instance of the `PublicKey` class representing the unique identifier for the product.     |
| `ORDERBOOK_ID` (PublicKey) | An instance of the `PublicKey` class representing the order book identifier for the product. |
| `BIDS` (PublicKey)         | An instance of the `PublicKey` class representing the bids in the order book.                |
| `ASKS` (PublicKey)         | An instance of the `PublicKey` class representing the asks in the order book.                |
| `EVENT_QUEUE` (PublicKey)  | An instance of the `PublicKey` class representing the event queue for the product.           |
| `tick_size` (int)          | An integer specifying the minimum price movement of the product.                             |
| `decimals` (int)           | An integer indicating the decimal precision of the product prices.                           |

**Methods**

The Product class primarily serves as a data structure and does not contain specific methods for operations.

| Properties     | Description                                     |
| -------------- | ----------------------------------------------- |
| `name`         | The name of the product.                        |
| `PRODUCT_ID`   | The unique identifier for the product.          |
| `ORDERBOOK_ID` | The identifier for the product's order book.    |
| `BIDS`         | The `PublicKey` for bids in the order book.     |
| `ASKS`         | The `PublicKey` for asks in the order book.     |
| `EVENT_QUEUE`  | The `PublicKey` for the product's event queue.  |
| `tick_size`    | The minimum price movement for the product.     |
| `decimals`     | The decimal precision for the product's prices. |

Initialization of the `product` class can be done in one of two ways:

1. By index:

```python
perp = Perp(rpc_client, 'devnet', wallet)
perp.init()
product = Product(perp)
product.initByIndex(0)
```

2. By name:

```python
perp = Perp(rpc_client, 'devnet', wallet)
perp.init()
product = Product(perp)
product.initByName('SOL-PERP')
```

This `product` instance will be useful for the following functions:

* `GET L2 Orderbook`: Get the latest layer 2 orderbook

```python
orderbook = product.get_orderbook_L2()
```

* `GET L3 Orderbook`: Get the latest layer 3 orderbook. (Orders mapped to users)

```python
orderbook = product.get_orderbook_L3()
```

### Trader

The `Trader` class is required to get instructions to send transactions to the program. Each wallet must have a unique trader account initialized to be able to place orders and deposit funds. This account needs to be created once using the `create_trader_account_ixs` instruction. After it has been created once, for all subsequent interactions by the wallet, the `Trader` class needs to be initialized using the `init` function.

**Constructor**

{% code overflow="wrap" %}

```python
trader = Trader(connection, network_type, wallet, product, order_type, trade_side, size, price)
```

{% endcode %}

| Parameters                     | Description                                                                                              |
| ------------------------------ | -------------------------------------------------------------------------------------------------------- |
| `connection` (Client)          | An instance of the `Client` class from `solana.rpc.api`, used to communicate with the Solana blockchain. |
| `network_type` (NETWORK\_TYPE) | An enum value representing the network type (either `NETWORK_TYPE.mainnet` or `NETWORK_TYPE.devnet`).    |
| `wallet` (Keypair)             | An instance of the `Keypair` class from `solders.keypair`, representing the user's wallet.               |
| `product` (Product)            | An instance of the `Product` class, representing the trading product.                                    |
| `order_type` (OrderType)       | An enum value representing the type of order (e.g., `OrderType.limit`, `OrderType.market`).              |
| `trade_side` (TradeSide)       | An enum value representing the side of the trade (`TradeSide.buy` or `TradeSide.sell`).                  |
| `size` (int)                   | An integer specifying the size of the order.                                                             |
| `price` (float)                | A float specifying the price at which the order is to be executed.                                       |

**Methods**

**place\_order()**

Places an order in the market.

```python
trader.place_order()
```

Returns: Varies depending on implementation, typically order details or confirmation.

**cancel\_order(order\_id)**

```python
trader.cancel_order(order_id)
```

| Parameters       | Description                          |
| ---------------- | ------------------------------------ |
| `order_id` (str) | The ID of the order to be cancelled. |

Returns: Varies depending on implementation, typically cancellation confirmation.

**update\_order(order\_id, new\_size, new\_price)**

Updates an existing order.

```python
trader.update_order(order_id, new_size, new_price)
```

| Parameters          | Description                        |
| ------------------- | ---------------------------------- |
| `order_id` (str)    | The ID of the order to be updated. |
| `new_size` (int)    | The new size of the order.         |
| `new_price` (float) | The new price of the order.        |

Returns: aries depending on implementation, typically update confirmation.

| Properties              | Description                                                         |
| ----------------------- | ------------------------------------------------------------------- |
| `wallet`                | The user's `Keypair` wallet instance.                               |
| `connection`            | The `Client` instance for communication with the Solana network.    |
| `networkType` (Keypair) | The network type (`NETWORK_TYPE.mainnet` or `NETWORK_TYPE.devnet`). |
| `product`               | The `Product` instance for the trading operations.                  |
| `orderType`             | The type of order to be placed.                                     |
| `tradeSide`             | The side of the trade (buy or sell).                                |
| `size`                  | The size of the trade order.                                        |
| `price`                 | The price at which the trade order will be executed.                |

* To create a new `Trader` account on-chain:

```python
  perp = Perp(rpc_client, 'devnet', wallet)
  perp.init()
  trader = Trader(perp)
  [ixs, signers] = trader.create_trader_account_ixs()
```

where `ixs` is an array of required instructions and `signers` is an array of required wallet pairs for signature. The wallet must also sign the transaction along with the wallet pairs in the `signers` array

* Once the account is created successfully, the `Trader` instance must be initialized in the following way:

```
  perp = Perp(rpc_client, 'devnet', wallet)
  perp.init()
  trader = Trader(perp)
  trader.init()
```

### Fractional Datatype

The Fractional data type uses a simple formula to represent a fractional number based on its mantissa (m) and exponent (exp): `number = mantissa / (10 ^ exponent)`

### Trader Instructions

#### Deposit Funds

To start placing new orders, traders need to deposit some collateral. This instruction will transfer the required USDC from the wallet to the trader account which will be used as collateral to place new orders.

The only parameter to this function is the amount of USDC to be deposited.

```
  perp = Perp(rpc_client, 'devnet', wallet)
  perp.init()
  trader = Trader(perp) 
  trader.init()
  [ix, signers] = trader.deposit_funds_ix(Fractional.to_decimal(100))
```

#### Withdraw Funds

Similar to deposit funds, this function takes the amount of USDC to be withdrawn as the only parameter. This instruction will transfer funds from the trader account to the wallet address.

```
  perp = Perp(rpc_client, 'devnet', wallet)
  perp.init()
  trader = Trader(perp) 
  trader.init()
  [ix, signers] = await trader.withdraw_funds_ix(Fractional.to_decimal(100))
```

NOTE: The above two instructions do not need a `product` instance as a parameter since the market is cross-collateralized and the amount of USDC deposited can be used across products. The following two instructions to place a new order and cancel an order are specific to products and hence need a `product` instance as one of the parameters.

#### Trader's open orders for a product

To get all open orders for a `Trader` for a `product`:

```
  perp = Perp(rpc_client, 'devnet', wallet)
  perp.init()
  product = Product(perp)
  product.initByIndex(0)
  trader = Trader(perp) 
  trader.init()
  orderbookData = trader.getOpenOrders(product)
```

#### New Order

The New order instruction needs the following as parameters

* Quantity (Fractional) **Please note: 1 unit of the product is denoted by 1 \* 100000 units. So to buy 1 unit, the parameter to pass as quantity should be**

```
  Fractional.to_decimal(100000)
```

* Price (Fractional)
* Order side ('buy' or 'sell')
* Order Type ('limit', 'market', 'immediateOrCancel', 'postOnly')
* Product instance

```
  perp = Perp(rpc_client, 'devnet',wallet)
  perp.init()
  product = Product(perp)
  product.initByIndex(0)
  trader = Trader(perp) 
  trader.init()
  [ix, signers] = trader.new_order_ix(product, Fractional.to_decimal(50000), Fractional.to_decimal(35), 'ask', 'limit')
```

#### Cancel Order

The cancel order instruction needs the orderId in string format to cancel the order. Use `getOpenOrders()` to get open orders and its id's to pass as a parameter to cancel the order

```
  perp = Perp(rpc_client, 'devnet',wallet)
  perp.init()
  product = Product(perp)
  product.initByIndex(0)
  trader = Trader(perp) 
  trader.init()
  [ix, signers] = trader.cancel_order_ix(product, 269375752548498747818049433352371) # Get this order id from t.get_open_orders()
```

#### Get All Trader Risk Group Accounts

`get_all_trg_accounts()` will fetch all the trader accounts in your wallet

#### Withdraw Funds for Trader Risk Group

`withdraw_funds_ix_for_trg()` will withdraw funds from specific trg(trader) account

#### Close Trader Risk Group

`close_trader_risk_group_ix_for_trg()` will close a specific trg(trader) account (ideally it can be done after withdrawing funds)

#### Get Cash Balance

`get_cash_balance()` will fetch available balances of the main trader account.

#### Get Cash Balance for Trader Risk Group

`get_cash_balance_for_trg()` will fetch available balance of specific trader account

#### Get Deposited Amount

`get_deposited_amount()` will fetch available deposited amounts

#### Get Withdrawn Amount

`get_withdrawn_amount()` will fetch available withdrawn amounts

#### Get Trader Positions by Product Index

`get_trader_positions_by_product_index()` will get all trader positions by product index

#### Get Trader Positions by Product Name

`get_trader_positions_by_product_name()` will get all trader positions by product name

#### Get Trader Positions by Trader Risk Group

`get_trader_positions_for_trg()` will get all trader positions for the Trader Risk Group

Checkout <https://github.com/GooseFX1/gfx-perps-python-sdk/blob/dev/test_perp.py> for examples on the above functionalities! Happy trading!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.goosefx.io/archived/perpetual-dex-sdks/python-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
