Typical Price (TP)

Function Syntax

=TP(data)  
  • data (array):
    Range of columns containing the date, Open, high, Low, close, volume data.

Returns:
A two-column array of dates and their corresponding TP values.

Google Sheets Output Example

Below is an example of the resulting array when applying the custom TP() function in Google Sheets

tp return array
TP Return Array

Spreadsheet

Apps Scripts Code

Here’s the full Google Apps Script code.
Paste this directly into the Google Sheets Apps Script editor (Extensions → Apps Script):

tp.gs
/**
 * Calculates the Typical Price (TP) for a given dataset.
 *
 * @param {array} data - A range containing date, high, low, and close prices.
 * @returns {array} - A 2D array with headers: Date, TP.
 * @customfunction
 */

function TP(data) {
  // Preprocess data using getData
  const processedData = getData(data);
  const dates = processedData.slice(1).map(row => row[0]); // Extract dates
  const highs = processedData.slice(1).map(row => row[2]); // Extract high prices
  const lows = processedData.slice(1).map(row => row[3]); // Extract low prices
  const closes = processedData.slice(1).map(row => row[4]); // Extract close prices

  // Initialize an array for TP values with headers
  const tpValues = [["Date", "TP"]];

  // Calculate TP for each row
  for (let i = 0; i < closes.length; i++) {
    const typicalPrice = (highs[i] + lows[i] + closes[i]) / 3;
    tpValues.push([dates[i], typicalPrice]);
  }

  return tpValues;
}

/**
 *
 * @param {Array<Array>} data - A 2D array of cell values to process. The first row should contain headers.
 * @returns {Array<Array>} - A 2D array where the first row contains headers and subsequent rows contain processed data.
 *
 * @customfunction
 * 
 */

function getData(data) {
  if (!data || data.length === 0) {
    throw new Error("Input data is empty or invalid.");
  }

  // Check if the first row contains headers
  const headers = Array.isArray(data[0]) && data[0].every(item => typeof item === "string")
    ? data[0]
    : null;

  if (!headers) {
    // If no headers, assume the first column is the date column and process data
    return data.map(row => row.map((value, index) => {
      return index === 0 ? new Date(value) : parseFloat(value);
    }));
  }

  // Process rows with headers
  return [headers, ...data.slice(1).map(row => headers.map((header, index) => {
    const key = header.toLowerCase();
    return key === "date" ? new Date(row[index]) : parseFloat(row[index]) || row[index];
  }))];
}
Last updated on