NAV
Python Golang

Change Log

2026-02-19

2025-11-10

2025-09-24

2025-07-29

2025-04-21

2025-02-17

2024-08-06

2024-07-30

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

Choose Exchange V1 or Exchange V2 queries

The Injective Python SDK provides two different clients for interacting with the exchange:

Example - Exchange V1 Client

from injective.async_client import AsyncClient
from injective.network import Network

async def main():
    # Initialize client with mainnet
    client = AsyncClient(network=Network.mainnet())
    # Or use testnet
    # client = AsyncClient(network=Network.testnet())
    # Use V1 exchange queries here
  1. Exchange V1 Client (async_client module):
    • Use this client if you need to interact with the original Injective Exchange API
    • Import using: from injective.async_client import AsyncClient
    • Suitable for applications that need to maintain compatibility with the original exchange interface

Example - Exchange V2 Client

from injective.async_client_v2 import AsyncClient
from injective.network import Network

async def main():
    # Initialize client with mainnet
    client = AsyncClient(network=Network.mainnet())
    # Or use testnet
    # client = AsyncClient(network=Network.testnet())
    # Use V2 exchange queries here
  1. Exchange V2 Client (async_client_v2 module):
    • Use this client for the latest exchange features and improvements
    • Import using: from injective.async_client_v2 import AsyncClient
    • Recommended for new applications and when you need access to the latest exchange features

Both clients provide similar interfaces but with different underlying implementations. Choose V2 for new projects unless you have specific requirements for V1 compatibility.

Market Format Differences:

Exchange Endpoint Format Differences:

Golang Client

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

go mod init foo

2. Import SDK into go.mod

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

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

Choose Exchange V1 or Exchange V2 queries

The SDK provides two different clients for interacting with the Injective Exchange:

Example - ChainClient

// For Exchange V1
client := chainclient.NewChainClient(...)

// For Exchange V2
clientV2 := chainclient.NewChainClientV2(...)

Markets Assistant

Example - Markets Assistant

// For Exchange V1 markets
marketsAssistant, err := chain.NewMarketsAssistant(ctx, client)  // ChainClient instance
if err != nil {
    // Handle error
}

// For Exchange V2 markets
marketsAssistantV2, err := chain.NewHumanReadableMarketsAssistant(ctx, clientV2)  // ChainClientV2 instance
if err != nil {
    // Handle error
}

The SDK provides a Markets Assistant to help you interact with markets in both V1 and V2. Here's how to create instances for each version

The Markets Assistant provides helper methods to:

Make sure to use the correct version of the Markets Assistant that matches your ChainClient version to ensure compatibility. The V1 assistant (NewMarketsAssistant) will only work with V1 markets, while the V2 assistant (NewHumanReadableMarketsAssistant) provides access to V2 markets and their features.

Format Differences

There are important format differences between V1 and V2 endpoints:

This format difference is one of the key improvements in V2, making it easier to work with market data without manual conversion.

Markets and Tokens information

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.

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

Gas estimation

Interactions with the Injective Chain that involve processing will incur gas consumption. The gas required for any action is related to the interactions with the chain store, and thus, the amount of gas is not deterministic. Users sending messages to the chain in transactions must estimate the gas required. There are two primary methods for determining the gas required for a transaction:

The InjectiveLabs team is developing a new functionality to make the gas requirement for certain Exchange module messages fixed, thereby making gas calculation deterministic. The fixed gas values, which will be implemented, can already serve as a reliable approximation for manually calculating the gas requirement for a transaction.

Fixed gas requirement

The following table lists message types with a fixed gas requirement. Any message not mentioned will continue to have a non-deterministic gas requirement based on chain store interactions.

Message type Gas units
MsgCreateDerivativeLimitOrderGas 120000
MsgCreateDerivativeLimitPostOnlyOrderGas 140000
MsgCreateDerivativeMarketOrderGas 105000
MsgCancelDerivativeOrderGas 70000
MsgCreateSpotLimitOrderGas 100000
MsgCreateSpotLimitPostOnlyOrderGas 120000
MsgCreateSpotMarketOrderGas 50000
MsgCancelSpotOrderGas 65000
MsgCreateBinaryOptionsLimitOrderGas 120000
MsgCreateBinaryOptionsLimitPostOnlyOrderGas 140000
MsgCreateBinaryOptionsMarketOrderGas 105000
MsgCancelBinaryOptionsOrderGas 70000
MsgDepositGas 70000
MsgWithdrawGas 70000
MsgSubaccountTransferGas 70000
MsgExternalTransferGas 70000
MsgIncreasePositionMarginGas 70000
MsgDecreasePositionMarginGas 70000

