BrokerBase

Implements IBroker

Base class for custom broker adapter implementations.

Provides default no-op implementations for all IBroker methods that log events. Extend this class to implement a real exchange adapter for:

  • Placing and canceling limit/market orders
  • Updating stop-loss and take-profit levels on exchange
  • Tracking position state in an external system
  • Sending trade notifications (Telegram, Discord, Email)
  • Recording trades to a database or analytics service

Key features:

  • All methods have default implementations (no need to override unused methods)
  • Automatic logging of all events via bt.loggerService
  • Implements the full IBroker interface
  • makeExtendable applied for correct subclass instantiation

Lifecycle:

  1. Constructor called (no arguments)
  2. waitForInit() called once for async initialization (e.g. exchange login)
  3. Event methods called as strategy executes
  4. No explicit dispose — clean up in waitForInit teardown or externally

Event flow (called only in live mode, skipped in backtest):

  • onSignalOpenCommit — new position opened
  • onSignalCloseCommit — position closed (SL/TP hit or manual close)
  • onPartialProfitCommit — partial close at profit executed
  • onPartialLossCommit — partial close at loss executed
  • onTrailingStopCommit — trailing stop-loss updated
  • onTrailingTakeCommit — trailing take-profit updated
  • onBreakevenCommit — stop-loss moved to entry price
  • onAverageBuyCommit — new DCA entry added to position
constructor();
waitForInit(): Promise<void>;

Performs async initialization before the broker starts receiving events.

Called once by BrokerProxy via waitForInit() (singleshot) before the first event. Override to establish exchange connections, authenticate API clients, load configuration.

Default implementation: Logs initialization event.

onSignalOpenCommit(payload: BrokerSignalOpenPayload): Promise<void>;

Called when a position is being opened (signal activated).

Triggered automatically via syncSubject when a scheduled signal's priceOpen is hit. Use to place the actual entry order on the exchange.

Default implementation: Logs signal-open event.

Manual wiring — EXCEPTION-BASED GATE: emitted BEFORE the framework mutates state, so a THROW here (e.g. limit order rejected) rolls back the open — the pending signal returns to idle and retries next tick; return normally to let it open. Live-only (backtest short-circuits). See IBroker.onSignalOpenCommit for the full semantics.

onOrderCheck(payload: BrokerSignalPendingPayload): Promise<void>;

Called on every live tick while a pending signal is monitored, BEFORE TP/SL/time evaluation.

Override to query the exchange for the order by payload.signalId and THROW ONLY when it is definitively NOT FOUND by that id (filled, cancelled, or liquidated externally) — the framework then closes the position with closeReason "closed". The default implementation logs and returns normally, which keeps the position under normal TP/SL monitoring.

CRITICAL: swallow transient/network errors (timeout, 5xx, rate limit, disconnect) — return normally instead of throwing. A thrown network error would wrongly close an open position; only a confirmed "order not found by id" response is a valid reason to throw.

Manual wiring — EXCEPTION-BASED VARIANT: the throw-driven alternative to the imperative commit-function wiring in onSignalActivePing. See IBroker.onOrderCheck for the full comparison and example.

onSignalActivePing(payload: BrokerActivePingPayload): Promise<void>;

Called on every live tick while a pending (open) signal is monitored.

Purely informational mirror of the active-ping lifecycle — unlike onOrderCheck, a throw here does NOT close the position. Override to mirror live monitoring state into your own systems. The default implementation logs.

Manual wiring — EVENT-BASED: this is the primary per-tick hook to drive an open position from real exchange state (commitCreateTakeProfit / commitCreateStopLoss / commitClosePending). See the IBroker.onSignalActivePing contract docs for the full guidance and example.

onSignalSchedulePing(payload: BrokerSchedulePingPayload): Promise<void>;

Called on every live tick while a scheduled signal is monitored (waiting for priceOpen).

Purely informational. Override to mirror scheduled-monitoring state. The default logs.

Manual wiring — EVENT-BASED: per-tick hook to drive a scheduled (resting) order from real exchange state (commitActivateScheduled / commitCancelScheduled). See IBroker.onSignalSchedulePing for full guidance and example.

onSignalIdlePing(payload: BrokerIdlePingPayload): Promise<void>;

Called on every live tick while the strategy is idle (no pending or scheduled signal).

Purely informational. Override to track idle heartbeats. The default logs.

onSignalScheduleOpen(payload: BrokerScheduleOpenPayload): Promise<void>;

Called when a new scheduled signal is created and starts waiting for priceOpen activation.

