> ## Documentation Index
> Fetch the complete documentation index at: https://docs.decibel.trade/llms.txt
> Use this file to discover all available pages before exploring further.

# Formatting Prices and Sizes for Orders

> Learn how to convert decimal prices and sizes to chain units using market configuration from the v1/markets endpoint

## Formatting Prices and Sizes for Orders

When placing orders on Decibel, you need to convert decimal prices and sizes to chain units that match the market's precision requirements. This guide explains how to use market configuration data from the `v1/markets` endpoint to properly format your order parameters.

## Market Configuration

Each market returned from the `v1/markets` endpoint includes precision configuration:

```json theme={null}
{
  "lot_size": 1,
  "market_addr": "<string>",
  "market_name": "<string>",
  "max_leverage": 1,
  "max_open_interest": 123,
  "min_size": 1,
  "px_decimals": 1,
  "sz_decimals": 1,
  "tick_size": 1
}
```

### Market Configuration Fields

* **`px_decimals`** - The number of decimal places used for price precision. Prices are stored as integers with this many implied decimal places. For example, if `px_decimals = 9`, a price of `5.67` is stored as `5670000000` (5.67 × 10^9).

* **`sz_decimals`** - The number of decimal places used for size precision. Order sizes are stored as integers with this many implied decimal places. For example, if `sz_decimals = 9`, a size of `1.5` is stored as `1500000000` (1.5 × 10^9).

* **`tick_size`** - The minimum price increment in chain units. Prices must be multiples of this value. For example, if `tick_size = 1000000` and `px_decimals = 9`, the minimum price increment is `0.001` (1000000 / 10^9).

* **`lot_size`** - The minimum size increment in chain units. Order sizes must be multiples of this value. For example, if `lot_size = 100000000` and `sz_decimals = 9`, the minimum size increment is `0.1` (100000000 / 10^9).

* **`min_size`** - The minimum order size in chain units. Orders smaller than this will be rejected. For example, if `min_size = 1000000000` and `sz_decimals = 9`, the minimum order size is `1.0` (1000000000 / 10^9).

## Conversion Functions

### Convert Decimal Amount to Chain Units

<CodeGroup>
  ```typescript Typescript theme={null}
  /**
   * Converts a decimal amount to chain units (e.g., USDC).
   * For USDC, this means multiplying by 10^6.
   * @param amount - The decimal amount to convert
   * @param decimal - The number of decimal places for the token (default is 6 for USDC).
   * @returns The amount in chain units
   */
  export function amountToChainUnits(amount: number, decimal = 6): number {
    return Math.floor(amount * 10 ** decimal);
  }
  ```

  ```python Python theme={null}
  def amount_to_chain_units(amount: float, decimal: int = 6) -> int:
      """
      Converts a decimal amount to chain units (e.g., USDC).
      For USDC, this means multiplying by 10^6.

      Args:
          amount: The decimal amount to convert
          decimal: The number of decimal places for the token (default is 6 for USDC)

      Returns:
          The amount in chain units
      """
      return int(amount * (10 ** decimal))
  ```
</CodeGroup>

### Convert Chain Units to Decimal Amount

<CodeGroup>
  ```typescript Typescript theme={null}
  /**
   * Converts chain units to decimal amount (e.g., USDC).
   * For USDC, this means dividing by 10^6.
   * @param chainUnits - The amount in chain units
   * @param decimal - The number of decimal places for the token (default is 6 for USDC).
   * @returns The decimal amount
   */
  export function chainUnitsToAmount(chainUnits: number, decimal = 6): number {
    return chainUnits / 10 ** decimal;
  }
  ```

  ```python Python theme={null}
  def chain_units_to_amount(chain_units: int, decimal: int = 6) -> float:
      """
      Converts chain units to decimal amount (e.g., USDC).
      For USDC, this means dividing by 10^6.

      Args:
          chain_units: The amount in chain units
          decimal: The number of decimal places for the token (default is 6 for USDC)

      Returns:
          The decimal amount
      """
      return chain_units / (10 ** decimal)
  ```
</CodeGroup>

## Price Formatting

### Round Price to Valid Tick Size

Prices must be rounded to the nearest valid tick size. Use this function to ensure your price is valid:

<CodeGroup>
  ```typescript Typescript theme={null}
  /**
   * Rounds a price to the nearest valid tick size
   * @param price - The decimal price to round
   * @param market - The market configuration object
   * @returns The rounded price
   */
  export function roundToValidPrice(price: number, market: PerpMarket): number {
    if (price === 0) {
      return 0;
    }

  // Convert to chain units
  const denormalizedPrice = price \* 10 \*\* market.px_decimals;

  // Round to nearest multiple of tickSize
  const roundedPrice =
  Math.round(denormalizedPrice / market.tick_size) \* market.tick_size;

  // Convert back to decimal
  const normalizedPrice = Math.round(roundedPrice) / 10 \*\* market.px_decimals;

  return normalizedPrice;
  }

  ```

  ```python Python theme={null}
  def round_to_valid_price(price: float, market: dict) -> float:
      """
      Rounds a price to the nearest valid tick size.

      Args:
          price: The decimal price to round
          market: The market configuration object with px_decimals and tick_size

      Returns:
          The rounded price
      """
      if price == 0:
          return 0.0

      # Convert to chain units
      denormalized_price = price * (10 ** market["px_decimals"])

      # Round to nearest multiple of tick_size
      rounded_price = round(denormalized_price / market["tick_size"]) * market["tick_size"]

      # Convert back to decimal
      normalized_price = round(rounded_price) / (10 ** market["px_decimals"])

      return normalized_price
  ```
</CodeGroup>

## Size Formatting

### Round Size to Valid Lot Size

Order sizes must be rounded to the nearest valid lot size and meet the minimum size requirement:

<CodeGroup>
  ```typescript Typescript theme={null}
  /**
   * Rounds an order size to the nearest valid lot size
   * @param orderSize - The decimal order size to round
   * @param market - The market configuration object
   * @returns The rounded order size
   */
  export function roundToValidOrderSize(
    orderSize: number,
    market: PerpMarket
  ): number {
    if (orderSize === 0) {
      return 0;
    }

  const normalizedMinSize = market.min_size / 10 \*\* market.sz_decimals;

  // Ensure size meets minimum requirement
  if (orderSize < normalizedMinSize) {
  return normalizedMinSize;
  }

  // Convert to chain units
  const denormalizedOrderSize = orderSize \* 10 \*\* market.sz_decimals;

  // Round to nearest multiple of lotSize
  const roundedOrderSize =
  Math.round(denormalizedOrderSize / market.lot_size) \* market.lot_size;

  // Convert back to decimal
  const normalizedOrderSize =
  Math.round(roundedOrderSize) / 10 \*\* market.sz_decimals;

  return normalizedOrderSize;
  }

  ```

  ```python Python theme={null}
  def round_to_valid_order_size(order_size: float, market: dict) -> float:
      """
      Rounds an order size to the nearest valid lot size.

      Args:
          order_size: The decimal order size to round
          market: The market configuration object with sz_decimals, lot_size, and min_size

      Returns:
          The rounded order size
      """
      if order_size == 0:
          return 0.0

      normalized_min_size = market["min_size"] / (10 ** market["sz_decimals"])

      # Ensure size meets minimum requirement
      if order_size < normalized_min_size:
          return normalized_min_size

      # Convert to chain units
      denormalized_order_size = order_size * (10 ** market["sz_decimals"])

      # Round to nearest multiple of lot_size
      rounded_order_size = round(denormalized_order_size / market["lot_size"]) * market["lot_size"]

      # Convert back to decimal
      normalized_order_size = round(rounded_order_size) / (10 ** market["sz_decimals"])

      return normalized_order_size
  ```
</CodeGroup>

## Complete Example

Here's a complete example of formatting prices and sizes for placing an order:

<CodeGroup>
  ```typescript Typescript theme={null}
  // Fetch market data from v1/markets endpoint
  const market = {
    market_addr: "0x456...def",
    market_name: "APT-USD",
    px_decimals: 9,
    sz_decimals: 9,
    tick_size: 1000000, // 0.001 in decimal (1000000 / 10^9)
    lot_size: 100000000, // 0.1 in decimal (100000000 / 10^9)
    min_size: 1000000000, // 1.0 in decimal (1000000000 / 10^9)
  };

  // User wants to place an order at $5.6789 with size 1.234
  const userPrice = 5.6789;
  const userSize = 1.234;

  // Step 1: Round price to valid tick size
  const roundedPrice = roundToValidPrice(userPrice, market);
  // Result: 5.679 (rounded to nearest 0.001)

  // Step 2: Round size to valid lot size and check minimum
  const roundedSize = roundToValidOrderSize(userSize, market);
  // Result: 1.2 (rounded to nearest 0.1, meets minimum of 1.0)

  // Step 3: Convert to chain units for the transaction
  const chainPrice = amountToChainUnits(roundedPrice, market.px_decimals);
  // Result: 5679000000 (5.679 × 10^9)

  const chainSize = amountToChainUnits(roundedSize, market.sz_decimals);
  // Result: 1200000000 (1.2 × 10^9)

  // Step 4: Build and submit transaction
  const transaction = await aptos.transaction.build.simple({
  sender: account.accountAddress,
  data: {
  function: `${PACKAGE}::dex_accounts_entry::place_order_to_subaccount`,
  typeArguments: [],
  functionArguments: [
  "0x123...abc", // subaccountAddr
  market.market_addr, // marketAddr
  chainPrice, // price in chain units
  chainSize, // size in chain units
  true, // isBuy
  0, // timeInForce
  false, // isReduceOnly
  null, // clientOrderId
  null, // stopPrice
  null, // tpTriggerPrice
  null, // tpLimitPrice
  null, // slTriggerPrice
  null, // slLimitPrice
  null, // builderAddress
  null, // builderFees
  ],
  },
  });

  ```

  ```python Python theme={null}
  # Fetch market data from v1/markets endpoint
  market = {
      "market_addr": "0x456...def",
      "market_name": "APT-USD",
      "px_decimals": 9,
      "sz_decimals": 9,
      "tick_size": 1000000,  # 0.001 in decimal (1000000 / 10^9)
      "lot_size": 100000000,  # 0.1 in decimal (100000000 / 10^9)
      "min_size": 1000000000,  # 1.0 in decimal (1000000000 / 10^9)
  }

  # User wants to place an order at $5.6789 with size 1.234
  user_price = 5.6789
  user_size = 1.234

  # Step 1: Round price to valid tick size
  rounded_price = round_to_valid_price(user_price, market)
  # Result: 5.679 (rounded to nearest 0.001)

  # Step 2: Round size to valid lot size and check minimum
  rounded_size = round_to_valid_order_size(user_size, market)
  # Result: 1.2 (rounded to nearest 0.1, meets minimum of 1.0)

  # Step 3: Convert to chain units for the transaction
  chain_price = amount_to_chain_units(rounded_price, market["px_decimals"])
  # Result: 5679000000 (5.679 × 10^9)

  chain_size = amount_to_chain_units(rounded_size, market["sz_decimals"])
  # Result: 1200000000 (1.2 × 10^9)

  # Step 4: Build and submit transaction
  from aptos_sdk.client import RestClient
  from aptos_sdk.account import Account

  PACKAGE = "0x50ead22afd6ffd9769e3b3d6e0e64a2a350d68e8b102c4e72e33d0b8cfdfdb06"
  rest_client = RestClient("https://fullnode.mainnet.aptoslabs.com")

  transaction = rest_client.build_transaction(
      sender=account.address(),
      payload={
          "function": f"{PACKAGE}::dex_accounts_entry::place_order_to_subaccount",
          "type_arguments": [],
          "function_arguments": [
              "0x123...abc",  # subaccountAddr
              market["market_addr"],  # marketAddr
              chain_price,  # price in chain units
              chain_size,  # size in chain units
              True,  # isBuy
              0,  # timeInForce
              False,  # isReduceOnly
              None,  # clientOrderId
              None,  # stopPrice
              None,  # tpTriggerPrice
              None,  # tpLimitPrice
              None,  # slTriggerPrice
              None,  # slLimitPrice
              None,  # builderAddress
              None,  # builderFees
          ],
      },
  )
  ```
</CodeGroup>

## Understanding the Values

### Example Market Configuration

Let's say a market has the following configuration:

```json theme={null}
{
  "px_decimals": 9,
  "sz_decimals": 9,
  "tick_size": 1000000,
  "lot_size": 100000000,
  "min_size": 1000000000
}
```

**What this means:**

* **Price Precision**: Prices can have up to 9 decimal places. A price of `5.67` is stored as `5670000000` chain units.

* **Size Precision**: Sizes can have up to 9 decimal places. A size of `1.5` is stored as `1500000000` chain units.

* **Tick Size**: The minimum price increment is `0.001` (1000000 / 10^9). Valid prices are: `5.000`, `5.001`, `5.002`, etc. Invalid: `5.0005`.

* **Lot Size**: The minimum size increment is `0.1` (100000000 / 10^9). Valid sizes are: `1.0`, `1.1`, `1.2`, etc. Invalid: `1.05`.

* **Min Size**: The minimum order size is `1.0` (1000000000 / 10^9). Orders smaller than 1.0 will be rejected.

## Market-Specific Values

For the actual `min_size`, `lot_size`, and `tick_size` values for each live market, see [Market Parameters](/developer-hub/on-chain/overview/market-parameters).

## Common Pitfalls

1. **Not rounding prices**: Prices must be multiples of `tick_size`. Always use `roundToValidPrice()` before converting to chain units.

2. **Not rounding sizes**: Sizes must be multiples of `lot_size`. Always use `roundToValidOrderSize()` before converting to chain units.

3. **Forgetting minimum size**: Orders below `min_size` will be rejected. The rounding function handles this automatically.

4. **Using wrong decimals**: Always use `px_decimals` for prices and `sz_decimals` for sizes when calling `amountToChainUnits()`.