For the MsgBatchUpdateOrders the gas requirement will also be fixed. The gas requirement for each order action will match the individual order message actions as specified in the table. This applies similarly to the following batch messages:

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 json
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client_v2 import AsyncClient
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()

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

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)

    message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
        network=network,
        private_key=private_key_in_hexa,
        gas_price=gas_price,
        client=client,
        composer=composer,
    )

    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(json.dumps(result, indent=2))

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)
    message_broadcaster.update_gas_price(gas_price=gas_price)


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 json
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client_v2 import AsyncClient
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()

    client = AsyncClient(network)
    composer = await client.composer()
    await client.sync_timeout_height()

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)

    message_broadcaster = MsgBroadcasterWithPk.new_using_gas_heuristics(
        network=network,
        private_key=private_key_in_hexa,
        gas_price=gas_price,
        client=client,
        composer=composer,
    )

    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(json.dumps(result, indent=2))

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)
    message_broadcaster.update_gas_price(gas_price=gas_price)


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 json
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client_v2 import AsyncClient
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()

    # initialize grpc client
    client = AsyncClient(network)
    composer = await client.composer()
    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()

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)

    message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_using_simulation(
        network=network,
        grantee_private_key=private_key_in_hexa,
        gas_price=gas_price,
        client=client,
        composer=composer,
    )

    # 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(json.dumps(result, indent=2))

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)
    message_broadcaster.update_gas_price(gas_price=gas_price)


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 json
import os
import uuid
from decimal import Decimal

import dotenv

from pyinjective.async_client_v2 import AsyncClient
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()

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

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

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)

    message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_without_simulation(
        network=network,
        grantee_private_key=private_key_in_hexa,
        gas_price=gas_price,
        client=client,
        composer=composer,
    )

    # 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(json.dumps(result, indent=2))

    gas_price = await client.current_chain_gas_price()
    # adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
    gas_price = int(gas_price * 1.1)
    message_broadcaster.update_gas_price(gas_price=gas_price)


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.



Fine-tunning message based gas fee 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:

Gas limit estimation based on gas heuristics

This is the estimator implemented with the class GasHeuristicsGasLimitEstimator.

Module Global Variable Description
pyinjective.core.gas_heuristics_gas_limit_estimator SPOT_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one spot limit order
pyinjective.core.gas_heuristics_gas_limit_estimator SPOT_MARKET_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one spot market order
pyinjective.core.gas_heuristics_gas_limit_estimator POST_ONLY_SPOT_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one post only spot limit order
pyinjective.core.gas_heuristics_gas_limit_estimator DERIVATIVE_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one derivative order
pyinjective.core.gas_heuristics_gas_limit_estimator DERIVATIVE_MARKET_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one derivative market order
pyinjective.core.gas_heuristics_gas_limit_estimator POST_ONLY_DERIVATIVE_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one post only derivative limit order
pyinjective.core.gas_heuristics_gas_limit_estimator BINARY_OPTIONS_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one binary options order
pyinjective.core.gas_heuristics_gas_limit_estimator BINARY_OPTIONS_MARKET_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one binary options market order
pyinjective.core.gas_heuristics_gas_limit_estimator POST_ONLY_BINARY_OPTIONS_ORDER_CREATION_GAS_LIMIT The gas cost associated to the creation of one post only binary options limit order
pyinjective.core.gas_heuristics_gas_limit_estimator SPOT_ORDER_CANCELATION_GAS_LIMIT The gas cost associated to the cancellation of one spot order
pyinjective.core.gas_heuristics_gas_limit_estimator DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT The gas cost associated to the cancellation of one derivative order
pyinjective.core.gas_heuristics_gas_limit_estimator BINARY_OPTIONS_ORDER_CANCELATION_GAS_LIMIT The gas cost associated to the cancellation of one binary options order
pyinjective.core.gas_heuristics_gas_limit_estimator DEPOSIT_GAS_LIMIT The gas cost associated to a deposit into a subaccount
pyinjective.core.gas_heuristics_gas_limit_estimator WITHDRAW_GAS_LIMIT The gas cost associated to a withdrawal from a subaccount
pyinjective.core.gas_heuristics_gas_limit_estimator SUBACCOUNT_TRANSFER_GAS_LIMIT The gas cost associated to a funds transfer between subaccounts of the same address
pyinjective.core.gas_heuristics_gas_limit_estimator EXTERNAL_TRANSFER_GAS_LIMIT The gas cost associated to a funds transfer to a subaccount from a different address
pyinjective.core.gas_heuristics_gas_limit_estimator INCREASE_POSITION_MARGIN_TRANSFER_GAS_LIMIT The gas cost associated to increasing a position's margin
pyinjective.core.gas_heuristics_gas_limit_estimator DECREASE_POSITION_MARGIN_TRANSFER_GAS_LIMIT The gas cost associated to decreasing a position's margin
Module Class Global Variable Description
pyinjective.core.broadcaster.py MessageBasedTransactionFeeCalculator TRANSACTION_GAS_LIMIT The gas cost associated to the TX processing
pyinjective.core.gas_heuristics_gas_limit_estimator GasHeuristicsGasLimitEstimator GENERAL_MESSAGE_GAS_LIMIT Generic base gas cost for any message
pyinjective.core.gas_heuristics_gas_limit_estimator 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
pyinjective.core.gas_heuristics_gas_limit_estimator ExecGasLimitEstimator DEFAULT_GAS_LIMIT Estimation of the general gas amount required for a MsgExec (for the general message processing)

Gas limit estimation based on chain statistics

