NAV
Python Golang

Change Log

2024-03-08

2024-01-25

2024-01-02

2023-09-06

2023-08-28

Introduction

Welcome to Injective's documentation!

Here you can find a comprehensive overview of our protocol, as well as tutorials, guides and general resources for developers and API traders.

If you would like to ask any questions or be a part of our community, please join our Discord Group or Telegram Group. We have a dedicated channel in our Discord group for questions related to the API.

Clients

Python Client

Dependencies

Ubuntu

sudo apt install python3.X-dev autoconf automake build-essential libffi-dev libtool pkg-config

Fedora

sudo dnf install python3-devel autoconf automake gcc gcc-c++ libffi-devel libtool make pkgconfig

macOS

brew install autoconf automake libtool

Installation

Install injective-py from PyPI using pip.

pip install injective-py

Reference

InjectiveLabs/sdk-python

Markets and Tokens information

Example - Traditional Composer instantiation

from pyinjective.composer import Composer
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network


network = Network.testnet()
composer = Composer(network=network.string())

Python SDK traditionally relied on local configuration files to get the list of available markets and tokens in each network (mainnet, testnet and devnet).

Since version 0.8 the SDK is able also to get the markets and tokens information directly from the chain data (through the Indexer process). The benefit of this approach is that it is not necessary to update the SDK version when a new market is created in the chain or a new token is added.



Example - Get the composer instance through the AsyncClient

from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.async_client import AsyncClient
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network


network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()

By default the AsyncClient and the Composer will only initialize the tokens that are part of an active market. In order to let them use any of the tokens available in the chain, the user has to execute the initialize_tokens_from_chain_denoms in the AsyncClient before the creation of the Composer.

Example - Initialize with all tokens from the chain

from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.async_client import AsyncClient
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network


network = Network.testnet()
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()

Golang Client

1. Create your own client repo and go.mod file

go mod init foo

2. Import SDK into go.mod

module foo

go 1.18

require ( github.com/InjectiveLabs/sdk-go v1.39.4 )

Consult the sdk-go repository to find the latest release and replace the version in your go.mod file. Version v1.39.4 is only an example and must be replaced with the newest release

3. Download the package

Download the package using go mod download

go mod download github.com/InjectiveLabs/sdk-go

Markets and Tokens information

Example - Traditional ChainClient instantiation

package main

import (
    "fmt"
    "github.com/InjectiveLabs/sdk-go/client"
    "os"

    "github.com/InjectiveLabs/sdk-go/client/common"

    chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
    rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
    if err != nil {
        panic(err)
    }

    senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
        os.Getenv("HOME")+"/.injectived",
        "injectived",
        "file",
        "inj-user",
        "12345678",
        "5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
        false,
    )

    if err != nil {
        panic(err)
    }

    // initialize grpc client
    clientCtx, err := chainclient.NewClientContext(
        network.ChainId,
        senderAddress.String(),
        cosmosKeyring,
    )
    if err != nil {
        fmt.Println(err)
    }
    clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)

    chainClient, err := chainclient.NewChainClient(
        clientCtx,
        network,
        common.OptionGasPrices(client.DefaultGasPriceWithDenom),
    )

    if err != nil {
        fmt.Println(err)
    }

}

Go SDK traditionally relied on local configuration files to get the list of available markets and tokens in each network (mainnet, testnet and devnet).

Since version 1.49 the SDK is able also to get the markets and tokens information directly from the chain data (through the Indexer process). The benefit of this approach is that it is not necessary to update the SDK version when a new market is created in the chain or a new token is added.













































Example - Get markets and tokens from Indexer (ExchangeClient)

package main

import (
    "context"
    "github.com/InjectiveLabs/sdk-go/client"
    "github.com/InjectiveLabs/sdk-go/client/core"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    "os"

    "github.com/InjectiveLabs/sdk-go/client/common"

    chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
    rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
    if err != nil {
        panic(err)
    }

    senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
        os.Getenv("HOME")+"/.injectived",
        "injectived",
        "file",
        "inj-user",
        "12345678",
        "5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
        false,
    )

    if err != nil {
        panic(err)
    }

    // initialize grpc client
    clientCtx, err := chainclient.NewClientContext(
        network.ChainId,
        senderAddress.String(),
        cosmosKeyring,
    )
    if err != nil {
        panic(err)
    }
    clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)

    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketsAssistant, err := core.NewMarketsAssistantUsingExchangeClient(ctx, exchangeClient)
    if err != nil {
        panic(err)
    }
}




















































Example - MarketsAssistant with all tokens

package main

import (
    "context"
    "github.com/InjectiveLabs/sdk-go/client"
    "github.com/InjectiveLabs/sdk-go/client/core"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    "os"

    "github.com/InjectiveLabs/sdk-go/client/common"

    chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
    rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
    if err != nil {
        panic(err)
    }

    senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
        os.Getenv("HOME")+"/.injectived",
        "injectived",
        "file",
        "inj-user",
        "12345678",
        "5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
        false,
    )

    if err != nil {
        panic(err)
    }

    // initialize grpc client
    clientCtx, err := chainclient.NewClientContext(
        network.ChainId,
        senderAddress.String(),
        cosmosKeyring,
    )
    if err != nil {
        panic(err)
    }
    clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)

    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    chainClient, err := chainclient.NewChainClient(
        clientCtx,
        network,
        common.OptionGasPrices(client.DefaultGasPriceWithDenom),
    )

    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketsAssistant, err := core.NewMarketsAssistantWithAllTokens(ctx, exchangeClient, chainClient)
    if err != nil {
        panic(err)
    }
}

By default the MarketsAssistant will only initialize the tokens that are part of an active market. In order to let it use any of the tokens available in the chain, the user has to create the MarketsAssistant instance using the function NewMarketsAssistantWithAllTokens.

The MarketsAssistant instance can be used with the following ChainClient functions:

Reference

InjectiveLabs/sdk-go.

Typescript Client

Installation

Install the @injectivelabs/sdk-ts npm package using yarn

yarn add @injectivelabs/sdk-ts

Reference

To see Typescript examples please check the Typescript SDK documentation page listed above

For other languages

Currently Injective provides SDKs only for Go, Python and TypeScript. To interact with the nodes using a different language please connect directly using the gRPC proto objects. The compiled proto files for C++, C# and Rust can be found in InjectiveLabs/injective-proto

Overview

Injective is a DeFi focused layer-1 blockchain built for the next generation of decentralized derivatives exchanges. The Injective Chain is a Tendermint-based IBC-compatible blockchain which supports a decentralized orderbook-based DEX protocol and a trustless ERC-20 token bridge to the Ethereum blockchain.

It is the first decentralized exchange focused layer-1 blockchain for perpetual swaps, futures, and spot trading that unlocks the full potential of decentralized derivatives and borderless DeFi. Every component of the protocol has been built to be fully trustless, censorship-resistant, publicly verifiable, and front-running resistant.

By providing the unrestricted and unprecedented ability to express diverse views in decentralized financial markets, we strive to empower individuals with the ability to more efficiently allocate capital in our society.

Architecture Overview

Injective enables traders to create and trade on arbitrary spot and derivative markets. The entire process includes on-chain limit orderbook management, on-chain trade execution, on-chain order matching, on-chain transaction settlement, and on-chain trading incentive distribution through the logic codified by the Injective Chain's exchange module.

Architecturally there are two main services that traders should concern themselves with:

  1. The Injective Chain node (the Chain API)
  2. The Injective Exchange API

The trading lifecycle is as follows:

  1. First, traders cryptographically sign a transaction containing one or more order messages (e.g. MsgBatchCreateDerivativeLimitOrders, MsgCreateSpotMarketOrder, MsgCancelDerivativeLimitOrder, etc. ).
  2. Then the transaction is broadcasted to an Injective Chain node.
  3. The transaction is then added to the mempool and becomes included in a block. More details on this process can be found here.
  4. The handler for each respective message is run. During handler execution, order cancel and liquidation messages are processed immediately, whereas order creation messages are added to a queue.
  5. At the end of the block, the batch auction process for order matching begins.
    • First, the queued market orders are executed against the resting orderbook (which does NOT include the new orders from the current block) and are cleared at a uniform clearing price.
    • Second, the queued limit orders are matched against each other and the resting orderbook to result in an uncrossed orderbook. Limit orders created in that block are cleared at a uniform clearing price while resting limit orders created in previous blocks are cleared at an equal or better price than their limit order price.
  6. The funds are settled accordingly, with positions being created for derivative trades and assets being swapped for spot trades.
  7. Events containing the trade and settlement information are emitted by the Chain.
  8. The Injective Exchange API backend indexes the events and pushes updates to all subscribed traders.

Key Differences To CEX

To summarize the sequence of state changes on the Injective Chain:

  1. Mempool: A queue of pending transactions.
  2. BeginBlocker: Code that is executed at the beginning of every block. We use it for certain maintenance tasks (details can be found in the exchange module documentation).
  3. Handler: Code that is executed when a transaction is included in a block.
  4. EndBlocker: Code that is executed at the end of every block. We use it to match orders, calculate changes in funds, and update positions.

Comparison to CEX

Centralized Exchange (CEX) Decentralized Exchange (DEX)
Exchange Gateway Injective Chain Handler
Exchange Matching Engine Injective Chain EndBlocker
Exchange Trade Report Injective Chain EndBlocker
Co-location Injective Node (Decentralized Validators)

Frequent Batch Auction (FBA)

The goal is to further prevent any Front-Running in a decentralized setting. Most DEX's suffer from this as all information is public and traders can collude with miners or pay high gas fees enabling them to front-run any trades. We mitigate this by combining fast block times with a Frequent Batch Auction:

In any given block:

  1. Calculate one uniform clearing price for all market orders and execute them. For an example for the market order matching in FBA fashion, look here.
  2. Limit orders are combined with the resting orderbook and orders are matched as long as there is still negative spread. The limit orders are all matched at one uniform clearing price. For an example for the limit order matching in FBA fashion, look here.

Trading Fees and Gas

If you are a trader on existing centralized exchanges, you will be familiar with the concept of trading fees. Traders are charged a fee for each successful trade. However, for a DEX, there are additional gas costs that must be paid to the network. And luckily, the gas fee from trading on Injective is very minimal.

Note: trading from bank balances, which automatically uses the default subaccount 0, will cost roughly 15% more gas than trading from other subaccounts. API traders can use other subaccounts to trade to avoid the extra gas fees—read here for more information.

Mark Price Margin Requirement

Quantity = 2 BTC, InitialMarginRatio = 0.05
MarkPrice = $45,000, EntryPrice = $43,000

Margin ≥ 2 * 0.05 * $45,000 = $4,500

MarginLong ≥ max(2 * (0.05 * $45,000 - ($45,000 - $43,000)), $4,500)
MarginLong ≥ max($500, $4,500) = $4,500

MarginShort ≥ max(2 * (0.05 * $45,000 - ($43,000 - $45,000)), $4,500)
MarginShort ≥ max($8,500, $4,500) = $8,500

So in this case if the trader wanted to create a short position with
an entry price which essentially starts at a loss of $2,000 as
unrealized PNL, he would need to post at a minimum $8,500 as margin,
rather than the usual required $4,500.

You might be familiar with margin requirements on Centralized Exchanges. When creating a new position, it must fulfill the following requirement:

For example in a market with maximally 20x leverage, your initial margin must be at least 0.05 of the order's notional (entryPrice * quantity). On Injective additionally the margin must also fulfill the following mark price requirement:

where PNL is the expected profit and loss of the position if it was closed at the MarkPrice.

Liquidations

Long Position:
Quantity = 1 BTC, MaintenanceMarginRatio = 0.05
EntryPrice = $50,000, Margin = $5,000

Now the MarkPrice drops down to $47,300, which is below the liquidation price of $47,368.42 (when margin = $2,368.42, maintenance ratio ≈ .04999998).

The position is auto-closed via reduce-only order:

Sell order:
Quantity = 1 BTC, Price = $0, Margin = $0

Assuming it gets matched with a clearing price of 47,100:

Liquidation Payout = Position Margin + PNL = $5,000 - $2,900 = $2,100
Liquidator Profit = $2,100 * 0.5 = $1,050
Insurance Fund Profit = $2,100 * 0.5 = $1,050

When your position falls below the maintenance margin ratio, the position can and likely will be liquidated by anyone running the liquidator bot. You will loose your entire position and all funds remaining in the position. On-chain, a reduce-only market order of the same size as the position is automatically created. The market order will have a worst price defined as Infinity or 0, implying it will be matched at whatever prices are available in the order book.

One key difference is that the payout from executing the reduce-only market order will not go towards the position owner. Instead, half of the remaining funds are transferred to the liquidator bot and the other half is transferred to the insurance fund.

If the payout in the position was negative, i.e., the position's negative PNL was greater than its margin, then the insurance fund will cover the missing funds.

Note: liquidations are executed immediately in a block before any other order matching occurs.

Fee Discounts

Fee discounts are enabled by looking at the past trailing 30 day window. As long as you meet both conditions for a tier (volume traded AND staked amount), you will receive the respective discounts.

Funding Rate

The hourly funding rate on perpetual markets determines the percentage that traders on one side have to pay to the other side each hour. If the rate is positive, longs pay shorts. If the rate is negative, shorts pay longs. The further trade prices deviate from the mark price within the hour, the higher the funding rate will be up to a maximum of 0.0625% (1.5% per day).

Closing a Position

Suppose you have an open position:

- Direction = Long
- Margin = $5,000
- EntryPrice = $50,000
- Quantity = 0.5 BTC

You create a new vanilla order for

- Direction = Sell
- Margin = $10,000
- Price = $35,000
- Quantity = 0.75 BTC

which is fully matched. First, the position is fully closed:

- OrderMarginUsedForClosing = OrderMargin * CloseQuantity / OrderQuantity
- OrderMarginUsedForClosing = $10,000 * 0.5 / 0.75 = $6,667

The proportional closing order margin is then used for the payout:

- Payout = PNL + PositionMargin + OrderMarginUsedForClosing
- Payout = ($35,000-$50,000) * 0.5 + $5,000 + $6,667 = $4,167

And a new position is opened in the opposite direction:

- Direction = Short
- Margin = $3,333
- Price = $35,000
- Quantity = 0.25 BTC

There are two ways to close a position:

Closing via Reduce-Only Order

When you close a position via a reduce-only order, no additional margin is used from the order. All reduce-only orders have a margin of zero. In addition, reduce-only orders are only used to close positions, not to open new ones.

Closing via Vanilla Order

You can also close a position via vanilla orders. When a sell vanilla order is getting matched while you have an open Long position, the position will be closed at the price of the sell order. Depending on the size of the order and position, the position may be either

  1. partially closed
  2. fully closed
  3. or fully closed with subsequent opening of a new position in the opposite direction.

Note that how the margin inside the order is used depends on which of the three scenarios you are in. If you close a position via vanilla order, the margin is only used to cover PNL payouts, not to go into the position. If the order subsequently opens a new position in the opposite direction (scenario 3), the remaining proportional margin will go towards the new position.

Trading Rewards

Assume you have a trading rewards campaign with 100 INJ as rewards:

Reward Tokens: 100 INJ
Trader Reward Points = 100
Total Reward Points = 1,000

Trader Rewards = Trader Reward Points / Total Reward Points * Reward Tokens
Trader Rewards = 100 / 1,000 * 100 INJ = 10 INJ

During a given campaign, the exchange will record each trader's cumulative trading reward points obtained from trading fees (with boosts applied, if applicable) from all eligible markets. At the end of each campaign each trader will receive a pro-rata percentage of the trading rewards pool based off their trading rewards points from that campaign epoch. Those rewards will be automatically deposited into the trader's respective wallets, it's not necessary to manually withdraw them.

Reduce-Only Order Precedence

Imagine a trader has the following position:

And the following SELL orders:

Buy Price Quantity Order Type
$66,500 0.2 BTC Vanilla
$65,500 0.1 BTC Reduce-only
$65,400 0.1 BTC Vanilla
$64,500 0.3 BTC Vanilla
$63,500 0.1 BTC Reduce-only

This has some implications when placing new orders.

Upon placing a reduce-only order:

We check if any reduce-only orders would be invalid after executing all of the trader's other limit sell orders that have better prices in the same direction.

In our example, consider a new reduce-only order of 0.4 BTC at $64,600.

Sell Price Quantity Order Type
$66,500 0.2 BTC Vanilla
$65,500 0.1 BTC Reduce-only
$65,400 0.1 BTC Vanilla
$64,600 0.4 BTC Reduce-only
$64,500 0.3 BTC Vanilla
$63,500 0.1 BTC Reduce-only

This is perfectly valid and no further action is required. If the buy price hit $65,500 and all limit sell orders less than or equal to that price were filled, then the long position would be closed. If the price hit $66,500 and the vanilla sell order was filled, then the trader would open a 0.2 BTC short position. But what if the reduce-only order was for 0.5 BTC instead?

Sell Price Quantity Order Type
$66,500 0.2 BTC Vanilla
$65,500 0.1 BTC Reduce-only
$65,400 0.1 BTC Vanilla
$64,600 0.5 BTC Reduce-only
$64,500 0.3 BTC Vanilla
$63,500 0.1 BTC Reduce-only

If the orders are getting matched, once the last vanilla order of 0.1 BTC at $65,400 is filled, the position will have been reduced to 1 BTC - 0.1 BTC - 0.3 BTC - 0.5 BTC - 0.1 BTC = 0 BTC. The next reduce-only order of 0.1 BTC at $65,500 will thus be invalid.

To prevent that, we automatically cancel all reduce-only orders at a price where the cumulative sum of orders up to and including the reduce-only order would add up to more than the trader’s current long amount. Another way to think about it: we find the reduce-only order with the highest price such that all orders (vanilla and reduce-only) including and below that price add up in quantity to less than the long quantity. All reduce-only orders above that price will be canceled so that no reduce-only orders exist when the position is closed or short. The same concept applies to reduce-only orders on short positions, but we look for the lowest price instead of the highest on buy orders so that no reduce-only orders exist when the position is closed or long.

Upon placing a vanilla limit order:

We check if any reduce-only limit orders would be invalidated if all the orders up to and including the new vanilla limit order were filled.

In our example, consider a new vanilla order of 0.4 BTC at $64,600.

Sell Price Quantity Order Type
$66,500 0.2 BTC Vanilla
$65,500 0.1 BTC Reduce-only
$65,400 0.1 BTC Vanilla
$64,600 0.4 BTC Vanilla
$64,500 0.3 BTC Vanilla
$63,500 0.1 BTC Reduce-only

Again this perfectly valid and no further action is required because all order quantities up to the highest priced reduce-only order add up to ≤ the long position quantity. But what if the order was for 0.5 BTC instead?

Sell Price Quantity Order Type
$66,500 0.2 BTC Vanilla
$65,500 0.1 BTC Reduce-only
$65,400 0.1 BTC Vanilla
$64,600 0.5 BTC Vanilla
$64,500 0.3 BTC Vanilla
$63,500 0.1 BTC Reduce-only

If the orders are getting matched, once the last reduce-only order of $65,500 is reached, the position will have been reduced to 1 BTC - 0.1 BTC - 0.3 BTC - 0.5 BTC - 0.1 BTC = 0 BTC. A reduce-only order of 0.1 BTC after that will thus be invalid.

To prevent this, we automatically cancel the existing 0.1 BTC reduce-only order. In other words, new vanilla limit orders can invalidate and auto-cancel existing reduce-only limit orders if the reduce-only order becomes invalid at its price.

Rate Limits

The public mainnet and testnet nodes have a request rate limit associated to the requester IP address. The limits are:

Each endpoint's section in this document clarifies which group the endpoint belongs to. When the limit is reached the server will respond sending an error response with code 429.

Order types

Market and Limit Order Examples

Adding a Spot Market Buy Order

→ The account's available balance is decremented by 5,000 USDT + Taker Fee = 5,005 USDT.

Upon matching with a resting sell order with price of 4 USDT the new account balances are calculated as:

Adding a Spot Market Sell Order

→ The account's available balance is decremented by 1,000 INJ.

Upon matching with a resting sell order with price of 4 USDT the new account balances are calculated as:

Adding a Spot Limit Buy Order

→ The account's available balance is decremented by 5,000 USDT + Taker Fee = 5,005 USDT.

After the order is submitted:

Adding a Spot Limit Sell Order

→ The account's available balance is decremented by 1,000 INJ.

After the order is submitted:

Derivative Market Order Payouts

The payouts for derivative market orders work the same way as for derivative limit orders, with the one difference being they are cancelled if not immediately matched. See spot market and derivative limit orders as reference.

Adding a Derivative Limit Buy Order

→ The account's available balance is decremented by Margin + Taker Fee = 1000 + 5000 * 0.001 = 1005 USDT.

After creation:

If Unmatched, the order becomes a resting limit order (maker) and we refund the taker fee on vanilla orders (reduce-only orders don't pay upfront fees):

If Matched:

Assuming:

Would result in:

1. Closing existing position with proportional order margin for closing:

2. Opening new position in opposite direction:

3. Refunding margin difference from order price vs. clearing price:

4. Refunding fee difference from order price vs. clearing price:

Market Order Matching

Existing Orderbook

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
$64,3600.5 BTC
PriceQuantity
$64,2100.1 BTC
$64,2050.4 BTC
$64,2000.2 BTC

New Orders

Resulting Orderbook

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
PriceQuantity
$64,2050.2 BTC
$64,2000.2 BTC

Market Buys: Matching the highest priced market buy order first for 0.4 BTC. Now for the second market buy order only 0.1 BTC is left at matchable price, meaning the other 0.1 BTC in the order will be cancelled. Both orders will be matched with the single resting limit order at a price of 64,360 for a total quantity of 0.5 BTC.

Market Sells: Matching the first two market sell orders for at a matching price of (64,210*0.1 + 64,205*0.2) / 0.3 = 64,206.67 for a total quantity of 0.3 BTC. The resting limit orders are both matched at their specified price points of 64,210 and 64,205. Since the last market sell order of 69,000 cannot be fulfilled, it is cancelled.

Limit Order Matching

Existing Orderbook

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
$64,2500.5 BTC
PriceQuantity
$64,2100.1 BTC
$64,2050.3 BTC
$64,2000.2 BTC

New Orders

Sells Buys
PriceQuantity
$64,2200.4 BTC
$64,1800.2 BTC
PriceQuantity
$64,3700.4 BTC
$64,3600.2 BTC

Matching Orders

All new orders are incorporated into the existing orderbook. In our case this results in a negative spread:

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
$64,2500.5 BTC
$64,2200.4 BTC
$64,1800.2 BTC
PriceQuantity
$64,3700.4 BTC
$64,3600.1 BTC
$64,2100.1 BTC
$64,2050.3 BTC
$64,2000.2 BTC

As long as negative spread exists, orders are matched against each other. The first buy order is fully matched:

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
$64,2500.4 BTC
$64,2200.2 BTC
PriceQuantity
$64,3600.1 BTC
$64,2100.1 BTC
$64,2050.3 BTC
$64,2000.2 BTC

Now the second buy order can still be fully matched:

Sells Buys
PriceQuantity
$64,3900.3 BTC
$64,3700.2 BTC
$64,2500.4 BTC
$64,2200.1 BTC
PriceQuantity
$64,2100.1 BTC
$64,2050.3 BTC
$64,2000.2 BTC

This is the end of the matching, since no more negative spread exists (64,220 > 62,210).

All orders will be matched with a uniform clearing price within the range of the last sell order price and the last buy order price.

Step 1: Check if clearing price range is out of bounds regarding the resting orderbook mid price.

Step 2: Check if clearing price range is out of bounds regarding the mark price.

Step 3: Set clearing price = mid price or mark price for spot or perpetual markets, respectively, or in the case where these prices are out of bounds, use last buy or last sell price.

Resources

Here you can find a comprehensive overview of the exchange ecosystem on Injective, guides and general resources for developers and API traders.

Coin denoms and market IDs for testnet and mainnet can be found on the Injective testnet explorer and mainnet explorer under the Markets tab and Assets tab.

Explorer

A Web interface that allows you to search for information on the Injective Chain

Explorer Mainnet

Explorer Testnet

Faucet

A web-based service that provides free tokens to users on testnet and allows them to experiment on the Injective Chain.

Faucet

Status

Monitor the uptime of all public services.

Testnet Status

Mainnet Status

Message Broadcaster

In the examples included in this documentation you will see all the steps required to interact with the chain, from deriving a public key from a private key, creating messages to query the chain or creating orders, to creating and broadcasting transactions to the chain. Before going to the examples of all the possible actions it is important to state that you can avoid implementing yourself all the steps to create and configure correctly a transaction. If you are not interested in defining all the low level aspects you can use the component called MsgBroadcasterWithPk. To use the broadcaster you just need to create an instance of MsgBroadcasterWithPk, and once all the messages to be included in the transaction have been created, use the broadcast method, passing the messages as a parameter. The broadcaster will take care of: - Calculate the gas fee to pay for the transaction - Create the transaction and configure it - Sign the transaction - Broadcast it to the chain

Broadcaster for standard account

Calculate gas fee simulating the transaction

Example - Calculate gas fee simulating the transaction:

import asyncio
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey


async def main() -> None:
    dotenv.load_dotenv()
    private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")

    # select network: local, testnet, mainnet
    network = Network.testnet()
    composer = ProtoMsgComposer(network=network.string())

    message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
        network=network,
        private_key=private_key_in_hexa,
    )

    priv_key = PrivateKey.from_hex(private_key_in_hexa)
    pub_key = priv_key.to_public_key()
    address = pub_key.to_address()
    subaccount_id = address.get_subaccount_id(index=0)

    # prepare trade info
    fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"

    spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"

    spot_orders_to_create = [
        composer.spot_order(
            market_id=spot_market_id_create,
            subaccount_id=subaccount_id,
            fee_recipient=fee_recipient,
            price=Decimal("3"),
            quantity=Decimal("55"),
            order_type="BUY",
            cid=(str(uuid.uuid4())),
        ),
        composer.spot_order(
            market_id=spot_market_id_create,
            subaccount_id=subaccount_id,
            fee_recipient=fee_recipient,
            price=Decimal("300"),
            quantity=Decimal("55"),
            order_type="SELL",
            cid=str(uuid.uuid4()),
        ),
    ]

    # prepare tx msg
    msg = composer.msg_batch_update_orders(
        sender=address.to_acc_bech32(),
        spot_orders_to_create=spot_orders_to_create,
    )

    # broadcast the transaction
    result = await message_broadcaster.broadcast([msg])
    print("---Transaction Response---")
    print(result)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

For the broadcaster to calculate the gas fee running the simulation, create an instance of MsgBroadcasterWithPk with the message new_using_simulation.

This is the most common broadcaster configuration. Unless you are using grantee accounts (delegated accounts with authz) you should use this one.




















































Calculate gas fee without simulation

Example - Calculate gas fee without simulation:

import asyncio
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey


async def main() -> None:
    dotenv.load_dotenv()
    private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")

    # select network: local, testnet, mainnet
    network = Network.testnet()
    composer = ProtoMsgComposer(network=network.string())

    message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
        network=network,
        private_key=private_key_in_hexa,
    )

    priv_key = PrivateKey.from_hex(private_key_in_hexa)
    pub_key = priv_key.to_public_key()
    address = pub_key.to_address()
    subaccount_id = address.get_subaccount_id(index=0)

    # prepare trade info
    fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"

    spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"

    spot_orders_to_create = [
        composer.spot_order(
            market_id=spot_market_id_create,
            subaccount_id=subaccount_id,
            fee_recipient=fee_recipient,
            price=Decimal("3"),
            quantity=Decimal("55"),
            order_type="BUY",
            cid=str(uuid.uuid4()),
        ),
        composer.spot_order(
            market_id=spot_market_id_create,
            subaccount_id=subaccount_id,
            fee_recipient=fee_recipient,
            price=Decimal("300"),
            quantity=Decimal("55"),
            order_type="SELL",
            cid=str(uuid.uuid4()),
        ),
    ]

    # prepare tx msg
    msg = composer.msg_batch_update_orders(
        sender=address.to_acc_bech32(),
        spot_orders_to_create=spot_orders_to_create,
    )

    # broadcast the transaction
    result = await message_broadcaster.broadcast([msg])
    print("---Transaction Response---")
    print(result)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

For the broadcaster to calculate the gas fee based on the messages included without running the simulation, create an instance of MsgBroadcasterWithPk with the message new_without_simulation.



Broadcaster for grantee account

This is the required broadcaster configuration when operating with grantee accounts. The broadcaster will take care of creating the MsgExec message, so that the user keeps passing the same messages to the broadcast method that are passed when using the standard broadcaster with non-grantee accounts.

Calculate gas fee simulating the transaction

Example - Calculate gas fee simulating the transaction:

import asyncio
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import Address, PrivateKey


async def main() -> None:
    dotenv.load_dotenv()
    private_key_in_hexa = os.getenv("INJECTIVE_GRANTEE_PRIVATE_KEY")
    granter_inj_address = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")

    # select network: local, testnet, mainnet
    network = Network.testnet()
    composer = ProtoMsgComposer(network=network.string())

    # initialize grpc client
    client = AsyncClient(network)
    await client.sync_timeout_height()

    # load account
    priv_key = PrivateKey.from_hex(private_key_in_hexa)
    pub_key = priv_key.to_public_key()
    address = pub_key.to_address()

    message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_using_simulation(
        network=network,
        grantee_private_key=private_key_in_hexa,
    )

    # prepare tx msg
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"

    granter_address = Address.from_acc_bech32(granter_inj_address)
    granter_subaccount_id = granter_address.get_subaccount_id(index=0)

    msg = composer.msg_create_spot_limit_order(
        market_id=market_id,
        sender=granter_inj_address,
        subaccount_id=granter_subaccount_id,
        fee_recipient=address.to_acc_bech32(),
        price=Decimal("7.523"),
        quantity=Decimal("0.01"),
        order_type="BUY",
        cid=str(uuid.uuid4()),
    )

    # broadcast the transaction
    result = await message_broadcaster.broadcast([msg])
    print("---Transaction Response---")
    print(result)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

For the broadcaster to calculate the gas fee running the simulation, create an instance of MsgBroadcasterWithPk with the message new_for_grantee_account_using_simulation.














































Calculate gas fee without simulation

Example - Calculate gas fee without simulation:

import asyncio
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import Address, PrivateKey


async def main() -> None:
    dotenv.load_dotenv()
    private_key_in_hexa = os.getenv("INJECTIVE_GRANTEE_PRIVATE_KEY")
    granter_inj_address = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")

    # select network: local, testnet, mainnet
    network = Network.testnet()
    composer = ProtoMsgComposer(network=network.string())

    # initialize grpc client
    client = AsyncClient(network)
    await client.sync_timeout_height()

    # load account
    priv_key = PrivateKey.from_hex(private_key_in_hexa)
    pub_key = priv_key.to_public_key()
    address = pub_key.to_address()

    message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_without_simulation(
        network=network,
        grantee_private_key=private_key_in_hexa,
    )

    # prepare tx msg
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    granter_address = Address.from_acc_bech32(granter_inj_address)
    granter_subaccount_id = granter_address.get_subaccount_id(index=0)

    msg = composer.msg_create_spot_limit_order(
        market_id=market_id,
        sender=granter_inj_address,
        subaccount_id=granter_subaccount_id,
        fee_recipient=address.to_acc_bech32(),
        price=Decimal("7.523"),
        quantity=Decimal("0.01"),
        order_type="BUY",
        cid=str(uuid.uuid4()),
    )

    # broadcast the transaction
    result = await message_broadcaster.broadcast([msg])
    print("---Transaction Response---")
    print(result)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

For the broadcaster to calculate the gas fee based on the messages included without running the simulation, create an instance of MsgBroadcasterWithPk with the message new_for_grantee_account_without_simulation.




NOTE:

There an important consideration when using the Transaction Broadcaster calculating the gas cost without simulation to send a MsgBatchUpdateOrders message. The logic that estimates the gas cost for the MsgBatchUpdateOrders correclty calculates the gas required for each order action (creation or cancelation) it includes. But there is no easy way to calculate the gas cost when canceling all orders for a market id using one of the following parameters: spot_market_ids_to_cancel_all, derivative_market_ids_to_cancel_all or binary_options_market_ids_to_cancel_all. The complexity is related to the fact that the gas cost depends on the number of orders to be cancelled. By default the estimation logic calculates a gas cost considering the number of orders to cancel for each market id is 20. To improve the gas cost calculation when using the MsgBatchUpdateOrders message to cancel all orders for one or more markets you can change the number of estimated orders to cancel per market running the following command:

BatchUpdateOrdersGasLimitEstimator.AVERAGE_CANCEL_ALL_AFFECTED_ORDERS = 30

Fine-tunning gas fee local estimation

As mentioned before the gas estimation without using simulation is implemented by using fixed values as gas cost for certain messages and actions. Since the real gas cost can differ at some point from the estimator calculations, the Python SDK allows the developer to fine-tune certain gas cost values in order to improve the gas cost estimation. In the next tables you can find the global values used for gas estimation calculations, that can be modified in your application:

Module Global Variable Description
pyinjective.core.gas_limit_estimator SPOT_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one spot order
pyinjective.core.gas_limit_estimator DERIVATIVE_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one derivative order
pyinjective.core.gas_limit_estimator SPOT_ORDER_CANCELATION_GAS_LIMIT The gas cost associated to the cancellation of one spot order
pyinjective.core.gas_limit_estimator DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT The gas cost associated to the cancellation of one derivative order
pyinjective.core.gas_limit_estimator SPOT_POST_ONLY_ORDER_MULTIPLIER Multiplier to increase the gas cost for post only spot orders (in addition to the normal spot order cost)
pyinjective.core.gas_limit_estimator DERIVATIVE_POST_ONLY_ORDER_MULTIPLIER Multiplier to increase the gas cost for post only derivative orders (in addition to the normal derivative order cost)
Class Global Variable Description
MessageBasedTransactionFeeCalculator TRANSACTION_GAS_LIMIT The gas cost associated to the TX processing
GasLimitEstimator GENERAL_MESSAGE_GAS_LIMIT Generic base gas cost for any message
GasLimitEstimator BASIC_REFERENCE_GAS_LIMIT Base gas cost for messages not related to orders. Each type of message will calculate its cost multiplying this reference cost by a multiplier
DefaultGasLimitEstimator DEFAULT_GAS_LIMIT The gas cost for all messages for which there is no especial estimator implemented
BatchUpdateOrdersGasLimitEstimator CANCEL_ALL_SPOT_MARKET_GAS_LIMIT This is an estimation of the gas cost per spot order cancel when cancelling all orders for a spot market
BatchUpdateOrdersGasLimitEstimator CANCEL_ALL_DERIVATIVE_MARKET_GAS_LIMIT This is an estimation of the gas cost per derivative order cancel when cancelling all orders for a derivative market
BatchUpdateOrdersGasLimitEstimator MESSAGE_GAS_LIMIT Estimation of the general gas amount required for a MsgBatchUpdateOrders (not for particular actions, but for the general message processing)
BatchUpdateOrdersGasLimitEstimator AVERAGE_CANCEL_ALL_AFFECTED_ORDERS This global represents the expected number of orders to be cancelled when executing a "cancel all orders for a market" action
ExecGasLimitEstimator DEFAULT_GAS_LIMIT Estimation of the general gas amount required for a MsgExec (for the general message processing)
GenericExchangeGasLimitEstimator BASIC_REFERENCE_GAS_LIMIT Base gas cost for messages not related to orders. Each type of message will calculate its cost multiplying this reference cost by a multiplier

Indexer API

The Indexer API is read-only whereas the Chain API is write and also includes a limited set of API requests to read data. The Chain API reads query the blockchain state from the node directly as opposed to the Indexer API which reconstructs state from events emitted by chain.

On a high-level the end-user trading applications and Injective Products use the Indexer API to read data and the Chain API to write data to the blockchain. Even though it’s possible to develop trading applications using the Chain API only, the Indexer API includes more methods, streaming support, gRPC, and also allows you to fetch historical data (the Chain API queries the blockchain state which doesn’t include historical records).

- InjectiveAccountsRPC

InjectiveAccountsRPC defines the gRPC API of the Exchange Accounts provider.

SubaccountsList

Get a list of subaccounts for a specific address.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
    subacc_list = await client.fetch_subaccounts_list(account_address)
    print(subacc_list)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    accountAddress := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
    res, err := exchangeClient.GetSubaccountsList(ctx, accountAddress)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
account_address String The Injective Chain address Yes

Response Parameters

Response Example:

{
   "subaccounts":[
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002",
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000"
   ]
}
{
 "subaccounts": [
  "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
  "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002"
 ]
}
Parameter Type Description
subaccounts String Array List of subaccounts, including default and all funded accounts

SubaccountHistory

Get the subaccount's transfer history.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    denom = "inj"
    transfer_types = ["withdraw", "deposit"]
    skip = 1
    limit = 15
    end_time = 1665118340224
    pagination = PaginationOption(skip=skip, limit=limit, end_time=end_time)
    subacc_history = await client.fetch_subaccount_history(
        subaccount_id=subaccount,
        denom=denom,
        transfer_types=transfer_types,
        pagination=pagination,
    )
    print(subacc_history)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    denom := "inj"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    transferTypes := []string{"deposit"}
    skip := uint64(0)
    limit := int32(10)

    req := accountPB.SubaccountHistoryRequest{
        Denom:         denom,
        SubaccountId:  subaccountId,
        TransferTypes: transferTypes,
        Skip:          skip,
        Limit:         limit,
    }

    res, err := exchangeClient.GetSubaccountHistory(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
denom String Filter by denom No
transfer_types String Array Filter by transfer types. Valid options: [“internal”, “external”, withdraw”, “deposit”] No
skip Integer Skip the last n transfers, you can use this to fetch all transfers since the API caps at 100. Note: The end_time filter takes precedence over skip; any skips will use the filtered results from end_time No
limit Integer Max number of items to be returned No
end_time Integer Upper bound (inclusive) of account transfer history executed_at unix timestamp No

Response Parameters

Response Example:

{
   "transfers":[
      {
         "transferType":"deposit",
         "srcAccountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
         "dstSubaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "amount":{
            "denom":"inj",
            "amount":"2000000000000000000"
         },
         "executedAt":"1665117493543",
         "srcSubaccountId":"",
         "dstAccountAddress":""
      },
      {
         "transferType":"deposit",
         "srcAccountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
         "dstSubaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "amount":{
            "denom":"inj",
            "amount":"15000000000000000000"
         },
         "executedAt":"1660313668990",
         "srcSubaccountId":"",
         "dstAccountAddress":""
      }
   ],
   "paging":{
      "total":"3",
      "from":0,
      "to":0,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}

{
 "transfers": [
  {
   "transfer_type": "deposit",
   "src_account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "dst_subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "amount": {
    "denom": "inj",
    "amount": "50000000000000000000"
   },
   "executed_at": 1651492257605
  },
  {
   "transfer_type": "deposit",
   "src_account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "dst_subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "amount": {
    "denom": "inj",
    "amount": "1000000000000000000"
   },
   "executed_at": 1652453978939
  }
 ],
 "paging": [
  {
   "total": 3
  }
 ]
}
Parameter Type Description
transfers SubaccountBalanceTransfer List of subaccount transfers
paging Paging Pagination of results

SubaccountBalanceTransfer

Parameter Type Description
amount CosmosCoin CosmosCoin
dst_account_address String Account address of the receiving side
executed_at Integer Timestamp of the transfer in UNIX millis
src_subaccount_id String Subaccount ID of the sending side
transfer_type String Type of the subaccount balance transfer. Valid options: ["internal", "external", "withdraw", "deposit"]

CosmosCoin

Parameter Type Description
amount String Coin amount
denom String Coin denominator

Paging

Parameter Type Description
total Integer Total number of available records

SubaccountBalance

Get the balance of a subaccount for a specific denom.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    denom = "inj"
    balance = await client.fetch_subaccount_balance(subaccount_id=subaccount_id, denom=denom)
    print(balance)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("mainnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    denom := "inj"
    res, err := exchangeClient.GetSubaccountBalance(ctx, subaccountId, denom)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
denom String Filter by denom Yes

Response Parameters

Response Example:

{
   "balance":{
      "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
      "accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
      "denom":"inj",
      "deposit":{
         "totalBalance":"0",
         "availableBalance":"0"
      }
   }
}
{
 "balance": {
  "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
  "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
  "denom": "inj",
  "deposit": {
   "total_balance": "1492235700000000000000",
   "available_balance": "1492235700000000000000"
  }
 }
}
Parameter Type Description
balance SubaccountBalance SubaccountBalance object

SubaccountBalance

Parameter Type Description
denom String Coin denom on the chain
deposit SubaccountDeposit SubaccountDeposit object
subaccount_id String ID of the subaccount
account_address String The Injective Chain address that owns the subaccount

SubaccountDeposit

Parameter Type Description
available_balance String The available balance for a denom (taking active orders into account)
total_balance String The total balance for a denom (balance if all active orders were cancelled)

SubaccountBalancesList

List the subaccount's balances for all denoms.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]
    subacc_balances_list = await client.fetch_subaccount_balances_list(subaccount_id=subaccount, denoms=denoms)
    print(subacc_balances_list)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    res, err := exchangeClient.GetSubaccountBalancesList(ctx, subaccountId)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String ID of subaccount to get balance info from Yes
denoms String Array Filter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided No

Response Parameters

Response Example:

{
   "balances":[
      {
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
         "denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
         "deposit":{
            "totalBalance":"131721505.337958346262317217",
            "availableBalance":"0.337958346262317217"
         }
      },
      {
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
         "denom":"inj",
         "deposit":{
            "totalBalance":"0",
            "availableBalance":"0"
         }
      }
   ]
}
{
 "balances": [
  {
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "deposit": {
    "total_balance": "200501904612800.13082016560359584",
    "available_balance": "200358014975479.130820165603595295"
   }
  },
  {
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "denom": "inj",
   "deposit": {
    "total_balance": "53790000010000000003",
    "available_balance": "52790000010000000003"
   }
  },
  {
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "denom": "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9",
   "deposit": {
    "total_balance": "1000000",
    "available_balance": "1000000"
   }
  }
 ]
}
Parameter Type Description
balances SubaccountBalance Array Array of SubaccountBalance objects

SubaccountBalance

Parameter Type Description
account_address String The Injective Chain address, owner of subaccount
denom String Coin denom on the chain
deposit SubaccountDeposit SubaccountDeposit object
subaccount_id String ID of subaccount associated with returned balances

SubaccountDeposit

Parameter Type Description
available_balance String The available balance for a denom
total_balance String The total balance for a denom

SubaccountOrderSummary

Get a summary of the subaccount's active/unfilled orders.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    order_direction = "buy"
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    subacc_order_summary = await client.fetch_subaccount_order_summary(
        subaccount_id=subaccount, order_direction=order_direction, market_id=market_id
    )
    print(subacc_order_summary)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    orderDirection := "buy"

    req := accountPB.SubaccountOrderSummaryRequest{
        MarketId:       marketId,
        SubaccountId:   subaccountId,
        OrderDirection: orderDirection,
    }

    res, err := exchangeClient.GetSubaccountOrderSummary(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println("spot orders:", res.SpotOrdersTotal)
    fmt.Println("derivative orders:", res.DerivativeOrdersTotal)
}
Parameter Type Description Required
subaccount_id String ID of the subaccount we want to get the summary from Yes
market_id String Limit the order summary to a specific market No
order_direction String Filter by the direction of the orders. Valid options: "buy", "sell" No

Response Parameters

Response Example:

{
   "derivativeOrdersTotal":"1",
   "spotOrdersTotal":"0"
}
spot orders: 1
derivative orders: 7
Parameter Type Description
derivative_orders_total Integer Total count of subaccount's active derivative orders in a given market and direction
spot_orders_total Integer Total count of subaccount's active spot orders in a given market and direction

StreamSubaccountBalance

Stream the subaccount's balance for all denoms.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def balance_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to balance updates ({exception})")


def stream_closed_processor():
    print("The balance updates stream has been closed")


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
    denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]
    task = asyncio.get_event_loop().create_task(
        client.listen_subaccount_balance_updates(
            subaccount_id=subaccount_id,
            callback=balance_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            denoms=denoms,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    subaccountId := "0x1b99514e320ae0087be7f87b1e3057853c43b799000000000000000000000000"
    stream, err := exchangeClient.StreamSubaccountBalance(ctx, subaccountId)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                fmt.Println(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
denoms String Array Filter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
  "balance": {
    "subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
    "accountAddress": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
    "denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "deposit": {
      "totalBalance": "200493439765890.695319283887814576",
      "availableBalance": "200493414240390.695319283887814031"
    }
  },
  "timestamp": 1654234765000
}
{
  "balance": {
    "subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
    "accountAddress": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
    "denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "deposit": {
      "totalBalance": "200493847328858.695319283887814576",
      "availableBalance": "200493821803358.695319283887814031"
    }
  },
  "timestamp": 1654234804000
}
{
 "balance": {
  "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
  "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
  "denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
  "deposit": {
   "total_balance": "200503979400874.28368413692326264",
   "available_balance": "200360046875708.283684136923262095"
  }
 },
 "timestamp": 1653037703000
}{
 "balance": {
  "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
  "account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
  "denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
  "deposit": {
   "total_balance": "200503560511302.28368413692326264",
   "available_balance": "200359627986136.283684136923262095"
  }
 },
 "timestamp": 1653037744000
}
Parameter Type Description
balance SubaccountBalance SubaccountBalance object
timestamp Integer Operation timestamp in UNIX millis

SubaccountBalance

Parameter Type Description
denom String Coin denom on the chain
deposit SubaccountDeposit SubaccountDeposit object
subaccount_id String ID of the subaccount to get balance from
account_address String The Injective Chain address that owns the subaccount

SubaccountDeposit

Parameter Type Description
available_balance String The available balance for a denom (taking active orders into account)
total_balance String The total balance for a denom (balance if all active orders were cancelled)

OrderStates

