Custom API Documentation

Create Custom Trade API

Overview

This endpoint allows custom strategy systems to create a trade with one or more legs. Each leg defines an individual trade action (e.g., BUY NIFTY CE, SELL BANKNIFTY PE, etc.). The system consolidates legs under a single strategyId + token combination and returns the updated open quantity, pending quantity, and position status for each leg.


Endpoint

POST {{baseUrl}}/trades/custom_orders


Authentication Flow

1

Generate API Key

Navigate to the Subroker Dashboard → Groups tab → Click "Generate API Key"

Groups
2

Login with API Key

Use the generated API key to authenticate and receive an access token

POST {{BASE_URL}}/users/login_api_key
{
  "apiKey": "your_generated_api_key"
}
Response
{
  "success": true,
  "message": "Login successful",
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
3

Use Access Token for API Calls

Include the access token in the Authorization header for all trade API requests

POST {{BASE_URL}}/trades/custom_orders
Authorization: Bearer <accessToken>
Content-Type: application/json
{
  "alertId": "your-alert-id",
  "isCustom": true,
  "legParams": [...]
}
Note: The access token from step 2 must be included in the Authorization header for all subsequent API requests. The token format should be: Authorization:<accessToken>

Request Body (JSON)

Field Type Required Description
alertId string Unique ID for this signal/trade trigger. Used for idempotency.
isCustom boolean Whether this is a custom trade.
isExitAll boolean Whether to exit all positions for the strategy.
isPaused boolean To exit all positions for the strategy and pause the strategy.
positionId string The position id to exit.
legParams array Array of leg objects defining each trade leg.

Note: The alertId is the id of the group that you have created, you can obtain this id for a strategy by navigating to the Subroker Dashboard → Groups tab → Click on the group you want to use → Click on the Settings button → Copy the Alert Id.

Leg Parameters

Field Type Required Description
direction string "CALL" or "PUT".
type string "ENTRY" or "EXIT". Defines whether this leg increase or decreases qty of position.
instrument string Name of the instrument (e.g., "BANKNIFTY", "SBIN").
lots integer Number of lots to trade.
transactionType string "BUY" or "SELL".
orderType string "MARKET" or "LIMIT".
anchorValue number Reference value for anchor calculation.
anchorType string "LTP", "DELTA", "THETHA", "GAMMA", "MONEYNESS", "FIXED_PRICE". Default = "MONEYNESS".
anchorDirection string "EQUAL", "ABOVE", "BELOW".
isOvernight boolean Whether the order is to be INTRADAY or CARRYFORWARD.
expiry string Expiry type: "W" (Weekly) or "M" (Monthly).
seq integer Execution sequence number (used for multi-leg execution order).
target number Target price value for the position.
targetType string Type of target value: "POINTS" or "PERCENT".
stoploss number Stop loss price value for the position.
stoplossType string Type of stop loss value: "POINTS" or "PERCENT".
limitValue number Limit order price value. Required when orderType is "LIMIT".
limitType string Type of limit value: "ABSOLUTE", "PERCENT", or "POINTS". Required when orderType is "LIMIT".

Anchor Type Details

The anchorType field determines how the strike is selected based on the anchorValue:

anchorType Description
"LTP" Premium Value - The anchorValue represents the premium price of the contract. Based on the anchorDirection, the system will select the appropriate strike that matches the specified premium value. For example, if you set anchorValue to 50, 60, or 70, the system will select the strike whose premium price matches that value according to the direction specified.
"MONEYNESS" Used to select In the Money (ITM) or Out of the Money (OTM) strikes. The anchorValue determines how far ITM or OTM the strike should be:
- For OTM strikes: Use negative values (e.g., -1, -5, -10) to specify how many strikes out of the money you want.
- For ITM strikes: Use positive values (e.g., 1, 5, 10) to specify how many strikes in the money you want.
"FIXED_PRICE" The order will be placed at the exact strike price specified in the anchorValue. For example, if you set anchorValue to 25000 or 25100, the order will be placed at that specific strike price.
"DELTA" Delta-based strike selection.
"THETHA" Theta-based strike selection.
"GAMMA" Gamma-based strike selection.

Limit Type Details

When orderType is "LIMIT", the limitType field determines how limitValue is interpreted:

limitType Description
"ABSOLUTE" The limitValue is taken as the absolute price to place the limit order.
"PERCENT" The limitValue represents a percentage of the current price.
"POINTS" The limitValue represents points offset from the current price.


Example Request

{
  "alertId": "03a6639a-2ac1-4baa-ac6a-c233cc8faecb",
  "isCustom": true,
  "legParams": [
    {
      "type": "ENTRY", 
      "instrument": "NIFTY",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "LIMIT",
      "anchorValue": 0,
      "direction": "CALL",
      "anchorType": "MONEYNESS",
      "anchorDirection": "EQUAL",
      "expiry": "W",
      "isOvernight": false,
      "seq": 1,
    },
    {
      "type": "ENTRY",
      "instrument": "BANKNIFTY",
      "lots": 2,
      "transactionType": "SELL",
      "direction": "CALL",
      "orderType": "MARKET",
      "anchorValue": 55000,
      "anchorType": "FIXED_PRICE",
      "anchorDirection": "EQUAL",
      "expiry": "W",
      "isOvernight": false,
      "seq": 2
    }
  ]
}

Success Response

The response now returns per-leg results keyed by seq
because multiple legs may open or modify multiple positions.

{
  "success": true,
  "message": "Trade request accepted",
  "data": {
    "1": {
      "positionId": "pos-5678",
      "token": "26009",
      "summary": {
        "openQty": 10,
        "pendingQty": 0
      },
      "positionStatus": "OPEN"
    },
    "2": {
      "positionId": "pos-5679",
      "token": "26037",
      "summary": {
        "openQty": 0,
        "pendingQty": 5
      },
      "positionStatus": "PENDING"
    }
  }
}

Response Field Description

Field Type Description
data object Object containing responses per leg seq.
positionId string Unique ID for the consolidated position.
token string Identifier used to group entries/exits.
summary.openQty number Total open quantity after consolidation.
summary.pendingQty number Quantity yet to execute.
positionStatus string "OPEN", "CLOSED", "PENDING", or "FAILED".

Error Response

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid trade parameters",
    "details": {
      "field": "instrument",
      "reason": "Missing or invalid value"
    }
  }
}
Code Meaning
VALIDATION_ERROR Missing or invalid request data.
DATABASE_ERROR Failure during persistence.
UNAUTHORIZED Invalid or missing API key.

