diff --git "a/classes/types.ActionBase.html" "b/classes/types.ActionBase.html" --- "a/classes/types.ActionBase.html" +++ "b/classes/types.ActionBase.html" @@ -34,13 +34,13 @@ Extend this class to implement custom action handlers for:

  • pingActive() - Called every minute during active pending signal monitoring
  • riskRejection() - Called when signal rejected by risk management
  • -
    import { ActionBase } from "backtest-kit";

    // Extend ActionBase and override only needed methods
    class TelegramNotifier extends ActionBase {
    private bot: TelegramBot | null = null;

    async init() {
    super.init(); // Call parent for logging
    this.bot = new TelegramBot(process.env.TELEGRAM_TOKEN);
    await this.bot.connect();
    }

    async signal(event: IStrategyTickResult) {
    super.signal(event); // Call parent for logging
    if (event.action === 'opened') {
    await this.bot.send(
    `[${this.strategyName}/${this.frameName}] Signal opened: ${event.signal.side}`
    );
    }
    }

    async breakeven(event: BreakevenContract) {
    super.breakeven(event); // Call parent for logging
    await this.bot.send(
    `[${this.strategyName}] Breakeven reached at ${event.currentPrice}`
    );
    }

    async dispose() {
    super.dispose(); // Call parent for logging
    await this.bot?.disconnect();
    this.bot = null;
    }
    }

    // Register the action
    addActionSchema({
    actionName: "telegram-notifier",
    handler: TelegramNotifier
    }); +
    import { ActionBase } from "backtest-kit";

    // Extend ActionBase and override only needed methods
    class TelegramNotifier extends ActionBase {
    private bot: TelegramBot | null = null;

    async init() {
    super.init(); // Call parent for logging
    this.bot = new TelegramBot(process.env.TELEGRAM_TOKEN);
    await this.bot.connect();
    }

    async signal(event: IStrategyTickResult) {
    super.signal(event); // Call parent for logging
    if (event.action === 'opened') {
    await this.bot.send(
    `[${this.strategyName}/${this.frameName}] Signal opened: ${event.signal.side}`
    );
    }
    }

    async breakeven(event: BreakevenContract) {
    super.breakeven(event); // Call parent for logging
    await this.bot.send(
    `[${this.strategyName}] Breakeven reached at ${event.currentPrice}`
    );
    }

    async dispose() {
    super.dispose(); // Call parent for logging
    await this.bot?.disconnect();
    this.bot = null;
    }
    }

    // Register the action
    addActionSchema({
    actionName: "telegram-notifier",
    handler: TelegramNotifier
    });
    -
    // Redux state management example
    class ReduxAction extends ActionBase {
    constructor(
    strategyName: StrategyName,
    frameName: FrameName,
    actionName: ActionName,
    private store: Store
    ) {
    super(strategyName, frameName, actionName);
    }

    signal(event: IStrategyTickResult) {
    this.store.dispatch({
    type: 'STRATEGY_SIGNAL',
    payload: { event, strategyName: this.strategyName, frameName: this.frameName }
    });
    }

    partialProfit(event: PartialProfitContract) {
    this.store.dispatch({
    type: 'PARTIAL_PROFIT',
    payload: { event, strategyName: this.strategyName }
    });
    }
    } +
    // Redux state management example
    class ReduxAction extends ActionBase {
    constructor(
    strategyName: StrategyName,
    frameName: FrameName,
    actionName: ActionName,
    private store: Store
    ) {
    super(strategyName, frameName, actionName);
    }

    signal(event: IStrategyTickResult) {
    this.store.dispatch({
    type: 'STRATEGY_SIGNAL',
    payload: { event, strategyName: this.strategyName, frameName: this.frameName }
    });
    }

    partialProfit(event: PartialProfitContract) {
    this.store.dispatch({
    type: 'PARTIAL_PROFIT',
    payload: { event, strategyName: this.strategyName }
    });
    }
    }
    -

    Implements

    Constructors

    Implements

    Constructors

    Properties

    actionName backtest frameName @@ -62,7 +62,7 @@ Extend this class to implement custom action handlers for:

  • frameName: string

    Timeframe identifier this action is attached to

  • actionName: string

    Action identifier

  • backtest: boolean

    If running in backtest

    -
  • Returns ActionBase

    Properties

    actionName: string
    backtest: boolean
    frameName: string
    strategyName: string

    Methods

    • Handles breakeven events when stop-loss is moved to entry price.

      +

    Returns ActionBase

    Properties

    actionName: string
    backtest: boolean
    frameName: string
    strategyName: string

    Methods

    • Handles breakeven events when stop-loss is moved to entry price.

      Called once per signal when price moves far enough to cover fees and slippage. Breakeven threshold: (CC_PERCENT_SLIPPAGE + CC_PERCENT_FEE) * 2 + CC_BREAKEVEN_THRESHOLD

      Triggered by: ActionCoreService.breakevenAvailable() via BreakevenConnectionService @@ -70,10 +70,10 @@ Source: breakevenSubject.next() in CREATE_COMMIT_BREAKEVEN_FN callback Frequency: Once per signal when threshold reached

      Default implementation: Logs breakeven event.

      Parameters

      • event: BreakevenContract

        Breakeven milestone data with signal info, current price, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      async breakevenAvailable(event: BreakevenContract) {
      await this.telegram.send(
      `[${event.strategyName}] Breakeven reached! ` +
      `Signal: ${event.data.side} @ ${event.currentPrice}`
      );
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    async breakevenAvailable(event: BreakevenContract) {
    await this.telegram.send(
    `[${event.strategyName}] Breakeven reached! ` +
    `Signal: ${event.data.side} @ ${event.currentPrice}`
    );
    }
    -
    • Cleans up resources and subscriptions when action handler is disposed.

      +
    • Cleans up resources and subscriptions when action handler is disposed.

      Called once when strategy execution ends. Guaranteed to run exactly once via singleshot pattern.

      Override to:

      @@ -85,10 +85,10 @@ Guaranteed to run exactly once via singleshot pattern.

    • Unsubscribe from observables

    Default implementation: Logs dispose event.

    -

    Parameters

    • Optionalsource: string

    Returns void | Promise<void>

    async dispose() {
    super.dispose(); // Keep parent logging
    await this.db?.disconnect();
    await this.telegram?.close();
    await this.cache?.quit();
    console.log('Action disposed successfully');
    } +

    Parameters

    • Optionalsource: string

    Returns void | Promise<void>

    async dispose() {
    super.dispose(); // Keep parent logging
    await this.db?.disconnect();
    await this.telegram?.close();
    await this.cache?.quit();
    console.log('Action disposed successfully');
    }
    -
    • Initializes the action handler.

      +
    • Initializes the action handler.

      Called once after construction. Override to perform async initialization:

      • Establish database connections
      • @@ -97,10 +97,10 @@ Guaranteed to run exactly once via singleshot pattern.

      • Open file handles or network sockets

      Default implementation: Logs initialization event.

      -

      Parameters

      • Optionalsource: string

      Returns void | Promise<void>

      async init() {
      super.init(); // Keep parent logging
      this.db = await connectToDatabase();
      this.telegram = new TelegramBot(process.env.TOKEN);
      } +

      Parameters

      • Optionalsource: string

      Returns void | Promise<void>

      async init() {
      super.init(); // Keep parent logging
      this.db = await connectToDatabase();
      this.telegram = new TelegramBot(process.env.TOKEN);
      }
      -
    • Handles partial loss level events (-10%, -20%, -30%, etc).

      +
    • Handles partial loss level events (-10%, -20%, -30%, etc).

      Called once per loss level per signal (deduplicated). Use to track loss milestones and implement risk management actions.

      Triggered by: ActionCoreService.partialLossAvailable() via PartialConnectionService @@ -108,10 +108,10 @@ Source: partialLossSubject.next() in CREATE_COMMIT_LOSS_FN callback Frequency: Once per loss level per signal

      Default implementation: Logs partial loss event.

      Parameters

      • event: PartialLossContract

        Loss milestone data with signal info, level (-10, -20, -30...), price, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      async partialLossAvailable(event: PartialLossContract) {
      await this.telegram.send(
      `[${event.strategyName}] Loss ${event.level}% reached! ` +
      `Current price: ${event.currentPrice}`
      );
      // Optionally adjust risk management
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    async partialLossAvailable(event: PartialLossContract) {
    await this.telegram.send(
    `[${event.strategyName}] Loss ${event.level}% reached! ` +
    `Current price: ${event.currentPrice}`
    );
    // Optionally adjust risk management
    }
    -
    • Handles partial profit level events (10%, 20%, 30%, etc).

      +
    • Handles partial profit level events (10%, 20%, 30%, etc).

      Called once per profit level per signal (deduplicated). Use to track profit milestones and adjust position management.

      Triggered by: ActionCoreService.partialProfitAvailable() via PartialConnectionService @@ -119,10 +119,10 @@ Source: partialProfitSubject.next() in CREATE_COMMIT_PROFIT_FN callback Frequency: Once per profit level per signal

      Default implementation: Logs partial profit event.

      Parameters

      • event: PartialProfitContract

        Profit milestone data with signal info, level (10, 20, 30...), price, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      async partialProfitAvailable(event: PartialProfitContract) {
      await this.telegram.send(
      `[${event.strategyName}] Profit ${event.level}% reached! ` +
      `Current price: ${event.currentPrice}`
      );
      // Optionally tighten stop-loss or take partial profit
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    async partialProfitAvailable(event: PartialProfitContract) {
    await this.telegram.send(
    `[${event.strategyName}] Profit ${event.level}% reached! ` +
    `Current price: ${event.currentPrice}`
    );
    // Optionally tighten stop-loss or take partial profit
    }
    -
    • Handles active ping events during active pending signal monitoring.

      +
    • Handles active ping events during active pending signal monitoring.

      Called every minute while a pending signal is active (position open). Use to monitor active positions and track lifecycle.

      Triggered by: ActionCoreService.pingActive() via StrategyConnectionService @@ -130,10 +130,10 @@ Source: activePingSubject.next() in CREATE_COMMIT_ACTIVE_PING_FN callback Frequency: Every minute while pending signal is active

      Default implementation: Logs active ping event.

      Parameters

      • event: ActivePingContract

        Active pending signal monitoring data with symbol, strategy info, signal data, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      pingActive(event: ActivePingContract) {
      const holdTime = getTimestamp() - event.data.pendingAt;
      const holdMinutes = Math.floor(holdTime / 60000);
      console.log(`Active signal holding ${holdMinutes} minutes`);
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    pingActive(event: ActivePingContract) {
    const holdTime = getTimestamp() - event.data.pendingAt;
    const holdMinutes = Math.floor(holdTime / 60000);
    console.log(`Active signal holding ${holdMinutes} minutes`);
    }
    -
    • Handles idle ping events when no signal is active.

      +
    • Handles idle ping events when no signal is active.

      Called every tick while no signal is pending or scheduled. Use to monitor idle strategy state and implement entry condition logic.

      Triggered by: ActionCoreService.pingIdle() via StrategyConnectionService @@ -141,7 +141,7 @@ Source: idlePingSubject.next() in CREATE_COMMIT_IDLE_PING_FN callback Frequency: Every tick while no signal is pending or scheduled

      Default implementation: Logs idle ping event.

      Parameters

      • event: IdlePingContract

        Idle ping data with symbol, strategy info, current price, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

    • Handles scheduled ping events during scheduled signal monitoring.

      +
    • Optionalsource: string

    Returns void | Promise<void>

    • Handles scheduled ping events during scheduled signal monitoring.

      Called every minute while a scheduled signal is waiting for activation. Use to monitor pending signals and track wait time.

      Triggered by: ActionCoreService.pingScheduled() via StrategyConnectionService @@ -149,10 +149,10 @@ Source: schedulePingSubject.next() in CREATE_COMMIT_SCHEDULE_PING_FN callback Frequency: Every minute while scheduled signal is waiting

      Default implementation: Logs scheduled ping event.

      Parameters

      • event: SchedulePingContract

        Scheduled signal monitoring data with symbol, strategy info, signal data, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      pingScheduled(event: SchedulePingContract) {
      const waitTime = getTimestamp() - event.data.timestampScheduled;
      const waitMinutes = Math.floor(waitTime / 60000);
      console.log(`Scheduled signal waiting ${waitMinutes} minutes`);
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    pingScheduled(event: SchedulePingContract) {
    const waitTime = getTimestamp() - event.data.timestampScheduled;
    const waitMinutes = Math.floor(waitTime / 60000);
    console.log(`Scheduled signal waiting ${waitMinutes} minutes`);
    }
    -
    • Handles risk rejection events when signals fail risk validation.

      +
    • Handles risk rejection events when signals fail risk validation.

      Called only when signal is rejected (not emitted for allowed signals). Use to track rejected signals and analyze risk management effectiveness.

      Triggered by: ActionCoreService.riskRejection() via RiskConnectionService @@ -160,10 +160,10 @@ Source: riskSubject.next() in CREATE_COMMIT_REJECTION_FN callback Frequency: Only when signal fails risk validation

      Default implementation: Logs risk rejection event.

      Parameters

      • event: RiskContract

        Risk rejection data with symbol, pending signal, rejection reason, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

      async riskRejection(event: RiskContract) {
      await this.telegram.send(
      `[${event.strategyName}] Signal rejected!\n` +
      `Reason: ${event.rejectionNote}\n` +
      `Active positions: ${event.activePositionCount}`
      );
      this.metrics.recordRejection(event.rejectionId);
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    async riskRejection(event: RiskContract) {
    await this.telegram.send(
    `[${event.strategyName}] Signal rejected!\n` +
    `Reason: ${event.rejectionNote}\n` +
    `Active positions: ${event.activePositionCount}`
    );
    this.metrics.recordRejection(event.rejectionId);
    }
    -
    • Handles signal events from all modes (live + backtest).

      +
    • Handles signal events from all modes (live + backtest).

      Called every tick/candle when strategy is evaluated. Receives all signal states: idle, scheduled, opened, active, closed, cancelled.

      Triggered by: ActionCoreService.signal() via StrategyConnectionService @@ -171,10 +171,10 @@ Source: signalEmitter.next() in tick() and backtest() methods Frequency: Every tick/candle

      Default implementation: Logs signal event.

      Parameters

      • event: IStrategyTickResult

        Signal state result with action, state, signal data, and context

        -
      • Optionalsource: string

      Returns void | Promise<void>

      signal(event: IStrategyTickResult) {
      if (event.action === 'opened') {
      console.log(`Signal opened: ${event.signal.side} at ${event.signal.priceOpen}`);
      }
      if (event.action === 'closed') {
      console.log(`Signal closed: PNL ${event.signal.revenue}%`);
      }
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    signal(event: IStrategyTickResult) {
    if (event.action === 'opened') {
    console.log(`Signal opened: ${event.signal.side} at ${event.signal.priceOpen}`);
    }
    if (event.action === 'closed') {
    console.log(`Signal closed: PNL ${event.signal.revenue}%`);
    }
    }
    -
    • Handles signal events from backtest only.

      +
    • Handles signal events from backtest only.

      Called every candle in backtest mode. Use for actions specific to backtesting (e.g., collecting test metrics).

      Triggered by: ActionCoreService.signalBacktest() via StrategyConnectionService @@ -182,10 +182,10 @@ Source: signalBacktestEmitter.next() in tick() and backtest() methods when backt Frequency: Every candle in backtest mode

      Default implementation: Logs backtest signal event.

      Parameters

      Returns void | Promise<void>

      signalBacktest(event: IStrategyTickResult) {
      if (event.action === 'closed') {
      this.backtestMetrics.recordTrade(event.signal);
      }
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    signalBacktest(event: IStrategyTickResult) {
    if (event.action === 'closed') {
    this.backtestMetrics.recordTrade(event.signal);
    }
    }
    -
    • Handles signal events from live trading only.

      +
    • Handles signal events from live trading only.

      Called every tick in live mode. Use for actions that should only run in production (e.g., sending real notifications).

      Triggered by: ActionCoreService.signalLive() via StrategyConnectionService @@ -193,10 +193,10 @@ Source: signalLiveEmitter.next() in tick() and backtest() methods when backtest= Frequency: Every tick in live mode

      Default implementation: Logs live signal event.

      Parameters

      Returns void | Promise<void>

      async signalLive(event: IStrategyTickResult) {
      if (event.action === 'opened') {
      await this.telegram.send('Real trade opened!');
      await this.placeRealOrder(event.signal);
      }
      } +
    • Optionalsource: string

    Returns void | Promise<void>

    async signalLive(event: IStrategyTickResult) {
    if (event.action === 'opened') {
    await this.telegram.send('Real trade opened!');
    await this.placeRealOrder(event.signal);
    }
    }
    -
    +