Skip to main content

Order Ticket

Order ticket with side, type, quantity, duration, impact, and submit controls
The ticket turns one exact symbol and broker-declared rules into one typed order intent.

TradingOrderTicket is the React adapter for standard stock, fund, forex, futures, and crypto order entry. It reads state and trading rules from TradingControllerApi, then submits one TradingOrderDraft through that same controller. For a framework-neutral mount, use sdk.orderTicket.mount(...) as shown in Order entry.

Use Option order ticket for option legs and Prediction-market order ticket for event outcomes.

Minimal ticket

Pass the exact symbol returned by market-data resolution. Do not rebuild it from ticker text in the ticket layer. The adapter behind trading must declare at least one supported order type and duration for the selected account and symbol.

OrderEntry.tsx
import type {
MarketDataControllerApi,
TradeScriptSdkProducts,
TradingControllerApi,
} from '@tradescript/pro/sdk';
import { TradingOrderTicket } from '@tradescript/pro/react/widgets/order-ticket';

declare const sdk: TradeScriptSdkProducts;
declare const marketData: MarketDataControllerApi;
declare const trading: TradingControllerApi;

const symbol = await marketData.resolveSymbol('AAPL');

export function OrderEntry() {
return (
<TradingOrderTicket
sdk={sdk}
controller={trading}
symbol={symbol}
currentPrice={214.4}
defaultQuantity={1}
quickQuantities={[1, 5, 10, 25]}
/>
);
}

Reuse one controller across the chart, ticket, and Account Manager for the same broker session. Unmounting this component does not destroy that controller.

User flow

When supported, the ticket loads rules through getTradingSymbolInfo(context). Preview uses previewOrder(draft, context); submission uses placeOrder(draft, context).

The chart and account tables update when the adapter publishes authoritative order state. onOrderAccepted is an acknowledgement callback, not a durable order-state source.

Broker-owned rules

getTradingSymbolInfo(context) can declare:

  • quantity minimums and steps
  • price steps and precision
  • canonical and broker-native order types
  • supported durations
  • brackets and exit limits
  • symbol/account ticket settings
  • a declarative fieldLayout

The ticket does not invent order-type or duration availability. Quantity and price inputs have presentation defaults when step facts are absent, but those defaults are not broker authorization. Keep provider mapping in the adapter and send the canonical type beside any brokerOrderTypeId.

import type { TradingOrderContext, TradingSymbolInfo } from '@tradescript/pro/sdk';

async function getTradingSymbolInfo(
context: TradingOrderContext,
): Promise<TradingSymbolInfo> {
return {
symbol: context.symbol,
accountId: context.accountId,
minQuantity: 1,
quantityStep: 1,
priceStep: 0.01,
supportedOrderRules: [
{ type: 'market', brokerOrderTypeId: 'MKT', label: 'Market' },
{ type: 'limit', brokerOrderTypeId: 'LMT', label: 'Limit', requiresLimitPrice: true },
],
supportedDurations: [
{ type: 'day', label: 'Day' },
{ type: 'gtc', label: 'GTC' },
],
};
}

See Order Ticket Configuration when the broker needs extra fields, conditions, calculated rows, or persisted preferences.

Preview and placement

previewOrder is optional for the generic ticket. When it is available, choose one preview mode:

ModeBehavior
noneSubmit after local validation. The backend still performs final validation.
backgroundDebounce advisory preview facts as the draft changes. The latest rejection blocks submission, but submission does not re-preview the current draft.
dialogRequire the user to accept the current preview before placement.

Preview results can include sections, estimated costs, warnings, errors, and a confirmId. The backend must revalidate placement; a preview is never an authorization token by itself. Use dialog when the user must review the exact draft that will be placed.

<TradingOrderTicket
sdk={sdk}
controller={trading}
symbol={symbol}
currentPrice={214.4}
orderPreviewMode="dialog"
messageAutoDismissMs={false}
onOrderAccepted={(orderId) => {
console.info('Placement acknowledged', orderId);
}}
/>

Transport failures and timeouts have an unknown outcome. Keep the error visible and reconcile the order stream before offering a retry.

Attach exits

The ticket can attach take-profit and protective stop levels to the entry. The effective account and exact-symbol rules control what the user can enter:

RuleEffect
supportsStopLossDeclares protective-stop support; omitted currently resolves as supported.
supportsMarketBracketsAllows exits on a market entry; limit and stop entries do not need this flag.
supportsTrailingStop, supportsGuaranteedStopAdds those protective-stop kinds.
supportsMultipleExitLevels, maxExitLevelsEnables a quantity ladder and limits its level count.
supportsUnpairedExitLevels: falseRequires take-profit and stop-loss legs to be paired at each level.

When the user enables exits, the placed TradingOrderDraft carries exits.levels. Every level has a stable id, the covered quantity, and an optional takeProfit and stopLoss. The adapter must preserve those identities when it creates and later publishes the broker's parent and child orders.

import type {
SdkSymbolInfo,
TradingAccountId,
TradingSymbolInfo,
} from '@tradescript/pro/sdk';

declare const symbol: SdkSymbolInfo;
declare const accountId: TradingAccountId;

const symbolRules: TradingSymbolInfo = {
symbol,
accountId,
supportedOrderTypes: ['market', 'limit'],
supportedDurations: [{ type: 'day', value: 'day' }],
supportsStopLoss: true,
supportsMarketBrackets: true,
supportsMultipleExitLevels: true,
supportsUnpairedExitLevels: false,
maxExitLevels: 3,
};

Ticket validation is presentation-time protection only. Preview and placement must revalidate prices, quantities, supported stop kinds, and total covered quantity at the broker boundary. Publish dormant and activated bracket children through authoritative order state; do not synthesize them after acknowledgement.

Modify an order

Pass the current broker-owned TradingOrder through modifyOrder. The ticket prefills the editable fields and submits a TradingOrderPatch through modifyOrder(orderId, patch, context).

<TradingOrderTicket
sdk={sdk}
controller={trading}
symbol={workingOrder.symbol}
modifyOrder={workingOrder}
currentPrice={214.4}
onModifyAccepted={(orderId) => console.info('Modification acknowledged', orderId)}
/>

Render modify mode only when trading.getOperationSupport().modifyOrder is true. The next broker snapshot remains authoritative.

Presentation

Keep broker semantics in TradingSymbolInfo and use React props only for this mounted ticket's presentation:

NeedProp
Match the charttheme
Rename built-in textlabels
Change Buy/Sell layoutdirectionSelector
Choose impact rowsorderInfo.items
Style one controlslotClassNames, slotStyles
Replace a React regionrenderDirectionSelector, renderOrderInfo

Unavailable calculated values render as -; they are not converted to zero. The complete field-layout and host-presentation example is in Customize the order ticket. Import TradingOrderTicketProps rather than copying the prop contract.

Configure order-impact rows

Use orderInfo.items to choose, order, and label SDK-calculated rows or add host-owned values. The shared React presentation type is named BrokerOrderTicketOrderInfoOptions; it does not introduce another broker adapter or state contract.

import type {
SdkSymbolInfo,
TradeScriptSdkProducts,
TradingControllerApi,
} from '@tradescript/pro/sdk';
import {
TradingOrderTicket,
type BrokerOrderTicketOrderInfoOptions,
} from '@tradescript/pro/react/widgets/order-ticket';

declare const sdk: TradeScriptSdkProducts;
declare const trading: TradingControllerApi;
declare const symbol: SdkSymbolInfo;
declare const customer: { accountTier: string };

<TradingOrderTicket
sdk={sdk}
controller={trading}
symbol={symbol}
orderInfo={{
items: [
{ id: 'notional', source: 'tradeValue', label: 'Order value' },
{ id: 'fees', source: 'commission', label: 'Fees' },
{ id: 'cash', source: 'cashAfter', label: 'Cash remaining' },
{ id: 'tier', label: 'Account tier', value: customer.accountTier },
],
} satisfies BrokerOrderTicketOrderInfoOptions}
renderOrderInfo={({ defaultContent }) => (
<aside aria-label="Estimated order impact">
{defaultContent}
<p>Estimates may change before execution.</p>
</aside>
)}
/>;

renderOrderInfo is the full-region escape hatch. Return defaultContent to wrap the configured rows, replace it with host markup, or remove the whole region explicitly:

renderOrderInfo={() => null}

These values are read-only presentation inputs. Preview and placement still revalidate the order at the broker boundary.

Verify the integration

  • The visible order types, durations, and steps match the selected account and symbol.
  • In dialog mode, changing the draft requires a new accepted preview.
  • In background mode, a latest rejected preview blocks placement and shows the broker message.
  • A rejected placement creates no local order record.
  • An accepted placement appears only after an orders or state update.
  • Switching symbols retains exact provider and broker identity.

Next steps