Strategy Types

The system supports three distinct strategy types, each with different behaviors for position management, target/stop loss settings, and order execution.

1. NORMAL

In this strategy type, target and stop loss cannot be set.

Position Management:

  • You can add quantity to a particular token by placing orders with type: "ENTRY".
  • You can decrease quantity for a particular token by placing orders with type: "EXIT" and by giving opposite-side transaction type (Example: If you have a position in NIFTY CE, you can decrease the quantity by placing an order with type: "EXIT" and transactionType: "SELL").
  • Positions are consolidated by token, allowing incremental adjustments to quantity.

2. ENTRY_ONLY

In this strategy type, target and stop loss can be set.

Position Behavior:

  • For the same token (e.g., token 123), every time you place an order, a new position will be opened.
  • Each order creates a separate position entry, even if a position already exists for that token.
  • Positions are not consolidated by token; each order maintains its own independent position.

Exit Methods:

  • Positions can only be exited by:
    • Specifying the positionId directly
    • Using the "exit all" functionality
  • Exit legs are not available - meaning in legParams, entries with type: "EXIT" will not be executed.
  • You cannot exit positions using exit-type leg parameters in the request.

3. ENTRY_ONCE

In this strategy type, target and stop loss can be set.

Position Behavior:

  • For a particular token (e.g., token 123), no new quantity can be added using legParams with type: "ENTRY".
  • Once an entry position is created for a token, subsequent entry orders for the same token will be rejected or ignored.
  • This ensures that only one entry position exists per token, preventing quantity accumulation through multiple entry orders.

