"function generateTrade(stockQuant, stockPrice, fees, action, assetClass, broker, user, date, tradeType) {
  return {
    shares: stockQuant,
    price: stockPrice,
    fees: fees, // Included Fees
    action: action,
    assetClass: assetClass,
    broker: broker,
    user: user,
    date: date,
    type: tradeType
  };
}

function generateFifo(type, date, security, actions, quantity, price, fees, assetClass, broker, user) { // Added fees parameter
  let positionsMap = new Map();
  let epsilon = 1e-8; // Epsilon value for floating-point comparisons

  for (var i = 0; i < security.length; i++) {
    // Skip empty rows
    if (!security[i] && !actions[i] && !quantity[i] && !price[i] && !fees[i]) { // Included fees in check
      continue;
    }
    var currentType = type[i] ? type[i].toString().trim().toLowerCase() : '';
    var currentDate = date[i] ? new Date(date[i]) : new Date();
    var ticker = security[i] ? security[i].toString().trim() : '';
    var action = actions[i] ? actions[i].toString().trim().toLowerCase() : '';

    var stockQuant = Number(quantity[i]) || 0;
    var stockPrice = Number(price[i]) || 0;
    var feeAmount = Number(fees[i]) || 0; // Extract Fees

    var currentAssetClass = assetClass && assetClass[i] ? assetClass[i] : 'Unknown';
    var currentBroker = broker && broker[i] ? broker[i] : 'Unknown';
    var currentUser = user && user[i] ? user[i] : 'Unknown';

    let tradeType = '';  // Will determine this based on action

    // Only process delivery trades
    if (currentType === 'delivery') {
      if (action === 'buy') {
        tradeType = 'Long';
        let key = `${ticker}|${currentBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let trade = generateTrade(stockQuant, stockPrice, feeAmount, action, currentAssetClass, currentBroker, currentUser, currentDate, tradeType);
        let activeTrades = positionsMap.get(key);
        if (!activeTrades) {
          positionsMap.set(key, [trade]);
        } else {
          activeTrades.push(trade);
        }
      } else if (action === 'sell') {
        tradeType = 'Long';  // Selling from Long positions
        let key = `${ticker}|${currentBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let activeTrades = positionsMap.get(key);
        if (activeTrades) {
          let sharesToProcess = stockQuant;
          activeTrades.sort((a, b) => new Date(a.date) - new Date(b.date)); // ensure FIFO
          let iTrade = 0;
          while (sharesToProcess > epsilon && iTrade < activeTrades.length) {
            let trade = activeTrades[iTrade];
            if (trade.shares <= sharesToProcess + epsilon) {
              sharesToProcess -= trade.shares;
              activeTrades.splice(iTrade, 1);
            } else {
              trade.shares -= sharesToProcess;
              sharesToProcess = 0;
            }
          }
          if (activeTrades.length === 0) {
            positionsMap.delete(key);
          }
        }
      } else if (action === 'sellshort') {
        tradeType = 'Short';
        let key = `${ticker}|${currentBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let trade = generateTrade(stockQuant, stockPrice, feeAmount, action, currentAssetClass, currentBroker, currentUser, currentDate, tradeType);
        let activeTrades = positionsMap.get(key);
        if (!activeTrades) {
          positionsMap.set(key, [trade]);
        } else {
          activeTrades.push(trade);
        }
      } else if (action === 'buytocover') {
        tradeType = 'Short';  // Covering Short positions
        let key = `${ticker}|${currentBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let activeTrades = positionsMap.get(key);
        if (activeTrades) {
          let sharesToProcess = stockQuant;
          activeTrades.sort((a, b) => new Date(a.date) - new Date(b.date)); // ensure FIFO
          let iTrade = 0;
          while (sharesToProcess > epsilon && iTrade < activeTrades.length) {
            let trade = activeTrades[iTrade];
            if (trade.shares <= sharesToProcess + epsilon) {
              sharesToProcess -= trade.shares;
              activeTrades.splice(iTrade, 1);
            } else {
              trade.shares -= sharesToProcess;
              sharesToProcess = 0;
            }
          }
          if (activeTrades.length === 0) {
            positionsMap.delete(key);
          }
        }
      }
    } else if (currentType === 'corp. action' && action === 'split') {
      // Process stock splits
      let splitRatioStr = quantity[i].toString().trim();
      let ratio = 1;
      if (splitRatioStr.includes(":")) {
        let ratioParts = splitRatioStr.split(':');
        let numerator = parseFloat(ratioParts[0]);
        let denominator = parseFloat(ratioParts[1]);
        ratio = numerator / denominator;
      } else {
        ratio = parseFloat(splitRatioStr);
      }
      positionsMap.forEach((value, pKey) => {
        if (pKey.startsWith(`${ticker}|`)) {
          value.forEach(trade => {
            trade.shares *= ratio;
            trade.price /= ratio;
          });
        }
      });
    } else if (currentType === 'my action') {
      if (action === 'transferfrom') {
        // Assuming transfer applies to Long positions
        tradeType = 'Long';
        let transferKey = `${ticker}|${currentBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let newBroker = broker[i + 1] ? broker[i + 1] : 'Unknown';
        let newKey = `${ticker}|${newBroker}|${currentUser}|${currentAssetClass}|${tradeType}`;
        let activeTrades = positionsMap.get(transferKey);
        if (activeTrades) {
          let sharesToTransfer = stockQuant;
          let totalAvailableShares = activeTrades.reduce((sum, trade) => sum + trade.shares, 0);
          if (sharesToTransfer > totalAvailableShares + epsilon) {
            continue; // Skip this transfer if not enough shares
          }
          let transferredTrades = [];
          activeTrades.sort((a, b) => new Date(a.date) - new Date(b.date)); // ensure FIFO
          while (sharesToTransfer > epsilon && activeTrades.length > 0) {
            let trade = activeTrades[0];
            if (trade.shares <= sharesToTransfer + epsilon) {
              sharesToTransfer -= trade.shares;
              transferredTrades.push({ ...trade }); // Copy trade to new broker
              activeTrades.splice(0, 1);
            } else {
              let transferredTrade = { ...trade, shares: sharesToTransfer };
              trade.shares -= sharesToTransfer;
              sharesToTransfer = 0;
              transferredTrades.push(transferredTrade);
            }
          }
          if (activeTrades.length === 0) {
            positionsMap.delete(transferKey);
          }
          // Add transferred trades to new broker
          let newActiveTrades = positionsMap.get(newKey);
          if (!newActiveTrades) {
            positionsMap.set(newKey, transferredTrades);
          } else {
            newActiveTrades.push(...transferredTrades);
          }
        }
      }
    }
  }
  return positionsMap;
}

function myPositions(type, date, security, actions, quantity, price, fees, assetClass, broker, user) { // Added fees parameter
  let positionsMap = generateFifo(type, date, security, actions, quantity, price, fees, assetClass, broker, user); // Pass fees
  let returnArry = [['SN.', 'Ticker', 'Type', '# Shares', 'Avg. Buy @', 'Asset Class', 'Broker', 'User']];
  let sn = 1;
  let sortedKeys = Array.from(positionsMap.keys()).sort();
  let epsilon = 1e-8; // Epsilon value for floating-point comparisons

  sortedKeys.forEach(key => {
    let value = positionsMap.get(key);
    if (!value || value.length === 0) return; // Skip if no active trades
    let totalShares = 0;
    let totalCost = 0;
    let totalFees = 0; // Initialize total fees
    let [ticker, currentBroker, currentUser, currentAssetClass, longOrShort] = key.split('|');
    value.forEach(trade => {
      totalShares += trade.shares;
      totalCost += trade.shares * trade.price;
      totalFees += trade.fees; // Accumulate fees
    });
    // Handle floating-point precision
    if (Math.abs(totalShares) > epsilon) {
      let avgPrice = (totalCost + totalFees) / totalShares; // Include fees in avg price
      returnArry.push([
        sn++,
        ticker,
        longOrShort,
        Number(totalShares.toFixed(4)), // Shares as Number
        avgPrice.toFixed(2),             // Avg. Buy @ remains as String
        currentAssetClass,
        currentBroker,
        currentUser
      ]);
    }
  });
  return returnArry;
}"

since ye custom function script h. google app script custom funtion ko execute krne ke liye 30 seconds ka samay detah apeksha 6 mintues ke jo wo inbulit function ko deta h. to is hisab se ye custom function kitte row ki data ka portfolio bana skta h.