Skip to content

onBar

onBar(ctx)

At a glance — the only required hook, and where most logic lives. Fires once per closed bar with a BarContext: the new bar, the indicator series, current position, account, the order API, clock and log.

Signature

onBar(ctx: BarContext): void

Example

hooks/lifecycle
import { defineStrategy } from '@nexpips/sdk-trading';
/**
* Cycle de vie complet : tous les hooks optionnels et les contextes qu'ils
* reçoivent — `InitContext` (init), `BarContext` (onBar), `TickContext`
* (onTick), `EventContext` + `Fill` / `Rejection` / `ClosedPosition` (events).
*/
export default defineStrategy({
symbol: 'EURUSD',
timeframe: 'M5',
risk: {
maxRiskPercentPerTrade: 0.5,
maxOpenPositions: 1,
maxDailyLossPercent: 3,
maxConsecutiveRejects: 5,
},
setup: () => ({
init(ctx) {
ctx.log.info('strategy started', { balance: ctx.account.balance, at: ctx.clock.now });
},
onBar(ctx) {
if (ctx.position.isFlat && !ctx.position.hasPendingOrder) {
ctx.order.marketBuy({
riskPercent: 0.5,
stopLoss: { type: 'pips', value: 20 },
takeProfit: { type: 'rr', value: 2 },
});
}
},
onTick(ctx) {
const spread = ctx.ask - ctx.bid;
if (spread > 0.0005) ctx.log.debug('wide spread', { spread });
},
onOrderFilled(ctx, fill) {
ctx.log.info('filled', { side: fill.side, price: fill.price, size: fill.size });
},
onOrderRejected(ctx, rejection) {
// rejection.reason est un RejectReason (union fermée).
ctx.log.warn('order rejected', { reason: rejection.reason, message: rejection.message });
},
onPositionClosed(ctx, closed) {
ctx.log.info('position closed', { pnl: closed.realizedPnl });
},
}),
});

onBar drives entries; the other hooks react to events.

To know

  • Runs on bar close, so values are final (no look-ahead). For intrabar logic use onTick.
  • Guard entries with ctx.position.isFlat and ctx.position.hasPendingOrder.

See also