Use Case:

  • Ideal for strategies where you want to ensure a single entry point per token, with the ability to set target and stop loss levels.

Test Cases & Examples

1. Entry (NORMAL Type) - Single Entry

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1
    }
  ]
}

Response:

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767866277315",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "27ee597f-a7e3-479b-9aef-cdb783b9f35a",
          "token": 58790,
          "summary": {
            "openQty": 65,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

2. Multi-Sequence Entry (NORMAL Type)

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1
    },
    {
      "type": "entry",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "PUT",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 2
    }
  ]
}

Response:

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767866277315",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "57f75283-a62a-4b4e-9480-7ba3998669ce",
          "token": 58790,
          "summary": {
            "openQty": 65,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        },
        "2": {
          "positionId": "867ccda5-96d2-40f1-a6a6-11ad12238842",
          "token": 58791,
          "summary": {
            "openQty": 65,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

3. Exit (NORMAL Type)

3a. Exit by Position ID

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "positionId": "57f75283-a62a-4b4e-9480-7ba3998669ce",
  "isCustom": true
}

3b. Exit All Positions for Strategy

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": true,
  "isCustom": true
}

3c. Exit and Pause Strategy

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isPaused": true,
  "isCustom": true
}

Response (for all exit methods):

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767867364227",
    "result": {
      "success": true,
      "message": "All positions exited successfully",
      "data": {}
    }
  }
}

4. Increase Quantity (NORMAL Type)

Initial Entry Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1
    }
  ]
}

Initial Response:

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767867490984",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "15bf55b3-53d6-4a54-bcb9-7b521355086d",
          "token": 58790,
          "summary": {
            "openQty": 65,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

Add 1 More Lot Request (same as initial, adds to existing position):

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1
    }
  ]
}

Response (with increased quantity):

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767867587071",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "15bf55b3-53d6-4a54-bcb9-7b521355086d" (Same positionId as initial response),
          "token": 58790,
          "summary": {
            "openQty": 130 (Increased quantity),
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

5. Decrease Quantity (NORMAL Type)

Request (using exit type):

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "status": null,
  "message": null,
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "exit",
      "instrument": "NIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "SELL",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1
    }
  ]
}

Response (with decreased quantity):

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767867658204",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "15bf55b3-53d6-4a54-bcb9-7b521355086d",
          "token": 58790,
          "summary": {
            "openQty": 65,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

6. Entry (ENTRY_ONCE Type) with Target and Stop Loss

Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "BANKNIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1,
      "target": 10,
      "targetType": "POINTS",
      "stoploss": 10,
      "stoplossType": "POINTS"
    }
  ]
}

Response:

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767868622369",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "a866240f-9dbf-4393-8f93-d2c27ad7bb4e",
          "token": 52022,
          "summary": {
            "openQty": 30,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

Note: In ENTRY_ONCE type, subsequent entry orders for the same token will be rejected. Only one entry position is allowed per token.


7. Entry (ENTRY_ONLY Type) with Target and Stop Loss

First Entry Request:

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "BANKNIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1,
      "target": 5,
      "targetType": "POINTS",
      "stoploss": 5,
      "stoplossType": "POINTS"
    }
  ]
}