This is the estimator implemented with the class GasLimitEstimator, and it is the original implementation for gas estimation without simulations. It has been replaced now by the GasHeuristicsGasLimitEstimator, but the user can still use it.

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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(network)
    account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
    subacc_list = await client.fetch_subaccounts_list(account_address)
    print(json.dumps(subacc_list, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
account_addressstringAccount address, the subaccounts ownerYes

Response Parameters

Response Example:

{
   "subaccounts":[
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002",
      "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000"
   ]
}
{
 "subaccounts": [
  "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
  "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002"
 ]
}
ParameterTypeDescription
subaccountsstring array

SubaccountHistory

Get the subaccount's transfer history.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(subacc_history, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the history fromYes
denomstringFilter history by denomYes
transfer_typesstring arrayFilter history by transfer typeYes
skipuint64Skip will skip the first n item from the resultYes
limitint32Limit is used to specify the maximum number of items to be returnedYes
end_timeint64Upper bound of account transfer history's executedAtYes

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
  }
 ]
}
ParameterTypeDescription
transfersSubaccountBalanceTransfer arrayList of subaccount transfers
pagingPaging


SubaccountBalanceTransfer

ParameterTypeDescription
transfer_typestringType of the subaccount balance transfer
src_subaccount_idstringSubaccount ID of the sending side
src_account_addressstringAccount address of the sending side
dst_subaccount_idstringSubaccount ID of the receiving side
dst_account_addressstringAccount address of the receiving side
amountCosmosCoinCoin amount of the transfer
executed_atint64Timestamp of the transfer in UNIX millis


CosmosCoin

ParameterTypeDescription
denomstringCoin denominator
amountstringCoin amount (big int)


Paging

ParameterTypeDescription
totalint64total number of txs saved in database
fromint32can be either block height or index num
toint32can be either block height or index num
count_by_subaccountint64count entries by subaccount, serving some places on helix
nextstring arrayarray of tokens to navigate to the next pages

SubaccountBalance

Get the balance of a subaccount for a specific denom.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


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


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
denomstringSpecify denom to get balanceYes

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"
  }
 }
}
ParameterTypeDescription
balanceSubaccountBalanceSubaccount balance


SubaccountBalance

ParameterTypeDescription
subaccount_idstringRelated subaccount ID
account_addressstringAccount address, owner of this subaccount
denomstringCoin denom on the chain.
depositSubaccountDeposit


SubaccountDeposit

ParameterTypeDescription
total_balancestring
available_balancestring
total_balance_usdstring
available_balance_usdstring

SubaccountBalancesList

List the subaccount's balances for all denoms.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


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


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
denomsstring arrayFilter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided.Yes

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"
   }
  }
 ]
}
ParameterTypeDescription
balancesSubaccountBalance arrayList of subaccount balances


SubaccountBalance

ParameterTypeDescription
subaccount_idstringRelated subaccount ID
account_addressstringAccount address, owner of this subaccount
denomstringCoin denom on the chain.
depositSubaccountDeposit


SubaccountDeposit

ParameterTypeDescription
total_balancestring
available_balancestring
total_balance_usdstring
available_balance_usdstring

SubaccountOrderSummary

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

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(subacc_order_summary, indent=2))


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)
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the summary fromYes
market_idstringMarketId is limiting order summary to specific market onlyYes
order_directionstringFilter by direction of the ordersYes

Response Parameters

Response Example:

{
   "derivativeOrdersTotal":"1",
   "spotOrdersTotal":"0"
}
spot orders: 1
derivative orders: 7
ParameterTypeDescription
spot_orders_totalint64Total count of subaccount's spot orders in given market and direction
derivative_orders_totalint64Total count of subaccount's derivative orders in 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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(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, "", "\t")
            fmt.Print(string(str))
        }
    }
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
denomsstring arrayFilter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided.Yes

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
}
ParameterTypeDescription
balanceSubaccountBalanceSubaccount balance
timestampint64Operation timestamp in UNIX millis.


SubaccountBalance

ParameterTypeDescription
subaccount_idstringRelated subaccount ID
account_addressstringAccount address, owner of this subaccount
denomstringCoin denom on the chain.
depositSubaccountDeposit


SubaccountDeposit

ParameterTypeDescription
total_balancestring
available_balancestring
total_balance_usdstring
available_balance_usdstring

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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(orders, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
spot_order_hashesstring arrayYes
derivative_order_hashesstring arrayYes

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
  }
 ]
}
ParameterTypeDescription
spot_order_statesOrderStateRecord arrayList of the spot order state records
derivative_order_statesOrderStateRecord arrayList of the derivative order state records


OrderStateRecord

ParameterTypeDescription
order_hashstringHash of the order
subaccount_idstringThe subaccountId that this order belongs to
market_idstringThe Market ID of the order
order_typestringThe type of the order
order_sidestringThe side of the order
statestringThe state (status) of the order
quantity_filledstringThe filled quantity of the order
quantity_remainingstringThe filled quantity of the order
created_atint64Order committed timestamp in UNIX millis.
updated_atint64Order updated timestamp in UNIX millis.
pricestringOrder prices
marginstringMargin for derivative order

Portfolio

Get an overview of your portfolio.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(network)
    account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
    portfolio = await client.fetch_portfolio(account_address=account_address)
    print(json.dumps(portfolio, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
account_addressstringAccount addressYes

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"
   }
  ]
 }
}
ParameterTypeDescription
portfolioAccountPortfolioThe portfolio of this account


