【问题标题】:GAS script for Daily Stock Price Alert with Google Sheets使用 Google 表格进行每日股票价格警报的 GAS 脚本
【发布时间】:2021-02-04 14:55:09
【问题描述】:

我在 Google 表格中找到了一个很棒的 article,其中包含用于股票警报系统的 GAS 脚本。它激发了我构建更广泛的东西,包括每日移动百分比的警报,但这已经超出了重点。

作者建议应用基于时间的触发器,以便接收者在股票达到预定义的目标价格时收到实时电子邮件警报。该脚本运行良好,但有一个问题:只要条件成立,它就会在每个周期中发送一封电子邮件。换句话说,如果触发器设置为每分钟,您将被电子邮件轰炸。

这是基础脚本。

    function myFunction() {
      
      var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
      
      var values = spreadSheet.getDataRange().getValues();
      values.shift();
      
      var emails = ['abc@gmail.com'];
      
      for (stock in values) {
        
        // Grabs the array we want to access
        var stockArray = values[stock];   
        
        // The first item in the array is the ticker
        var stockTicker = stockArray[0];  
        
        // The CURRENT price of the stock
        var stockCurrent = stockArray[1]; 
        
        // Mathematical symbol to compare the prices (>,<)
        var stockSymbol = stockArray[2];  
        
        // The TARGET price of the stock 
        var stockTarget = stockArray[3];  
        
        // If we want to use the less than symbol
        if ( stockSymbol === '<' ) {
          
          // If current price is less than target
          if ( stockCurrent < stockTarget) {
            // Do something
          }
        }
        
        // If we want to use the greater than symbol
        if ( stockSymbol === '>' ) {
          
          // If current price is greater than target
          if ( stockCurrent > stockTarget) {
            // Do something
          }
        }   
      } 
    }

我只想(每天)收到一次警报。这个author 通过在“else”条件后添加以下函数解决了类似的问题:

function createTriggerCheckAgain() {
      ScriptApp.newTrigger('myFunction')
      .timeBased()
      .after(60 * 60 * 24 * 1000) // one day cycle time
      .create();}
      }

我尝试将此函数添加到原始脚本中,但不幸的是,每次脚本运行时我仍然会收到一封警报电子邮件。

为了检查脚本是否实时工作,我添加了一个电子邮件功能。将它们放在一起给出以下内容。这是spreadsheet的链接。

function myFunction() {
  
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  
  var values = spreadSheet.getDataRange().getValues();
  values.shift();
  
  var emails = ['webkowuite@gmail.com'];
  
  for (stock in values) {
    
    // Grabs the array we want to access
    var stockArray = values[stock];   
    
    // The first item in the array is the ticker
    var stockTicker = stockArray[0];  
    
    // The CURRENT price of the stock
    var stockCurrent = stockArray[1]; 
    
    // Mathematical symbol to compare the prices (>,<)
    var stockSymbol = stockArray[2];  
    
    // The TARGET price of the stock 
    var stockTarget = stockArray[3];  
        
    // Emails
    var emailSubject = 'PRICE ALERT';
    var emailBody = 'your stock '+stockTicker+' has moved to its target price';
    
    // If we want to use the less than symbol
    if ( stockSymbol === '<' ) {
      
      // If current price is less than target
      if ( stockCurrent < stockTarget) {
        
        for (email in emails) {
          MailApp.sendEmail(emails[email], emailSubject, '', {
            htmlBody: emailBody
          });
        }
        
      }
      else {
        function createTriggerCheckAgain() {
          ScriptApp.newTrigger('myFunction')
          .timeBased()
          .after(60 * 60 * 24 * 1000)
          .create();
    }
  }
    }
    
    // If we want to use the greater than symbol
    if ( stockSymbol === '>' ) {
      
      // If current price is greater than target
      if ( stockCurrent > stockTarget) {
        
        for (email in emails) {
          MailApp.sendEmail(emails[email], emailSubject, '', {
            htmlBody: emailBody
          });
        }
        
      }
    }
   else {
    function createTriggerCheckAgain() {
      ScriptApp.newTrigger('myFunction')
      .timeBased()
      .after(60 * 60 * 24 * 1000)
      .create();
    }
  } 
  }
  
}

任何提示/帮助将不胜感激。


顺便说一句,原文章的​​评论者提出了不同的路线:

// Named range could be get spreadsheet-wise
var notified_range = spread_sheet.getRangeByName('Notified?');
var notified_values = notified_range.getValues();
...
// We don't want to spam ourselves
var isNotified = notified_values[+stock+1][0];
...
if ( stockSymbol === '<' ) {
if ( stockCurrent < stockTarget && isNotified != true) {
for (email in emails) {
MailApp.sendEmail(emails[email], emailSubject, '', {
htmlBody: emailBody
});
}
// GetCell index starts from 1, not 0. So we +2
notified_range.getCell(stock+2, 1).setValue(true);
}
}

