Conditional Orders Handler

The Conditional Orders Handler enables users to automate the creation, management, and cancellation of conditional orders (such as stop-loss or take-profit orders) with SYMMIO. By leveraging a bot and API, users can delegate specific permissions to a solver (Party B) to manage these conditional actions on-chain. Below is a general outline of the process and how solvers should interact with the handler.

Overview

Permission Delegation

  • Party A delegates the necessary roles and permissions to Party B (the solver) using the SYMMIO platform.

  • This delegation allows Party B to execute actions on Party A’s behalf, such as triggering stop-loss or take-profit orders.

  • The delegation process ensures that the bot can interact with the conditional orders on behalf of Party A when price hits a specific target.

Submitting a Conditional Order

  • Party A sends a conditional order request via the API, which includes:

    • Quote ID: Identifying the specific order.

    • Conditional order details (quantity, price, type).

    • Signature: Party A signs the transaction using their private key, ensuring authenticity.

  • The request is passed to the Conditional Orders Handler API, where it undergoes validation to ensure all required details are correct and the signature is valid.

Validation and Registration

  • Once received, the handler validates the order request to:

    • Verify the quote ID and details of the order.

    • Ensure the signature matches the expected address (Party A).

    • Check that the order adheres to platform rules (e.g., correct order types, quantities, etc.).

  • If the request passes validation, the bot registers the order, storing it and monitoring price conditions.

Execution by the Bot

  • The bot is responsible for monitoring price movements.

  • When the target price of the conditional order (either stop-loss or take-profit) is met, the bot triggers the appropriate on-chain action.

  • The bot interacts with the SYMMIOPartyB contract to execute the transaction on behalf of Party A, calling the necessary functions (e.g., closing a position).

Canceling Orders

  • Conditional orders should be able to be canceled through the API if needed. This cancellation also requires proper permissions and is processed similarly to the original order.

  • The bot ensures that only valid cancellations are processed, and once an order is canceled, no further actions can be triggered.

Permission Delegation

The user (Party A) must delegate specific permissions to SYMMIOPartyB, allowing it to execute conditional orders such as closing a position or canceling a close request on Party A's behalf. This is done through the delegateAccess() function, where two primary roles are delegated:

  • CLOSE: Grants the bot the permission to invoke requestToClosePosition, allowing it to close a position when certain conditions (e.g., stop-loss or take-profit) are met.

  • CANCEL_CLOSE: Grants the bot the permission to invoke requestToCancelCloseRequest, which allows it to cancel a pending close request if necessary.

These delegated permissions are critical for the bot to automatically execute or cancel conditional orders without requiring Party A’s intervention for every action.

It is important to regularly check the status of these delegated permissions to ensure the bot has the appropriate access. There are cases where Party A might revoke these permissions, either intentionally or accidentally, which would prevent the bot from executing its intended actions (such as closing a position or canceling a close request).

To handle this, a periodic permission check function should be implemented. This function should:

  1. Checks Delegated Access: Verify that the SYMMIOPartyB contract still holds the delegated permissions for CLOSE and CANCEL_CLOSE actions on behalf of Party A.

  2. Handle Invalid Permissions: If the bot detects that these permissions have been revoked or are otherwise invalid, it flags all conditional orders related to that PartyA as invalid.

Conditional Orders: API Endpoints

Conditional Order Reqyest:

Endpoint

  • Route: conditional-order/

  • Method: POST

Request Schema

All requests must adhere to the following schema:

class ConditionalOrderSchema(BaseModel):
    quantity: Union[Decimal, str]
    price: Optional[Union[Decimal, str]] = None
    conditional_price: Union[Decimal, str]
    order_type: OrderType  # LIMIT = 0, MARKET = 1
    conditional_order_type: ConditionalOrderType  # STOP_LOSS = 'stop_loss', TAKE_PROFIT = 'take_profit'


class ConditionalOrderRequestSchema(BaseModel):
    quote_id: int
    conditional_orders: List[ConditionalOrderSchema]
    time_stamp: int
    transaction_signature: Dict

Parameters

  • quote_id : The ID of the quote.

Request Example

