Skip to content
EliteChart

Broker contract

The trading-side interface — orders, positions, account state — symmetric to Datafeed but for writes.

Datafeed handles the read side of trading — bars, ticks, symbols. Broker handles the write side — orders, positions, account state. Keeping them separate lets you ship read-only demos (data-only) or full interactive trading UIs (data + orders) by plugging in either or both.

Status. The Broker contract is designed and the surface is frozen below. The broker prop on <EliteChart /> activates it end-to-end in Phase 2 — see reference/roadmap.

Quick example

code
import type { Broker, OrderRequest, OrderResult } from '@elitechart/elitechart';

export const myBroker: Broker = {
  async getAccount() {
    return { id: 'demo', currency: 'USD', balance: 10000, equity: 10000, margin: 0, freeMargin: 10000, marginLevel: null };
  },
  async getPositions() { return []; },
  async getOrders() { return []; },
  async placeOrder(req: OrderRequest): Promise<OrderResult> {
    const r = await fetch('/api/orders', { method: 'POST', body: JSON.stringify(req) });
    return r.json();
  },
  async modifyOrder(id, patch) {
    await fetch(`/api/orders/${id}`, { method: 'PATCH', body: JSON.stringify(patch) });
  },
  async cancelOrder(id) {
    await fetch(`/api/orders/${id}`, { method: 'DELETE' });
  },
  async closePosition(id) {
    await fetch(`/api/positions/${id}/close`, { method: 'POST' });
  },
  subscribe(onEvent) {
    const ws = new WebSocket('wss://example.com/broker-events');
    ws.onmessage = (e) => onEvent(JSON.parse(e.data));
    return () => ws.close();
  },
};

How it works

The interface mirrors a generic broker REST API.

getAccount() returns balance, equity, margin, free margin, and margin level. Called once on mount, then refreshed on every account event from subscribe.

getPositions() / getOrders() enumerate open positions and pending/filled orders. Same lifecycle — initial load, then driven by events.

placeOrder(req) submits a market / limit / stop / stop-limit order. Returns immediately with the broker's order id; fill notification comes through the event stream.

modifyOrder(id, patch) edits SL / TP / quantity / limit on an existing order. Used by the chart's drag-handle UI to repositioning SL/TP lines on screen.

cancelOrder(id) / closePosition(id) are exactly what they sound like.

subscribe(onEvent) opens a live event stream: account / position:open / position:update / position:close / order:fill / order:cancel / error.

Variations

Paper trading (no backend)

See recipes/paper-trading for an in-memory implementation that simulates fills against the live mid.

Read-only mode

Don't pass a broker prop. The Trading Panel tab in the bottom bar gracefully degrades to a "trading not available" state.

API

MethodReturnsNotes
getAccount()Promise<AccountState>balance, equity, margin
getPositions()Promise<ReadonlyArray<Position>>open positions
getOrders()Promise<ReadonlyArray<BrokerOrder>>pending + recent
placeOrder(req)Promise<OrderResult>market / limit / stop
modifyOrder(id, patch)Promise<void>SL / TP / qty / limit
cancelOrder(id)Promise<void>
closePosition(id)Promise<void>market close
subscribe(onEvent)() => voidunsubscribe