First Entry Response:

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767868853771",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "1c23ba9f-2c95-49f6-a326-beca3d0abb52",
          "token": 52022,
          "summary": {
            "openQty": 30,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

Second Entry Request (Same Token - Creates New Position):

{
  "alertId": "b9d4d22a-290a-445b-a44d-0f55f8dfb4cf",
  "isExitAll": false,
  "isCustom": true,
  "isPaused": false,
  "positionId": null,
  "legParams": [
    {
      "type": "entry",
      "instrument": "BANKNIFTY",
      "segment": "FNO",
      "lots": 1,
      "transactionType": "BUY",
      "orderType": "MARKET",
      "direction": "CALL",
      "anchorValue": 0,
      "anchorType": "Moneyness",
      "anchorDirection": "EQUAL",
      "expiry": "M",
      "isOvernight": false,
      "seq": 1,
      "target": 5,
      "targetType": "POINTS",
      "stoploss": 5,
      "stoplossType": "POINTS"
    }
  ]
}

Second Entry Response (Different Position ID):

{
  "success": true,
  "message": "Job completed successfully",
  "data": {
    "jobId": "custom-trade-undefined-1767868903326",
    "result": {
      "success": true,
      "message": "Positions processed successfully",
      "data": {
        "1": {
          "positionId": "f4d2ae26-8b73-43be-a0ec-19e6f483d577",
          "token": 52022,
          "summary": {
            "openQty": 30,
            "pendingQty": 0
          },
          "positionStatus": "OPEN"
        }
      }
    }
  }
}

Note: In ENTRY_ONLY type, each entry order for the same token creates a new separate position with a different positionId. Positions are not consolidated by token.


Position Adjustment Rules (Detailed)

Core Logic

All trade updates are grouped by (strategyId, token) to form a consolidated position.

  1. If transactionType is same as existing open side → increase openQty.
  2. If transactionType is opposite side
    • Execute against existing openQty first.
    • Reduce openQty by min(incomingQty, openQty).
    • If openQty reaches 0 → mark position CLOSED.
  3. If no open position exists, handle as pending or new depending on orderType.
  4. Before modifying or creating a new position, always reconcile any pendingQty.

Pending Quantity Matching

When an opposite-side trade arrives, it follows this evaluation order:

Matching priority → openQty → pendingQty → new order

Case Behavior
Incoming opposite-side ≤ openQty Execute against open position; reduce openQty accordingly.
Incoming opposite-side > openQty Fully close open position (openQty = 0), then recheck remaining quantity against pendingQty.
Remaining opposite-side ≤ pendingQty Reduce pendingQty by that amount and do not execute.
Remaining opposite-side > pendingQty Cancel all pending orders (pendingQty = 0) and do not execute remaining quantity.
No openQty and no pendingQty Treat as a new position (open or pending depending on orderType).

RELIANCE Examples

# Scenario Before Incoming After Result
1 Pending Buy 10 → Sell 2 pendingBuy = 10 sell = 2 pendingBuy = 8 Reduce pending; no execution
2 Pending Buy 10 → Sell 20 pendingBuy = 10 sell = 20 pendingBuy = 0 Cancel pending; no execution
3 Open Buy 10 → Sell 2 openBuy = 10 sell = 2 openBuy = 8 Execute 2; position remains OPEN
4 Open Buy 10 → Sell 20 openBuy = 10 sell = 20 openBuy = 0 Execute 10; position CLOSED; remaining sell discarded
5 Open 10 + Pending 10 → Sell 15 openBuy = 10, pendingBuy = 10 sell = 15 openBuy = 0, pendingBuy = 5 Execute 10 (close open), reduce pending by 5; position OPEN (5 pending left)
6 Open 10 + Pending 5 → Sell 20 openBuy = 10, pendingBuy = 5 sell = 20 openBuy = 0, pendingBuy = 0 Execute 10 (close open), cancel 5 pending; remaining 5 ignored; position CLOSED
7 Open 10 + Pending 5 → Buy 20 openBuy = 10, pendingBuy = 5 buy = 20 openBuy = 30, pendingBuy = 5 Same-side add: open increased; position remains OPEN

Sequencing & Execution

  • Execute legs in ascending seq order.
  • Each leg's result appears under its seq key in response.
  • If seq is omitted → processed in received order.

Example Workflow

  1. Strategy system sends trade request → POST /trades/custom
  2. Receives per-leg results:
  3. {
  4. "1": { "openQty": 10, "positionStatus": "OPEN" },
  5. "2": { "openQty": 0, "pendingQty": 5, "positionStatus": "PENDING" }
  6. }
  7. Positions can later be queried with:
  8. GET /positions/:strategyId