Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-kit-docs/llms.txt

Use this file to discover all available pages before exploring further.

Commit functions are the only way to mutate position state in Backtest Kit. They are transactional: in live mode, every commit function fires the corresponding IBroker adapter method before the internal state changes. If the exchange rejects the order, the network fails, or the fill times out, the adapter throws, the mutation is skipped, and Backtest Kit retries automatically on the next tick. In backtest mode, commits update the in-memory simulation state directly.
Commit functions must only be called inside event listener callbacks such as listenActivePing, listenIdlePing, listenSchedulePing, and strategy lifecycle callbacks (onActivePing, onIdlePing, etc.). Calling them at the top level of your module — outside of any callback — will result in a runtime error because there is no active execution context.
In backtest mode without a broker adapter registered, commit functions skip the exchange interaction and update the simulation state directly. To enable broker integration in live mode, call Broker.useBrokerAdapter(...) and Broker.enable() at startup.

commitAverageBuy(symbol, cost?)

Adds a new DCA (Dollar Cost Averaging) entry to the current position. By default, the entry is only accepted if the current VWAP is strictly below the effective average entry price of the existing position — this prevents averaging up and enforces downward DCA discipline. The acceptance threshold is configurable via setConfig. When accepted, the new entry is appended to the position’s _entry array, the harmonic-mean entry price is recalculated, and the stop-loss and take-profit levels on the exchange are updated to reflect the full combined position.
import {
  listenActivePing,
  commitAverageBuy,
  getPositionEntryOverlap,
  getPositionInvestedCount,
} from 'backtest-kit';

listenActivePing(async ({ symbol, currentPrice }) => {
  const entryCount = await getPositionInvestedCount(symbol);

  // Cap at 5 DCA entries
  if (entryCount >= 5) return;

  // Prevent overlapping entries within a 2% band
  const overlap = await getPositionEntryOverlap(symbol, currentPrice, {
    upperPercent: 2,
    lowerPercent: 2,
  });
  if (overlap) return;

  await commitAverageBuy(symbol);
});
symbol
string
required
The trading pair symbol. Must match the symbol of the currently active position.
cost
number
Dollar amount for this DCA entry. Defaults to the cost value from the original signal if not provided.
When to use: Inside listenActivePing (or onActivePing) to build DCA ladders. Use getPositionEntryOverlap to prevent stacking entries at similar price levels and getPositionInvestedCount to cap the total number of entries.

commitPartialProfit(symbol, percentToClose)

Closes a percentage of the current position at the current VWAP as a profit-taking action. The closed portion’s cost basis is removed proportionally from the total, and the remaining position continues to be monitored with the same TP/SL levels (adjusted on the exchange for the reduced quantity).
import { listenActivePing, commitPartialProfit, getPositionPnlPercent } from 'backtest-kit';

listenActivePing(async ({ symbol }) => {
  const pnl = await getPositionPnlPercent(symbol);
  if (pnl === null) return;

  if (pnl > 5) {
    // Lock in 50% of the position at +5% PnL
    await commitPartialProfit(symbol, 50);
  }
});
symbol
string
required
The trading pair symbol.
percentToClose
number
required
Percentage of the current position to close (1–100). For example, 50 closes half the position.
Effect on cost basis: After commitPartialProfit(symbol, 30), the remaining cost basis is 70% of what it was. The effective entry price is unchanged, but the weight of this position in subsequent PnL calculations is reduced proportionally.

commitPartialLoss(symbol, percentToClose)

Closes a percentage of the current position at the current VWAP as a loss-cutting action. Identical mechanics to commitPartialProfit but intended for reducing exposure before the stop-loss level is hit.
import { listenActivePing, commitPartialLoss, getPositionPnlPercent } from 'backtest-kit';

listenActivePing(async ({ symbol }) => {
  const pnl = await getPositionPnlPercent(symbol);
  if (pnl === null) return;

  if (pnl < -3) {
    // Cut 25% of exposure at -3% to reduce risk before stop-loss fires
    await commitPartialLoss(symbol, 25);
  }
});
symbol
string
required
The trading pair symbol.
percentToClose
number
required
Percentage of the current position to close (1–100).

commitClosePending(symbol, options?)

Manually closes the active position at the current VWAP, regardless of the TP/SL levels. This is a clean close — it does not mark the signal as a stop-loss or take-profit hit. The closeReason on the resulting closed event will be 'close_pending'. This commit does not interrupt strategy execution. The strategy continues running after the close and can generate new signals on subsequent ticks.
import { commitClosePending } from 'backtest-kit';

