Overview
The Rebalancer aligns a portfolio with the model it tracks. It identifies securities that are underweight or overweight relative to their model targets and generates buy and sell trade orders to bring the portfolio back into line.
This guide covers Standard rebalances of non-sleeved (Normal) portfolios. For other variants, see:
- Sleeve Portfolio Rebalances — sleeved portfolios
- Focused (Tactical) Rebalances — constraining a run to a subset of symbols
1. Endpoint
Headers
| Header | Value |
|---|---|
| Authorization | Session <access_token> |
| Content-Type | application/json |
2. Quick Start
To kick off a standard rebalance, you need three things:
- A valid session token
- The portfolioId of the non-sleeved portfolio you want to rebalance
- A POST request with the body below
Copy this template exactly, replace the portfolio id in portfolioIds, and send it. The fields you may want to customize are covered in §3.2 — all others should be sent as shown.
{
"portfolioIds": [154694],
"tradeInstanceType": 6,
"tradeInstanceSubType": 14,
"tradeToolSelection": 10,
"useDefaultPreference": true,
"isViewOnly": null,
"reason": null,
"isExcelImport": false,
"minimumTradeAmount": { "type": "$", "amount": null },
"maxGainAmount": null,
"allowWashSale": null,
"allowShortTermGain": null,
"priorityRanking": null,
"rounding": null,
"rebalanceType": null
}
Send the request and you’ll get back a trade instance id and the trades the rebalancer generated. See §4 for the response shape.
3. Request Body
3.1 Required identifiers & metadata
These four fields must always be present.
| Field | Type | Value | Notes |
|---|---|---|---|
| portfolioIds | int[] | e.g. [154694] | One or more non-sleeved portfolio IDs. For a single portfolio, send a one-element array. |
| tradeInstanceType | int | 6 | Portfolio rebalance. |
| tradeInstanceSubType | int | 14 | Standard portfolio rebalance. |
| tradeToolSelection | int | 10 | From the rebalance tool. |
You do not send tradeInstanceId. The backend creates the trade instance and returns its id in the response.
3.2 Fields you may want to customize
| Field | Type | Recommended | Notes |
|---|---|---|---|
| useDefaultPreference | bool | true | Use the firm’s saved rebalance preferences. Strongly recommended. When true, allowWashSale, allowShortTermGain, and maxGainAmount are ignored and the firm’s saved values are used instead. |
| isViewOnly | bool | null | null | null generates committable trades that flow to execution. Set to true only to preview trades without committing them. |
| rebalanceType | string | null | null | null = Standard Rebalance. For focused/tactical runs, see the Focused Rebalance guide. |
| reason | string | null | null | Optional free-text reason logged on the trade instance. |
| minimumTradeAmount | { type, amount } | { “type”: “$”, “amount”: null } | Minimum trade amount. amount: null uses the firm’s default. If type: “%”, amount must be ≤ 100. |
| maxGainAmount | decimal | null | null | Cap on the total realized gain produced by this run. null = no override (uses firm default). Only honored when useDefaultPreference: false. |
| allowWashSale | bool | null | null | Override the firm’s wash-sale rule. null = use the firm’s saved value. Only honored when useDefaultPreference: false. |
| allowShortTermGain | string | null | null | Override the firm’s short-term-gain rule. null = use the firm’s saved value. Accepted values: “Allow”, “Full Position Disallow”, “TaxLot Disallow”. Only honored when useDefaultPreference: false. |
All other fields in the Quick Start template should be sent exactly as shown.
4. Response
A successful call returns 200 OK.
4.1 Sample response
{
"shouldUseV2PostTradeProcess": true,
"isViewOnly": false,
"tradeInstanceId": 57400,
"instanceId": 57400,
"trades": [
{
"tradeId": 2120490,
"tradeInstanceId": 57400,
"portfolioId": 154694,
"accountId": 141448,
"securityId": 94,
"symbol": "MSFT",
"securityName": "Microsoft Corp",
"securityType": "Equity",
"action": "BUY",
"tradeShares": 748,
"price": 413.62,
"tradeAmount": 309387.76,
"cashValuePostTrade": 0.000145,
"custodianId": 38,
"custodian": "Schwab (TDA)",
"approvalStatus": "Approved",
"rebalanceLevel": "Portfolio",
"rebalanceLevelId": 2,
"taxableType": "TAXABLE",
"tradeCreatedDate": "2026-05-13T06:30:18.000Z",
"priceDate": "2026-05-13T00:00:00.000Z"
}
]
}
An empty trades: [] array is success, not failure. It means the portfolio is already in tolerance. Handle this case explicitly in your caller.
4.2 Top-level fields
| Field | Type | Description |
|---|---|---|
| tradeInstanceId | long | Server-generated id for this run. Save it — it’s how you’ll find or reconcile the trades downstream. |
| instanceId | long | Same value as tradeInstanceId. Both are returned for backward compatibility. |
| isViewOnly | bool | Echoes the resolved value. Confirms whether trades were saved as preview or committable. |
| shouldUseV2PostTradeProcess | bool | true when the run used the current post-trade pipeline. |
| trades | Trade[] | Every trade saved against this instance. For non-sleeved portfolios, contains only BUY and SELL rows. |
4.3 Trade object fields (response only)
Each entry in the trades[] array is generated by the rebalancer — none of these fields are set by the caller. The list below covers the fields most external consumers use.
Identity
| Field | Type | Description |
|---|---|---|
| tradeId | int | Unique id of this trade row. |
| tradeInstanceId | long | Parent trade instance id. |
| portfolioId | int | Portfolio this trade belongs to. |
| accountId | int | Account this trade belongs to. |
| securityId | int | Internal security id. |
| symbol | string | Security symbol (e.g. MSFT). |
| securityName | string | Human-readable security name. |
| securityType | string | Equity, Mutual Fund, Bond, Other. |
Action
| Field | Type | Description |
|---|---|---|
| action | string | BUY or SELL. |
| approvalStatus | string | Current approval state (e.g. Approved). |
| rebalanceLevel | string | Always Portfolio for this endpoint. |
| rebalanceLevelId | int | Always 2. |
| tradeCreatedDate | ISO datetime | When the trade was created. |
Quantity & price
| Field | Type | Description |
|---|---|---|
| tradeShares | decimal | Whole shares (rounded inline). |
| price | decimal | Per-share price used. |
| tradeAmount | decimal | Total dollar value (tradeShares × price). |
| cashValuePostTrade | decimal | Account cash immediately after the trade. |
| priceDate | ISO datetime | As-of date of the price. |
Cost basis & gain/loss (sells only)
| Field | Type | Description |
|---|---|---|
| costAmount | decimal | Total cost basis. |
| costPerShare | decimal | Per-share cost basis. |
| tradeGainLoss | decimal | Total realized gain or loss. |
| tradeSTGainLoss / tradeLTGainLoss | decimal | Short-term / long-term split. |
Custodian & fees
| Field | Type | Description |
|---|---|---|
| custodianId | int | Internal custodian id. |
| custodian | string | Custodian display name. |
| transactionFee | decimal | Transaction fee on this trade. |
| redemptionFee | decimal | Redemption fee on this trade. |
Account & tax context
| Field | Type | Description |
|---|---|---|
| taxableType | string | TAXABLE, TAXDEF, TAXEXMPT. |
| billingAccount | int (0/1) | 1 if this is a billing account. |
5. Errors
5.1 Error body
{
"success": false,
"message": "[REBAL] : No Model Assigned to this portfolio.",
"portfolioId": 154694,
"firmId": 1100,
"tradeInstanceId": 57400
}
The message field (prefixed with [REBAL] : is the canonical signal for what went wrong. Surface it in your logs — don’t rely on the HTTP status alone.
5.2 Status codes
| Code | Meaning |
|---|---|
| 200 OK | Rebalance completed. Includes the case where trades: [] because the portfolio was already in tolerance. |
| 400 Bad Request | Request validation failed (missing required field, or minimumTradeAmount.type = “%” with amount > 100). |
| 401 / 403 | Missing, invalid, or unauthorized token. |
| 500 Internal Server Error | Portfolio, model, or account-level check failed. Read the [REBAL] : message. |
5.3 Common failure messages
- [REBAL] : No Model Assigned to this portfolio.
- [REBAL] : Portfolio is marked Do Not Trade.
- [REBAL] : Portfolio analytics are still running.
- [REBAL] : No Primary Team Assigned to this portfolio.
- [REBAL] : Invalid Portfolio/Account type sent in request parameters. — typically means you sent a sleeved portfolio to this endpoint. Sleeved portfolios use the same URL but must meet the sleeved requirements;
6. Important Reminders
- Save the tradeInstanceId from the response. It’s how you’ll look up or reconcile the generated trades later. You cannot supply it in the request — the backend always creates a new one.
- Empty trades: [] is success. It means the portfolio was already within tolerance. Handle it explicitly.
- Run post-import analysis first if the portfolio was just imported. If analytics are pending, this endpoint returns 500 with a message saying analysis is required or running. Wait for post-import analysis to complete, then retry.
- This endpoint does not execute trades. It only generates and saves them. Execution to a custodian or broker is a separate downstream system.
- You own idempotency, concurrency, and rate limiting. Every call creates a new trade instance and a new set of trades — the endpoint does not de-duplicate retries or block concurrent runs against the same portfolio.
- Send a non-sleeved portfolio. The endpoint infers the variant from portfolioIds. A sleeved portfolio here will return 500 with Invalid Portfolio/Account type sent in request parameters.