AccountPortfolio

ParameterTypeDescription
portfolio_valuestringThe account's portfolio value in USD.
available_balancestringThe account's available balance value in USD.
locked_balancestringThe account's locked balance value in USD.
unrealized_pnlstringThe account's total unrealized PnL value in USD.
subaccountsSubaccountPortfolio arrayList of all subaccounts' portfolio


SubaccountPortfolio

ParameterTypeDescription
subaccount_idstringThe ID of this subaccount
available_balancestringThe subaccount's available balance value in USD.
locked_balancestringThe subaccount's locked balance value in USD.
unrealized_pnlstringThe 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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


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


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
epochint64The distribution epoch sequence number. -1 for latest.Yes
account_addressstringAccount address for the rewards distributionYes

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
  }
 ]
}
ParameterTypeDescription
rewardsReward arrayThe trading rewards distributed


Reward

ParameterTypeDescription
account_addressstringAccount address
rewardsCoin arrayReward coins distributed
distributed_atint64Rewards distribution timestamp in UNIX millis.


Coin

ParameterTypeDescription
denomstringDenom of the coin
amountstring
usd_valuestring

- 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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(network)
    market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
    market = await client.fetch_spot_market(market_id=market_id)
    print(json.dumps(market, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_idstringMarketId of the market we want to fetchYes

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",
      "minNotional": "1000000"
   }
}
{
 "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",
  "min_notional": "1000000"
 }
}
ParameterTypeDescription
marketSpotMarketInfoInfo about particular spot market


SpotMarketInfo

ParameterTypeDescription
market_idstringSpotMarket ID is keccak265(baseDenom || quoteDenom)
market_statusstringThe status of the market
tickerstringA name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset.
base_denomstringCoin denom used for the base asset.
base_token_metaTokenMetaToken metadata for base asset
quote_denomstringCoin denom used for the quote asset.
quote_token_metaTokenMetaToken metadata for quote asset
maker_fee_ratestringDefines the fee percentage makers pay when trading (in quote asset)
taker_fee_ratestringDefines the fee percentage takers pay when trading (in quote asset)
service_provider_feestringPercentage of the transaction fee shared with the service provider
min_price_tick_sizestringDefines the minimum required tick size for the order's price
min_quantity_tick_sizestringDefines the minimum required tick size for the order's quantity
min_notionalstringMinimum notional value for the market


TokenMeta

ParameterTypeDescription
namestringToken full name
addressstringToken contract address (native or not)
symbolstringToken symbol short name
logostringURL to the logo image
decimalsint32Token decimals
updated_atint64Token metadata fetched timestamp in UNIX millis.

Markets

Get a list of spot markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(market, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_statusstringFilter by market statusYes
base_denomstringFilter by the Coin denomination of the base currencyYes
quote_denomstringFilter by the Coin denomination of the quote currencyYes
market_statusesstring arrayYes

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",
         "minNotional":"1000000"
      }
   ]
}
{
 "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",
   "min_notional": "1000000"
  }
 ]
}
ParameterTypeDescription
marketsSpotMarketInfo arraySpot Markets list


SpotMarketInfo

ParameterTypeDescription
market_idstringSpotMarket ID is keccak265(baseDenom || quoteDenom)
market_statusstringThe status of the market
tickerstringA name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset.
base_denomstringCoin denom used for the base asset.
base_token_metaTokenMetaToken metadata for base asset
quote_denomstringCoin denom used for the quote asset.
quote_token_metaTokenMetaToken metadata for quote asset
maker_fee_ratestringDefines the fee percentage makers pay when trading (in quote asset)
taker_fee_ratestringDefines the fee percentage takers pay when trading (in quote asset)
service_provider_feestringPercentage of the transaction fee shared with the service provider
min_price_tick_sizestringDefines the minimum required tick size for the order's price
min_quantity_tick_sizestringDefines the minimum required tick size for the order's quantity
min_notionalstringMinimum notional value for the market


TokenMeta

ParameterTypeDescription
namestringToken full name
addressstringToken contract address (native or not)
symbolstringToken symbol short name
logostringURL to the logo image
decimalsint32Token decimals
updated_atint64Token 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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(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, "", "\t")
            fmt.Print(string(str))
        }
    }
}
ParameterTypeDescriptionRequired
market_idsstring arrayList of market IDs for updates streaming, empty means 'ALL' spot marketsYes

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",
      "minNotional":"0"
   },
   "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",
  "min_notional": "0",
},
  "operation_type": "update",
  "timestamp": 1632535055790
}
ParameterTypeDescription
marketSpotMarketInfoInfo about particular spot market
operation_typestringUpdate type
timestampint64Operation timestamp in UNIX millis.


SpotMarketInfo