Get orders with an order hash. This request will return market orders and limit orders in all states [booked, partial_filled, filled, canceled]. For filled and canceled orders, there is a TTL of 3 minutes. Should your order be filled or canceled you will still be able to fetch it for 3 minutes.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    spot_order_hashes = [
        "0xce0d9b701f77cd6ddfda5dd3a4fe7b2d53ba83e5d6c054fb2e9e886200b7b7bb",
        "0x2e2245b5431638d76c6e0cc6268970418a1b1b7df60a8e94b8cf37eae6105542",
    ]
    derivative_order_hashes = [
        "0x82113f3998999bdc3892feaab2c4e53ba06c5fe887a2d5f9763397240f24da50",
        "0xbb1f036001378cecb5fff1cc69303919985b5bf058c32f37d5aaf9b804c07a06",
    ]
    orders = await client.fetch_order_states(
        spot_order_hashes=spot_order_hashes, derivative_order_hashes=derivative_order_hashes
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    spotOrderHashes := []string{"0x0b156df549747187210ca5381f0291f179d76d613d0bae1a3c4fd2e3c0504b7c"}
    derivativeOrderHashes := []string{"0x82113f3998999bdc3892feaab2c4e53ba06c5fe887a2d5f9763397240f24da50"}

    req := accountPB.OrderStatesRequest{
        SpotOrderHashes:       spotOrderHashes,
        DerivativeOrderHashes: derivativeOrderHashes,
    }

    res, err := exchangeClient.GetOrderStates(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
spot_order_hashes String Array Array with the order hashes you want to fetch in spot markets No
derivative_order_hashes String Array Array with the order hashes you want to fetch in derivative markets No

Response Parameters

Response Example:

{
  "spotOrderStates": [
    {
      "orderHash": "0xb7b556d6eab10c4c185a660be44757a8a6715fb16db39708f2f76d9ce5ae8617",
      "subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
      "marketId": "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa",
      "orderType": "limit",
      "orderSide": "buy",
      "state": "booked",
      "quantityFilled": "0",
      "quantityRemaining": "1000000",
      "createdAt": 1654080262300,
      "updatedAt": 1654080262300
    }
  ],
  "derivativeOrderStates": [
    {
      "orderHash": "0x4228f9a56a5bb50de4ceadc64df694c77e7752d58b71a7c557a27ec10e1a094e",
      "subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
      "marketId": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
      "orderType": "limit",
      "orderSide": "buy",
      "state": "booked",
      "quantityFilled": "0",
      "quantityRemaining": "1",
      "createdAt": 1654235059957,
      "updatedAt": 1654235059957
    }
  ]
}
{
 "spot_order_states": [
  {
   "order_hash": "0xb7b556d6eab10c4c185a660be44757a8a6715fb16db39708f2f76d9ce5ae8617",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "market_id": "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa",
   "order_type": "limit",
   "order_side": "buy",
   "state": "booked",
   "quantity_filled": "0",
   "quantity_remaining": "1000000",
   "created_at": 1654080262300,
   "updated_at": 1654080262300
  }
 ],
 "derivative_order_states": [
  {
   "order_hash": "0x4228f9a56a5bb50de4ceadc64df694c77e7752d58b71a7c557a27ec10e1a094e",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "market_id": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
   "order_type": "limit",
   "order_side": "buy",
   "state": "booked",
   "quantity_filled": "0",
   "quantity_remaining": "1",
   "created_at": 1654235059957,
   "updated_at": 1654235059957
  }
 ]
}
Parameter Type Description
spot_order_states OrderStateRecord Array Array of OrderStateRecord objects
derivative_order_states OrderStateRecord Array Array of OrderStateRecord objects

SpotOrderStates

Parameter Type Description
order_hash String Hash of the order
subaccount_id String The subaccount ID that posted the order
market_id String The market ID of the order
order_type String The order type. Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]. If execution_type (market or limit) is needed, use the OrdersHistory request in Spot/DerivativeExchangeRPC instead
order_side String The order side. Should be one of: ["buy", "sell"]
state String The order state. Should be one of: ["booked", "partial_filled", "filled", "canceled"]
quantity_filled String The quantity that has been filled for the order
quantity_remaining String The quantity that hasn't been filled for the order
created_at String The UNIX timestamp of the order when it was first created
updated_at String The UNIX timestamp of the order when it was last updated

DerivativeOrderStates

Parameter Type Description
order_hash String Hash of the order
subaccount_id String The subaccount ID that posted the order
market_id String The market ID of the order
order_type String The order type. Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]. If execution_type (market or limit) is needed, use the OrdersHistory request in Spot/DerivativeExchangeRPC instead
order_side String The order side. Should be one of: ["buy", "sell"]
state String The order state. Should be one of: ["booked", "partial_filled", "filled", "canceled"]
quantity_filled String The quantity that has been filled for the order
quantity_remaining String The quantity that hasn't been filled for the order
created_at String The UNIX timestamp of the order when it was first created
updated_at String The UNIX timestamp of the order when it was last updated

Portfolio

Get an overview of your portfolio.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
    portfolio = await client.fetch_portfolio(account_address=account_address)
    print(portfolio)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    accountAddress := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
    res, err := exchangeClient.GetPortfolio(ctx, accountAddress)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
account_address String The Injective Chain address Yes

Response Parameters

Response Example:

{
   "portfolio":{
      "portfolioValue":"6229.040631548905238875",
      "availableBalance":"92.4500010811984646",
      "lockedBalance":"13218.3573583009093604",
      "unrealizedPnl":"-7081.766727833202586125",
      "subaccounts":[
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000002",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000006",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000008",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000009",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f971347490200000061746f6d2d75736474",
            "availableBalance":"0.00000066622556",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
            "availableBalance":"0.0000003382963046",
            "lockedBalance":"13218.3573583009093604",
            "unrealizedPnl":"-7081.766727833202586125"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f971347490200000000696e6a2d75736474",
            "availableBalance":"0.0000000766766",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000001",
            "availableBalance":"92.45",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000003",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000007",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000004",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         },
         {
            "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000005",
            "availableBalance":"0",
            "lockedBalance":"0",
            "unrealizedPnl":"0"
         }
      ]
   }
}
{
 "portfolio": {
  "portfolio_value": "16961.63886335580191347385",
  "available_balance": "10127.8309908372442029",
  "locked_balance": "8192.6038127728038576",
  "unrealized_pnl": "-1358.79594025424614702615",
  "subaccounts": [
   {
    "subaccount_id": "0x792bb0b9001d71a8efcb3c026ba4e34608a68a8c000000000000000000000000",
    "available_balance": "10127.8309908372442029",
    "locked_balance": "8192.6038127728038576",
    "unrealized_pnl": "-1358.79594025424614702615"
   }
  ]
 }
}
Parameter Type Description
portfolio_value String The total value (in USD) of your portfolio including bank balance, subaccounts' balance, unrealized profit & loss as well as margin in open positions
available_balance String The total available balance (in USD) in all subaccounts
locked_balance String The amount of margin in open orders and positions (in USD)
unrealized_pnl String The approximate unrealized profit and loss across all positions (based on mark prices, in USD)
subaccounts SubaccountPortfolio Array List of all subaccounts' portfolios

SubaccountPortfolio

Parameter Type Description
subaccount_id String The ID of this subaccount
available_balance String The subaccount's available balance (in USD)
locked_balance String The subaccount's locked balance (in USD)
unrealized_pnl String The Subaccount's total unrealized PnL value (in USD)

Rewards

Get the rewards for Trade & Earn, the request will fetch all addresses for the latest epoch (-1) by default.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
    epoch = -1
    rewards = await client.fetch_rewards(account_address=account_address, epoch=epoch)
    print(rewards)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    accountAddress := "inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e"
    epoch := int64(1)

    req := accountPB.RewardsRequest{
        Epoch:          epoch,
        AccountAddress: accountAddress,
    }

    res, err := exchangeClient.GetRewards(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
account_address String The Injective Chain address to fetch rewards amount for No
epoch Integer The rewards distribution epoch number. Use -1 for the latest epoch No

Response Parameters

Response Example:

{
   "rewards":[
      {
         "accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
         "rewards":[
            {
               "denom":"inj",
               "amount":"11169382212463849"
            }
         ],
         "distributedAt":"1672218001897"
      }
   ]
}
{
 "rewards": [
  {
   "account_address": "inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e",
   "rewards": [
    {
     "denom": "inj",
     "amount": "755104058929571177652"
    }
   ],
   "distributed_at": 1642582800716
  }
 ]
}
Parameter Type Description
rewards Reward Array List of trading rewards

Reward

Parameter Type Description
account_address String The Injective Chain address
rewards Coin Array List of rewards by denom and amount
distributed_at Integer Timestamp of the transfer in UNIX millis

Coin

Parameter Type Description
denom String Denom of the reward
amount String Amount of denom in reward

- InjectiveSpotExchangeRPC

InjectiveSpotExchangeRPC defines the gRPC API of the Spot Exchange provider.

Market

Get details of a single spot market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    market = await client.fetch_spot_market(market_id=market_id)
    print(market)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    res, err := exchangeClient.GetSpotMarket(ctx, marketId)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_id String MarketId of the market we want to fetch Yes

Response Parameters

Response Example:

{
   "market":{
      "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
      "marketStatus":"active",
      "ticker":"INJ/USDT",
      "baseDenom":"inj",
      "baseTokenMeta":{
         "name":"Injective Protocol",
         "address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
         "symbol":"INJ",
         "logo":"https://static.alchemyapi.io/images/assets/7226.png",
         "decimals":18,
         "updatedAt":"1683119359318"
      },
      "quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
      "quoteTokenMeta":{
         "name":"Testnet Tether USDT",
         "address":"0x0000000000000000000000000000000000000000",
         "symbol":"USDT",
         "logo":"https://static.alchemyapi.io/images/assets/825.png",
         "decimals":6,
         "updatedAt":"1683119359320"
      },
      "makerFeeRate":"-0.0001",
      "takerFeeRate":"0.001",
      "serviceProviderFee":"0.4",
      "minPriceTickSize":"0.000000000000001",
      "minQuantityTickSize":"1000000000000000"
   }
}
{
 "market": {
  "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
  "market_status": "active",
  "ticker": "INJ/USDT",
  "base_denom": "inj",
  "base_token_meta": {
   "name": "Injective Protocol",
   "address": "0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
   "symbol": "INJ",
   "logo": "https://static.alchemyapi.io/images/assets/7226.png",
   "decimals": 18,
   "updated_at": 1650978921934
  },
  "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
  "maker_fee_rate": "0.001",
  "taker_fee_rate": "0.002",
  "service_provider_fee": "0.4",
  "min_price_tick_size": "0.000000000000001",
  "min_quantity_tick_size": "1000000000000000"
 }
}
Parameter Type Description
market SpotMarketInfo Info about particular spot market

SpotMarketInfo

Parameter Type Description
base_denom String Coin denom of the base asset
market_id String ID of the spot market of interest
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
quote_token_meta TokenMeta Token metadata for quote asset, only for Ethereum-based assets
service_provider_fee String Percentage of the transaction fee shared with the service provider
base_token_meta TokenMeta Token metadata for base asset, only for Ethereum-based assets
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
quote_denom String Coin denom of the quote asset
taker_fee_rate String Defines the fee percentage takers pay (in the quote asset) when trading
ticker String A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

Markets

Get a list of spot markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_status = "active"
    base_denom = "inj"
    quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
    market = await client.fetch_spot_markets(
        market_statuses=[market_status], base_denom=base_denom, quote_denom=quote_denom
    )
    print(market)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketStatus := "active"
    quoteDenom := "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7"

    req := spotExchangePB.MarketsRequest{
        MarketStatus: marketStatus,
        QuoteDenom:   quoteDenom,
    }

    res, err := exchangeClient.GetSpotMarkets(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_statuses String Array Filter by status of the market (Should be any of: ["active", "paused", "suspended", "demolished", "expired"]) No
base_denom String Filter by the Coin denomination of the base currency No
quote_denom String Filter by the Coin denomination of the quote currency No

Response Parameters

Response Example:

{
   "markets":[
      {
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "marketStatus":"active",
         "ticker":"INJ/USDT",
         "baseDenom":"inj",
         "baseTokenMeta":{
            "name":"Injective Protocol",
            "address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
            "symbol":"INJ",
            "logo":"https://static.alchemyapi.io/images/assets/7226.png",
            "decimals":18,
            "updatedAt":"1683119359318"
         },
         "quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
         "quoteTokenMeta":{
            "name":"Testnet Tether USDT",
            "address":"0x0000000000000000000000000000000000000000",
            "symbol":"USDT",
            "logo":"https://static.alchemyapi.io/images/assets/825.png",
            "decimals":6,
            "updatedAt":"1683119359320"
         },
         "makerFeeRate":"-0.0001",
         "takerFeeRate":"0.001",
         "serviceProviderFee":"0.4",
         "minPriceTickSize":"0.000000000000001",
         "minQuantityTickSize":"1000000000000000"
      }
   ]
}
{
 "markets": [
  {
   "market_id": "0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
   "market_status": "active",
   "ticker": "AAVE/USDT",
   "base_denom": "peggy0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
   "base_token_meta": {
    "name": "Aave",
    "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
    "symbol": "AAVE",
    "logo": "https://static.alchemyapi.io/images/assets/7278.png",
    "decimals": 18,
    "updated_at": 1650978921846
   },
   "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "maker_fee_rate": "0.001",
   "taker_fee_rate": "0.002",
   "service_provider_fee": "0.4",
   "min_price_tick_size": "0.000000000000001",
   "min_quantity_tick_size": "1000000000000000"
  },
  {
   "market_id": "0xe8bf0467208c24209c1cf0fd64833fa43eb6e8035869f9d043dbff815ab76d01",
   "market_status": "active",
   "ticker": "UNI/USDT",
   "base_denom": "peggy0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
   "base_token_meta": {
    "name": "Uniswap",
    "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
    "symbol": "UNI",
    "logo": "https://static.alchemyapi.io/images/assets/7083.png",
    "decimals": 18,
    "updated_at": 1650978922133
   },
   "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "maker_fee_rate": "0.001",
   "taker_fee_rate": "0.002",
   "service_provider_fee": "0.4",
   "min_price_tick_size": "0.000000000000001",
   "min_quantity_tick_size": "1000000000000000"
  }
 ]
}
Parameter Type Description
markets SpotMarketInfo Array List of spot markets

SpotMarketInfo

Parameter Type Description
base_denom String Coin denom of the base asset
market_id String ID of the spot market of interest
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
quote_token_meta TokenMeta Token metadata for quote asset, only for Ethereum-based assets
service_provider_fee String Percentage of the transaction fee shared with the service provider
base_token_meta TokenMeta Token metadata for base asset, only for Ethereum-based assets
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
quote_denom String Coin denom of the quote asset
taker_fee_rate String Defines the fee percentage takers pay (in the quote asset) when trading
ticker String A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

StreamMarkets

Stream live updates of spot markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def market_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to spot markets updates ({exception})")


def stream_closed_processor():
    print("The spot markets updates stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.mainnet()
    client = AsyncClient(network)

    task = asyncio.get_event_loop().create_task(
        client.listen_spot_markets_updates(
            callback=market_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
    stream, err := exchangeClient.StreamSpotMarket(ctx, marketIds)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                fmt.Println(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_ids String Array List of market IDs for updates streaming, empty means 'ALL' spot markets No

Response Parameters

Streaming Response Example:

{
   "market":{
      "marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
      "marketStatus":"active",
      "ticker":"INJ/USDT",
      "baseDenom":"inj",
      "baseTokenMeta":{
         "name":"Injective Protocol",
         "address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
         "symbol":"INJ",
         "logo":"https://static.alchemyapi.io/images/assets/7226.png",
         "decimals":18,
         "updatedAt":1632535055751
      },
      "quoteDenom":"peggy0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
      "quoteTokenMeta":{
         "name":"Tether",
         "address":"0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
         "symbol":"USDT",
         "logo":"https://static.alchemyapi.io/images/assets/825.png",
         "decimals":6,
         "updatedAt":1632535055759
      },
      "makerFeeRate":"0.001",
      "takerFeeRate":"0.002",
      "serviceProviderRate":"0.4",
      "minPriceTickSize":"0.000000000000001",
      "minQuantityTickSize":"1000000000000000"
   },
   "operationType":"update",
   "timestamp":1632535055790
}
{
  "market": {
  "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
  "market_status": "active",
  "ticker": "INJ/USDT",
  "base_denom": "inj",
  "base_token_meta": {
    "name": "Injective Protocol",
    "address": "0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
    "symbol": "INJ",
    "logo": "https://static.alchemyapi.io/images/assets/7226.png",
    "decimals": 18,
    "updated_at": 1632535055751
  },
  "quote_denom": "peggy0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
  "quote_token_meta": {
    "name": "Tether",
    "address": "0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
    "symbol": "USDT",
    "logo": "https://static.alchemyapi.io/images/assets/825.png",
    "decimals": 6,
    "updated_at": 1632535055759
  },
  "maker_fee_rate": "0.001",
  "taker_fee_rate": "0.002",
  "service_provider_fee": "0.4",
  "min_price_tick_size": "0.000000000000001",
  "min_quantity_tick_size": "1000000000000000"
},
  "operation_type": "update",
  "timestamp": 1632535055790
}
Parameter Type Description
market SpotMarketInfo Info about particular spot market
operation_type String Update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis

SpotMarketInfo

Parameter Type Description
base_denom String Coin denom of the base asset
market_id String ID of the spot market of interest
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
quote_token_meta TokenMeta Token metadata for quote asset, only for Ethereum-based assets
service_provider_fee String Percentage of the transaction fee shared with the service provider
base_token_meta TokenMeta Token metadata for base asset, only for Ethereum-based assets
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
quote_denom String Coin denom of the quote asset
taker_fee_rate String Defines the fee percentage takers pay (in the quote asset) when trading
ticker String A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

OrdersHistory

List history of orders (all states) for a spot market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"]
    subaccount_id = "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000"
    skip = 10
    limit = 3
    order_types = ["buy_po"]
    pagination = PaginationOption(skip=skip, limit=limit)
    orders = await client.fetch_spot_orders_history(
        subaccount_id=subaccount_id,
        market_ids=market_ids,
        order_types=order_types,
        pagination=pagination,
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)
    orderTypes := []string{"buy_po"}

    req := spotExchangePB.OrdersHistoryRequest{
        SubaccountId: subaccountId,
        MarketId:     marketId,
        Skip:         skip,
        Limit:        limit,
        OrderTypes:   orderTypes,
    }

    res, err := exchangeClient.GetHistoricalSpotOrders(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID No
market_ids String Array Filter by multiple market IDs No
order_types String Array The order types to be included (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) No
direction String Filter by order direction (Should be one of: ["buy", "sell"]) No
state String The order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) No
execution_types String Array The execution of the order (Should be one of: ["limit", "market"]) No
trade_id String Filter by the trade's trade id No
active_markets_only Bool Return only orders for active markets No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "orders":[
      {
         "orderHash":"0x4e6629ce45597a3dc3941c5382cc7bc542d52fbcc6b03c4fd604c94a9bec0cc1",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"0.000000000000001",
         "triggerPrice":"0",
         "quantity":"1000000000000000",
         "filledQuantity":"1000000000000000",
         "state":"filled",
         "createdAt":"1668264339149",
         "updatedAt":"1682667017745",
         "direction":"buy",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "cid":""
      },
      {
         "orderHash":"0x347de654c8484fe36473c3569382ff27d25e95c660fd055163b7193607867a8b",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"0.000000000000001",
         "triggerPrice":"0",
         "quantity":"1000000000000000",
         "filledQuantity":"1000000000000000",
         "state":"filled",
         "createdAt":"1668264339149",
         "updatedAt":"1682667017745",
         "direction":"buy",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "cid":""
      },
      {
         "orderHash":"0x2141d52714f5c9328170cc674de8ecf876463b1999bea4124d1de595152b718f",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"0.000000000000001",
         "triggerPrice":"0",
         "quantity":"1000000000000000",
         "filledQuantity":"1000000000000000",
         "state":"filled",
         "createdAt":"1668264339149",
         "updatedAt":"1682667017745",
         "direction":"buy",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "cid":""
      }
   ],
   "paging":{
      "total":"1000",
      "from":0,
      "to":0,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "orders": [
  {
   "order_hash": "0x47a3858df766691a6124255a959ac17c79588fa36e52bed6d8aea2d927bb6a60",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000007789",
   "trigger_price": "0",
   "quantity": "12000000000000000000",
   "filled_quantity": "12000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x4a0f7bec21c2861ec390510f461ab94a6e4425453e113ba41d67c5e79a45538b",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000007692",
   "trigger_price": "0",
   "quantity": "14000000000000000000",
   "filled_quantity": "14000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x447b593a3c1683b64bd6ac4e60aa6ff22078951312eb3bfacf0b8b163eb015e4",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000005787",
   "trigger_price": "0",
   "quantity": "18000000000000000000",
   "filled_quantity": "18000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x77d1c86d0b04b3347ace0f4a7f708adbb160d54701891d0c212a8c28bb10f77f",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000005457",
   "trigger_price": "0",
   "quantity": "8000000000000000000",
   "filled_quantity": "8000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x76899c13fa3e591b1e2cbadfc2c84db5a7f4f97e42cee2451a6a90d04b100642",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000007134",
   "trigger_price": "0",
   "quantity": "4000000000000000000",
   "filled_quantity": "4000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0xf353711353a98ac3aceee62a4d7fed30e0c65cf38adfa898c455be5e5c671445",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000006138",
   "trigger_price": "0",
   "quantity": "2000000000000000000",
   "filled_quantity": "2000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0xb599db2124630b350e0ca2ea3453ece84e7721334e1009b451fa21d072a6cf8f",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000005667",
   "trigger_price": "0",
   "quantity": "22000000000000000000",
   "filled_quantity": "22000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x1c28300cfebfef73c26e32d396162e45089e34a5ba0c627cc8b6e3fb1d9861ad",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000006263",
   "trigger_price": "0",
   "quantity": "20000000000000000000",
   "filled_quantity": "20000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x7a2b9753c94c67f5e79e2f9dcd8af8a619d55d2f9ba1a134a22c5ef154b76e7f",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000007683",
   "trigger_price": "0",
   "quantity": "16000000000000000000",
   "filled_quantity": "16000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  },
  {
   "order_hash": "0x4984a08abefd29ba6bc914b11182251e18c0235842916955a4ffdc8ff149d188",
   "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy_po",
   "price": "0.000000000007668",
   "trigger_price": "0",
   "quantity": "6000000000000000000",
   "filled_quantity": "6000000000000000000",
   "state": "filled",
   "created_at": 1681812187591,
   "updated_at": 1681886620984,
   "direction": "buy"
  }
 ],
 "paging": {
  "total": 1000
 }
}

Parameter Type Description
orders SpotOrderHistory Array List of prior spot orders
paging Paging Pagination of results

SpotOrderHistory

Parameter Type Description
order_hash String Hash of the order
market_id String ID of the spot market
is_active Boolean Indicates if the order is active
subaccount_id String ID of the subaccount that the order belongs to
execution_type String The type of the order (Should be one of: ["limit", "market"])
order_type String Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"])
price String Price of the order
trigger_price String Trigger price used by stop/take orders
quantity String Quantity of the order
filled_quantity String The amount of the quantity filled
state String Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order created timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
direction String The direction of the order (Should be one of: ["buy", "sell"])
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

Paging

Parameter Type Description
total Integer Total number of available records

StreamOrdersHistory

Stream order updates for spot markets. If no parameters are given, updates to all subaccounts in all spot markets will be streamed.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def order_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to spot orders history updates ({exception})")


def stream_closed_processor():
    print("The spot orders history updates stream has been closed")


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    order_direction = "buy"

    task = asyncio.get_event_loop().create_task(
        client.listen_spot_orders_history_updates(
            callback=order_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            market_id=market_id,
            direction=order_direction,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
    direction := "buy"

    req := spotExchangePB.StreamOrdersHistoryRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Direction:    direction,
    }
    stream, err := exchangeClient.StreamHistoricalSpotOrders(ctx, &req)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                panic(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_id String Filter by market ID No
subaccount_id String Filter by subaccount ID No
direction String Filter by direction (Should be one of: ["buy", "sell"]) No
state String Filter by state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) No
order_types String Array Filter by order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) No
execution_types String Array Filter by execution type (Should be one of: ["limit", "market"]) No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "order":{
      "orderHash":"0xff6a1ce6339911bb6f0765e17e70144ae62834e65e551e910018203d62bc6d12",
      "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
      "subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
      "executionType":"limit",
      "orderType":"buy_po",
      "price":"0.000000000019028",
      "triggerPrice":"0",
      "quantity":"67129093000000000000000",
      "filledQuantity":"0",
      "state":"canceled",
      "createdAt":"1702044186286",
      "updatedAt":"1702044188683",
      "direction":"buy",
      "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
      "isActive":false,
      "cid":""
   },
   "operationType":"update",
   "timestamp":"1702044191000"
}
{
 "order": {
  "order_hash": "0xf8a90ee4cfb4c938035b791d3b3561e8991803793b4b5590164b2ecbfa247f3d",
  "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
  "subaccount_id": "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
  "execution_type": "limit",
  "order_type": "buy_po",
  "price": "0.000000000007438",
  "trigger_price": "0",
  "quantity": "76848283000000000000000",
  "filled_quantity": "0",
  "state": "canceled",
  "created_at": 1696621893030,
  "updated_at": 1696621895445,
  "direction": "buy"
 },
 "operation_type": "update",
 "timestamp": 1696621898000
}{
 "order": {
  "order_hash": "0xfd6bf489944cb181ee94057b80ffdfc113a17d48d0455c8d10e4deadf341bdfd",
  "market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
  "subaccount_id": "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
  "execution_type": "limit",
  "order_type": "buy_po",
  "price": "0.000000000007478",
  "trigger_price": "0",
  "quantity": "76437220000000000000000",
  "filled_quantity": "0",
  "state": "canceled",
  "created_at": 1696621893030,
  "updated_at": 1696621895445,
  "direction": "buy"
 },
 "operation_type": "update",
 "timestamp": 1696621898000
}
Parameter Type Description
order SpotOrderHistory Updated Order
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis

SpotOrderHistory

Parameter Type Description
order_hash String Hash of the order
market_id String ID of the spot market
is_active Boolean Indicates if the order is active
subaccount_id String ID of the subaccount that the order belongs to
execution_type String The type of the order (Should be one of: ["limit", "market"])
order_type String Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"])
price String Price of the order
trigger_price String Trigger price used by stop/take orders
quantity String Quantity of the order
filled_quantity String The amount of the quantity filled
state String Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order created timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
direction String The direction of the order (Should be one of: ["buy", "sell"])
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

TradesV2

Get trade history for a spot market. The default request returns all spot trades from all markets.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"]
    execution_side = "taker"
    direction = "buy"
    subaccount_ids = ["0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"]
    execution_types = ["limitMatchNewOrder", "market"]
    orders = await client.fetch_spot_trades(
        market_ids=market_ids,
        subaccount_ids=subaccount_ids,
        execution_side=execution_side,
        direction=direction,
        execution_types=execution_types,
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"

    req := spotExchangePB.TradesV2Request{
        MarketId:     marketId,
        SubaccountId: subaccountId,
    }

    res, err := exchangeClient.GetSpotTradesV2(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_ids String Array Filter by multiple market IDs No
subaccount_ids String Array Filter by multiple subaccount IDs No
execution_side String Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) No
direction String Filter by the direction of the trade (Should be one of: ["buy", "sell"]) No
execution_types String Array Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) No
trade_id String Filter by the trade id of the trade No
account_address String Filter by the account address No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "trades":[
      {
         "orderHash":"0x952bb14a7a377697d724c60d6077ef3dfe894c98f854970fab187247be832b6f",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
         "tradeExecutionType":"limitMatchRestingOrder",
         "tradeDirection":"buy",
         "price":{
            "price":"0.00000000001",
            "quantity":"1000000000000000000",
            "timestamp":"1701961116630"
         },
         "fee":"-600",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_0",
         "executionSide":"maker",
         "cid":"96866b8b-02dd-4288-97d3-e5254e4888b3"
      },
      {
         "orderHash":"0x85a824c31f59cf68235b48666c4821334813f2b80db937f02d192f1e3fc74368",
         "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
         "marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
         "tradeExecutionType":"limitMatchNewOrder",
         "tradeDirection":"sell",
         "price":{
            "price":"0.00000000001",
            "quantity":"1000000000000000000",
            "timestamp":"1701961116630"
         },
         "fee":"10000",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_1",
         "executionSide":"taker",
         "cid":"spot_AAVE/USDT"
      },
      {
         "orderHash":"0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
         "tradeExecutionType":"limitMatchRestingOrder",
         "tradeDirection":"buy",
         "price":{
            "price":"0.00000000001",
            "quantity":"2000000000000000000",
            "timestamp":"1701960607140"
         },
         "fee":"-2400",
         "executedAt":"1701960607140",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"646_0",
         "executionSide":"maker",
         "cid":"ec581735-f801-4bf3-9101-282b301bf5cd"
      },
      {
         "orderHash":"0xa19e24eef9877ec4980b8d259c1d21fa1dafcd50691e6f853e84af74fb23c05c",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
         "tradeExecutionType":"limitMatchNewOrder",
         "tradeDirection":"sell",
         "price":{
            "price":"0.00000000001",
            "quantity":"2000000000000000000",
            "timestamp":"1701960607140"
         },
         "fee":"40000",
         "executedAt":"1701960607140",
         "feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
         "tradeId":"646_1",
         "executionSide":"taker",
         "cid":""
      },
      {
         "orderHash":"0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
         "tradeExecutionType":"limitMatchRestingOrder",
         "tradeDirection":"buy",
         "price":{
            "price":"0.00000000001",
            "quantity":"8000000000000000000",
            "timestamp":"1701960594997"
         },
         "fee":"-9600",
         "executedAt":"1701960594997",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"630_0",
         "executionSide":"maker",
         "cid":"ec581735-f801-4bf3-9101-282b301bf5cd"
      },
      {
         "orderHash":"0x87b786072190a2f38e9057987be7bdcb4e2274a6c16fdb9670e5c2ded765140f",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
         "tradeExecutionType":"limitMatchNewOrder",
         "tradeDirection":"sell",
         "price":{
            "price":"0.00000000001",
            "quantity":"8000000000000000000",
            "timestamp":"1701960594997"
         },
         "fee":"160000",
         "executedAt":"1701960594997",
         "feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
         "tradeId":"630_1",
         "executionSide":"taker",
         "cid":""
      }
   ],
   "paging":{
      "total":"6",
      "from":1,
      "to":6,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}

{
 "trades": [
  {
   "order_hash": "0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
   "subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitMatchRestingOrder",
   "trade_direction": "buy",
   "price": {
    "price": "0.00000000001",
    "quantity": "2000000000000000000",
    "timestamp": 1701960607140
   },
   "fee": "-2400",
   "executed_at": 1701960607140,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "646_0",
   "execution_side": "maker",
   "cid": "ec581735-f801-4bf3-9101-282b301bf5cd"
  },
  {
   "order_hash": "0xa19e24eef9877ec4980b8d259c1d21fa1dafcd50691e6f853e84af74fb23c05c",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitMatchNewOrder",
   "trade_direction": "sell",
   "price": {
    "price": "0.00000000001",
    "quantity": "2000000000000000000",
    "timestamp": 1701960607140
   },
   "fee": "40000",
   "executed_at": 1701960607140,
   "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
   "trade_id": "646_1",
   "execution_side": "taker"
  },
  {
   "order_hash": "0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
   "subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitMatchRestingOrder",
   "trade_direction": "buy",
   "price": {
    "price": "0.00000000001",
    "quantity": "8000000000000000000",
    "timestamp": 1701960594997
   },
   "fee": "-9600",
   "executed_at": 1701960594997,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "630_0",
   "execution_side": "maker",
   "cid": "ec581735-f801-4bf3-9101-282b301bf5cd"
  },
  {
   "order_hash": "0x87b786072190a2f38e9057987be7bdcb4e2274a6c16fdb9670e5c2ded765140f",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitMatchNewOrder",
   "trade_direction": "sell",
   "price": {
    "price": "0.00000000001",
    "quantity": "8000000000000000000",
    "timestamp": 1701960594997
   },
   "fee": "160000",
   "executed_at": 1701960594997,
   "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
   "trade_id": "630_1",
   "execution_side": "taker"
  }
 ],
 "paging": {
  "total": 4,
  "from": 1,
  "to": 4
 }
}

Parameter Type Description
trades SpotTrade Array Trades of a particular spot market
paging Paging Pagination of results

SpotTrade

Parameter Type Description
order_hash String The order hash
subaccount_id String The subaccountId that executed the trade
market_id String The ID of the market that this trade is in
trade_execution_type String Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"])
trade_direction String Direction of the trade(Should be one of: ["buy", "sell"])
price PriceLevel Price level at which trade has been executed
fee String The fee associated with the trade (quote asset denom)
executed_at Integer Timestamp of trade execution (on chain) in UNIX millis
fee_recipient String The address that received 40% of the fees
trade_id String Unique identifier to differentiate between trades
execution_side String Execution side of trade (Should be one of: ["maker", "taker"])
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

Paging

Parameter Type Description
total Integer Total number of records available

StreamTradesV2

Stream newly executed trades of spot markets. The default request streams trades from all spot markets.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def trade_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to spot trades updates ({exception})")


def stream_closed_processor():
    print("The spot trades updates stream has been closed")


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
        "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
    ]
    execution_side = "maker"
    direction = "sell"
    subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
    execution_types = ["limitMatchRestingOrder"]

    task = asyncio.get_event_loop().create_task(
        client.listen_spot_trades_updates(
            callback=trade_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            market_ids=market_ids,
            subaccount_ids=[subaccount_id],
            execution_side=execution_side,
            direction=direction,
            execution_types=execution_types,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"

    req := spotExchangePB.StreamTradesV2Request{
        MarketId:     marketId,
        SubaccountId: subaccountId,
    }
    stream, err := exchangeClient.StreamSpotTradesV2(ctx, &req)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                fmt.Println(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_ids String Array Filter by multiple market IDs No
subaccount_ids String Array Filter by multiple subaccount IDs No
execution_side String Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) No
direction String Filter by the direction of the trade (Should be one of: ["buy", "sell"]) No
execution_types String Array Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) No
trade_id String Filter by the trade's trade id No
account_address String Filter by the account address No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "trade":{
      "orderHash":"0xa7f4a7d85136d97108d271caadd93bf697ff965790e0e1558617b953cced4adc",
      "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
      "marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
      "tradeExecutionType":"limitMatchNewOrder",
      "tradeDirection":"sell",
      "price":{
         "price":"0.00000000001",
         "quantity":"1000000000000000000",
         "timestamp":"1701978102242"
      },
      "fee":"10000",
      "executedAt":"1701978102242",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"22868_1",
      "executionSide":"taker",
      "cid":"96866b8b-02dd-4288-97d3-e5254e4999d4"
   },
   "operationType":"insert",
   "timestamp":"1701978103000"
}
{
   "trade":{
      "orderHash":"0x952bb14a7a377697d724c60d6077ef3dfe894c98f854970fab187247be832b6f",
      "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
      "marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
      "tradeExecutionType":"limitMatchRestingOrder",
      "tradeDirection":"buy",
      "price":{
         "price":"0.00000000001",
         "quantity":"1000000000000000000",
         "timestamp":"1701978102242"
      },
      "fee":"-600",
      "executedAt":"1701978102242",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"22868_0",
      "executionSide":"maker",
      "cid":"96866b8b-02dd-4288-97d3-e5254e4888b3"
   },
   "operationType":"insert",
   "timestamp":"1701978103000"
}
{
 "trade": {
  "order_hash": "0x88e34872af0147f57c8c5a093c3a6a8a97358615bccf975b4a06dfb5162daeaf",
  "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
  "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
  "trade_execution_type": "market",
  "trade_direction": "sell",
  "price": {
   "price": "0.000000000001654",
   "quantity": "1000000000000000000",
   "timestamp": 1653042087046
  },
  "fee": "3308",
  "executed_at": 1653042087046,
  "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
 },
 "operation_type": "insert",
 "timestamp": 1653042089000
}{
 "trade": {
  "order_hash": "0xb5d651a01faa90ec53b0fa34f00f3ecdfe169f9fc35be8114ee113eea9257c30",
  "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
  "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
  "trade_execution_type": "market",
  "trade_direction": "sell",
  "price": {
   "price": "0.000000000001654",
   "quantity": "2000000000000000000",
   "timestamp": 1653042093023
  },
  "fee": "6616",
  "executed_at": 1653042093023,
  "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
 },
 "operation_type": "insert",
 "timestamp": 1653042098000
}
Parameter Type Description
trade SpotTrade New spot market trade
operation_type String Trade operation type (Should be one of: ["insert", "invalidate"])
timestamp Integer Timestamp the new trade is written into the database in UNIX millis

SpotTrade

Parameter Type Description
order_hash String The order hash
subaccount_id String The subaccountId that executed the trade
market_id String The ID of the market that this trade is in
trade_execution_type String Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"])
trade_direction String Direction of the trade(Should be one of: ["buy", "sell"])
price PriceLevel Price level at which trade has been executed
fee String The fee associated with the trade (quote asset denom)
executed_at Integer Timestamp of trade execution (on chain) in UNIX millis
fee_recipient String The address that received 40% of the fees
trade_id String Unique identifier to differentiate between trades
execution_side String Execution side of trade (Should be one of: ["maker", "taker"])
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

OrderbooksV2

Get an orderbook snapshot for one or more spot markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
        "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
    ]
    orderbooks = await client.fetch_spot_orderbooks_v2(market_ids=market_ids)
    print(orderbooks)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
    res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_ids String Array List of IDs of markets to get orderbook snapshots from Yes

Response Parameters

Response Example:

{
   "orderbooks":[
      {
         "marketId":"0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
         "orderbook":{
            "sells":[
               {
                  "price":"0.000000000005",
                  "quantity":"27767884000000000000000",
                  "timestamp":"1694702425539"
               },
               {
                  "price":"0.0000000000045",
                  "quantity":"3519999000000000000000000",
                  "timestamp":"1694424758707"
               }
            ],
            "timestamp":"-62135596800000",
            "buys":[

            ],
            "sequence":"0"
         }
      },
      {
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "orderbook":{
            "buys":[
               {
                  "price":"0.000000000073489",
                  "quantity":"129000000000000000",
                  "timestamp":"1702042963690"
               },
               {
                  "price":"0.000000000064261",
                  "quantity":"1292000000000000000",
                  "timestamp":"1702039612697"
               }
            ],
            "sells":[
               {
                  "price":"0.000000000085",
                  "quantity":"6693248000000000000000",
                  "timestamp":"1702044317059"
               },
               {
                  "price":"0.000000000085768",
                  "quantity":"581000000000000000",
                  "timestamp":"1701944786578"
               }
            ],
            "sequence":"6916386",
            "timestamp":"1702044336800"
         }
      }
   ]
}

Parameter Type Description
orderbooks SingleSpotLimitOrderbookV2 Array List of spot market orderbooks with market IDs

SingleSpotLimitOrderbookV2

Parameter Type Description
market_id String ID of spot market
orderbook SpotLimitOrderBookV2 Orderbook of the market

SpotLimitOrderbookV2

Parameter Type Description
buys PriceLevel Array List of price levels for buys
sells PriceLevel Array List of price levels for sells
sequence Integer Sequence number of the orderbook; increments by 1 each update

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

StreamOrderbooksV2

Stream orderbook snapshot updates for one or more spot markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def orderbook_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to spot orderbook snapshots ({exception})")


def stream_closed_processor():
    print("The spot orderbook snapshots stream has been closed")


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
        "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
    ]

    task = asyncio.get_event_loop().create_task(
        client.listen_spot_orderbook_snapshots(
            market_ids=market_ids,
            callback=orderbook_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("devnet-1", "")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
    stream, err := exchangeClient.StreamSpotOrderbookV2(ctx, marketIds)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                fmt.Println(err)
                return
            }
            fmt.Println(res.MarketId, res.Orderbook, len(res.Orderbook.Sells), len(res.Orderbook.Buys))
        }
    }
}
Parameter Type Description Required
market_ids String Array List of market IDs for orderbook streaming; empty means all spot markets Yes
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "orderbook":{
      "buys":[
         {
            "price":"0.000000000073489",
            "quantity":"129000000000000000",
            "timestamp":"1702042963690"
         },
         {
            "price":"0.000000000064261",
            "quantity":"1292000000000000000",
            "timestamp":"1702039612697"
         }
      ],
      "sells":[
         {
            "price":"0.000000000085",
            "quantity":"6681507000000000000000",
            "timestamp":"1702044411262"
         },
         {
            "price":"0.000000000085768",
            "quantity":"581000000000000000",
            "timestamp":"1701944786578"
         }
      ],
      "sequence":"6916434",
      "timestamp":"1702044439698"
   },
   "operationType":"update",
   "timestamp":"1702044441000",
   "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
}

