Source: nifty_fifty_bank_nifty_NodeJS/src/controllers/scheduleOrder.controller.ts
Flags: options.isRecurringSell (options segment only)

What it does

After a completed unsold BUY, the system schedules a SELL, then a trailing loop watches index price and exits when strike-match or target conditions are met. This strategy uses two separate 1-second loops:

Loop 1 — Schedule creation (startScheduleOrder)

Per-index interval registered as scheduleOrder_${indexName} (~1s):
  1. Requires activeSegment === "options", lastActiveRight, and isRecurringSell.
  2. Skips when exchange is closed or tick data is missing.
  3. Finds the oldest eligible BUY with status COMPLETE (isSold: false, isScheduled: false). Orders still in TRIGGER PENDING are not scheduled yet.
  4. Marks that buy as scheduled and creates a ScheduleOrder with:
    • strikeMatchPrice from index base ± strike match difference
    • targetPrice from base ± target sell % of base
    • timeDuration from callSellDuration / putSellDuration
  5. If there is no open BUY and no pending schedule, it switches leg (CALL ↔ PUT): stops the current recurring buy side and starts the opposite side when that side’s recurring buy flag is enabled. Resets firstCandleEndTime for the index on leg switch.
Started per symbol via marketSessionManager.startOrderServicesForSymbol.

Loop 2 — Trailing exit (startInterval + trailingSell)

Global 1s loop started/stopped by marketSessionManager.syncTrailingSellInterval() (runs when at least one exchange session is open; stopped on session close):
  1. Reads latest tick from latestDataMap[$TickData] for each active symbol.
  2. Uses candle range from timeDuration to compute min/max of index baseValue (from indexDataModel aggregation plus in-memory tick buffer at candle end).
  3. Tracks firstCandleEndTime per index; reset via marketDataEmitter.resetFirstCandleEndTime or on leg switch.
  4. Updates trailing strikeMatchPrice:
    • First candle: keep initial strike match price
    • Later candles: CALL uses candle min, PUT uses candle max
  5. Price match conditions:
    • PUT: exit if baseValue >= strikeMatchPrice, or baseValue <= targetPrice (when target is set)
    • CALL: exit if baseValue <= strikeMatchPrice, or baseValue >= targetPrice (when target is set)
  6. On match, executeSideSellOnce places MARKET SELL for all pending schedules on that right (linked to parent BUY via parent_order_id).
  7. On failed SELL, rolls back parent isSold and schedule status to Pending.

Schedule cancellation

PUT /api/scheduleOrder/:id (admin) with status: "Cancelled" cancels the schedule and reverts the parent BUY (isSold: false, status CANCELLED).

Important limits

  • Recurring / trailing sell scheduling is options-only today; cash and futures do not use this sell scheduler.
  • Sell execution from trailing is MARKET.