ParameterTypeDescription
market_idstringSpotMarket ID is keccak265(baseDenom || quoteDenom)
market_statusstringThe status of the market
tickerstringA name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset.
base_denomstringCoin denom used for the base asset.
base_token_metaTokenMetaToken metadata for base asset
quote_denomstringCoin denom used for the quote asset.
quote_token_metaTokenMetaToken metadata for quote asset
maker_fee_ratestringDefines the fee percentage makers pay when trading (in quote asset)
taker_fee_ratestringDefines the fee percentage takers pay when trading (in quote asset)
service_provider_feestringPercentage of the transaction fee shared with the service provider
min_price_tick_sizestringDefines the minimum required tick size for the order's price
min_quantity_tick_sizestringDefines the minimum required tick size for the order's quantity
min_notionalstringMinimum notional value for the market


TokenMeta

ParameterTypeDescription
namestringToken full name
addressstringToken contract address (native or not)
symbolstringToken symbol short name
logostringURL to the logo image
decimalsint32Token decimals
updated_atint64Token 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
import json

from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(orders, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringsubaccount ID to filter orders for specific subaccountYes
market_idstringMarket ID to filter orders for specific marketYes
skipuint64Skip will skip the first n item from the resultYes
limitint32Limit is used to specify the maximum number of items to be returnedYes
order_typesstring arrayfilter by order typesYes
directionstringorder side filterYes
start_timeint64Search for orders which createdAt >= startTime, time in millisecondYes
end_timeint64Search for orders which createdAt <= endTime, time in millisecondYes
statestringFilter by order stateYes
execution_typesstring arrayYes
market_idsstring arrayYes
trade_idstringTradeId of the order we want to fetchYes
active_markets_onlyboolReturn only orders for active marketsYes
cidstringClient order IDYes

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
 }
}

ParameterTypeDescription
ordersSpotOrderHistory arrayList of history spot orders
pagingPaging


SpotOrderHistory

ParameterTypeDescription
order_hashstringHash of the order
market_idstringSpot Market ID is keccak265(baseDenom + quoteDenom)
is_activeboolactive state of the order
subaccount_idstringThe subaccountId that this order belongs to
execution_typestringThe execution type
order_typestringThe side of the order
pricestringPrice of the order
trigger_pricestringTrigger price
quantitystringQuantity of the order
filled_quantitystringFilled amount
statestringOrder state
created_atint64Order committed timestamp in UNIX millis.
updated_atint64Order updated timestamp in UNIX millis.
directionstringOrder direction (order side)
tx_hashstringTransaction Hash where order is created. Not all orders have this field
cidstringCustom client order ID


Paging

ParameterTypeDescription
totalint64total number of txs saved in database
fromint32can be either block height or index num
toint32can be either block height or index num
count_by_subaccountint64count entries by subaccount, serving some places on helix
nextstring arrayarray of tokens to navigate to the next pages

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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(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, "", "\t")
            fmt.Print(string(str))
        }
    }
}
ParameterTypeDescriptionRequired
subaccount_idstringsubaccount ID to filter orders for specific subaccountYes
market_idstringMarket ID to filter orders for specific marketYes
order_typesstring arrayfilter by order typesYes
directionstringorder side filterYes
statestringFilter by order stateYes
execution_typesstring arrayYes

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
}
ParameterTypeDescription
orderSpotOrderHistoryUpdated order
operation_typestringOrder update type
timestampint64Operation timestamp in UNIX millis.


SpotOrderHistory

ParameterTypeDescription
order_hashstringHash of the order
market_idstringSpot Market ID is keccak265(baseDenom + quoteDenom)
is_activeboolactive state of the order
subaccount_idstringThe subaccountId that this order belongs to
execution_typestringThe execution type
order_typestringThe side of the order
pricestringPrice of the order
trigger_pricestringTrigger price
quantitystringQuantity of the order
filled_quantitystringFilled amount
statestringOrder state
created_atint64Order committed timestamp in UNIX millis.
updated_atint64Order updated timestamp in UNIX millis.
directionstringOrder direction (order side)
tx_hashstringTransaction Hash where order is created. Not all orders have this field
cidstringCustom client order ID

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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(orders, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_idstringMarketId of the market's orderbook we want to fetchYes
execution_sidestringFilter by execution side of the tradeYes
directionstringFilter by direction the tradeYes
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
skipuint64Skip will skip the first n item from the item resultYes
limitint32Limit is used to specify the maximum number of items to be returned.Yes
start_timeint64The starting timestamp in UNIX milliseconds that the trades must be equal or older thanYes
end_timeint64The ending timestamp in UNIX milliseconds that the trades must be equal or younger thanYes
market_idsstring arrayMarketIds of the markets of which we want to get tradesYes
subaccount_idsstring arraySubaccount ids of traders we want to get tradesYes
execution_typesstring arrayYes
trade_idstringFilter by the tradeId of the tradeYes
account_addressstringAccount addressYes
cidstringClient order IDYes
fee_recipientstringFee recipient addressYes

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
 }
}

ParameterTypeDescription
tradesSpotTrade arrayTrades of a Spot Market
pagingPagingPaging indicates pages response is on


SpotTrade

ParameterTypeDescription
order_hashstringMaker order hash.
subaccount_idstringThe subaccountId that executed the trade
market_idstringThe ID of the market that this trade is in
trade_execution_typestringThe execution type of the trade
trade_directionstringThe direction the trade
pricePriceLevelPrice level at which trade has been executed
feestringThe fee associated with the trade (quote asset denom)
executed_atint64Timestamp of trade execution in UNIX millis
fee_recipientstringFee recipient address
trade_idstringA unique string that helps differentiate between trades
execution_sidestringTrade's execution side, marker/taker
cidstringCustom client order ID