The scheduled -> active transition is reported via onSignalOpenCommit, not here. Override to place a resting/limit order on the exchange. The default logs.

Manual wiring — EVENT-BASED: fires ONCE at creation — place the real resting order (tag it with payload.signalId) and optionally commitActivateScheduled / commitCancelScheduled. See IBroker.onSignalScheduleOpen for full guidance and example.

onSignalScheduleCancelled(payload: BrokerScheduleCancelledPayload): Promise<void>;

Called when a scheduled signal is cancelled before activation (timeout / price_reject / user).

Override to cancel the resting/limit order on the exchange. The default logs.

Manual wiring — EVENT-BASED (outbound): the strategy already dropped the scheduled signal — cancel the matching exchange order by payload.signalId. See IBroker.onSignalScheduleCancelled.

onSignalPendingOpen(payload: BrokerPendingOpenPayload): Promise<void>;

Called when a pending position is opened (new signal / immediate / scheduled or user activation).

Informational lifecycle hook. Override to mirror the open into your own systems. The default logs.

Manual wiring — EVENT-BASED: fires ONCE at open — place entry + protective TP/SL orders (tag with payload.signalId), then drive per-tick from onSignalActivePing. See IBroker.onSignalPendingOpen.

onSignalPendingClose(payload: BrokerPendingClosePayload): Promise<void>;

Called when a pending position is closed (take_profit / stop_loss / time_expired / closed).

Informational lifecycle hook. Override to mirror the close into your own systems. The default logs.

Manual wiring — EVENT-BASED (outbound): the strategy already removed the pending signal — flatten the real position and cancel leftover TP/SL orders by payload.signalId. See IBroker.onSignalPendingClose.

onSignalCloseCommit(payload: BrokerSignalClosePayload): Promise<void>;

Called when a position is being closed (SL/TP hit or manual close).

Triggered automatically via syncSubject when a pending signal is closed. Use to place the exit order and record final PnL.

Default implementation: Logs signal-close event.

Manual wiring — EXCEPTION-BASED GATE: emitted BEFORE the framework mutates state, so a THROW here (e.g. exit order failed) SKIPS the close — the position stays open and the close retries next tick; return normally to let it close. Live-only (backtest short-circuits). See IBroker.onSignalCloseCommit for the full semantics.

onPartialProfitCommit(payload: BrokerPartialProfitPayload): Promise<void>;

Called when a partial close at profit is executed.

Triggered explicitly from strategy.ts / Live.ts / Backtest.ts after all validations pass, before strategyCoreService.partialProfit(). If this method throws, the DI mutation is skipped. Use to partially close the position on the exchange at the profit level.

Default implementation: Logs partial profit event.

onPartialLossCommit(payload: BrokerPartialLossPayload): Promise<void>;

Called when a partial close at loss is executed.

Triggered explicitly from strategy.ts / Live.ts / Backtest.ts after all validations pass, before strategyCoreService.partialLoss(). If this method throws, the DI mutation is skipped. Use to partially close the position on the exchange at the loss level.

Default implementation: Logs partial loss event.

onTrailingStopCommit(payload: BrokerTrailingStopPayload): Promise<void>;

Called when the trailing stop-loss level is updated.

Triggered explicitly after all validations pass, before strategyCoreService.trailingStop(). newStopLossPrice is the absolute SL price — use it to update the exchange order directly.

Default implementation: Logs trailing stop event.

onTrailingTakeCommit(payload: BrokerTrailingTakePayload): Promise<void>;

Called when the trailing take-profit level is updated.

Triggered explicitly after all validations pass, before strategyCoreService.trailingTake(). newTakeProfitPrice is the absolute TP price — use it to update the exchange order directly.

Default implementation: Logs trailing take event.

onBreakevenCommit(payload: BrokerBreakevenPayload): Promise<void>;

Called when the stop-loss is moved to breakeven (entry price).

Triggered explicitly after all validations pass, before strategyCoreService.breakeven(). newStopLossPrice equals effectivePriceOpen — the position's effective entry price. newTakeProfitPrice is unchanged by breakeven.

Default implementation: Logs breakeven event.

onAverageBuyCommit(payload: BrokerAverageBuyPayload): Promise<void>;

Called when a new DCA entry is added to the active position.

Triggered explicitly after all validations pass, before strategyCoreService.averageBuy(). currentPrice is the market price at which the new averaging entry is placed. cost is the dollar amount of the new DCA entry.

Default implementation: Logs average buy event.