order_request={
  "quote_id": 13
  "conditional_orders": [
    {
      "quantity": "0.03",
      "price": "3261",
      "conditional_price": "2608",
      "order_type": 1,
      "conditional_order_type": "stop_loss"
    },
    {
      "quantity": "0.03",
      "price": "3261",
      "conditional_price": "3913",
      "order_type": 1,
      "conditional_order_type": "take_profit"
    }
  ],
  "time_stamp": 1709030850,
  "transaction_signature": {}

Pre-Signature Requirement

Before signing, it is crucial that the transaction_signature field in the request remains empty:

order_request["transaction_signature"] = {}

Signature Generation and Inclusion

Encode request data : Use Ethereum's encode standards to encode the request data like this:

SignableMessage(version=b'E', header=b'thereum Signed Message:\n329', body=b'{"conditional_orders": [{"quantity": "0.03", "price": "3259", "conditional_price": "2607", "order_type": 1, "conditional_order_type": "stop_loss"}, {"quantity": "0.03", "price": "3259", "conditional_price": "3910", "order_type": 1, "conditional_order_type": "take_profit"}], "time_stamp": 1709031749, "transaction_signature": {}}')

Signature Generation: Use Ethereum's signing standards to sign the request data.

Including the Signature in the Request: After generating the signature, insert it into the transaction_signature field of the request:

Format: {"signature": signed_data.signature.hex()}

Validation and Checks

The API should perform several validations and checks, including:

  1. Quote ID Validation: Raises an exception if no quote is found with the given quote ID.

  2. Pending Close Request Check: Raises an exception if there's a pending close request for the position.

  3. Signature Verification: Validates the timestamp and ensures the signature matches the expected party A's address.

  4. Active Orders Check: Raises an exception if active conditional orders are found for the given quote ID.

  5. Order Count and Type Constraints: Ensures there are either 1 or 2 conditional orders. If there are 2, they must be of types stop_loss and take_profit. An error is raised if these conditions are not met.

  6. Order Limit Check: Counts the conditional orders associated with a specified party A's address. If the count exceeds the default limit, an error is raised.

  7. Price Validation: Checks for mandatory prices in LIMIT orders, validates floating point precision for various price fields, and ensures price margins are within acceptable ranges based on the position type and market price.

Canceling Conditional Order Requests:

Endpoint

  • Route: conditional-order/delete/

  • Method: POST

Request Schema

The request must follow this schema:

class ConditionalOrderCancelSchema(BaseModel):
    quote_id: int
    conditional_order_type: ConditionalOrderType  # STOP_LOSS = 'stop_loss', TAKE_PROFIT = 'take_profit'
    time_stamp: int
    transaction_signature: Dict

Request Example

cancel_request={
  "quote_id": 9,
  "conditional_order_type": "stop_loss",
  "time_stamp": 1709040215,
  "transaction_signature": {}
}

Pre-Signature Requirement

Before signing, the transaction_signature field in the request should be empty:

cancel_request["transaction_signature"] = {}

Signature Generation and Inclusion

Encode request data : Use Ethereum's encode standards to encode the request data in format:

SignableMessage(version=b'E', header=b'thereum Signed Message:\n109', body=b'{"quote_id": 9, "conditional_order_type": "stop_loss", "time_stamp": 1709040215, "transaction_signature": {}}')

Signature Generation: Use Ethereum's signing standards to sign the request data.

Including the Signature in the Request: After generating the signature, add it to the transaction_signature field:

Format: {"signature": signed_data.signature.hex()}

Validation and Checks

Before processing the request, the API should perform several checks:

  1. Signature Verification: Validates the timestamp and ensures the signature matches the expected Party A's address.

  2. Order Existence Check: Ensures the specified conditional order exists.

  3. Quote Status Verification: Confirms the quote's position state is 'OPENED' or 'PENDING' and that the quote is found.

Get Conditional Orders

Endpoint

  • Route: conditional-order/{quote_id}

  • Method: GET

Description

This API retrieves details of a conditional order based on a specific quote ID . It returns the first order's details if such an order is found. If no matching order is found, an error is raised indicating that the order was not found.

Parameters

  • quote_id: The ID of the quote.

Searching for Conditional Orders

Endpoint

  • Route: /all/{start}/{size}

  • Method: POST

Request Schema

The request must follow this schema

class ConditionalOrderSearchRequestSchema(BaseModel):
    party_a_address: str
    state: Optional[
        List[ConditionalOrdersState]]  # NEW = 'new', TRIGGERED = 'triggered', CANCELED = 'canceled', KILLED = 'killed'
    order_type: Optional[OrderType]  # LIMIT = 0, MARKET = 1
    conditional_order_type: Optional[ConditionalOrderType]  # STOP_LOSS = 'stop_loss', TAKE_PROFIT = 'take_profit'

This API searches for conditional orders based on specified criteria and returns a paginated result set.

Parameters

  • start : The starting index for pagination.

  • size : The number of records to return in the paginated result.

Execution Details

When the price condition for a stop-loss or take-profit order is met, the bot triggers the appropriate action (e.g., closing a position). The bot uses the SYMMIOPartyB contract to execute the necessary on-chain functions. This includes actions like:

  • Closing a position: When the market price hits the take-profit or stop-loss trigger.

  • Canceling a close request: If a cancellation is requested before the condition is met.

The bot should utilize an address pool to handle multiple transactions concurrently. Each address in the pool should have its own set of public and private keys, and each transaction locks an address until the transaction is completed. This approach ensures that the bot can perform multiple actions simultaneously without creating a bottleneck where multiple transactions are queued behind a single address.

Execution Flow for Stop-Loss and Take-Profit Orders:

  • When a price condition is met, the bot should call a handle_triggered function (or similar function) to execute the on-chain close action.

  • It fetches a free address from the pool, ensuring that the address is locked until the transaction is completed.

  • After executing the on-chain close function via the SYMMIOPartyB contract, the address is released back into the pool for future use.

Bot Handling Process

The bot performs actions based on the type of request it receives. Below are the key functions:

  • Handling a Request or Edit: When a conditional order request is created or edited, the bot should store it in the database and log the action.

  • Handling Cancel Requests: If a Party A requests to cancel a stop-loss or take-profit order, the bot should first check if the order is in the CLOSE_PENDING state and then uses an address from the pool to perform the cancellation.

  • Handling Triggered Orders: When a stop-loss or take-profit condition is met, the bot retrieves the appropriate address from the pool, locks it, and calls the on-chain close function with multi-RPC to ensure the tx is reliably sent.

Last updated