PriceLevel

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
timestampint64Price level last updated timestamp in UNIX millis.


Paging

ParameterTypeDescription
totalint64total number of txs saved in database
fromint32can be either block height or index num
toint32can be either block height or index num
count_by_subaccountint64count entries by subaccount, serving some places on helix
nextstring arrayarray of tokens to navigate to the next pages

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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(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, "", "\t")
            fmt.Print(string(str))
        }
    }
}
ParameterTypeDescriptionRequired
market_idstringMarketId of the market's orderbook we want to fetchYes
execution_sidestringFilter by execution side of the tradeYes
directionstringFilter by direction the tradeYes
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
skipuint64Skip will skip the first n item from the item resultYes
limitint32Limit is used to specify the maximum number of items to be returned.Yes
start_timeint64The starting timestamp in UNIX milliseconds that the trades must be equal or older thanYes
end_timeint64The ending timestamp in UNIX milliseconds that the trades must be equal or younger thanYes
market_idsstring arrayMarketIds of the markets of which we want to get tradesYes
subaccount_idsstring arraySubaccount ids of traders we want to get tradesYes
execution_typesstring arrayYes
trade_idstringFilter by the tradeId of the tradeYes
account_addressstringAccount addressYes
cidstringClient order IDYes
fee_recipientstringFee recipient addressYes

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
}
ParameterTypeDescription
tradeSpotTradeNew spot market trade
operation_typestringExecuted trades update type
timestampint64Operation timestamp in UNIX millis.


SpotTrade

ParameterTypeDescription
order_hashstringMaker order hash.
subaccount_idstringThe subaccountId that executed the trade
market_idstringThe ID of the market that this trade is in
trade_execution_typestringThe execution type of the trade
trade_directionstringThe direction the trade
pricePriceLevelPrice level at which trade has been executed
feestringThe fee associated with the trade (quote asset denom)
executed_atint64Timestamp of trade execution in UNIX millis
fee_recipientstringFee recipient address
trade_idstringA unique string that helps differentiate between trades
execution_sidestringTrade's execution side, marker/taker
cidstringCustom client order ID


PriceLevel

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
timestampint64Price 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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    network = Network.testnet()
    client = IndexerClient(network)
    market_ids = [
        "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
        "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
    ]
    depth = 1
    orderbooks = await client.fetch_spot_orderbooks_v2(market_ids=market_ids, depth=depth)
    print(json.dumps(orderbooks, indent=2))


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"}
    depth := int32(10)
    res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds, depth)
    if err != nil {
        fmt.Println(err)
    }

    str, _ := json.MarshalIndent(res, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_idsstring arrayMarketIds of the marketsYes
depthint32Depth of the orderbookYes

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"
         }
      }
   ]
}

ParameterTypeDescription
orderbooksSingleSpotLimitOrderbookV2 array


SingleSpotLimitOrderbookV2

ParameterTypeDescription
market_idstringmarket's ID
orderbookSpotLimitOrderbookV2Orderbook of the market


SpotLimitOrderbookV2

ParameterTypeDescription
buysPriceLevel arrayArray of price levels for buys
sellsPriceLevel arrayArray of price levels for sells
sequenceuint64market orderbook sequence
timestampint64Last update timestamp in UNIX millis.
heightint64Block height at which the orderbook was last updated.


PriceLevel

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
timestampint64Price level last updated timestamp in UNIX millis.

StreamOrderbookV2

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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(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))
        }
    }
}
ParameterTypeDescriptionRequired
market_idsstring arrayList of market IDs for orderbook streaming, empty means 'ALL' spot marketsYes

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"
}

ParameterTypeDescription
orderbookSpotLimitOrderbookV2Orderbook of a Spot Market
operation_typestringOrder update type
timestampint64Operation timestamp in UNIX millis.
market_idstringMarketId of the market's orderbook


SpotLimitOrderbookV2

ParameterTypeDescription
buysPriceLevel arrayArray of price levels for buys
sellsPriceLevel arrayArray of price levels for sells
sequenceuint64market orderbook sequence
timestampint64Last update timestamp in UNIX millis.
heightint64Block height at which the orderbook was last updated.


PriceLevel

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
timestampint64Price 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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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(client: IndexerClient, orderbook: Orderbook):
    # load the snapshot
    res = await client.fetch_spot_orderbooks_v2(market_ids=[orderbook.market_id], depth=0)
    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"]),
            )


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = IndexerClient(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(
        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(client=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)
    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{}
    depth := int32(0)
    res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds, depth)
    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, depth)
        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
}
ParameterTypeDescriptionRequired
market_idsstring arrayList of market IDs for orderbook streaming, empty means 'ALL' spot marketsYes

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
====================================

ParameterTypeDescription
orderbook_level_updatesOrderbookLevelUpdatesOrderbook level updates of a Spot Market
operation_typestringOrder update type
timestampint64Operation timestamp in UNIX millis.
market_idstringMarketId of the market's orderbook


OrderbookLevelUpdates