我尝试在原始代码中实现这些。也没有成功。

【问题讨论】:

标签: google-apps-script google-sheets triggers gmail stock


【解决方案1】:

您的代码中存在括号不匹配以及我尝试优化的一些冗余部分。

你能检查一下这是否符合你的要求吗?

代码:

function myFunction() {
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var values = spreadSheet.getDataRange().getValues();
  values.shift();

  var stocks = [];
  var emails = ['test@gmail.com'];
  var emailSubject = 'PRICE ALERT';
  var emailBody = 'The following tickers reached its target price:';

  values.forEach(function (stockArray, index) {
    // ticker, CURRENT price, comparison symbol, TARGET price
    var [stockTicker, stockCurrent, stockSymbol, stockTarget, dates] = stockArray;
    
    var dateToday = convertDate(new Date());
    // Make string into array and removes all blank elements
    var dateArray = dates.toString().split(",").filter(date => date);
    // Properly format dates 
    dateArray.forEach(function (date, index){
      dateArray[index] = convertDate(new Date(date));
    });
    
    // If current price is <stockSymbol> than target and dateToday isn't in column E
    if (eval(stockCurrent + " " + stockSymbol + " " + stockTarget) && !dateArray.includes(dateToday)) {
      // Take note of the tickers so we can send in 1 email
      stocks.push(stockTicker);
      // Add dateToday to dateArray if date is new
      dateArray.push(dateToday);
      // Set dateArray as string as value to column E 
      spreadSheet.getRange("E" + (index + 2)).setValue(dateArray.join(","));
    }
  });

  // Only proceed to mail if we had a new valid ticker that satisfies the condition
  if(stocks.length > 0) {
    // Join all stocks in one email per user, send as 1 email
    emailBody = emailBody + "<br> - " + stocks.join("<br> - ");
    emails.forEach(function (email) {
      MailApp.sendEmail(email, emailSubject, '', {
        htmlBody: emailBody
      });
    });
  }

  // Create trigger after every run (will trigger every minute)
  createTrigger();
}

function convertDate(date){
  // Convert date to proper timezone
  return Utilities.formatDate(date, SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "MM/dd/YYYY");
}

function createTrigger(){
  // Delete all existing triggers before creating one
  // Ensuring none will exist before creating trigger.
  var triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(function (trigger){
    ScriptApp.deleteTrigger(trigger);
  });

  // Create trigger after every run which is per minute
  ScriptApp.newTrigger('myFunction')
    .timeBased()
    .after(60 * 1000)
    .create();
}

样本输出:

注意:

如果我没记错的话,这些代码的价格可以随时更改,但每天只能更改一次。所以上面代码上面的代码只会在当天第一次满足条件时给你发邮件。

这里的触发器不会达到限制,因为我总是在添加触发器之前删除所有触发器,所以我们确信它不会因为达到触发器的限制而失败。

要测试,只需运行一次函数,然后让触发器完成它的工作。

此外,由于配额,您可能会遇到问题。有关更多信息/详细信息,请阅读以下资源:

资源/秒:

【讨论】:

  • 优秀作品;太感谢了!您的代码确实可以完成这项工作,但我的想法是每 1、5 或 10 分钟运行一次脚本,因为股票价格会不断变化。如果您可以添加用于“数据样本”输出(包括“满足条件的日期”)的代码 sn-p,将不胜感激
  • 嗨@WebkoWuite,我实际上正在修改我的代码以在E 列上使用日期。经过大量测试后,我将发布它。也会包含您的评论
  • 检查@WebkoWuite 后,您每天可以发送多少封电子邮件是有配额的。我将使用工作代码更新上面的答案,但一旦达到配额,它可能无法正确执行代码。 developers.google.com/apps-script/guides/services/quotas
  • 我已经更新了答案@WebkoWuite。你能在你身边测试它吗?如果您的问题得到解决,请按接受按钮。与您有相同问题的其他人也可以将您的问题作为可以解决的问题。如果找不到按钮,请随时告诉我。 stackoverflow.com/help/accepted-answer
  • 这太棒了@NaziA!会接受答案。也许超出了问题的重点,但原作者通过定义一个变量在电子邮件中包含了指向股票价格的链接:var stockLink = 'https://www.google.com/search?q=' + stockTicker +'+stock&amp;oq=appl+stock&amp;aqs=chrome..69i57j0l7.2828j1j1&amp;sourceid=chrome&amp;ie=UTF-8';。他还包括变量,例如电子邮件主题中的股票价格。试图包含它,但脚本无法识别变量。你会怎么做呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多