Skip to main content

Positions

TradingState.positions contains broker-owned net exposure. Optional individualPositions contains per-entry or per-lot rows. The SDK renders these facts but never reconstructs them from executions.

Position states

Opening or fully closing a position moves through flat. A reversal moves directly between long and short; resizing or partially closing a position keeps the same side. A flat or non-positive record is not shown as open. Omitting the closed row from the next replacement snapshot has the same visible result.

Minimal position

position.ts
import type { SdkSymbolInfo, TradingPosition } from '@tradescript/pro/sdk';

declare const symbol: SdkSymbolInfo;

export const position: TradingPosition = {
id: 'pos-3',
accountId: 'acct-1',
symbol,
side: 'long',
quantity: 200,
averagePrice: 184.98,
marketPrice: 185,
unrealizedPnl: 4,
currency: 'USD',
};

Keep the same globally unique id while quantity, average price, market price, and P&L change. Prefix native account-scoped ids before publishing them. actionable: false hides close, protection, and reverse actions on the chart position line. Account Manager does not read this flag; omit those rowActions from the positions table metadata when that surface must be read-only.

P&L ownership

Prefer broker-calculated unrealizedPnl and realizedPnl. A chart overlay can display a fallback from average price, market price, side, and quantity. That display calculation never alters controller state.

Account Manager displays broker-provided money P&L or -. Its percent, tick, and pip views use declared price facts such as minTick and pipSize.

For frequent updates, emit position-pl. Publish a complete positions or state snapshot when a field must be removed or exposure changes.

Position actions

Position operations are optional adapter capabilities:

User actionAdapter method
Preview closepreviewClosePosition
Add or edit protectionmodifyPosition
Full or partial closeclosePosition
Close an individual rowcloseIndividualPosition
ReversereversePosition
Flatten an account or scopeflattenPositions
Edit individual bracketseditIndividualPositionBrackets

Chart action visibility also reads adapter method presence, chart display overrides, and actionable. If risk wiring or production entitlements narrow trading.getOperationSupport(), set positionCloseActionVisible, positionProtectActionVisible, and positionReverseActionVisible from that filtered map. Otherwise a visible chart action can still be rejected by the controller boundary.

For an actionable chart position, the close control is available by default when the adapter implements closePosition. Set positionCloseActionVisible: false to hide it, or set positionCloseConfirmationVisible: true to require an inline confirmation before the adapter call. The controller supplies the position id, symbol, and account context; the adapter remains responsible for the actual exit order.

Each method has a defined local completion path:

MethodCompletion behavior
modifyPositionReturns the updated position. The controller applies it through position-modified.
Full closePositionResolves after confirmation. The controller applies position-closed and removes the id.
Partial closePositionPreserves options.quantity, then calls getState() after the adapter resolves. The snapshot must contain the reduced or closed exposure.
reversePositionResolves after confirmation, then the controller calls getState().
flattenPositionsReturns the flattened count, then the controller calls getState().

Do not silently convert a partial request into full liquidation.

Net and individual rows use different methods. Declare supportsPositionNetting and supportsIndividualPositions to match the backend model.

Protection

modifyPosition accepts typed stop-loss and take-profit levels. Stable exitLevelId values let broker state, placed orders, and editors reconcile levels without relying on array position.

Chart-side protection defaults can prefill an editor, but the broker remains the authority for level limits, supported stop types, validation, modification, and the resulting position and order state.

Enable the chart action explicitly and provide defaults when the native editor should start with a generated protection ladder:

import type { ChartApi } from '@tradescript/pro/sdk';

declare const chart: ChartApi;

chart.customization().applyOverrides({
trading: {
display: {
positionProtectActionVisible: true,
positionProtectionEditorVisible: true,
positionProtectionDefaults: {
stopDistanceTicks: 20,
takeProfitRiskRatio: 2,
stopLevels: [
{ id: 'initial-risk', distanceTicks: 20, quantityRatio: 0.5 },
{ id: 'runner-risk', distanceTicks: 40, quantityRatio: 0.5 },
],
takeProfitLevels: [
{ id: 'target-1', riskRatio: 2, quantityRatio: 0.5 },
{ id: 'target-2', riskRatio: 4, quantityRatio: 0.5 },
],
limits: {
maxStopLossLevels: 2,
maxTakeProfitLevels: 2,
maxTotalLevels: 4,
},
},
},
},
});

positionProtectionEditorVisible: false routes the action through a position-protect-requested event for a host-owned editor. positionProtectConfirmationVisible: true instead skips the editor and asks for inline confirmation before submitting the generated patch. The request includes resolved limits and, when price and quantity facts are sufficient, a TradingPositionProtectionSummary with coverage, risk, reward, and per-level P&L. The resolver applies the strictest valid limits declared by defaults, runtime features, account capabilities, and symbol rules.

Verify the contract

  • A fill changes exposure only after the adapter publishes a position update.
  • A partial close retains the position id with the correct reduced quantity.
  • Missing P&L renders unavailable rather than zero.
  • A read-only surface hides chart actions and omits Account Manager row actions.
  • Reversal publishes the backend's new side, quantity, and average price.

Next steps