ParameterTypeDescription
market_idstringmarket's ID
sequenceuint64orderbook update sequence
buysPriceLevelUpdate arraybuy levels
sellsPriceLevelUpdate arraysell levels
updated_atint64updates timestamp


PriceLevelUpdate

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
is_activeboolPrice level status.
timestampint64Price level last updated timestamp in UNIX millis.

SubaccountOrdersList

Get orders of a subaccount.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(orders, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringsubaccount ID to filter orders for specific subaccountYes
market_idstringMarket ID to filter orders for specific marketYes
skipuint64Skip will skip the first n item from the resultYes
limitint32Limit is used to specify the maximum number of items to be returnedYes

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
  }
 ]
}
ParameterTypeDescription
ordersSpotLimitOrder array
pagingPaging


SpotLimitOrder

ParameterTypeDescription
order_hashstringHash of the order
order_sidestringThe side of the order
market_idstringSpot Market ID is keccak265(baseDenom + quoteDenom)
subaccount_idstringThe subaccountId that this order belongs to
pricestringPrice of the order
quantitystringQuantity of the order
unfilled_quantitystringThe amount of the quantity remaining unfilled
trigger_pricestringTrigger price is the trigger price used by stop/take orders. 0 if the trigger price is not set.
fee_recipientstringFee recipient address
statestringOrder state
created_atint64Order committed timestamp in UNIX millis.
updated_atint64Order updated timestamp in UNIX millis.
tx_hashstringTransaction Hash where order is created. Not all orders have this field
cidstringCustom client order ID


Paging

ParameterTypeDescription
totalint64total number of txs saved in database
fromint32can be either block height or index num
toint32can be either block height or index num
count_by_subaccountint64count entries by subaccount, serving some places on helix
nextstring arrayarray of tokens to navigate to the next pages

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
import json

from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


async def main() -> None:
    # select network: local, testnet, mainnet
    network = Network.testnet()
    client = IndexerClient(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(json.dumps(trades, indent=2))


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
subaccount_idstringSubaccountId of the trader we want to get the trades fromYes
market_idstringFilter trades by market IDYes
execution_typestringFilter by execution type of tradesYes
directionstringFilter by direction tradesYes
skipuint64Skip will skip the first n item from the resultYes
limitint32Limit is used to specify the maximum number of items to be returnedYes

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"
  }
 ]
}

ParameterTypeDescription
tradesSpotTrade arrayList of spot market trades


SpotTrade

ParameterTypeDescription
order_hashstringMaker order hash.
subaccount_idstringThe subaccountId that executed the trade
market_idstringThe ID of the market that this trade is in
trade_execution_typestringThe execution type of the trade
trade_directionstringThe direction the trade
pricePriceLevelPrice level at which trade has been executed
feestringThe fee associated with the trade (quote asset denom)
executed_atint64Timestamp of trade execution in UNIX millis
fee_recipientstringFee recipient address
trade_idstringA unique string that helps differentiate between trades
execution_sidestringTrade's execution side, marker/taker
cidstringCustom client order ID


PriceLevel

ParameterTypeDescription
pricestringPrice number of the price level.
quantitystringQuantity of the price level.
timestampint64Price 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
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


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


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_idstringMarketId of the market we want to fetchYes

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"
      },
      "min_notional":"1000000"
   }
}
{
 "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
  },
  "min_notional": "1000000"
 }
}
ParameterTypeDescription
marketDerivativeMarketInfoInfo about particular derivative market

DerivativeMarketInfo

ParameterTypeDescription
market_idstringDerivativeMarket ID is crypto.Keccak256Hash([]byte((oracleType.String() + ticker + quoteDenom + oracleBase + oracleQuote))) for perpetual markets and crypto.Keccak256Hash([]byte((oracleType.String() + ticker + quoteDenom + oracleBase + oracleQuote + strconv.Itoa(int(expiry))))) for expiry futures markets
market_statusstringThe status of the market
tickerstringA name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset.
oracle_basestringOracle base currency
oracle_quotestringOracle quote currency
oracle_typestringOracle Type
oracle_scale_factoruint32OracleScaleFactor
initial_margin_ratiostringDefines the initial margin ratio of a derivative market
maintenance_margin_ratiostringDefines the maintenance margin ratio of a derivative market
quote_denomstringCoin denom used for the quote asset.
quote_token_metaTokenMetaToken metadata for quote asset
maker_fee_ratestringDefines the fee percentage makers pay when trading (in quote asset)
taker_fee_ratestringDefines the fee percentage takers pay when trading (in quote asset)
service_provider_feestringPercentage of the transaction fee shared with the service provider
is_perpetualboolTrue if the market is a perpetual swap market
min_price_tick_sizestringDefines the minimum required tick size for the order's price
min_quantity_tick_sizestringDefines the minimum required tick size for the order's quantity
perpetual_market_infoPerpetualMarketInfo
perpetual_market_fundingPerpetualMarketFunding
expiry_futures_market_infoExpiryFuturesMarketInfo
min_notionalstringMinimum notional value for the order
reduce_margin_ratiostringDefines the reduce margin ratio of a derivative market
open_notional_capOpenNotionalCapThe open notional cap of the market, if any


TokenMeta

