Overview
A focused rebalance generates trades for only part of a portfolio. Holdings outside the focus are left as they are.
This guide covers focused rebalances of non-sleeved (Normal) portfolios. For other variants, see:
- Standard Portfolio Rebalance
- Sleeve Focused Rebalance
- Sleeve Portfolio Rebalance
This is the same URL as a standard non-sleeved rebalance. The run is treated as focused when you send rebalanceType: “Focused Rebalance” and tradeInstanceSubType: 4 and at least one symbol in tacticalRebalanceSecurities.
1. Endpoint
Headers
| Header | Value |
|---|---|
| Authorization | Session <access_token> |
| Content-Type | application/json |
2. Quick Start
To kick off a non-sleeved focused rebalance, you need:
- A valid session token
- The portfolioId of the non-sleeved portfolio you want to rebalance
- The list of symbols you want the run to focus on
- A POST request with the body below
Copy this template exactly, replace portfolioIds and tacticalRebalanceSecurities, 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": 4,
"tradeToolSelection": 10,
"rebalanceType": "Focused Rebalance",
"tacticalRebalanceSecurities": ["AAPL", "MSFT"],
"tacticalRebalanceDoNotSellUnAssignedSecurities": true,
"tacticalRebalanceDoNotRebalanceCash": true,
"tacticalRebalanceCashProtection": null,
"useDefaultPreference": true,
"isViewOnly": true,
"reason": null,
"isExcelImport": false,
"minimumTradeAmount": { "type": "$", "amount": null },
"maxGainAmount": null,
"allowWashSale": null,
"allowShortTermGain": null,
"priorityRanking": null,
"rounding": null
}
3. Request Body
3.1 Required identifiers & metadata
| Field | Type | Value | Notes |
|---|---|---|---|
| portfolioIds | int[] | e.g. [154694] | One or more non-sleeved portfolio IDs. |
| tradeInstanceType | int | 6 | Portfolio rebalance. |
| tradeInstanceSubType | int | 4 | Focused rebalance. 14 is a full-portfolio standard rebalance — a different operation. |
| tradeToolSelection | int | 10 | From the rebalance tool. |
| rebalanceType | string | “Focused Rebalance” | Triggers the focused flow. |
| tacticalRebalanceSecurities | string[] | e.g. [“AAPL”, “MSFT”] | The symbols to focus on. Must have at least one symbol — an empty array means no focus, which is not a valid focused run. |
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
The first three fields are the focused-run knobs that control how the rebalancer behaves around the symbols and cash it isn’t focused on. They only take effect on a focused run.
| Field | Type | Recommended | Notes |
|---|---|---|---|
| tacticalRebalanceDoNotSellUnAssignedSecurities | bool | null | true | When true, holdings outside the model are not sold during the run. Common on focused runs so the rebalancer doesn’t touch positions you didn’t ask about. |
| tacticalRebalanceDoNotRebalanceCash | bool | null | true | When true, cash is not rebalanced during the run. |
| tacticalRebalanceCashProtection | string | null | null | Controls how existing cash may be used to fund focused buys. null uses the firm’s default. Accepted values in §3.3. |
| 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 | true for the first call | true = preview only (will not flow to execution). null or false = committable trades. |
| 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. 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.
3.3 tacticalRebalanceCashProtection values
| Value | Behavior |
|---|---|
| null | Use the firm’s default. |
| “Protect Full Account Target” | Preserve the full account-level cash target. |
| “Protect Full Account Target (Lower Trade Tolerance)” | Preserve the full account-level cash target, using the lower trade tolerance band. |
| “Protect Only Excluded Cash” | Preserve only excluded cash (set-aside amounts). |
| “Allow Cash To Go To $0” | Allow cash to be drained to $0. |
| “Allow Cash To Go Negative” | Allow cash to go below $0. |
| “Only Allow Cash From Sells” | Don’t use any pre-existing cash; only spend cash freshly produced by focused sells in this run. |
| “Spend All Cash From Sells” | Spend all cash produced by focused sells in this run. |
4. Response
A successful call returns 200 OK.
4.1 Sample response
{
"shouldUseV2PostTradeProcess": true,
"isViewOnly": true,
"tradeInstanceId": 57812,
"instanceId": 57812,
"trades": [
{
"tradeId": 2120491,
"tradeInstanceId": 57812,
"portfolioId": 154694,
"accountId": 141448,
"securityId": 94,
"symbol": "MSFT",
"securityName": "Microsoft Corp",
"securityType": "Equity",
"action": "BUY",
"tradeShares": 42,
"price": 413.62,
"tradeAmount": 17372.04,
"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 focused symbols were already in tolerance (or would produce no trades under your cash-protection settings). 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 — no JOURNAL entries. |
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. Non-sleeved focused runs never produce JOURNAL entries. |
| 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": 57812
}
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 focused symbols were 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. Use the Sleeve Focused Rebalance guide instead.
6. Important Reminders
- Send the focused recipe completely. rebalanceType: “Focused Rebalance” + tradeInstanceSubType: 4 + at least one symbol in tacticalRebalanceSecurities.
- Symbols must exactly match how they’re stored in Eclipse. A symbol in tacticalRebalanceSecurities that isn’t in the portfolio’s model produces no trades for that symbol — the run doesn’t error, it just quietly excludes it. Check your response against the symbols you sent.
- Empty trades: [] is success. It means either the focused symbols were already in tolerance, or your cash-protection settings prevented any trades from being generated. Handle it explicitly.
- tacticalRebalanceDoNotSellUnAssignedSecurities: true is usually what you want. Without it, a focused run will liquidate unassigned holdings outside your focus list
- Save tradeInstanceId from the response. It’s how you’ll look up or reconcile the generated trades. You cannot supply it in the request — the backend always creates a new one.
- 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. A sleeved portfolio here will return 500 with Invalid Portfolio/Account type sent in request parameters.