I found a great article with a GAS script for a stock alert system in Google Sheets. It has inspired me to build something more extensive including alerts for daily % moves but that's beyond the point.
The author recommends applying a time-based trigger so the receiver gets a real time email alert when the stock hits the predefined target price. The script works great, but has one problem: it will send an email during every cycle as long as the condition holds true. In other words, you will be bombarded with emails if the trigger is set to every minute.
Here's the basis script.
function myFunction() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var values = spreadSheet.getDataRange().getValues();
values.shift();
var emails = ['[email protected]'];
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
}
}
}
}
I want to receive the alert only once (per day). This author solved a similar issue by adding the following function after an 'else' condition:
function createTriggerCheckAgain() {
ScriptApp.newTrigger('myFunction')
.timeBased()
.after(60 * 60 * 24 * 1000) // one day cycle time
.create();}
}
I tried to add this function to the original script but unfortunately I still get an alert email every time the script runs.
To check if the script works in real time I've added an email function. Putting it all together gives the following. Here's a link to the spreadsheet.
function myFunction() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var values = spreadSheet.getDataRange().getValues();
values.shift();
var emails = ['[email protected]'];
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();
}
}
}
}
Any tips/help would be much appreciated.
Btw, a commenter on the original article suggested a different route:
// 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);
}
}
I've tried to implement these in the original code. Also without success.