Parameter Type Description
orderbook SpotLimitOrderbookV2 Orderbook of a Spot Market
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis
market_id String ID of the market the orderbook belongs to

SpotLimitOrderbookV2

Parameter Type Description
buys PriceLevel Array List of price levels for buys
sells PriceLevel Array List of price levels for sells
sequence Integer Sequence number of the orderbook; increments by 1 each update

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

StreamOrderbookUpdate

Stream incremental orderbook updates for one or more spot markets. This stream should be started prior to obtaining orderbook snapshots so that no incremental updates are omitted between obtaining a snapshot and starting the update stream.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from decimal import Decimal
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to spot orderbook updates ({exception})")


def stream_closed_processor():
    print("The spot orderbook updates stream has been closed")


class PriceLevel:
    def __init__(self, price: Decimal, quantity: Decimal, timestamp: int):
        self.price = price
        self.quantity = quantity
        self.timestamp = timestamp

    def __str__(self) -> str:
        return "price: {} | quantity: {} | timestamp: {}".format(self.price, self.quantity, self.timestamp)


class Orderbook:
    def __init__(self, market_id: str):
        self.market_id = market_id
        self.sequence = -1
        self.levels = {"buys": {}, "sells": {}}


async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderbook):
    # load the snapshot
    res = await async_client.fetch_spot_orderbooks_v2(market_ids=[orderbook.market_id])
    for snapshot in res["orderbooks"]:
        if snapshot["marketId"] != orderbook.market_id:
            raise Exception("unexpected snapshot")

        orderbook.sequence = int(snapshot["orderbook"]["sequence"])

        for buy in snapshot["orderbook"]["buys"]:
            orderbook.levels["buys"][buy["price"]] = PriceLevel(
                price=Decimal(buy["price"]),
                quantity=Decimal(buy["quantity"]),
                timestamp=int(buy["timestamp"]),
            )
        for sell in snapshot["orderbook"]["sells"]:
            orderbook.levels["sells"][sell["price"]] = PriceLevel(
                price=Decimal(sell["price"]),
                quantity=Decimal(sell["quantity"]),
                timestamp=int(sell["timestamp"]),
            )
        break


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    async_client = AsyncClient(network)

    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    orderbook = Orderbook(market_id=market_id)
    updates_queue = asyncio.Queue()
    tasks = []

    async def queue_event(event: Dict[str, Any]):
        await updates_queue.put(event)

    # start getting price levels updates
    task = asyncio.get_event_loop().create_task(
        async_client.listen_spot_orderbook_updates(
            market_ids=[market_id],
            callback=queue_event,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )
    tasks.append(task)

    # load the snapshot once we are already receiving updates, so we don't miss any
    await load_orderbook_snapshot(async_client=async_client, orderbook=orderbook)

    task = asyncio.get_event_loop().create_task(
        apply_orderbook_update(orderbook=orderbook, updates_queue=updates_queue)
    )
    tasks.append(task)

    await asyncio.sleep(delay=60)
    for task in tasks:
        task.cancel()


async def apply_orderbook_update(orderbook: Orderbook, updates_queue: asyncio.Queue):
    while True:
        updates = await updates_queue.get()
        update = updates["orderbookLevelUpdates"]

        # discard updates older than the snapshot
        if int(update["sequence"]) <= orderbook.sequence:
            return

        print(" * * * * * * * * * * * * * * * * * * *")

        # ensure we have not missed any update
        if int(update["sequence"]) > (orderbook.sequence + 1):
            raise Exception(
                "missing orderbook update events from stream, must restart: {} vs {}".format(
                    update["sequence"], (orderbook.sequence + 1)
                )
            )

        print("updating orderbook with updates at sequence {}".format(update["sequence"]))

        # update orderbook
        orderbook.sequence = int(update["sequence"])
        for direction, levels in {"buys": update["buys"], "sells": update["sells"]}.items():
            for level in levels:
                if level["isActive"]:
                    # upsert level
                    orderbook.levels[direction][level["price"]] = PriceLevel(
                        price=Decimal(level["price"]), quantity=Decimal(level["quantity"]), timestamp=level["timestamp"]
                    )
                else:
                    if level["price"] in orderbook.levels[direction]:
                        del orderbook.levels[direction][level["price"]]

        # sort the level numerically
        buys = sorted(orderbook.levels["buys"].values(), key=lambda x: x.price, reverse=True)
        sells = sorted(orderbook.levels["sells"].values(), key=lambda x: x.price, reverse=True)

        # lowest sell price should be higher than the highest buy price
        if len(buys) > 0 and len(sells) > 0:
            highest_buy = buys[0].price
            lowest_sell = sells[-1].price
            print("Max buy: {} - Min sell: {}".format(highest_buy, lowest_sell))
            if highest_buy >= lowest_sell:
                raise Exception("crossed orderbook, must restart")

        # for the example, print the list of buys and sells orders.
        print("sells")
        for k in sells:
            print(k)
        print("=========")
        print("buys")
        for k in buys:
            print(k)
        print("====================================")


if __name__ == "__main__":
    asyncio.run(main())
package main

import (
    "context"
    "fmt"
    "io"
    "os"
    "sort"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
    "github.com/shopspring/decimal"
)

type MapOrderbook struct {
    Sequence uint64
    Levels   map[bool]map[string]*spotExchangePB.PriceLevel
}

func main() {
    network := common.LoadNetwork("devnet-1", "")
    exchangeClient, err := exchangeclient.NewExchangeClient(network.ExchangeGrpcEndpoint)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
    stream, err := exchangeClient.StreamSpotOrderbookUpdate(ctx, marketIds)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    updatesCh := make(chan *spotExchangePB.OrderbookLevelUpdates, 100000)
    receiving := make(chan struct{})
    var receivingClosed bool

    // stream orderbook price levels
    go func() {
        for {
            select {
            case <-ctx.Done():
                return
            default:
                res, err := stream.Recv()
                if err == io.EOF {
                    fmt.Println("change stream needs to be restarted")
                    os.Exit(0)
                }
                if err != nil {
                    panic(err) // rester on errors
                }
                u := res.OrderbookLevelUpdates
                if !receivingClosed {
                    fmt.Println("receiving updates from stream")
                    close(receiving)
                    receivingClosed = true
                }
                updatesCh <- u
            }
        }
    }()

    // ensure we are receiving updates before getting the orderbook snapshot,
    // we will skip past updates later.
    fmt.Println("waiting for streaming updates")
    <-receiving

    // prepare orderbooks map
    orderbooks := map[string]*MapOrderbook{}
    res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
    if err != nil {
        panic(err)
    }
    for _, ob := range res.Orderbooks {
        // init inner maps not ready
        _, ok := orderbooks[ob.MarketId]
        if !ok {
            orderbook := &MapOrderbook{
                Sequence: ob.Orderbook.Sequence,
                Levels:   map[bool]map[string]*spotExchangePB.PriceLevel{},
            }
            orderbook.Levels[true] = map[string]*spotExchangePB.PriceLevel{}
            orderbook.Levels[false] = map[string]*spotExchangePB.PriceLevel{}
            orderbooks[ob.MarketId] = orderbook
        }

        for _, level := range ob.Orderbook.Buys {
            orderbooks[ob.MarketId].Levels[true][level.Price] = level
        }
        for _, level := range ob.Orderbook.Sells {
            orderbooks[ob.MarketId].Levels[false][level.Price] = level
        }
    }

    // continuously consume level updates and maintain orderbook
    skippedPastEvents := false
    for {
        updates := <-updatesCh

        // validate orderbook
        orderbook, ok := orderbooks[updates.MarketId]
        if !ok {
            fmt.Println("updates channel closed, must restart")
            return // closed
        }

        // skip if update sequence <= orderbook sequence until it's ready to consume
        if !skippedPastEvents {
            if orderbook.Sequence >= updates.Sequence {
                continue
            }
            skippedPastEvents = true
        }

        // panic if update sequence > orderbook sequence + 1
        if updates.Sequence > orderbook.Sequence+1 {
            fmt.Printf("skipping levels: update sequence %d vs orderbook sequence %d\n", updates.Sequence, orderbook.Sequence)
            panic("missing orderbook update events from stream, must restart")
        }

        // update orderbook map
        orderbook.Sequence = updates.Sequence
        for isBuy, update := range map[bool][]*spotExchangePB.PriceLevelUpdate{
            true:  updates.Buys,
            false: updates.Sells,
        } {
            for _, level := range update {
                if level.IsActive {
                    // upsert
                    orderbook.Levels[isBuy][level.Price] = &spotExchangePB.PriceLevel{
                        Price:     level.Price,
                        Quantity:  level.Quantity,
                        Timestamp: level.Timestamp,
                    }
                } else {
                    // remove inactive level
                    delete(orderbook.Levels[isBuy], level.Price)
                }
            }
        }

        // construct orderbook arrays
        sells, buys := maintainOrderbook(orderbook.Levels)
        fmt.Println("after", orderbook.Sequence, len(sells), len(buys))

        if len(sells) > 0 && len(buys) > 0 {
            // assert orderbook
            topBuyPrice := decimal.RequireFromString(buys[0].Price)
            lowestSellPrice := decimal.RequireFromString(sells[0].Price)
            if topBuyPrice.GreaterThanOrEqual(lowestSellPrice) {
                panic(fmt.Errorf("crossed orderbook, must restart: buy %s >= %s sell", topBuyPrice, lowestSellPrice))
            }
        }

        res, _ = exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
        fmt.Println("query", res.Orderbooks[0].Orderbook.Sequence, len(res.Orderbooks[0].Orderbook.Sells), len(res.Orderbooks[0].Orderbook.Buys))

        // print orderbook
        fmt.Println(" [SELLS] ========")
        for _, s := range sells {
            fmt.Println(s)
        }
        fmt.Println(" [BUYS] ========")
        for _, b := range buys {
            fmt.Println(b)
        }
        fmt.Println("=======================================================")
    }
}

func maintainOrderbook(orderbook map[bool]map[string]*spotExchangePB.PriceLevel) (buys, sells []*spotExchangePB.PriceLevel) {
    for _, v := range orderbook[false] {
        sells = append(sells, v)
    }
    for _, v := range orderbook[true] {
        buys = append(buys, v)
    }

    sort.Slice(sells, func(i, j int) bool {
        return decimal.RequireFromString(sells[i].Price).LessThan(decimal.RequireFromString(sells[j].Price))
    })

    sort.Slice(buys, func(i, j int) bool {
        return decimal.RequireFromString(buys[i].Price).GreaterThan(decimal.RequireFromString(buys[j].Price))
    })

    return sells, buys
}
Parameter Type Description Required
market_ids String Array List of market IDs for orderbook streaming; empty means all spot markets Yes
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

 * * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 724
Max buy: 7.523E-12 - Min sell: 7.525E-12
sells
price: 8E-12 | quantity: 10000000000000000 | timestamp: 1675904636889
price: 7.526E-12 | quantity: 50000000000000000 | timestamp: 1676089482358
price: 7.525E-12 | quantity: 10000000000000000 | timestamp: 1676015247335
=========
buys
price: 7.523E-12 | quantity: 30000000000000000 | timestamp: 1676616192052
price: 7E-12 | quantity: 1000000000000000000 | timestamp: 1675904400063
price: 1E-12 | quantity: 10000000000000000 | timestamp: 1675882430039
price: 1E-15 | quantity: 17983000000000000000 | timestamp: 1675880932648
====================================
 * * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 725
Max buy: 7.523E-12 - Min sell: 7.525E-12
sells
price: 8E-12 | quantity: 10000000000000000 | timestamp: 1675904636889
price: 7.526E-12 | quantity: 50000000000000000 | timestamp: 1676089482358
price: 7.525E-12 | quantity: 10000000000000000 | timestamp: 1676015247335
=========
buys
price: 7.523E-12 | quantity: 40000000000000000 | timestamp: 1676616222476
price: 7E-12 | quantity: 1000000000000000000 | timestamp: 1675904400063
price: 1E-12 | quantity: 10000000000000000 | timestamp: 1675882430039
price: 1E-15 | quantity: 17983000000000000000 | timestamp: 1675880932648
====================================

Parameter Type Description
orderbook_level_updates OrderbookLevelUpdates Orderbook level updates of a spot market
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis
market_id String ID of the market the orderbook belongs to

OrderbookLevelUpdates

Parameter Type Description
market_id String ID of the market the orderbook belongs to
sequence Integer Orderbook update sequence number; increments by 1 each update
buys PriceLevelUpdate Array List of buy level updates
sells PriceLevelUpdate Array List of sell level updates
updated_at Integer Timestamp of the updates in UNIX millis

PriceLevelUpdate

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
is_active Boolean Price level status
timestamp Integer Price level last updated timestamp in UNIX millis

SubaccountOrdersList

Get orders of a subaccount.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    skip = 10
    limit = 10
    pagination = PaginationOption(skip=skip, limit=limit)
    orders = await client.fetch_spot_subaccount_orders_list(
        subaccount_id=subaccount_id, market_id=market_id, pagination=pagination
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    subaccountId := "0x0b46e339708ea4d87bd2fcc61614e109ac374bbe000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)

    req := spotExchangePB.SubaccountOrdersListRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Skip:         skip,
        Limit:        limit,
    }

    res, err := exchangeClient.GetSubaccountSpotOrdersList(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
market_id String Filter by market ID No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "orders":[
      {
         "orderHash":"0x3414f6f1a37a864166b19930680eb62a99798b5e406c2d14ed1ee66ab9958503",
         "orderSide":"buy",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
         "price":"0.000000000003",
         "quantity":"55000000000000000000",
         "unfilledQuantity":"55000000000000000000",
         "triggerPrice":"0",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "state":"booked",
         "createdAt":"1701808096494",
         "updatedAt":"1701808096494",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "cid":"670c52ec-f68f-456c-8aeb-e271071a43ac"
      },
      {
         "orderHash":"0xb7b6d54d1e01e1eb0005e34e08a96b715b557eeee7c5f3a439636f98ddd66b91",
         "orderSide":"buy",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
         "price":"0.000000000003",
         "quantity":"55000000000000000000",
         "unfilledQuantity":"55000000000000000000",
         "triggerPrice":"0",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "state":"booked",
         "createdAt":"1701808058512",
         "updatedAt":"1701808058512",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "cid":"bba97476-e7f4-4313-874b-7ef115daccb4"
      }
   ],
   "paging":{
      "total":"53",
      "from":1,
      "to":2,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "orders": [
  {
   "order_hash": "0x5e970df47eb5a65a5f907e3a2912067dde416eca8609c838e08c0dbebfbefaa5",
   "order_side": "sell",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "price": "0.000000000005",
   "quantity": "1000000000000000000",
   "unfilled_quantity": "1000000000000000000",
   "trigger_price": "0",
   "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
   "state": "booked",
   "created_at": 1652809317404,
   "updated_at": 1652809317404
  },
  {
   "order_hash": "0x318418b546563a75c11dc656ee0fb41608e2893b0de859cf2b9e2d65996b6f9c",
   "order_side": "buy",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "price": "0.000000000001",
   "quantity": "1000000000000000000",
   "unfilled_quantity": "1000000000000000000",
   "trigger_price": "0",
   "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
   "state": "booked",
   "created_at": 1652809253308,
   "updated_at": 1652809253308
  }
 ]
}
Parameter Type Description
orders SpotLimitOrder Array List of spot market orders
paging Paging Pagination of results

SpotLimitOrder

Parameter Type Description
order_hash String Hash of the order
order_side String The side of the order (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell"])
market_id String ID of the market the order belongs to
subaccount_id String The subaccount ID the order belongs to
price String The price of the order
quantity String The quantity of the order
unfilled_quantity String The amount of the quantity remaining unfilled
trigger_price String The price that triggers stop and take orders. If no price is set, the default is 0
fee_recipient String The address that receives fees if the order is executed
state String State of the order (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order committed timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

Paging

Parameter Type Description
total Integer Total number of available records
from Integer Lower bound of indices of records returned
to integer Upper bound of indices of records returned

SubaccountTradesList

Get trades of a subaccount.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    execution_type = "market"
    direction = "buy"
    skip = 2
    limit = 3
    pagination = PaginationOption(skip=skip, limit=limit)
    trades = await client.fetch_spot_subaccount_trades_list(
        subaccount_id=subaccount_id,
        market_id=market_id,
        execution_type=execution_type,
        direction=direction,
        pagination=pagination,
    )
    print(trades)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)

    req := spotExchangePB.SubaccountTradesListRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Skip:         skip,
        Limit:        limit,
    }

    res, err := exchangeClient.GetSubaccountSpotTradesList(ctx, &req)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
market_id String Filter by market ID No
execution_type String Filter by the *execution type of the trades (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) No
direction String Filter by the direction of the trades (Should be one of: ["buy", "sell"]) No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "trades":[
      {
         "orderHash":"0x6dfd01151a5b3cfb3a61777335f0d8d324a479b9006fd9642f52b402aec53d4f",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "tradeExecutionType":"market",
         "tradeDirection":"buy",
         "price":{
            "price":"0.000000000015589",
            "quantity":"1000000000000000",
            "timestamp":"1700675201676"
         },
         "fee":"10.9123",
         "executedAt":"1700675201676",
         "feeRecipient":"inj1zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3t5qxqh",
         "tradeId":"18740619_240_0",
         "executionSide":"taker",
         "cid":""
      },
      {
         "orderHash":"0x6a6cd0afb038322b67a88cd827e2800483e3571c5e82663df37a33770fa0a8d1",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "tradeExecutionType":"market",
         "tradeDirection":"buy",
         "price":{
            "price":"0.000000000015742",
            "quantity":"1000000000000000",
            "timestamp":"1700232025894"
         },
         "fee":"11.0194",
         "executedAt":"1700232025894",
         "feeRecipient":"inj1zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3t5qxqh",
         "tradeId":"18529043_240_0",
         "executionSide":"taker",
         "cid":""
      },
      {
         "orderHash":"0xa3049ebaa97ac3755c09bd53ea30e86b98aef40bf037cb9d91dedfc1fd4b7735",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
         "tradeExecutionType":"limitMatchNewOrder",
         "tradeDirection":"buy",
         "price":{
            "price":"0.000000000015874",
            "quantity":"21000000000000000000",
            "timestamp":"1700221121919"
         },
         "fee":"233347.8",
         "executedAt":"1700221121919",
         "feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
         "tradeId":"18523837_243_0",
         "executionSide":"taker",
         "cid":""
      }
   ]
}
{
 "trades": [
  {
   "order_hash": "0xbf5cf18a5e73c61d465a60ca550c5fbe0ed37b9ca0a49f7bd1de012e983fe55e",
   "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitFill",
   "trade_direction": "sell",
   "price": {
    "price": "0.000000000002305",
    "quantity": "1000000000000000000",
    "timestamp": 1652809734211
   },
   "fee": "2305",
   "executed_at": 1652809734211,
   "fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
  },
  {
   "order_hash": "0xfd474dc696dc291bca8ca1b371653994fd846a303c08d26ccc17a7b60939d256",
   "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
   "market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
   "trade_execution_type": "limitFill",
   "trade_direction": "sell",
   "price": {
    "price": "0.000000000002318",
    "quantity": "4000000000000000000",
    "timestamp": 1652773190338
   },
   "fee": "9272",
   "executed_at": 1652773190338,
   "fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
  }
 ]
}

Parameter Type Description
trades SpotTrade Array List of spot market trades

SpotTrade

Parameter Type Description
order_hash String The order hash
subaccount_id String The subaccountId that executed the trade
market_id String The ID of the market that this trade is in
trade_execution_type String Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"])
trade_direction String Direction of the trade(Should be one of: ["buy", "sell"])
price PriceLevel Price level at which trade has been executed
fee String The fee associated with the trade (quote asset denom)
executed_at Integer Timestamp of trade execution (on chain) in UNIX millis
fee_recipient String The address that received 40% of the fees
trade_id String Unique identifier to differentiate between trades
execution_side String Execution side of trade (Should be one of: ["maker", "taker"])
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

- InjectiveDerivativeExchangeRPC

InjectiveDerivativeExchangeRPC defines the gRPC API of the Derivative Exchange provider.

Market

Get details of a single derivative market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    market = await client.fetch_derivative_market(market_id=market_id)
    print(market)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    res, err := exchangeClient.GetDerivativeMarket(ctx, marketId)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_id String ID of the market to fetch Yes

Response Parameters

Response Example:

{
   "market":{
      "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
      "marketStatus":"active",
      "ticker":"INJ/USDT PERP",
      "oracleBase":"0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3",
      "oracleQuote":"0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588",
      "oracleType":"pyth",
      "oracleScaleFactor":6,
      "initialMarginRatio":"0.05",
      "maintenanceMarginRatio":"0.02",
      "quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
      "quoteTokenMeta":{
         "name":"Testnet Tether USDT",
         "address":"0x0000000000000000000000000000000000000000",
         "symbol":"USDT",
         "logo":"https://static.alchemyapi.io/images/assets/825.png",
         "decimals":6,
         "updatedAt":"1698247516758"
      },
      "makerFeeRate":"-0.0001",
      "takerFeeRate":"0.001",
      "serviceProviderFee":"0.4",
      "isPerpetual":true,
      "minPriceTickSize":"100",
      "minQuantityTickSize":"0.0001",
      "perpetualMarketInfo":{
         "hourlyFundingRateCap":"0.000625",
         "hourlyInterestRate":"0.00000416666",
         "nextFundingTimestamp":"1701990000",
         "fundingInterval":"3600"
      },
      "perpetualMarketFunding":{
         "cumulativeFunding":"-156010.283874921534910863",
         "cumulativePrice":"566.477789213654772072",
         "lastTimestamp":"1701906508"
      }
   }
}
{
 "market": {
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "market_status": "active",
  "ticker": "BTC/USDT PERP",
  "oracle_base": "BTC",
  "oracle_quote": "USDT",
  "oracle_type": "bandibc",
  "oracle_scale_factor": 6,
  "initial_margin_ratio": "0.095",
  "maintenance_margin_ratio": "0.05",
  "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
  "quote_token_meta": {
   "name": "Tether",
   "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "symbol": "USDT",
   "logo": "https://static.alchemyapi.io/images/assets/825.png",
   "decimals": 6,
   "updated_at": 1650978923435
  },
  "maker_fee_rate": "0.0005",
  "taker_fee_rate": "0.0012",
  "service_provider_fee": "0.4",
  "is_perpetual": true,
  "min_price_tick_size": "100000",
  "min_quantity_tick_size": "0.0001",
  "perpetual_market_info": {
   "hourly_funding_rate_cap": "0.000625",
   "hourly_interest_rate": "0.00000416666",
   "next_funding_timestamp": 1652864400,
   "funding_interval": 3600
  },
  "perpetual_market_funding": {
   "cumulative_funding": "7246105747.050586213851272386",
   "cumulative_price": "31.114148427047982579",
   "last_timestamp": 1652793510
  }
 }
}
Parameter Type Description
market DerivativeMarketInfo Info about a particular derivative market

DerivativeMarketInfo

Parameter Type Description
oracle_quote String Oracle quote currency
oracle_type String Oracle Type
quote_denom String Coin denom used for the quote asset
is_perpetual Boolean True if the market is a perpetual swap market
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
oracle_scale_factor Integer Scaling multiple to scale oracle prices to the correct number of decimals
taker_fee_rate String Defines the fee percentage takers pay (in quote asset) when trading
expiry_futures_market_info ExpiryFuturesMarketInfo Info about expiry futures market
initial_margin_ratio String The initial margin ratio of the derivative market
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
service_provider_fee String Percentage of the transaction fee shared with the service provider
oracle_base String Oracle base currency
perpetual_market_funding PerpetualMarketFunding PerpetualMarketFunding object
perpetual_market_info PerpetualMarketInfo Information about the perpetual market
ticker String The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset
maintenance_margin_ratio String The maintenance margin ratio of the derivative market
market_id String The market ID
quoteTokenMeta TokenMeta Token metadata for quote asset, only for Ethereum-based assets

ExpiryFuturesMarketInfo

Parameter Type Description
expiration_timestamp Integer Defines the expiration time for a time expiry futures market in UNIX seconds
settlement_price String Defines the settlement price for a time expiry futures market

PerpetualMarketFunding

Parameter Type Description
cumulative_funding String Defines the cumulative funding of a perpetual market
cumulative_price String Defines the cumulative price for the current hour up to the last timestamp
last_timestamp Integer Defines the last funding timestamp in UNIX seconds

PerpetualMarketInfo

Parameter Type Description
hourly_funding_rate_cap String Defines the default maximum absolute value of the hourly funding rate
hourly_interest_rate String Defines the hourly interest rate of the perpetual market
next_funding_timestamp Integer Defines the next funding timestamp in UNIX seconds
funding_interval Integer Defines the funding interval in seconds

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

Markets

Get a list of one or more derivative markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_statuses = ["active"]
    quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
    market = await client.fetch_derivative_markets(market_statuses=market_statuses, quote_denom=quote_denom)
    print(market)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("mainnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketStatus := "active"
    quoteDenom := "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7"

    req := derivativeExchangePB.MarketsRequest{
        MarketStatus: marketStatus,
        QuoteDenom:   quoteDenom,
    }

    res, err := exchangeClient.GetDerivativeMarkets(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_statuses String Array Filter by market status (Should be any of: ["active", "paused", "suspended", "demolished", "expired"]) No
quote_denom String Filter by the Coin denomination of the quote currency No

Response Parameters

Response Example:

[
  {
    "marketId": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
    "marketStatus": "active",
    "ticker": "BNB/USDT PERP",
    "oracleBase": "BNB",
    "oracleQuote": "USDT",
    "oracleType": "bandibc",
    "oracleScaleFactor": 6,
    "initialMarginRatio": "0.095",
    "maintenanceMarginRatio": "0.05",
    "quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "quoteTokenMeta": {
      "name": "Tether",
      "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "symbol": "USDT",
      "logo": "https://static.alchemyapi.io/images/assets/825.png",
      "decimals": 6,
      "updatedAt": 1650978923353
    },
    "makerFeeRate": "0.0005",
    "takerFeeRate": "0.0012",
    "serviceProviderFee": "0.4",
    "isPerpetual": true,
    "minPriceTickSize": "10000",
    "minQuantityTickSize": "0.01",
    "perpetualMarketInfo": {
      "hourlyFundingRateCap": "0.000625",
      "hourlyInterestRate": "0.00000416666",
      "nextFundingTimestamp": 1654246800,
      "fundingInterval": 3600
    },
    "perpetualMarketFunding": {
      "cumulativeFunding": "56890491.178246679699729639",
      "cumulativePrice": "7.082760891515203314",
      "lastTimestamp": 1654245985
    }
  },
  {
    "marketId": "0x00030df39180df04a873cb4aadc50d4135640af5c858ab637dbd4d31b147478c",
    "marketStatus": "active",
    "ticker": "Frontrunner Futures: Expires 5.21.2023",
    "oracleBase": "FRNT",
    "oracleQuote": "USDT",
    "oracleType": "pricefeed",
    "oracleScaleFactor": 6,
    "initialMarginRatio": "0.999999999999999999",
    "maintenanceMarginRatio": "0.1",
    "quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "quoteTokenMeta": {
      "name": "Tether",
      "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "symbol": "USDT",
      "logo": "https://static.alchemyapi.io/images/assets/825.png",
      "decimals": 6,
      "updatedAt": 1653064108501
    },
    "makerFeeRate": "0.005",
    "takerFeeRate": "0.012",
    "serviceProviderFee": "0.4",
    "isPerpetual": false,
    "minPriceTickSize": "0.000000000000001",
    "minQuantityTickSize": "0.0001",
    "expiryFuturesMarketInfo": {
      "expirationTimestamp": 1684600043,
      "settlementPrice": "0"
    }
  }
]
{
 "markets": [
  {
   "market_id": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
   "market_status": "active",
   "ticker": "BNB/USDT PERP",
   "oracle_base": "BNB",
   "oracle_quote": "USDT",
   "oracle_type": "bandibc",
   "oracle_scale_factor": 6,
   "initial_margin_ratio": "0.095",
   "maintenance_margin_ratio": "0.05",
   "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "quote_token_meta": {
    "name": "Tether",
    "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "symbol": "USDT",
    "logo": "https://static.alchemyapi.io/images/assets/825.png",
    "decimals": 6,
    "updated_at": 1650978923353
   },
   "maker_fee_rate": "0.0005",
   "taker_fee_rate": "0.0012",
   "service_provider_fee": "0.4",
   "is_perpetual": true,
   "min_price_tick_size": "10000",
   "min_quantity_tick_size": "0.01",
   "perpetual_market_info": {
    "hourly_funding_rate_cap": "0.000625",
    "hourly_interest_rate": "0.00000416666",
    "next_funding_timestamp": 1652864400,
    "funding_interval": 3600
   },
   "perpetual_market_funding": {
    "cumulative_funding": "48248742.484852568471323698",
    "cumulative_price": "5.691379282523162906",
    "last_timestamp": 1652775374
   }
  },
  {
   "market_id": "0xfb5f14852bd01af901291dd2aa65e997b3a831f957124a7fe7aa40d218ff71ae",
   "market_status": "active",
   "ticker": "XAG/USDT PERP",
   "oracle_base": "XAG",
   "oracle_quote": "USDT",
   "oracle_type": "bandibc",
   "oracle_scale_factor": 6,
   "initial_margin_ratio": "0.8",
   "maintenance_margin_ratio": "0.4",
   "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "quote_token_meta": {
    "name": "Tether",
    "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "symbol": "USDT",
    "logo": "https://static.alchemyapi.io/images/assets/825.png",
    "decimals": 6,
    "updated_at": 1650978923534
   },
   "maker_fee_rate": "0.003",
   "taker_fee_rate": "0.005",
   "service_provider_fee": "0.4",
   "is_perpetual": true,
   "min_price_tick_size": "10000",
   "min_quantity_tick_size": "0.01",
   "perpetual_market_info": {
    "hourly_funding_rate_cap": "0.000625",
    "hourly_interest_rate": "0.00000416666",
    "next_funding_timestamp": 1652864400,
    "funding_interval": 3600
   },
   "perpetual_market_funding": {
    "cumulative_funding": "1099659.417190990913058692",
    "cumulative_price": "-4.427475055338306767",
    "last_timestamp": 1652775322
   }
  }
 ]
}
Parameter Type Description
markets DerivativeMarketInfo Array List of derivative markets and associated info