ParameterTypeDescription
namestringToken full name
addressstringToken contract address (native or not)
symbolstringToken symbol short name
logostringURL to the logo image
decimalsint32Token decimals
updated_atint64Token metadata fetched timestamp in UNIX millis.


PerpetualMarketInfo

ParameterTypeDescription
hourly_funding_rate_capstringDefines the default maximum absolute value of the hourly funding rate of the perpetual market.
hourly_interest_ratestringDefines the hourly interest rate of the perpetual market.
next_funding_timestampint64Defines the next funding timestamp in seconds of a perpetual market in UNIX seconds.
funding_intervalint64Defines the funding interval in seconds of a perpetual market in seconds.


PerpetualMarketFunding

ParameterTypeDescription
cumulative_fundingstringDefines the cumulative funding of a perpetual market.
cumulative_pricestringDefines defines the cumulative price for the current hour up to the last timestamp.
last_timestampint64Defines the last funding timestamp in seconds of a perpetual market in UNIX seconds.
last_funding_ratestringDefines the last funding rate of a perpetual market.


ExpiryFuturesMarketInfo

ParameterTypeDescription
expiration_timestampint64Defines the expiration time for a time expiry futures market in UNIX seconds.
settlement_pricestringDefines the settlement price for a time expiry futures market.


Markets

Get a list of one or more derivative markets.

IP rate limit group: indexer

Request Parameters

Request Example:

import asyncio
import json

from pyinjective.core.network import Network
from pyinjective.indexer_client import IndexerClient


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


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, "", "\t")
    fmt.Print(string(str))
}
ParameterTypeDescriptionRequired
market_statusstringFilter by market statusYes
quote_denomstringFilter by the Coin denomination of the quote currencyYes
market_statusesstring arrayYes

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
    },
    "min_notional": "1000000",
  },
  {
    "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"
    },
    "min_notional": "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
   },
   "min_notional": "1000000"
  },
  {
   "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
   },
   "min_notional": "0",
  }
 ]
}
ParameterTypeDescription
marketsDerivativeMarketInfo arrayDerivative Markets list


DerivativeMarketInfo

ParameterTypeDescription
market_idstringDerivativeMarket ID is crypto.Keccak256Hash([]byte((oracleType.String() + ticker + quoteDenom + oracleBase + oracleQuote))) for perpetual markets and crypto.Keccak256Hash([]byte((oracleType.String() + ticker + quoteDenom + oracleBase + oracleQuote + strconv.Itoa(int(expiry))))) for expiry futures markets
market_statusstringThe status of the market
tickerstringA name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset.
oracle_basestringOracle base currency
oracle_quotestringOracle quote currency
oracle_typestringOracle Type
oracle_scale_factoruint32OracleScaleFactor
initial_margin_ratiostringDefines the initial margin ratio of a derivative market
maintenance_margin_ratiostringDefines the maintenance margin ratio of a derivative market
quote_denomstringCoin denom used for the quote asset.
quote_token_metaTokenMetaToken metadata for quote asset
maker_fee_ratestringDefines the fee percentage makers pay when trading (in quote asset)
taker_fee_ratestringDefines the fee percentage takers pay when trading (in quote asset)
service_provider_feestringPercentage of the transaction fee shared with the service provider
is_perpetualboolTrue if the market is a perpetual swap market
min_price_tick_sizestringDefines the minimum required tick size for the order's price
min_quantity_tick_sizestringDefines the minimum required tick size for the order's quantity
perpetual_market_infoPerpetualMarketInfo
perpetual_market_fundingPerpetualMarketFunding
expiry_futures_market_infoExpiryFuturesMarketInfo
min_notionalstringMinimum notional value for the order
reduce_margin_ratiostringDefines the reduce margin ratio of a derivative market
open_notional_capOpenNotionalCapThe open notional cap of the market, if any


PerpetualMarketInfo

ParameterTypeDescription
hourly_funding_rate_capstringDefines the default maximum absolute value of the hourly funding rate of the perpetual market.
hourly_interest_ratestringDefines the hourly interest rate of the perpetual market.
next_funding_timestampint64Defines the next funding timestamp in seconds of a perpetual market in UNIX seconds.
funding_intervalint64Defines the funding interval in seconds of a perpetual market in seconds.


PerpetualMarketFunding

ParameterTypeDescription
cumulative_fundingstringDefines the cumulative funding of a perpetual market.
cumulative_pricestringDefines defines the cumulative price for the current hour up to the last timestamp.
last_timestampint64Defines the last funding timestamp in seconds of a perpetual market in UNIX seconds.
last_funding_ratestringDefines the last funding rate of a perpetual market.


ExpiryFuturesMarketInfo

ParameterTypeDescription
expiration_timestampint64Defines the expiration time for a time expiry futures market in UNIX seconds.
settlement_pricestringDefines the settlement price for a time expiry futures market.


TokenMeta

ParameterTypeDescription
namestringToken full name
addressstringToken contract address (native or not)
symbolstringToken symbol short name
logostringURL to the logo image
decimalsint32Token decimals
updated_atint64Token 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.core.network import Network
from pyinjective.indexer_client import IndexerClient


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 = IndexerClient(network)

    <