TrueData TrueData Sheets
search
Searching...
functions Formulas
menu_book Pages
manage_search Content Match
search_off

No results for ""

Loading Content
lightbulb

Best Practices

Follow these guidelines to keep scripts reliable, performant, and easy to debug during live market hours. This page also covers Rule 17 in depth, since it governs the overall shape of a script rather than a single line of code.

17

Prefer sockets over REST — REST calls are strictly one-shot

If live, continuously updating data is needed, subscribe via TD.Feed.addSymbols and a TD.on(...) listener instead of a REST call. When a REST method (TD.Historical.*, TD.Analytics.*, TD.OptionChain.*) is the right tool, call it exactly once, inside onStart. Never wrap a REST call in setInterval, a polling loop, or call it again from inside a TD.on() handler.

close Wrong — polling a REST call
TD.onStart = async () => {
  setInterval(async () => {
    const data = await TD.OptionChain.getOptionChain({
      symbol: "NIFTY", expiry: "07-07-2026",
    });
    // re-fetches every tick of the interval — banned
  }, 5000);
};
check Correct — one call, then sockets for live data
TD.onStart = async () => {
  const data = await TD.OptionChain.getOptionChain({
    symbol: "NIFTY", expiry: "07-07-2026",
  });
  // one-shot, done. For live updates, subscribe instead:
  await TD.Feed.addSymbols(["NIFTY26070723500CE"]);
};

Do

check_circle

Register events at the top level

Call TD.on(...) before any hook runs — never inside onStart or another function.

check_circle

Always clean up in onStop

Call await TD.Feed.removeSymbols() for every symbol you added. Orphaned subscriptions accumulate across runs and cause memory leaks.

check_circle

Store symbols in a constant

Declare const SYMBOLS = [...] once at the top. Use the same array in addSymbols and removeSymbols to avoid mismatches.

check_circle

Define TD.onError

Without an error handler, runtime errors are silently swallowed. Always define TD.onError so you can see what went wrong.

check_circle

Await every async call, everywhere

Feed, Sheet, Historical, Analytics, and OptionChain calls are all async. Missing await causes race conditions and silently wrong sheet data.

check_circle

Check response.success before reading data

Every Feed response and most REST responses can fail gracefully. Check the status field before touching symbollist or records.

check_circle

Use bar1min / bar5min for heavy logic

Move indicator calculations and most sheet writes to a bar event. It fires once per candle — far more manageable than dozens of ticks per second.

check_circle

Use TD.log for debugging

Prefer TD.log() over console.log(). Output appears in the built-in console panel and is preserved in the session log.

Avoid

cancel

Heavy work inside 'tick' or 'bidAsk'

Avoid REST calls, large loops, or many sheet writes inside high-frequency handlers. At peak market hours, events arrive faster than they can be processed.

cancel

Looping or polling REST calls

TD.Historical.*, TD.Analytics.*, and TD.OptionChain.* are one-shot. Use sockets for anything that needs to stay live (Rule 17).

cancel

Treating data[0] as the symbol name

In every live event, data[0] is the symbolId. Build a lookup map in onStart to match by name.

cancel

Using setInterval / setTimeout

Timers registered with setInterval are not cleared on Stop. Use 'heartbeat' for periodic checks instead — it's lifecycle-managed automatically.

cancel

Subscribing the same symbol twice

Calling addSymbols with an already-subscribed symbol creates a duplicate stream. De-duplicate your SYMBOLS array before subscribing.

cancel

Unbounded sheet row growth

Append-style logging (Templates 3 and 10) fills the sheet quickly on high-frequency events. Prefer a fixed-row overwrite pattern unless an audit log is explicitly wanted.

Method Quick-Lookup

Namespace Method Type Where to call
TD.Feed addSymbols / removeSymbols async onStart / onStop
TD.on tick / bar1min / bar5min / bidAsk / heartbeat / greeks listener top level only
TD.Sheet setCell / setCellRange / getCell / getCellRange async anywhere, awaited
TD.Historical getBars / getLastNBars / getTicks / getLastNTicks / getTopNGainers / getTopNLosers / getTopNVolumeGainers async, one-shot onStart only
TD.OptionChain getOptionChain / getOptionChainWithGreeks async, one-shot onStart only
TD.Analytics getIndexGainers/Losers, getIndustryGainers/Losers, getMostActiveByTurnover/Volume, getOIGainers/Losers async, one-shot onStart only
TD.UI showAlert(message, type) async anywhere, awaited
TD.log log(...) sync anywhere

Known Gaps

warning Underlying / spot LTP in the option chain: neither getOptionChain nor getOptionChainWithGreeks documents a field for the underlying index's current spot price. If a script needs spot LTP alongside the chain, subscribe to the underlying separately with TD.Feed.addSymbols and read it from the tick event rather than guessing a row index in the chain response.

Quick Checklist Before Clicking Start

  • check_boxTD.on(...) handlers are registered at the top level, not inside any hook
  • check_boxTD.onStart — subscribes symbols, checks response.success, writes headers
  • check_boxTD.onStop — removes the same symbols
  • check_boxTD.onError — defined so errors surface in the console
  • check_boxEvery Feed / Sheet / Historical / Analytics / OptionChain call is awaited and wrapped in try/catch
  • check_boxNumeric fields are parsed with parseFloat() / parseInt() before use
  • check_boxREST calls (Historical / Analytics / OptionChain) are called once in onStart — no loop, no timer, no polling
  • check_boxOption chain index symbols are mapped (e.g. "NIFTY 50" → "NIFTY") before calling the API
  • check_boxHeavy work is inside 'bar1min' / 'bar5min', not 'tick' or 'bidAsk'
  • check_boxSheet rows are bounded, or an unbounded append is an intentional, explicit choice
Truedata Icon Sheets by Truedata

Empowering traders and analysts with high-performance real-time market data directly within their spreadsheets.

© 2026 TrueData Market Data Services LLP. All rights reserved.