DerivativeMarketInfo

Parameter Type Description
oracle_quote String Oracle quote currency
oracle_type String Oracle Type
quote_denom String Coin denom used for the quote asset
is_perpetual Boolean True if the market is a perpetual swap market
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
oracle_scale_factor Integer Scaling multiple to scale oracle prices to the correct number of decimals
taker_fee_rate String Defines the fee percentage takers pay (in quote asset) when trading
expiry_futures_market_info ExpiryFuturesMarketInfo Info about expiry futures market
initial_margin_ratio String The initial margin ratio of the derivative market
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
service_provider_fee String Percentage of the transaction fee shared with the service provider
oracle_base String Oracle base currency
perpetual_market_funding PerpetualMarketFunding PerpetualMarketFunding object
perpetual_market_info PerpetualMarketInfo Information about the perpetual market
ticker String The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset
maintenance_margin_ratio String The maintenance margin ratio of the derivative market
market_id String The market ID
quoteTokenMeta TokenMeta Token metadata for quote asset, only for Ethereum-based assets

ExpiryFuturesMarketInfo

Parameter Type Description
expiration_timestamp Integer Defines the expiration time for a time expiry futures market in UNIX seconds
settlement_price String Defines the settlement price for a time expiry futures market

PerpetualMarketFunding