// Close with an optional ID and note for audit trail
await commitClosePending('BTCUSDT', {
  id: 'manual-exit-001',
  note: 'Regime change detected — exiting early',
});
symbol
string
required
The trading pair symbol.
options.id
string
Optional identifier for this close action. Appears in the closeId field of the resulting IStrategyTickResultClosed event.
options.note
string
Optional human-readable annotation for the close reason. Appears in reports and notification payloads.

commitBreakeven(symbol)

Moves the stop-loss to the effective entry price (accounting for fee and slippage buffer so a breakeven close is still profitable net of costs). This is a one-time operation per signal — calling commitBreakeven multiple times on the same signal is a no-op after the first call. The engine calculates the breakeven threshold automatically using CC_PERCENT_FEE and CC_PERCENT_SLIPPAGE. Calling commitBreakeven before the price has cleared this threshold is silently ignored.
import { listenActivePing, commitBreakeven, getPositionPnlPercent } from 'backtest-kit';

listenActivePing(async ({ symbol }) => {
  const pnl = await getPositionPnlPercent(symbol);
  if (pnl === null) return;

  // Move SL to breakeven once the position is 1.5% in profit
  if (pnl > 1.5) {
    await commitBreakeven(symbol);
  }
});
symbol
string
required
The trading pair symbol.

commitTrailingStop(symbol, percentShift, currentPrice)

Adjusts the trailing stop-loss by a percentage shift relative to the original stop-loss distance (not the current trailing value). This avoids compounding rounding errors when chaining multiple trailing adjustments. The engine enforces ratchet absorption: for long positions, the adjusted stop-loss is only applied if it is higher than the current stop-loss (only tightening allowed). For short positions, only a lower stop-loss is accepted. Use a negative percentShift to bring the stop closer to entry; use a positive value to widen it. To set an absolute stop-loss price directly, use commitTrailingStopCost(symbol, newStopLossPrice) instead.
import { listenActivePing, commitTrailingStop } from 'backtest-kit';

listenActivePing(async ({ symbol, currentPrice }) => {
  // Tighten the stop-loss by 10% of the original stop distance
  await commitTrailingStop(symbol, -10, currentPrice);
});
symbol
string
required
The trading pair symbol.
percentShift
number
required
Percentage adjustment relative to the original stop-loss distance. Negative values move the stop closer to entry (tightening); positive values widen it. The ratchet ensures the result is only applied if it improves the stop level.
currentPrice
number
required
Current market price, used to compute the adjusted stop-loss level.

commitTrailingTake(symbol, percentShift, currentPrice)

Adjusts the trailing take-profit by a percentage shift relative to the original take-profit distance. Always calculates from the original TP, not the current trailing value, to prevent error accumulation. The engine enforces ratchet absorption: for long positions, only a lower take-profit is accepted (tightening the target). For short positions, only a higher take-profit is accepted. Use a negative percentShift to bring TP closer to entry (more conservative); positive to move it further away. To set an absolute take-profit price directly, use commitTrailingTakeCost(symbol, newTakeProfitPrice) instead.
import { listenActivePing, commitTrailingTake } from 'backtest-kit';

listenActivePing(async ({ symbol, currentPrice }) => {
  // Tighten the take-profit by 5% of the original TP distance
  await commitTrailingTake(symbol, -5, currentPrice);
});
symbol
string
required
The trading pair symbol.
percentShift
number
required
Percentage adjustment relative to the original take-profit distance. Negative values move TP closer to entry (more conservative); positive values move it further away. Ratchet semantics apply.
currentPrice
number
required
Current market price, used to compute the adjusted take-profit level.

Dollar-Amount Variants

For convenience, commitPartialProfit and commitPartialLoss have dollar-amount variants that compute the correct percentage automatically:
import { commitPartialProfitCost, commitPartialLossCost } from 'backtest-kit';

// Close $150 worth of the position as profit
await commitPartialProfitCost('BTCUSDT', 150);

// Close $100 worth of the position as a loss
await commitPartialLossCost('BTCUSDT', 100);
Trailing stop and take-profit also have absolute-price variants that set the level directly without requiring a percentage shift calculation:
import { commitTrailingStopCost, commitTrailingTakeCost } from 'backtest-kit';

// Set stop-loss to an absolute price (e.g. trail 3% below all-time high)
const highestPrice = await getPositionHighestProfitPrice('BTCUSDT');
if (highestPrice) {
  await commitTrailingStopCost('BTCUSDT', highestPrice * 0.97);
}

// Set take-profit to an absolute price
await commitTrailingTakeCost('BTCUSDT', currentPrice * 1.005);
Use commitTrailingStopCost / commitTrailingTakeCost when you have a concrete target price. Use commitTrailingStop / commitTrailingTake when you want to shift relative to the original stop/TP distance.

Build docs developers (and LLMs) love