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.
Average buy details: symbol, currentPrice, cost, context, backtest
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.
Breakeven details: symbol, currentPrice, newStopLossPrice, newTakeProfitPrice, context, backtest
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.
Pending ping details: symbol, signalId, position, prices, pnl, context, backtest
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.
Partial loss details: symbol, percentToClose, cost (dollar value), currentPrice, context, backtest
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.
Partial profit details: symbol, percentToClose, cost (dollar value), currentPrice, context, backtest
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.
Active ping details: symbol, signalId, position, prices, pnl, context, backtest
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.
Signal close details: symbol, cost, position, currentPrice, pnl, totalEntries, totalPartials, context, backtest
async onSignalCloseCommit(payload: BrokerSignalClosePayload) {
super.onSignalCloseCommit(payload); // Keep parent logging
const ok = await this.exchange.closePosition(payload.symbol);
if (!ok) {
throw new Error(`Exit not filled for ${payload.symbol}`); // -> keep position open, retry next tick
}
await this.db.recordTrade({ symbol: payload.symbol, pnl: payload.pnl });
}
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.
Idle ping details: symbol, currentPrice, context, backtest
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.
Signal open details: symbol, cost, position, priceOpen, priceTakeProfit, priceStopLoss, context, backtest
async onSignalOpenCommit(payload: BrokerSignalOpenPayload) {
super.onSignalOpenCommit(payload); // Keep parent logging
const order = await this.exchange.placeMarketOrder({
symbol: payload.symbol,
side: payload.position === "long" ? "BUY" : "SELL",
quantity: payload.cost / payload.priceOpen,
});
if (!order.filled) {
throw new Error(`Entry not filled for ${payload.symbol}`); // -> roll back the open, retry next tick
}
}
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.
Pending close details: symbol, signalId, position, prices, closeReason, context, backtest
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.
Pending open details: symbol, signalId, position, prices, context, backtest
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.
Scheduled cancel details: symbol, signalId, position, prices, reason, context, backtest
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.
Scheduled open details: symbol, signalId, position, prices, context, backtest
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.
Schedule ping details: symbol, signalId, position, prices, context, backtest
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.
Trailing stop details: symbol, percentShift, currentPrice, newStopLossPrice, context, backtest
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.
Trailing take details: symbol, percentShift, currentPrice, newTakeProfitPrice, context, backtest
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.
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:
Key features:
makeExtendableapplied for correct subclass instantiationLifecycle:
waitForInit()called once for async initialization (e.g. exchange login)waitForInitteardown or externallyEvent flow (called only in live mode, skipped in backtest):
onSignalOpenCommit— new position openedonSignalCloseCommit— position closed (SL/TP hit or manual close)onPartialProfitCommit— partial close at profit executedonPartialLossCommit— partial close at loss executedonTrailingStopCommit— trailing stop-loss updatedonTrailingTakeCommit— trailing take-profit updatedonBreakevenCommit— stop-loss moved to entry priceonAverageBuyCommit— new DCA entry added to positionExample
Example