Parameter Type Description
cumulative_funding String Defines the cumulative funding of a perpetual market
cumulative_price String Defines the cumulative price for the current hour up to the last timestamp
last_timestamp Integer Defines the last funding timestamp in UNIX seconds

PerpetualMarketInfo

Parameter Type Description
hourly_funding_rate_cap String Defines the default maximum absolute value of the hourly funding rate
hourly_interest_rate String Defines the hourly interest rate of the perpetual market
next_funding_timestamp Integer Defines the next funding timestamp in UNIX seconds
funding_interval Integer Defines the funding interval in seconds

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

StreamMarkets

Stream live updates of derivative markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def market_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative markets updates ({exception})")


def stream_closed_processor():
    print("The derivative markets updates stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)

    task = asyncio.get_event_loop().create_task(
        client.listen_derivative_market_updates(
            callback=market_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
    stream, err := exchangeClient.StreamDerivativeMarket(ctx, marketIds)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                panic(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_ids String Array List of market IDs for updates streaming, empty means 'ALL' derivative markets No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
  "market": {
    "marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
    "marketStatus": "active",
    "ticker": "BTC/USDT PERP",
    "oracleBase": "BTC",
    "oracleQuote": "USDT",
    "oracleType": "bandibc",
    "oracleScaleFactor": 6,
    "initialMarginRatio": "0.095",
    "maintenanceMarginRatio": "0.05",
    "quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
    "quoteTokenMeta": {
      "name": "Tether",
      "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "symbol": "USDT",
      "logo": "https://static.alchemyapi.io/images/assets/825.png",
      "decimals": 6,
      "updatedAt": 1650978923435
    },
    "makerFeeRate": "0.0005",
    "takerFeeRate": "0.0012",
    "serviceProviderFee": "0.4",
    "isPerpetual": true,
    "minPriceTickSize": "100000",
    "minQuantityTickSize": "0.0001",
    "perpetualMarketInfo": {
      "hourlyFundingRateCap": "0.000625",
      "hourlyInterestRate": "0.00000416666",
      "nextFundingTimestamp": 1654246800,
      "fundingInterval": 3600
    },
    "perpetualMarketFunding": {
      "cumulativeFunding": "8239865636.851083559033030036",
      "cumulativePrice": "7.15770685160786651",
      "lastTimestamp": 1654246073
    }
  },
  "operationType": "update",
  "timestamp": 1654246076000
}
{
 "market": {
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "market_status": "active",
  "ticker": "BTC/USDT PERP",
  "oracle_base": "BTC",
  "oracle_quote": "USDT",
  "oracle_type": "bandibc",
  "oracle_scale_factor": 6,
  "initial_margin_ratio": "0.095",
  "maintenance_margin_ratio": "0.05",
  "quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
  "quote_token_meta": {
   "name": "Tether",
   "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
   "symbol": "USDT",
   "logo": "https://static.alchemyapi.io/images/assets/825.png",
   "decimals": 6,
   "updated_at": 1650978923435
  },
  "maker_fee_rate": "0.0005",
  "taker_fee_rate": "0.0012",
  "service_provider_fee": "0.4",
  "is_perpetual": true,
  "min_price_tick_size": "100000",
  "min_quantity_tick_size": "0.0001",
  "perpetual_market_info": {
   "hourly_funding_rate_cap": "0.000625",
   "hourly_interest_rate": "0.00000416666",
   "next_funding_timestamp": 1653040800,
   "funding_interval": 3600
  },
  "perpetual_market_funding": {
   "cumulative_funding": "7356035675.459202347630388315",
   "cumulative_price": "3.723976370878870887",
   "last_timestamp": 1653038971
  }
 },
 "operation_type": "update",
 "timestamp": 1653038974000
}
Parameter Type Description
market DerivativeMarketInfo Info about a particular derivative market
operation_type String Update type (Should be one of: ["insert", "delete", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis

DerivativeMarketInfo

Parameter Type Description
oracle_quote String Oracle quote currency
oracle_type String Oracle Type
quote_denom String Coin denom used for the quote asset
is_perpetual Boolean True if the market is a perpetual swap market
maker_fee_rate String Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading
min_price_tick_size String Defines the minimum required tick size for the order's price
min_quantity_tick_size String Defines the minimum required tick size for the order's quantity
oracle_scale_factor Integer Scaling multiple to scale oracle prices to the correct number of decimals
taker_fee_rate String Defines the fee percentage takers pay (in quote asset) when trading
expiry_futures_market_info ExpiryFuturesMarketInfo Info about expiry futures market
initial_margin_ratio String The initial margin ratio of the derivative market
market_status String The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"])
service_provider_fee String Percentage of the transaction fee shared with the service provider
oracle_base String Oracle base currency
perpetual_market_funding PerpetualMarketFunding PerpetualMarketFunding object
perpetual_market_info PerpetualMarketInfo Information about the perpetual market
ticker String The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset
maintenance_margin_ratio String The maintenance margin ratio of the derivative market
market_id String The market ID
quoteTokenMeta TokenMeta Token metadata for quote asset, only for Ethereum-based assets

ExpiryFuturesMarketInfo

Parameter Type Description
expiration_timestamp Integer Defines the expiration time for a time expiry futures market in UNIX seconds
settlement_price String Defines the settlement price for a time expiry futures market

PerpetualMarketFunding

Parameter Type Description
cumulative_funding String Defines the cumulative funding of a perpetual market
cumulative_price String Defines the cumulative price for the current hour up to the last timestamp
last_timestamp Integer Defines the last funding timestamp in UNIX seconds

PerpetualMarketInfo

Parameter Type Description
hourly_funding_rate_cap String Defines the default maximum absolute value of the hourly funding rate
hourly_interest_rate String Defines the hourly interest rate of the perpetual market
next_funding_timestamp Integer Defines the next funding timestamp in UNIX seconds
funding_interval Integer Defines the funding interval in seconds

TokenMeta

Parameter Type Description
address String Token's Ethereum contract address
decimals Integer Token decimals
logo String URL to the logo image
name String Token full name
symbol String Token symbol short name
updatedAt Integer Token metadata fetched timestamp in UNIX millis

OrdersHistory

Lists historical orders posted from a subaccount

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
    subaccount_id = "0x295639d56c987f0e24d21bb167872b3542a6e05a000000000000000000000000"
    is_conditional = "false"
    skip = 10
    limit = 3
    pagination = PaginationOption(skip=skip, limit=limit)
    orders = await client.fetch_derivative_orders_history(
        subaccount_id=subaccount_id,
        market_ids=market_ids,
        is_conditional=is_conditional,
        pagination=pagination,
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)
    isConditional := "false"

    req := derivativeExchangePB.OrdersHistoryRequest{
        SubaccountId:  subaccountId,
        MarketId:      marketId,
        Skip:          skip,
        Limit:         limit,
        IsConditional: isConditional,
    }

    res, err := exchangeClient.GetHistoricalDerivativeOrders(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID No
market_ids String Array Filter by multiple market IDs No
order_types String Array The order types to be included (Should be any of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) No
direction String Filter by order direction (Should be one of: ["buy", "sell"]) No
is_conditional String Search for conditional/non-conditional orders(Should be one of: ["true", "false"]) No
state String The order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) No
execution_types String Array The execution of the order (Should be one of: ["limit", "market"]) No
trade_id String Filter by the trade's trade id No
active_markets_only Bool Return only orders for active markets No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "orders":[
      {
         "orderHash":"0x3c98f1e38781ce8780f8f5ffe3a78cf3dbfa4d96f54d774a4847f46e9e89d6dc",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"13097700",
         "triggerPrice":"0",
         "quantity":"110660.5284",
         "filledQuantity":"0",
         "state":"canceled",
         "createdAt":"1701995288222",
         "updatedAt":"1702002966962",
         "direction":"buy",
         "margin":"724699201412.34",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "isReduceOnly":false,
         "isConditional":false,
         "triggerAt":"0",
         "placedOrderHash":"",
         "cid":""
      },
      {
         "orderHash":"0xc7c34746158b1e21bbdfa8edce0876fa00810f7b6f2236c302945c8e6b9eeb38",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"13064100",
         "triggerPrice":"0",
         "quantity":"110945.1399",
         "filledQuantity":"0",
         "state":"canceled",
         "createdAt":"1701995288222",
         "updatedAt":"1702002966962",
         "direction":"buy",
         "margin":"724699201083.795",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "isReduceOnly":false,
         "isConditional":false,
         "triggerAt":"0",
         "placedOrderHash":"",
         "cid":""
      },
      {
         "orderHash":"0x4478897d21c94df929c7d12c33d71973027ced1899ff253199b6e46124e680c1",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
         "executionType":"limit",
         "orderType":"buy_po",
         "price":"13030500",
         "triggerPrice":"0",
         "quantity":"111231.2193",
         "filledQuantity":"0",
         "state":"canceled",
         "createdAt":"1701995288222",
         "updatedAt":"1702002966962",
         "direction":"buy",
         "margin":"724699201544.325",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isActive":false,
         "isReduceOnly":false,
         "isConditional":false,
         "triggerAt":"0",
         "placedOrderHash":"",
         "cid":""
      }
   ],
   "paging":{
      "total":"1000",
      "from":0,
      "to":0,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "orders": [
  {
   "order_hash": "0x17da6aa0ba9c192da6c9d5a043b4c36a91af5117636cb1f6e69654fc6cfc1bee",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "market",
   "order_type": "sell",
   "price": "6494113.703056872037914692",
   "trigger_price": "0",
   "quantity": "2110",
   "filled_quantity": "2110",
   "state": "filled",
   "created_at": 1692857306725,
   "updated_at": 1692857306725,
   "direction": "sell",
   "margin": "0"
  },
  {
   "order_hash": "0xeac94983c5e1a47885e5959af073c475e4ec6ec343c1e1d441af1ba65f8aa5ee",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "limit",
   "order_type": "buy",
   "price": "8111100",
   "trigger_price": "0",
   "quantity": "10",
   "filled_quantity": "10",
   "state": "filled",
   "created_at": 1688738648747,
   "updated_at": 1688738648747,
   "direction": "buy",
   "margin": "82614000"
  },
  {
   "order_hash": "0x41a5c6f8c8c8ff3f37e443617dda589f46f1678ef1a22e2ab2b6ca54e0788210",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "market",
   "order_type": "buy",
   "price": "8261400",
   "trigger_price": "0",
   "quantity": "100",
   "filled_quantity": "100",
   "state": "filled",
   "created_at": 1688591280030,
   "updated_at": 1688591280030,
   "direction": "buy",
   "margin": "274917218.543"
  },
  {
   "order_hash": "0x2f667629cd06ac9fd6e54aa2544ad63cd43efc29418d0e1e12df9ba783c9a7ab",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "market",
   "order_type": "buy",
   "price": "7166668.98546",
   "trigger_price": "0",
   "quantity": "2000",
   "filled_quantity": "2000",
   "state": "filled",
   "created_at": 1687507605674,
   "updated_at": 1687507605674,
   "direction": "buy",
   "margin": "4814400000"
  },
  {
   "order_hash": "0x4c42bca7b65f18bf96e75be03a53f73854da15e8030c38e63d1531307f8cd40c",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "market",
   "order_type": "sell",
   "price": "7123287.02926",
   "trigger_price": "0",
   "quantity": "1000",
   "filled_quantity": "1000",
   "state": "filled",
   "created_at": 1687507547684,
   "updated_at": 1687507547684,
   "direction": "sell",
   "margin": "0"
  },
  {
   "order_hash": "0x70c66ce3e92aa616d3dbdbcd565c37a3d42b2b5a0951a8bebe9ddaca9852d547",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "execution_type": "market",
   "order_type": "buy",
   "price": "7162504.91532",
   "trigger_price": "0",
   "quantity": "1000",
   "filled_quantity": "1000",
   "state": "filled",
   "created_at": 1687507348068,
   "updated_at": 1687507348068,
   "direction": "buy",
   "margin": "7212200000"
  }
 ],
 "paging": {
  "total": 6
 }
}

Parameter Type Description
orders DerivativeOrderHistory Array list of historical derivative orders
paging Paging Pagination of results

DerivativeOrderHistory

Parameter Type Description
order_hash String Hash of the order
market_id String Derivative market ID
is_active Boolean Indicates if the order is active
subaccount_id String The subaccountId that this order belongs to
execution_type String The type of the order (Should be one of: ["limit", "market"])
order_type String Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"])
price String Price of the order
trigger_price String The price that triggers stop/take orders
quantity String Quantity of the order
filled_quantity String The amount of the quantity filled
state String Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order created timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
is_reduce_only Boolean Indicates if the order is reduce-only
direction String The direction of the order (Should be one of: ["buy", "sell"])
is_conditional Boolean Indicates if the order is conditional
trigger_at Integer Trigger timestamp in UNIX millis
placed_order_hash String Hash of order placed upon conditional order trigger
margin String The margin of the order
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

Paging

Parameter Type Description
total Integer Total number of available records

StreamOrdersHistory

Stream order updates of a derivative market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def order_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative orders history updates ({exception})")


def stream_closed_processor():
    print("The derivative orders history updates stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"

    task = asyncio.get_event_loop().create_task(
        client.listen_derivative_orders_history_updates(
            callback=order_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            market_id=market_id,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
    direction := "buy"

    req := derivativeExchangePB.StreamOrdersHistoryRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Direction:    direction,
    }
    stream, err := exchangeClient.StreamHistoricalDerivativeOrders(ctx, &req)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                panic(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID No
market_id String Filter by market ID No
order_types String Array Filter by order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) No
direction String Filter by direction (Should be one of: ["buy", "sell"]) No
state String Filter by state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) No
execution_types String Array Filter by execution type (Should be one of: ["limit", "market"]) No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "order":{
      "order_hash":"0x4aeb72ac2ae5811126a0c384e05ce68745316add0e705c39e73f68c76431515e",
      "market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
      "is_active":true,
      "subaccount_id":"0x7619f89a2172c6705aac7482f3adbf0601ea140e000000000000000000000000",
      "execution_type":"limit",
      "order_type":"sell_po",
      "price":"27953000000",
      "trigger_price":"0",
      "quantity":"0.0344",
      "filled_quantity":"0",
      "state":"booked",
      "created_at":1696617269292,
      "updated_at":1696617269292,
      "direction":"sell",
      "margin":"320527734"
   },
   "operation_type":"insert",
   "timestamp":1696617272000
}
{
   "order":{
      "order_hash":"0x24d82da3530ce5d2d392c9563d29b79c3a25e058dd6d79e0d8f651703256eb78",
      "market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
      "subaccount_id":"0x6590d14d9e9c1d964f8c83bddc8a092f4a2d1284000000000000000000000000",
      "execution_type":"limit",
      "order_type":"buy_po",
      "price":"27912000000",
      "trigger_price":"0",
      "quantity":"0.0344",
      "filled_quantity":"0",
      "state":"canceled",
      "created_at":1696617207873,
      "updated_at":1696617269292,
      "direction":"buy",
      "margin":"320057600"
   },
   "operation_type":"update",
   "timestamp":1696617272000
}
{
   "order":{
      "order_hash":"0x4aeb72ac2ae5811126a0c384e05ce68745316add0e705c39e73f68c76431515e",
      "market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
      "is_active":true,
      "subaccount_id":"0x7619f89a2172c6705aac7482f3adbf0601ea140e000000000000000000000000",
      "execution_type":"limit",
      "order_type":"sell_po",
      "price":"27953000000",
      "trigger_price":"0",
      "quantity":"0.0344",
      "filled_quantity":"0",
      "state":"booked",
      "created_at":1696617269292,
      "updated_at":1696617269292,
      "direction":"sell",
      "margin":"320527734"
   },
   "operation_type":"insert",
   "timestamp":1696617272000
}
{
   "order":{
      "order_hash":"0x24d82da3530ce5d2d392c9563d29b79c3a25e058dd6d79e0d8f651703256eb78",
      "market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
      "subaccount_id":"0x6590d14d9e9c1d964f8c83bddc8a092f4a2d1284000000000000000000000000",
      "execution_type":"limit",
      "order_type":"buy_po",
      "price":"27912000000",
      "trigger_price":"0",
      "quantity":"0.0344",
      "filled_quantity":"0",
      "state":"canceled",
      "created_at":1696617207873,
      "updated_at":1696617269292,
      "direction":"buy",
      "margin":"320057600"
   },
   "operation_type":"update",
   "timestamp":1696617272000
}
Parameter Type Description
order DerivativeOrderHistory Updated order
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis

DerivativeOrderHistory

Parameter Type Description
order_hash String Hash of the order
market_id String Derivative market ID
is_active Boolean Indicates if the order is active
subaccount_id String The subaccountId that this order belongs to
execution_type String The type of the order (Should be one of: ["limit", "market"])
order_type String Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"])
price String Price of the order
trigger_price String The price that triggers stop/take orders
quantity String Quantity of the order
filled_quantity String The amount of the quantity filled
state String Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order created timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
is_reduce_only Boolean Indicates if the order is reduce-only
direction String The direction of the order (Should be one of: ["buy", "sell"])
is_conditional Boolean Indicates if the order is conditional
trigger_at Integer Trigger timestamp in UNIX millis
placed_order_hash String Hash of order placed upon conditional order trigger
margin String The margin of the order
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

TradesV2

Get trades of a derivative market. The difference between Trades and TradesV2 is that the latter returns a trade_id compatible witht the one used for trade events in chain stream.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
    subaccount_ids = ["0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"]
    skip = 0
    limit = 4
    pagination = PaginationOption(skip=skip, limit=limit)
    trades = await client.fetch_derivative_trades(
        market_ids=market_ids, subaccount_ids=subaccount_ids, pagination=pagination
    )
    print(trades)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"

    req := derivativeExchangePB.TradesV2Request{
        MarketId:     marketId,
        SubaccountId: subaccountId,
    }

    res, err := exchangeClient.GetDerivativeTradesV2(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_ids String Array Filter by multiple market IDs No
subaccount_ids String Array Filter by multiple subaccount IDs No
execution_side String Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) No
direction String Filter by the direction of the trade (Should be one of: ["buy", "sell"]) No
execution_types String Array Filter by the *trade execution type (Should be any of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) No
trade_id String Filter by the trade id of the trade No
account_address String Filter by the account address No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "trades":[
      {
         "orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
         "tradeExecutionType":"limitMatchRestingOrder",
         "positionDelta":{
            "tradeDirection":"buy",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"-60000",
         "executedAt":"1701978102242",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"22868_2",
         "executionSide":"maker",
         "cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
         "isLiquidation":false
      },
      {
         "orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
         "tradeExecutionType":"limitMatchRestingOrder",
         "positionDelta":{
            "tradeDirection":"buy",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"-600",
         "executedAt":"1701978102242",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"22868_4",
         "executionSide":"maker",
         "cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
         "isLiquidation":false
      },
      {
         "orderHash":"0x404577bc40896028733f7740d4efc6f6695fb9194f43dd545fb8923cbb01efd6",
         "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
         "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
         "tradeExecutionType":"limitMatchNewOrder",
         "positionDelta":{
            "tradeDirection":"sell",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"5000000",
         "executedAt":"1701978102242",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"22868_3",
         "executionSide":"taker",
         "cid":"derivative_ATOM/USDT",
         "isLiquidation":false
      },
      {
         "orderHash":"0x3fde93ceabc67a13372c237f5271784c0bbe97801ef12e883cfbde4c13e16300",
         "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
         "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
         "tradeExecutionType":"limitMatchNewOrder",
         "positionDelta":{
            "tradeDirection":"sell",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"9000000"
         },
         "payout":"0",
         "fee":"10000",
         "executedAt":"1701978102242",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"22868_5",
         "executionSide":"taker",
         "cid":"derivative_INJ/USDT",
         "isLiquidation":false
      },
      {
         "orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
         "tradeExecutionType":"limitMatchRestingOrder",
         "positionDelta":{
            "tradeDirection":"buy",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"-60000",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_2",
         "executionSide":"maker",
         "cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
         "isLiquidation":false
      },
      {
         "orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
         "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
         "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
         "tradeExecutionType":"limitMatchRestingOrder",
         "positionDelta":{
            "tradeDirection":"buy",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"-600",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_4",
         "executionSide":"maker",
         "cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
         "isLiquidation":false
      },
      {
         "orderHash":"0xf6ae77b0a1e267b7f0b8618f3f226c39ba702a09fb3bdb650b0c28197d36d91d",
         "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
         "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
         "tradeExecutionType":"limitMatchNewOrder",
         "positionDelta":{
            "tradeDirection":"sell",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"10000000"
         },
         "payout":"0",
         "fee":"5000000",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_3",
         "executionSide":"taker",
         "cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
         "isLiquidation":false
      },
      {
         "orderHash":"0x01ba4dd3b30bc946a31f5fe1aba9918e95d3dc8cf31a6c4b2d793068eae529e8",
         "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
         "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
         "tradeExecutionType":"limitMatchNewOrder",
         "positionDelta":{
            "tradeDirection":"sell",
            "executionPrice":"10000000",
            "executionQuantity":"1",
            "executionMargin":"9000000"
         },
         "payout":"0",
         "fee":"10000",
         "executedAt":"1701961116630",
         "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
         "tradeId":"1321_5",
         "executionSide":"taker",
         "cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
         "isLiquidation":false
      }
   ],
   "paging":{
      "total":"8",
      "from":1,
      "to":8,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "trades": [
  {
   "order_hash": "0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
   "subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
   "market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
   "trade_execution_type": "limitMatchRestingOrder",
   "position_delta": {
    "trade_direction": "buy",
    "execution_price": "10000000",
    "execution_quantity": "1",
    "execution_margin": "10000000"
   },
   "payout": "0",
   "fee": "-600",
   "executed_at": 1701978102242,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "22868_4",
   "execution_side": "maker",
   "cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
  },
  {
   "order_hash": "0x3fde93ceabc67a13372c237f5271784c0bbe97801ef12e883cfbde4c13e16300",
   "subaccount_id": "0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
   "market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
   "trade_execution_type": "limitMatchNewOrder",
   "position_delta": {
    "trade_direction": "sell",
    "execution_price": "10000000",
    "execution_quantity": "1",
    "execution_margin": "9000000"
   },
   "payout": "0",
   "fee": "10000",
   "executed_at": 1701978102242,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "22868_5",
   "execution_side": "taker",
   "cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
  },
  {
   "order_hash": "0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
   "subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
   "market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
   "trade_execution_type": "limitMatchRestingOrder",
   "position_delta": {
    "trade_direction": "buy",
    "execution_price": "10000000",
    "execution_quantity": "1",
    "execution_margin": "10000000"
   },
   "payout": "0",
   "fee": "-600",
   "executed_at": 1701961116630,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "1321_4",
   "execution_side": "maker",
   "cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
  },
  {
   "order_hash": "0x01ba4dd3b30bc946a31f5fe1aba9918e95d3dc8cf31a6c4b2d793068eae529e8",
   "subaccount_id": "0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
   "market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
   "trade_execution_type": "limitMatchNewOrder",
   "position_delta": {
    "trade_direction": "sell",
    "execution_price": "10000000",
    "execution_quantity": "1",
    "execution_margin": "9000000"
   },
   "payout": "0",
   "fee": "10000",
   "executed_at": 1701961116630,
   "fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
   "trade_id": "1321_5",
   "execution_side": "taker",
   "cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
  }
 ],
 "paging": {
  "total": 4,
  "from": 1,
  "to": 4
 }
}

Parameter Type Description
trades DerivativeTrade Array List of trades of derivative markets
paging Paging Pagination of results

DerivativeTrade

Parameter Type Description
order_hash String The order hash
subaccount_id String ID of subaccount that executed the trade
market_id String The market ID
trade_execution_type String *Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"])
is_liquidation Boolean True if the trade is a liquidation
position_delta PositionDelta Position delta from the trade
payout String The payout associated with the trade
fee String The fee associated with the trade
executed_at Integer Timestamp of trade execution (on chain) in UNIX millis
fee_recipient String The address that received 40% of the fees
trade_id String Unique identifier to differentiate between trades
execution_side String Execution side of trade (Should be one of: ["maker", "taker"])
cid String Custom client order id

PositionDelta

Parameter Type Description
execution_price String Execution price of the trade
execution_quantity String Execution quantity of the trade
trade_direction String The direction the trade (Should be one of: ["buy", "sell"])
execution_margin String Execution margin of the trade

Paging

Parameter Type Description
total Integer Total number of records available

StreamTradesV2

Stream newly executed trades of a derivative market. The default request streams trades from all derivative markets. The difference between StreamTrades and StreamTradesV2 is that the latter returns a trade_id compatible witht the one used for trade events in chain stream.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def market_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative trades updates ({exception})")


def stream_closed_processor():
    print("The derivative trades updates stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
        "0x70bc8d7feab38b23d5fdfb12b9c3726e400c265edbcbf449b6c80c31d63d3a02",
    ]
    subaccount_ids = ["0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"]

    task = asyncio.get_event_loop().create_task(
        client.listen_derivative_trades_updates(
            callback=market_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            market_ids=market_ids,
            subaccount_ids=subaccount_ids,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"

    req := derivativeExchangePB.StreamTradesV2Request{
        MarketId:     marketId,
        SubaccountId: subaccountId,
    }
    stream, err := exchangeClient.StreamDerivativeV2Trades(ctx, &req)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                panic(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_ids String Array Filter by multiple market IDs No
execution_side String Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) No
direction String Filter by the direction of the trade (Should be one of: ["buy", "sell"]) No
subaccount_ids String Array Filter by multiple subaccount IDs No
execution_types String Array Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) No
trade_id String Filter by the trade's trade id No
account_address String Filter by the account address No
cid String Filter by the custom client order id of the trade's order No
pagination PaginationOption Pagination configuration No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "trade":{
      "orderHash":"0x01e6b3df831734c88c84522f9834b3656b3afde6891ac671742dd269be776510",
      "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
      "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
      "tradeExecutionType":"limitMatchNewOrder",
      "positionDelta":{
         "tradeDirection":"sell",
         "executionPrice":"10000000",
         "executionQuantity":"1",
         "executionMargin":"10000000"
      },
      "payout":"0",
      "fee":"5000000",
      "executedAt":"1701979920875",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"25116_3",
      "executionSide":"taker",
      "cid":"derivative_ATOM/USDT",
      "isLiquidation":false
   },
   "operationType":"insert",
   "timestamp":"1701979922000"
}
{
   "trade":{
      "orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
      "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
      "marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
      "tradeExecutionType":"limitMatchRestingOrder",
      "positionDelta":{
         "tradeDirection":"buy",
         "executionPrice":"10000000",
         "executionQuantity":"1",
         "executionMargin":"10000000"
      },
      "payout":"0",
      "fee":"-60000",
      "executedAt":"1701979920875",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"25116_2",
      "executionSide":"maker",
      "cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
      "isLiquidation":false
   },
   "operationType":"insert",
   "timestamp":"1701979922000"
}
{
   "trade":{
      "orderHash":"0xa0446c80b66dd6ab75b32e51e4e04929ae92df9fa7a64fe2d21ed9be536bb6d5",
      "subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
      "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
      "tradeExecutionType":"limitMatchNewOrder",
      "positionDelta":{
         "tradeDirection":"sell",
         "executionPrice":"10000000",
         "executionQuantity":"1",
         "executionMargin":"9000000"
      },
      "payout":"0",
      "fee":"10000",
      "executedAt":"1701979920875",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"25116_5",
      "executionSide":"taker",
      "cid":"derivative_INJ/USDT",
      "isLiquidation":false
   },
   "operationType":"insert",
   "timestamp":"1701979922000"
}
{
   "trade":{
      "orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
      "subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
      "marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
      "tradeExecutionType":"limitMatchRestingOrder",
      "positionDelta":{
         "tradeDirection":"buy",
         "executionPrice":"10000000",
         "executionQuantity":"1",
         "executionMargin":"10000000"
      },
      "payout":"0",
      "fee":"-600",
      "executedAt":"1701979920875",
      "feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
      "tradeId":"25116_4",
      "executionSide":"maker",
      "cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
      "isLiquidation":false
   },
   "operationType":"insert",
   "timestamp":"1701979922000"
}
{
 "trade": {
  "order_hash": "0x0403d2e51d73aa1cb46004b16d76279afece9ad14e3784eb93aa6370de466f81",
  "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "trade_execution_type": "limitMatchRestingOrder",
  "position_delta": {
   "trade_direction": "sell",
   "execution_price": "40249100000",
   "execution_quantity": "0.06",
   "execution_margin": "2388462000"
  },
  "payout": "0",
  "fee": "1207473",
  "executed_at": 1653040243183,
  "fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
 },
 "operation_type": "insert",
 "timestamp": 1653040246000
}{
 "trade": {
  "order_hash": "0x728d69975e4057d1801f1a7031d0ccf7242abacbf73320da55abab677efc2a7e",
  "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "trade_execution_type": "limitMatchRestingOrder",
  "position_delta": {
   "trade_direction": "sell",
   "execution_price": "40249100000",
   "execution_quantity": "0.02",
   "execution_margin": "779300000"
  },
  "payout": "0",
  "fee": "402491",
  "executed_at": 1653040243183,
  "fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
 },
 "operation_type": "insert",
 "timestamp": 1653040246000
}
Parameter Type Description
trade DerivativeTrade New derivative market trade
operation_type String Trade operation type (Should be one of: ["insert", "invalidate"])
timestamp Integer Timestamp the new trade is written into the database in UNIX millis

DerivativeTrade

Parameter Type Description
order_hash String The order hash
subaccount_id String ID of subaccount that executed the trade
market_id String The market ID
trade_execution_type String *Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"])
is_liquidation Boolean True if the trade is a liquidation
position_delta PositionDelta Position delta from the trade
payout String The payout associated with the trade
fee String The fee associated with the trade
executed_at Integer Timestamp of trade execution (on chain) in UNIX millis
fee_recipient String The address that received 40% of the fees
trade_id String Unique identifier to differentiate between trades
execution_side String Execution side of trade (Should be one of: ["maker", "taker"])
cid String Custom client order id

PositionDelta

Parameter Type Description
execution_price String Execution price of the trade
execution_quantity String Execution quantity of the trade
trade_direction String The direction the trade (Should be one of: ["buy", "sell"])
execution_margin String Execution margin of the trade

Positions

Get the positions of a market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
        "0xd97d0da6f6c11710ef06315971250e4e9aed4b7d4cd02059c9477ec8cf243782",
    ]
    subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
    direction = "short"
    subaccount_total_positions = False
    skip = 4
    limit = 4
    pagination = PaginationOption(skip=skip, limit=limit)
    positions = await client.fetch_derivative_positions_v2(
        market_ids=market_ids,
        subaccount_id=subaccount_id,
        direction=direction,
        subaccount_total_positions=subaccount_total_positions,
        pagination=pagination,
    )
    print(positions)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)

    req := derivativeExchangePB.PositionsV2Request{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Skip:         skip,
        Limit:        limit,
    }

    res, err := exchangeClient.GetDerivativePositionsV2(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_ids String Array Filter by multiple market IDs No
subaccount_id String Filter by subaccount ID No
direction String Filter by direction of position (Should be one of: ["long", "short"]) No
subaccount_total_positions Boolean Choose to return subaccount total positions (Should be one of: [True, False]) No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "positions":[
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
         "direction":"short",
         "quantity":"0.087829315829932072",
         "entryPrice":"26453271.813315285838444221",
         "margin":"1156906.224974",
         "liquidationPrice":"38848511.946759",
         "markPrice":"35561999.99",
         "updatedAt":"1703793600379"
      },
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x0000040f1111c5c3d2037940658ee770bb37e0a2000000000000000000000000",
         "direction":"long",
         "quantity":"0.000068500966722584",
         "entryPrice":"12293600",
         "margin":"440.389918",
         "liquidationPrice":"5984327.380009",
         "markPrice":"35561999.99",
         "updatedAt":"1703793600379"
      },
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
         "direction":"short",
         "quantity":"0.022151816236313182",
         "entryPrice":"15980281.340438795311756833",
         "margin":"172782.601001",
         "liquidationPrice":"23313932.022168",
         "markPrice":"35561999.99",
         "updatedAt":"1703793600379"
      },
   ],
   "paging":{
      "total":"1166",
      "from":0,
      "to":0,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "positions": [
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
   "direction": "short",
   "quantity": "0.087829315829932072",
   "entry_price": "26453271.813315285838444221",
   "margin": "1156893.718782",
   "liquidation_price": "38848372.346758",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0000040f1111c5c3d2037940658ee770bb37e0a2000000000000000000000000",
   "direction": "long",
   "quantity": "0.000068500966722584",
   "entry_price": "12293600",
   "margin": "440.399672",
   "liquidation_price": "5984182.081895",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
   "direction": "short",
   "quantity": "0.022151816236313182",
   "entry_price": "15980281.340438795311756833",
   "margin": "172779.44676",
   "liquidation_price": "23313792.422186",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00606da8ef76ca9c36616fa576d1c053bb0f7eb2000000000000000000000000",
   "direction": "short",
   "quantity": "0.041121486263975195",
   "entry_price": "15980281.340438795311756842",
   "margin": "320624.783065",
   "liquidation_price": "23311073.361647",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00cd2929594559000670af009e2f5ef15fefa6cf000000000000000000000000",
   "direction": "long",
   "quantity": "0.000050211853307914",
   "entry_price": "12293600",
   "margin": "322.774915",
   "liquidation_price": "5985039.457698",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00cf63fab44e827a4fb12142d6e0d8e82099701a000000000000000000000000",
   "direction": "long",
   "quantity": "0.000058171926973086",
   "entry_price": "12293600",
   "margin": "374.127106",
   "liquidation_price": "5981833.667338",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x010d36443f440708892e79dcbb6c1350c4c76662000000000000000000000000",
   "direction": "long",
   "quantity": "0.00008708028566368",
   "entry_price": "12293600",
   "margin": "559.983294",
   "liquidation_price": "5982596.709155",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0154fc01caf0e4c82b7ea6c9be719c260e940ef3000000000000000000000000",
   "direction": "short",
   "quantity": "0.005684726095134712",
   "entry_price": "19468749.344033524349659551",
   "margin": "54688.034814",
   "liquidation_price": "28518548.958621",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0198b3d3691bcc1718dcda4277bb27c68fd19a6f000000000000000000000000",
   "direction": "short",
   "quantity": "1.950155851194068459",
   "entry_price": "34111005.753742189227540816",
   "margin": "33194528.351493",
   "liquidation_price": "50129882.732098",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x021a86b9858f6e4150a724d444e94d10cb75c1b1000000000000000000000000",
   "direction": "short",
   "quantity": "0.077749303393590607",
   "entry_price": "15980281.340438795311756851",
   "margin": "605813.214778",
   "liquidation_price": "23306040.184987",
   "mark_price": "35294291.44",
   "updated_at": 1703790001819
  }
 ],
 "paging": {
  "total": 1153
 }
}
Parameter Type Description
positions DerivativePosition Array List of derivative positions
paging Paging Pagination of results

DerivativePosition

Parameter Type Description
ticker String Ticker of the derivative market
market_id String ID of the market the position is in
subaccount_id String The subaccount ID the position belongs to
direction String Direction of the position (Should be one of: ["long", "short"])
quantity String Quantity of the position
entry_price String Entry price of the position
margin String Margin of the position
liquidation_price String Liquidation price of the position
mark_price String Oracle price of the base asset
updated_at Integer Position updated timestamp in UNIX millis

Paging

Parameter Type Description
total Integer Total number of available records

StreamPositions

Stream position updates for a specific market.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def positions_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative positions updates ({exception})")


def stream_closed_processor():
    print("The derivative positions updates stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
    subaccount_ids = ["0xea98e3aa091a6676194df40ac089e40ab4604bf9000000000000000000000000"]

    task = asyncio.get_event_loop().create_task(
        client.listen_derivative_positions_updates(
            callback=positions_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
            market_ids=market_ids,
            subaccount_ids=subaccount_ids,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"

    req := derivativeExchangePB.StreamPositionsRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
    }
    stream, err := exchangeClient.StreamDerivativePositions(ctx, &req)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                panic(err)
                return
            }
            str, _ := json.MarshalIndent(res, "", " ")
            fmt.Print(string(str))
        }
    }
}
Parameter Type Description Required
market_ids String Array IDs of the markets to stream position data from No
subaccount_ids String Array Subaccount IDs of the traders to stream positions from No
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
  "position": {
    "ticker": "BTC/USDT PERP",
    "marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
    "subaccountId": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
    "direction": "short",
    "quantity": "1.6321",
    "entryPrice": "40555935751.758890674529114982",
    "margin": "65283896141.678537523412631302",
    "liquidationPrice": "76719878206.648298",
    "markPrice": "40128736026.4094317665",
    "aggregateReduceOnlyQuantity": "0"
  },
  "timestamp": 1654246646000
}
{
  "position": {
    "ticker": "BTC/USDT PERP",
    "marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
    "subaccountId": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
    "direction": "short",
    "quantity": "1.6321",
    "entryPrice": "40489113688.030524225816723708",
    "margin": "65069810777.851918748331744252",
    "liquidationPrice": "76531312698.56045",
    "markPrice": "40128736026.4094317665",
    "aggregateReduceOnlyQuantity": "0"
  },
  "timestamp": 1654246687000
}
{
 "position": {
  "ticker": "BTC/USDT PERP",
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
  "direction": "short",
  "quantity": "0.4499",
  "entry_price": "40187334829.308997167725462798",
  "margin": "17648170480.844939276952101173",
  "liquidation_price": "75632579558.528471",
  "mark_price": "40128736026.4094317665",
  "aggregate_reduce_only_quantity": "0"
 },
 "timestamp": 1653039418000
}{
 "position": {
  "ticker": "BTC/USDT PERP",
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
  "direction": "short",
  "quantity": "0.4499",
  "entry_price": "40415133266.89312760388339505",
  "margin": "17780087110.130349528796488556",
  "liquidation_price": "76128781140.582706",
  "mark_price": "40128736026.4094317665",
  "aggregate_reduce_only_quantity": "0"
 },
 "timestamp": 1653039464000
}{
 "position": {
  "ticker": "BTC/USDT PERP",
  "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
  "subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
  "direction": "short",
  "quantity": "0.4499",
  "entry_price": "40306914705.252255649316986606",
  "margin": "17654816331.908168110936068341",
  "liquidation_price": "75760533574.235878",
  "mark_price": "40128736026.4094317665",
  "aggregate_reduce_only_quantity": "0"
 },
 "timestamp": 1653039501000
}
Parameter Type Description
position DerivativePosition Updated derivative position
timestamp Integer Timestamp of update in UNIX millis

DerivativePosition

Parameter Type Description
direction String Direction of the position (Should be one of: ["long", "short"])
market_id String ID of the market the position is in
subaccount_id String The subaccount ID the position belongs to
ticker String Ticker of the derivative market
aggregate_reduce_only_quantity String Aggregate quantity of the reduce-only orders associated with the position
entry_price String Entry price of the position
liquidation_price String Liquidation price of the position
margin String Margin of the position
mark_price String Oracle price of the base asset
quantity String Quantity of the position
updated_at Integer Position updated timestamp in UNIX millis
created_at Integer Position created timestamp in UNIX millis. Currently not supported (value will be inaccurate).

LiquidablePositions

Gets all the liquidable positions

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    network = Network.testnet()
    client = AsyncClient(network)
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    skip = 10
    limit = 3
    pagination = PaginationOption(skip=skip, limit=limit)
    positions = await client.fetch_derivative_liquidable_positions(
        market_id=market_id,
        pagination=pagination,
    )
    print(positions)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    //marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    skip := uint64(0)
    limit := int32(10)

    req := derivativeExchangePB.LiquidablePositionsRequest{
        //MarketId: marketId,
        Skip:  skip,
        Limit: limit,
    }

    res, err := exchangeClient.GetDerivativeLiquidablePositions(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_id String ID of the market to query liquidable positions for Yes
skip Integer Skip the first n cosmwasm contracts. This can be used to fetch all results since the API caps at 100 No
limit Integer Max number of items to be returned, defaults to 100 No

Response Parameters

Streaming Response Example:

{
   "positions":[
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x0a5d67f3616a9e7b53c301b508e9384c6321be47000000000000000000000000",
         "direction":"short",
         "quantity":"0.00966730135521481",
         "entryPrice":"15980281.340438795311756819",
         "margin":"75611.273514",
         "liquidationPrice":"23334925.188149",
         "markPrice":"39291123.99",
         "aggregateReduceOnlyQuantity":"0",
         "updatedAt":"1705525203015",
         "createdAt":"-62135596800000"
      },
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x0c812012cf492aa422fb888e172fbd6e19df517b000000000000000000000000",
         "direction":"short",
         "quantity":"0.066327809378915175",
         "entryPrice":"16031762.538045163086357667",
         "margin":"520412.029703",
         "liquidationPrice":"23409630.791347",
         "markPrice":"39291123.99",
         "aggregateReduceOnlyQuantity":"0",
         "updatedAt":"1705525203015",
         "createdAt":"-62135596800000"
      },
      {
         "ticker":"INJ/USDT PERP",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0x0d750ad3404b6f23579706e44111e8dd774fd1fa000000000000000000000000",
         "direction":"short",
         "quantity":"0.000080602003464734",
         "entryPrice":"16031762.53804516308635803",
         "margin":"632.408209",
         "liquidationPrice":"23409630.592378",
         "markPrice":"39291123.99",
         "aggregateReduceOnlyQuantity":"0",
         "updatedAt":"1705525203015",
         "createdAt":"-62135596800000"
      }
   ]
}
{
 "positions": [
  {
   "ticker": "SOL/USDT PERP",
   "market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
   "subaccount_id": "0x0ddbe7ea40134ae14ed6a5d104d8783c80663edb000000000000000000000000",
   "direction": "short",
   "quantity": "135965",
   "entry_price": "24074541.242231456624866694",
   "margin": "922840147876.471312471775929175",
   "liquidation_price": "29392264.1007154944460271",
   "mark_price": "102769181.99",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "SOL/USDT PERP",
   "market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
   "subaccount_id": "0x16aef18dbaa341952f1af1795cb49960f68dfee3000000000000000000000000",
   "direction": "short",
   "quantity": "34.99",
   "entry_price": "25000000",
   "margin": "963925977.452838924992513061",
   "liquidation_price": "50046298.3288514793340278",
   "mark_price": "102769181.99",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "SOL/USDT PERP",
   "market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "direction": "short",
   "quantity": "160",
   "entry_price": "24375243.283322806982741737",
   "margin": "3774845657.765183864053125849",
   "liquidation_price": "45683836.8041478153648322",
   "mark_price": "102769181.99",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "SOL/USDT PERP",
   "market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
   "subaccount_id": "0xce4c01573f2a5f4db5d184b666ecfccb9313cc65000000000000000000000000",
   "direction": "short",
   "quantity": "8",
   "entry_price": "17700000",
   "margin": "141673770.450618846533455704",
   "liquidation_price": "33723067.9107879579206495",
   "mark_price": "102769181.99",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
   "direction": "short",
   "quantity": "0.087829315829932072",
   "entry_price": "26453271.813315285838444221",
   "margin": "1154483.475338511428917818",
   "liquidation_price": "38821468.0751518485185464",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
   "direction": "short",
   "quantity": "0.022151816236313182",
   "entry_price": "15980281.340438795311756833",
   "margin": "172410.019375666543049786",
   "liquidation_price": "23297442.3538099336017081",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x00606da8ef76ca9c36616fa576d1c053bb0f7eb2000000000000000000000000",
   "direction": "short",
   "quantity": "0.041121486263975195",
   "entry_price": "15980281.340438795311756842",
   "margin": "320053.045217395063737578",
   "liquidation_price": "23297442.3538099336017082",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x0154fc01caf0e4c82b7ea6c9be719c260e940ef3000000000000000000000000",
   "direction": "short",
   "quantity": "0.005684726095134712",
   "entry_price": "19468749.344033524349659551",
   "margin": "54563.593706555517738922",
   "liquidation_price": "28497087.7512237107551938",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x021a86b9858f6e4150a724d444e94d10cb75c1b1000000000000000000000000",
   "direction": "short",
   "quantity": "0.077749303393590607",
   "entry_price": "15980281.340438795311756851",
   "margin": "605131.369885566651321656",
   "liquidation_price": "23297442.3538099336017081",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  },
  {
   "ticker": "INJ/USDT PERP",
   "market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
   "subaccount_id": "0x03ca8d57285836857dddf42cbb896448015246e7000000000000000000000000",
   "direction": "short",
   "quantity": "3.933956815705317214",
   "entry_price": "20294270.597312410912417203",
   "margin": "39442957.950528509629919537",
   "liquidation_price": "29726031.3451969744796065",
   "mark_price": "40421744.55",
   "aggregate_reduce_only_quantity": "0",
   "updated_at": 1703361600801,
   "created_at": -62135596800000
  }
 ]
}

Parameter Type Description
positions DerivativePosition Array List of liquidable lpositions

DerivativePosition

Parameter Type Description
direction String Direction of the position (Should be one of: ["long", "short"])
market_id String ID of the market the position is in
subaccount_id String The subaccount ID the position belongs to
ticker String Ticker of the derivative market
aggregate_reduce_only_quantity String Aggregate quantity of the reduce-only orders associated with the position
entry_price String Entry price of the position
liquidation_price String Liquidation price of the position
margin String Margin of the position
mark_price String Oracle price of the base asset
quantity String Quantity of the position
updated_at Integer Position updated timestamp in UNIX millis
created_at Integer Position created timestamp in UNIX millis. Currently not supported (value will be inaccurate).

OrderbooksV2

Get an orderbook snapshot for one or more derivative markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = [
        "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
        "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff",
    ]
    orderbooks = await client.fetch_derivative_orderbooks_v2(market_ids=market_ids)
    print(orderbooks)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
    res, err := exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
market_ids String Array List of IDs of markets to get orderbook snapshots from Yes

Response Parameters

Response Example:

{
   "orderbooks":[
      {
         "marketId":"0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff",
         "orderbook":{
            "sequence":"4099",
            "timestamp":"1681978300931",
            "buys":[

            ],
            "sells":[

            ]
         }
      },
      {
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "orderbook":{
            "buys":[
               {
                  "price":"13400000",
                  "quantity":"683.3032",
                  "timestamp":"1702002966962"
               },
               {
                  "price":"13366500",
                  "quantity":"108438.1403",
                  "timestamp":"1702002966962"
               }
            ],
            "sells":[
               {
                  "price":"18390200",
                  "quantity":"78815.8042",
                  "timestamp":"1702002966962"
               }
            ],
            "sequence":"1919116",
            "timestamp":"1702003451726"
         }
      }
   ]
}
{
 "orderbooks": [
  {
   "market_id": "0x2e94326a421c3f66c15a3b663c7b1ab7fb6a5298b3a57759ecf07f0036793fc9",
   "orderbook": {
    "buys": [
     {
      "price": "25100000000",
      "quantity": "0.46",
      "timestamp": 1701558751779
     },
     {
      "price": "25000000000",
      "quantity": "99.51",
      "timestamp": 1702216325243
     },
     {
      "price": "24192180000",
      "quantity": "0.05",
      "timestamp": 1681812143213
     },
     {
      "price": "24000180000",
      "quantity": "3",
      "timestamp": 1681811751044
     },
     {
      "price": "21295940000",
      "quantity": "1",
      "timestamp": 1681811119316
     },
     {
      "price": "20160150000",
      "quantity": "1",
      "timestamp": 1681812143213
     },
     {
      "price": "20000000000",
      "quantity": "200",
      "timestamp": 1699699685300
     },
     {
      "price": "19894890000",
      "quantity": "1",
      "timestamp": 1681811751044
     },
     {
      "price": "19764860000",
      "quantity": "4",
      "timestamp": 1681810803871
     },
     {
      "price": "18900140000",
      "quantity": "3",
      "timestamp": 1681812143213
     },
     {
      "price": "18439160000",
      "quantity": "10",
      "timestamp": 1681812143213
     },
     {
      "price": "15000000000",
      "quantity": "400",
      "timestamp": 1699699705568
     },
     {
      "price": "10000000000",
      "quantity": "1000",
      "timestamp": 1699699744160
     }
    ],
    "sells": [
     {
      "price": "50501180000",
      "quantity": "4",
      "timestamp": 1681811955314
     },
     {
      "price": "50198770000",
      "quantity": "2.48",
      "timestamp": 1681811955314
     }
    ],
    "timestamp": -62135596800000
   }
  }
 ]
}

Parameter Type Description
orderbooks SingleDerivativeLimitOrderbookV2 Array List of derivative market orderbooks

SingleDerivativeLimitOrderbookV2

Parameter Type Description
market_id String ID of the market that the orderbook belongs to
orderbook DerivativeLimitOrderbookV2 Orderbook of the market

DerivativeLimitOrderbookV2

Parameter Type Description
buys PriceLevel Array List of price levels for buys
sells PriceLevel Array List of price levels for sells
sequence Integer Sequence number of the orderbook; increments by 1 each update

PriceLevel

Parameter Type Description
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis
price String Price number of the price level

StreamOrderbooksV2

Stream orderbook snapshot updates for one or more derivative markets

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


async def orderbook_event_processor(event: Dict[str, Any]):
    print(event)


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative orderbook snapshots ({exception})")


def stream_closed_processor():
    print("The derivative orderbook snapshots stream has been closed")


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]

    task = asyncio.get_event_loop().create_task(
        client.listen_derivative_orderbook_snapshots(
            market_ids=market_ids,
            callback=orderbook_event_processor,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )

    await asyncio.sleep(delay=60)
    task.cancel()


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)

func main() {
    network := common.LoadNetwork("devnet-1", "")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
    stream, err := exchangeClient.StreamDerivativeOrderbookV2(ctx, marketIds)
    if err != nil {
        panic(err)
    }

    for {
        select {
        case <-ctx.Done():
            return
        default:
            res, err := stream.Recv()
            if err != nil {
                fmt.Println(err)
                return
            }
            fmt.Println(res.MarketId, len(res.Orderbook.Sells), len(res.Orderbook.Buys))
        }
    }
}
Parameter Type Description Required
market_ids String Array List of market IDs for orderbook streaming; empty means all spot markets Yes
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

{
   "orderbook":{
      "buys":[
         {
            "price":"13400000",
            "quantity":"683.3032",
            "timestamp":"1702002966962"
         },
         ...
      ],
      "sells":[
         {
            "price":"18390200",
            "quantity":"78815.8042",
            "timestamp":"1702002966962"
         },
         ...
      ],
      "sequence":"1919121",
      "timestamp":"1702003627697"
   },
   "operationType":"update",
   "timestamp":"1702003629000",
   "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
}

Parameter Type Description
orderbook DerivativeLimitOrderbookV2 Orderbook of a Derivative Market
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis
market_id String ID of the market the orderbook belongs to

DerivativeLimitOrderbookV2

Parameter Type Description
buys PriceLevel Array List of price levels for buys
sells PriceLevel Array List of price levels for sells
sequence Integer Sequence number of the orderbook; increments by 1 each update

PriceLevel

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
timestamp Integer Price level last updated timestamp in UNIX millis

StreamOrderbookUpdate

Stream incremental orderbook updates for one or more derivative markets. This stream should be started prior to obtaining orderbook snapshots so that no incremental updates are omitted between obtaining a snapshot and starting the update stream.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
from decimal import Decimal
from typing import Any, Dict

from grpc import RpcError

from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network


def stream_error_processor(exception: RpcError):
    print(f"There was an error listening to derivative orderbook updates ({exception})")


def stream_closed_processor():
    print("The derivative orderbook updates stream has been closed")


class PriceLevel:
    def __init__(self, price: Decimal, quantity: Decimal, timestamp: int):
        self.price = price
        self.quantity = quantity
        self.timestamp = timestamp

    def __str__(self) -> str:
        return "price: {} | quantity: {} | timestamp: {}".format(self.price, self.quantity, self.timestamp)


class Orderbook:
    def __init__(self, market_id: str):
        self.market_id = market_id
        self.sequence = -1
        self.levels = {"buys": {}, "sells": {}}


async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderbook):
    # load the snapshot
    res = await async_client.fetch_derivative_orderbooks_v2(market_ids=[orderbook.market_id])
    for snapshot in res["orderbooks"]:
        if snapshot["marketId"] != orderbook.market_id:
            raise Exception("unexpected snapshot")

        orderbook.sequence = int(snapshot["orderbook"]["sequence"])

        for buy in snapshot["orderbook"]["buys"]:
            orderbook.levels["buys"][buy["price"]] = PriceLevel(
                price=Decimal(buy["price"]),
                quantity=Decimal(buy["quantity"]),
                timestamp=int(buy["timestamp"]),
            )
        for sell in snapshot["orderbook"]["sells"]:
            orderbook.levels["sells"][sell["price"]] = PriceLevel(
                price=Decimal(sell["price"]),
                quantity=Decimal(sell["quantity"]),
                timestamp=int(sell["timestamp"]),
            )
        break


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    async_client = AsyncClient(network)

    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    orderbook = Orderbook(market_id=market_id)
    updates_queue = asyncio.Queue()
    tasks = []

    async def queue_event(event: Dict[str, Any]):
        await updates_queue.put(event)

    # start getting price levels updates
    task = asyncio.get_event_loop().create_task(
        async_client.listen_derivative_orderbook_updates(
            market_ids=[market_id],
            callback=queue_event,
            on_end_callback=stream_closed_processor,
            on_status_callback=stream_error_processor,
        )
    )
    tasks.append(task)

    # load the snapshot once we are already receiving updates, so we don't miss any
    await load_orderbook_snapshot(async_client=async_client, orderbook=orderbook)

    task = asyncio.get_event_loop().create_task(
        apply_orderbook_update(orderbook=orderbook, updates_queue=updates_queue)
    )
    tasks.append(task)

    await asyncio.sleep(delay=60)
    for task in tasks:
        task.cancel()


async def apply_orderbook_update(orderbook: Orderbook, updates_queue: asyncio.Queue):
    while True:
        updates = await updates_queue.get()
        update = updates["orderbookLevelUpdates"]

        # discard updates older than the snapshot
        if int(update["sequence"]) <= orderbook.sequence:
            return

        print(" * * * * * * * * * * * * * * * * * * *")

        # ensure we have not missed any update
        if int(update["sequence"]) > (orderbook.sequence + 1):
            raise Exception(
                "missing orderbook update events from stream, must restart: {} vs {}".format(
                    update["sequence"], (orderbook.sequence + 1)
                )
            )

        print("updating orderbook with updates at sequence {}".format(update["sequence"]))

        # update orderbook
        orderbook.sequence = int(update["sequence"])
        for direction, levels in {"buys": update["buys"], "sells": update["sells"]}.items():
            for level in levels:
                if level["isActive"]:
                    # upsert level
                    orderbook.levels[direction][level["price"]] = PriceLevel(
                        price=Decimal(level["price"]), quantity=Decimal(level["quantity"]), timestamp=level["timestamp"]
                    )
                else:
                    if level["price"] in orderbook.levels[direction]:
                        del orderbook.levels[direction][level["price"]]

        # sort the level numerically
        buys = sorted(orderbook.levels["buys"].values(), key=lambda x: x.price, reverse=True)
        sells = sorted(orderbook.levels["sells"].values(), key=lambda x: x.price, reverse=True)

        # lowest sell price should be higher than the highest buy price
        if len(buys) > 0 and len(sells) > 0:
            highest_buy = buys[0].price
            lowest_sell = sells[-1].price
            print("Max buy: {} - Min sell: {}".format(highest_buy, lowest_sell))
            if highest_buy >= lowest_sell:
                raise Exception("crossed orderbook, must restart")

        # for the example, print the list of buys and sells orders.
        print("sells")
        for k in sells:
            print(k)
        print("=========")
        print("buys")
        for k in buys:
            print(k)
        print("====================================")


if __name__ == "__main__":
    asyncio.run(main())
package main

import (
    "context"
    "fmt"
    "sort"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
    "github.com/shopspring/decimal"
)

type MapOrderbook struct {
    Sequence uint64
    Levels   map[bool]map[string]*derivativeExchangePB.PriceLevel
}

func main() {
    network := common.LoadNetwork("devnet-1", "")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    ctx := context.Background()
    marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
    stream, err := exchangeClient.StreamDerivativeOrderbookUpdate(ctx, marketIds)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    updatesCh := make(chan *derivativeExchangePB.OrderbookLevelUpdates, 100000)
    receiving := make(chan struct{})
    var receivingClosed bool

    // stream orderbook price levels
    go func() {
        defer close(updatesCh)
        for {
            select {
            case <-ctx.Done():
                return
            default:
                res, err := stream.Recv()
                if err != nil {
                    fmt.Println(err)
                    return
                }
                u := res.OrderbookLevelUpdates
                if !receivingClosed {
                    fmt.Println("receiving updates from stream")
                    close(receiving)
                    receivingClosed = true
                }
                updatesCh <- u
            }
        }
    }()

    // ensure we are receiving updates before getting orderbook
    fmt.Println("waiting for streaming updates")
    <-receiving

    // prepare orderbooks map
    orderbooks := map[string]*MapOrderbook{}
    res, err := exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
    if err != nil {
        panic(err)
    }
    for _, ob := range res.Orderbooks {
        // init inner maps not ready
        _, ok := orderbooks[ob.MarketId]
        if !ok {
            orderbook := &MapOrderbook{
                Sequence: ob.Orderbook.Sequence,
                Levels:   make(map[bool]map[string]*derivativeExchangePB.PriceLevel),
            }
            orderbook.Levels[true] = make(map[string]*derivativeExchangePB.PriceLevel)
            orderbook.Levels[false] = make(map[string]*derivativeExchangePB.PriceLevel)
            orderbooks[ob.MarketId] = orderbook
        }

        for _, level := range ob.Orderbook.Buys {
            orderbooks[ob.MarketId].Levels[true][level.Price] = level
        }
        for _, level := range ob.Orderbook.Sells {
            orderbooks[ob.MarketId].Levels[false][level.Price] = level
        }
    }

    // continuously consume level updates and maintain orderbook
    skippedPastEvents := false
    for {
        updates, ok := <-updatesCh
        if !ok {
            fmt.Println("updates channel closed, must restart")
            return // closed
        }

        // validate orderbook
        orderbook, ok := orderbooks[updates.MarketId]
        if !ok {
            panic("level update doesn't belong to any orderbooks")
        }

        // skip if update sequence <= orderbook sequence until it's ready to consume
        if !skippedPastEvents {
            if orderbook.Sequence >= updates.Sequence {
                continue
            }
            skippedPastEvents = true
        }

        // panic if update sequence > orderbook sequence + 1
        if updates.Sequence > orderbook.Sequence+1 {
            fmt.Printf("skipping levels: update sequence %d vs orderbook sequence %d\n", updates.Sequence, orderbook.Sequence)
            panic("missing orderbook update events from stream, must restart")
        }

        // update orderbook map
        orderbook.Sequence = updates.Sequence
        for isBuy, update := range map[bool][]*derivativeExchangePB.PriceLevelUpdate{
            true:  updates.Buys,
            false: updates.Sells,
        } {
            for _, level := range update {
                if level.IsActive {
                    // upsert
                    orderbook.Levels[isBuy][level.Price] = &derivativeExchangePB.PriceLevel{
                        Price:     level.Price,
                        Quantity:  level.Quantity,
                        Timestamp: level.Timestamp,
                    }
                } else {
                    // remove inactive level
                    delete(orderbook.Levels[isBuy], level.Price)
                }
            }
        }

        // construct orderbook arrays
        sells, buys := maintainOrderbook(orderbook.Levels)
        fmt.Println("after", orderbook.Sequence, len(sells), len(buys))

        if len(sells) > 0 && len(buys) > 0 {
            // assert orderbook
            topBuyPrice := decimal.RequireFromString(buys[0].Price)
            lowestSellPrice := decimal.RequireFromString(sells[0].Price)
            if topBuyPrice.GreaterThanOrEqual(lowestSellPrice) {
                panic(fmt.Errorf("crossed orderbook, must restart: buy %s >= %s sell", topBuyPrice, lowestSellPrice))
            }
        }

        res, _ = exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
        fmt.Println("query", res.Orderbooks[0].Orderbook.Sequence, len(res.Orderbooks[0].Orderbook.Sells), len(res.Orderbooks[0].Orderbook.Buys))

        // print orderbook
        fmt.Println(" [SELLS] ========")
        for _, s := range sells {
            fmt.Println(s)
        }
        fmt.Println(" [BUYS] ========")
        for _, b := range buys {
            fmt.Println(b)
        }
        fmt.Println("=======================================================")
    }
}

func maintainOrderbook(orderbook map[bool]map[string]*derivativeExchangePB.PriceLevel) (buys, sells []*derivativeExchangePB.PriceLevel) {
    for _, v := range orderbook[false] {
        sells = append(sells, v)
    }
    for _, v := range orderbook[true] {
        buys = append(buys, v)
    }

    sort.Slice(sells, func(i, j int) bool {
        return decimal.RequireFromString(sells[i].Price).LessThan(decimal.RequireFromString(sells[j].Price))
    })
    sort.Slice(buys, func(i, j int) bool {
        return decimal.RequireFromString(buys[i].Price).GreaterThan(decimal.RequireFromString(buys[j].Price))
    })

    return sells, buys
}
Parameter Type Description Required
market_ids String Array List of market IDs for orderbook streaming; empty means all derivative markets Yes
callback Function Function receiving one parameter (a stream event JSON dictionary) to process each new event Yes
on_end_callback Function Function with the logic to execute when the stream connection is interrupted No
on_status_callback Function Function receiving one parameter (the exception) with the logic to execute when an exception happens No

Response Parameters

Streaming Response Example:

* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 589
Max buy: 10000000000 - Min sell: 50000000000
sells
price: 101000000000 | quantity: 0.0007 | timestamp: 1675291761230
price: 100000000000 | quantity: 0.0037 | timestamp: 1675291786816
price: 70000000000 | quantity: 0.0001 | timestamp: 1671787246665
price: 65111000000 | quantity: 0.0449 | timestamp: 1675291786816
price: 50000000000 | quantity: 0.1 | timestamp: 1676326399734
=========
buys
price: 10000000000 | quantity: 0.0004 | timestamp: 1676622014694
price: 5000000000 | quantity: 0.0097 | timestamp: 1676383776468
price: 1000000000 | quantity: 0.0013 | timestamp: 1676622213616
====================================
* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 590
Max buy: 10000000000 - Min sell: 50000000000
sells
price: 101000000000 | quantity: 0.0007 | timestamp: 1675291761230
price: 100000000000 | quantity: 0.0037 | timestamp: 1675291786816
price: 70000000000 | quantity: 0.0001 | timestamp: 1671787246665
price: 65111000000 | quantity: 0.0449 | timestamp: 1675291786816
price: 50000000000 | quantity: 0.1 | timestamp: 1676326399734
=========
buys
price: 10000000000 | quantity: 0.0004 | timestamp: 1676622014694
price: 5000000000 | quantity: 0.0097 | timestamp: 1676383776468
price: 1000000000 | quantity: 0.0014 | timestamp: 1676622220695
====================================

Parameter Type Description
orderbook_level_updates OrderbookLevelUpdates Orderbook level updates of a derivative market
operation_type String Order update type (Should be one of: ["insert", "replace", "update", "invalidate"])
timestamp Integer Operation timestamp in UNIX millis
market_id String ID of the market the orderbook belongs to

OrderbookLevelUpdates

Parameter Type Description
market_id String ID of the market the orderbook belongs to
sequence Integer Orderbook update sequence number; increments by 1 each update
buys PriceLevelUpdate Array List of buy level updates
sells PriceLevelUpdate Array List of sell level updates
updated_at Integer Timestamp of the updates in UNIX millis

PriceLevelUpdate

Parameter Type Description
price String Price number of the price level
quantity String Quantity of the price level
is_active Boolean Price level status
timestamp Integer Price level last updated timestamp in UNIX millis

SubaccountOrdersList

Get the derivative orders of a specific subaccount.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    skip = 1
    limit = 2
    pagination = PaginationOption(skip=skip, limit=limit)
    orders = await client.fetch_subaccount_orders_list(
        subaccount_id=subaccount_id, market_id=market_id, pagination=pagination
    )
    print(orders)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)

    req := derivativeExchangePB.SubaccountOrdersListRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Skip:         skip,
        Limit:        limit,
    }

    res, err := exchangeClient.GetSubaccountDerivativeOrdersList(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Filter by subaccount ID Yes
market_id String Filter by market ID No
pagination PaginationOption Pagination configuration No

Response Parameters

Response Example:

{
   "orders":[
      {
         "orderHash":"0x0a3db65baf5d253b10e6f42e606a95503f72e920176b94e31ee802acde53ec84",
         "orderSide":"buy",
         "marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
         "subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
         "margin":"10107500",
         "price":"10107500",
         "quantity":"1",
         "unfilledQuantity":"1",
         "triggerPrice":"0",
         "feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
         "state":"booked",
         "createdAt":"1699794939298",
         "updatedAt":"1699794939298",
         "orderType":"buy",
         "txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
         "isReduceOnly":false,
         "orderNumber":"0",
         "isConditional":false,
         "triggerAt":"0",
         "placedOrderHash":"",
         "executionType":"",
         "cid":""
      }
   ],
   "paging":{
      "total":"2",
      "from":2,
      "to":2,
      "countBySubaccount":"0",
      "next":[

      ]
   }
}
{
 "orders": [
  {
   "order_hash": "0x8af0b619d31acda68d04b8a14e1488eee3c28792ded6fbb7393a489a4a8dbb58",
   "order_side": "buy",
   "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "margin": "36000000000",
   "price": "36000000000",
   "quantity": "1",
   "unfilled_quantity": "1",
   "trigger_price": "0",
   "fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
   "state": "booked",
   "created_at": 1652792829016,
   "updated_at": 1652792829016
  },
  {
   "order_hash": "0x457aadf92c40e5b2c4c7e6c3176872e72f36e11e7d4e718222b94a08a35ab071",
   "order_side": "buy",
   "market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
   "subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
   "margin": "155000000",
   "price": "31000000000",
   "quantity": "0.01",
   "unfilled_quantity": "0.01",
   "trigger_price": "0",
   "fee_recipient": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
   "state": "booked",
   "created_at": 1652701438661,
   "updated_at": 1652701438661
  }
 ]
}
Parameter Type Description
orders DerivativeLimitOrder Array List of derivative orders
paging Paging Pagination of results

DerivativeLimitOrder

Parameter Type Description
order_hash String Hash of the order
order_side String The side of the order (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell"])
market_id String The market ID
subaccount_id String The subaccount ID this order belongs to
is_reduce_only Boolean True if the order is a reduce-only order
margin String Margin of the order
price String Price of the order
quantity String Quantity of the order
unfilled_quantity String The amount of the quantity remaining unfilled
trigger_price String The price that triggers stop/take orders
fee_recipient String Fee recipient address
state String Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"])
created_at Integer Order created timestamp in UNIX millis
updated_at Integer Order updated timestamp in UNIX millis
order_number Integer Order number of subaccount
order_type String Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"])
is_conditional Boolean If the order is conditional
trigger_at Integer Trigger timestamp, only exists for conditional orders
placed_order_hash String OrderHash of order that is triggered by this conditional order
execution_type String Execution type of conditional order
tx_hash String Transaction hash in which the order was created (not all orders have this value)
cid String Identifier for the order specified by the user (up to 36 characters, like a UUID)

SubaccountTradesList

Get the derivative trades for a specific subaccount.

IP rate limit group: indexer

*Trade execution types

  1. "market" for market orders
  2. "limitFill" for a resting limit order getting filled by a market order
  3. "limitMatchRestingOrder" for a resting limit order getting matched with another new limit order
  4. "limitMatchNewOrder" for a new limit order getting matched immediately

Request Parameters

Request Example:

import asyncio

from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = AsyncClient(network)
    subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
    execution_type = "market"
    direction = "sell"
    skip = 10
    limit = 2
    pagination = PaginationOption(skip=skip, limit=limit)
    trades = await client.fetch_derivative_subaccount_trades_list(
        subaccount_id=subaccount_id,
        market_id=market_id,
        execution_type=execution_type,
        direction=direction,
        pagination=pagination,
    )
    print(trades)


if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())
package main

import (
    "context"
    "encoding/json"
    "fmt"

    "github.com/InjectiveLabs/sdk-go/client/common"
    exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
    derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)

func main() {
    //network := common.LoadNetwork("mainnet", "k8s")
    network := common.LoadNetwork("testnet", "lb")
    exchangeClient, err := exchangeclient.NewExchangeClient(network)
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
    subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
    skip := uint64(0)
    limit := int32(10)

    req := derivativeExchangePB.SubaccountTradesListRequest{
        MarketId:     marketId,
        SubaccountId: subaccountId,
        Skip:         skip,
        Limit:        limit,
    }

    res, err := exchangeClient.GetSubaccountDerivativeTradesList(ctx, &req)
    if err != nil {
        panic(err)
    }

    str, _ := json.MarshalIndent(res, "", " ")
    fmt.Print(string(str))
}
Parameter Type Description Required
subaccount_id String Subaccount ID of trader to get trades from Yes
market_id String Filter by Market ID