Insert value new cell - google-apps-script

good morning
this script adds a cell below, it is wrong I would rather copy the value of E2 and paste it in E3, E4 etc etc every 1 hour.
Thanks to those who solve my problem.
var activeSheet = SpreadsheetApp.getActiveSheet();
SpreadsheetApp.getActiveSheet().getRange('E2').setValue(jsonResponse.price);
var sheet =SpreadsheetApp.getActiveSheet()
var range = sheet.getRange("E2:E2");
range.insertCells(SpreadsheetApp.Dimension.ROWS);

Time-driven trigger:
The script you shared will effectively shift the cells in column E down, with E3 containing the newest value (E2 will be blank). You want this function to run automatically each hour. For this, you need to install a time-driven trigger. The trigger needed in this case would be everyHours(n). You can install either manually, by following these steps, or programmatically, by running the following function once:
function createHourTrigger() {
var triggeredFunction = "shiftAndSet"; // Triggered function name, change accordingly
ScriptApp.newTrigger(triggeredFunction)
.timeBased()
.everyHours(1)
.create();
}
Note:
Your script has a certain amount of repetition and could be reduced to this (the code to retrieve jsonResponse is obviously missing):
function shiftAndSet() {
var range = SpreadsheetApp.getActiveSheet().getRange("E2");
range.setValue(jsonResponse.price);
range.insertCells(SpreadsheetApp.Dimension.ROWS);
}
Also, if you want E2 and not E3 to have the newest value at the end of each execution, you could change the order of actions, like this:
function shiftAndSet() {
var range = SpreadsheetApp.getActiveSheet().getRange("E2");
range.insertCells(SpreadsheetApp.Dimension.ROWS);
range.setValue(jsonResponse.price);
}

Related

Is there a Google Sheets method to have coded formulas fill values in the next empty row each day?

I have a Google Sheets document that has 36 formulas across a row in the "Historical Data" tab. When I run the script each morning it populates the next empty row with the formulas in the previous row and then makes the previous row a value (so as to remove the formulas). I have an issue sometimes that the row with formulas loses the values and display "#N/A". I believe this is because the data is pulled from GoogleFinance.
Error in the image below.
I am curious if there is a method to do the following:
Define the formulas for each column in the code.
Run the script each morning and populate the next empty row with the values of the formulas.
The biggest item I need help with is adding the following formulas to the code so they will not be present in the worksheet. Additionally, some of the formulas rely on the value in a cell. For example the first formula is to create the date based on the date in the last row cell (A). The remaining formulas use the date from the new row columnm (a) and inputs from other columns in the new row. So when you see A2736 that is in last row and A2737 is the new row that was create when I last ran the script.
//DATE(A)=workday(A2736,1,'NYSE Holidays'!$A$2:$A$27)
//VIX9D(B)=INDEX(GOOGLEFINANCE("INDEXCBOE:VIX9D","close",$A2737),2,2)
//VIX1D(C)=INDEX(GOOGLEFINANCE("INDEXCBOE:VIX","close",$A2737),2,2)
//VIX3M(D)=index(GOOGLEFINANCE("INDEXCBOE:VIX3M","close",$A2737),2,2)
//VIX6M(E)=index(GOOGLEFINANCE("INDEXCBOE:VIX6M","close",$A2737),2,2)
//VIX1Y(F)=index(GOOGLEFINANCE("INDEXCBOE:VIX1Y","close",$A2737),2,2)
//VVIX(G)=index(GOOGLEFINANCE("INDEXCBOE:VVIX","close",$A2737),2,2)
//SPX(H)=index(GOOGLEFINANCE("INDEXSP:.INX","close",$A2737),2,2)
//VIX9D:VIX(I)=B2737/C2737
//VIX:VIX3M(J)=C2737/D2737
//VIX:VIX6M(K)=C2737/E2737
//VIX:VIX1Y(L)=C2737/F2737
//CORR, SPX , VVIX, 5(M)=correl(H2733:H2737,G2733:G2737)
//CORR, SPX , VIX, 10(N)=correl(H2728:H2737,C2728:C2737)
//Contango VIX2:VIX1(O) No formula yet
//Vix4:Vix7 Contango(P) No formula yet
//Log Ret(Q)=ln(H2737/H2736)
//V10(R)=stdev(Q2728:Q2737)
//V20(S)=stdev(Q2719:Q2737)
//HV10(T)=sqrt(252)*R2737
//HV20(U)=sqrt(252)*S2737
//VIX - HV10(V)=C2737-(T2737*100)
//VIX - hv20(W)=C2737-(U2737*100)
//VIX9D % Rank(X)=PERCENTRANK(B$2:B,B2737)
//VIX1D % Rank(Y)=PERCENTRANK(C$2:C,C2737)
//VIX3M % Rank(Z)=PERCENTRANK(D$2:D,D2737)
//VIX6M % Rank(AA)=PERCENTRANK(E$2:E,E2737)
//VIX1Y % Rank(AB)=PERCENTRANK(F$2:F,F2737)
//VVIX % Rank(AC)=PERCENTRANK(G$2:G,G2737)
//VIX9D Median(AD)=MEDIAN(B$2:B)
//VIX1D Median(AE)=MEDIAN(C$2:C)
//VIX3M Median(AF)=MEDIAN(D$2:D)
//VIX6M Median(AG)=MEDIAN(E$2:E)
//VIX1Y Median(AH)=MEDIAN(F$2:F)
//VVIX Median(AI)=MEDIAN(G$2:G)
//VDelta (VIX-VIX9D)(AJ)=C2737-B2737
Current code is below.
// Add Run button to menu
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("Auto Trigger")
.addItem("Run","runAuto")
.addToUi();
}
// Define function to run with menu button
function runAuto() {
recordValue()
}
function createTimeDrivenTrigger() {
// Trigger every Weekday at 09:00.
ScriptApp.newTrigger('recordValue')
.timeBased()
.onWeekDay(ScriptApp.WeekDay)
.atHour(9)
.create();
}
// Record history from a cell and append to next available row
function recordValue() {
if (isNotHoliday()){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Historical_Data");
var lastRow = sheet.getLastRow();
var oldDate = sheet.getRange(lastRow,1).getValue();
var rng = sheet.getRange(lastRow,1,1,36);
rng.copyTo(sheet.getRange(lastRow+1,1,1,36));
rng.setValues(rng.getValues());
}
}
function isNotHoliday(){
var yesterday = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()-1);
var formattedDate = Utilities.formatDate(yesterday, Session.getScriptTimeZone(), "M/d/yy")
var holidays = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('NYSE Holidays').getRange('A2:A').getDisplayValues().join().split(",");
return (! ~holidays.indexOf(formattedDate))
}
If you wish to run the script once every morning you could use programmatically triggers. This way you can easily set up a script run inside your desired time frame. Then you only would need to get the range of the last row and paste the formula there. I see that the script already gets the range, so you only need Range.setFormula() to drop the formula.
There is a much simpler way to do this - which is to flip time the other way.
You leave the google finance formulas in row 2 along with a =TODAY() in cell B2, with headers in row 1.
every night at 11pm, your sheet inserts a row above row 3, copies the values from row 2 into the new row 3 as values only.
That's it. super simple. you never need to copy formulas at all.
The newest prices are always at the top. This is how most people track portfolios.

Trouble triggering a macro when a specific cell has a specific value

I'm trying to trigger a google sheet macro / apps script to reformat a sheet when a specific value is entered into a specific cell. I have been working on it to get it to work but without success.
Here is my code;
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange('C2');
var cellContent = cell.getValue();
if(cellContent === 'Past campaigns - actual cashflows to date only') {
spreadsheet.getRange('7:12').activate();
spreadsheet.getActiveSheet().hideRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
spreadsheet.getRange('13:13').activate();
}
};
I'm new to macros and apps scripts. I have tried to implement all the suggestions from the following links without success;
How can I get a macro to automatically trigger when a cell reaches a certain value in a Google Sheet?
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/sheets
As #Cooper has said you cannot make a trigger based on a cell value. Only on user changes.
You could try to make the onEdit trigger to execute only inside an if statement. But that's already what you have done.
Try this:
function onEdit(e) {
e.source.toast('Entry');
const sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetname
const X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
It's not necessary to use activate in most scripts and certainly in this one since it has to finish in 30 seconds. They use activate in macros because they are following you actions as you move around the screen. But in a script, generally to don't want to interact with the screen very much because it slows down the script and it doesn't really accomplish anything.
I'm currently using in a script that run when a Spreadsheet opens up because it has a lot rows in it and I want it to go down to the last row. So activate is useful because I don't have to scroll down to the last row every time I open the spreadsheet.
try it this way:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetnamee
var X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
//e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
I hope you're not trying to run this from the script editor because that's not going to work.

Updating a Cell on a Certain Date and Locking in Data

I was wondering if there was a way to create a function for the following. I am trying to update a cell, say G3 with a value in D3 but I want to do it on a certain date. I want for that cell to update on that date and then lock in with the value.
For example, if D3 has a value of 30, I want for my G3 cell to update with 30 on 10/12/2012. After that date I want that value to lock in as the data in D3 will change over time. This formula would need to be copied as I am trying to find a trend detail on a weekly basis.
Any help would be appreciated, thanks in advance!
If you don't mind doing this in Google Apps Script, you can achieve this easily via a time-driven trigger. Specifically, with atDate(year, month, day) you can make a function run at a certain date. To do this, you would first have to create the trigger. You can do this manually from the script editor, as explained here. You could also do this programmatically, by running a function that creates such trigger. The function would be, in this case:
function createTrigger() {
ScriptApp.newTrigger("setAndLock")
.timeBased()
.atDate(2012, 12, 10)
.create();
}
Running this function will create a trigger that will fire a function called setAndLock at date 2012/12/10, which should copy the value from D3 to G3 and protect this last cell. Such a function could be similar to this one:
function setAndLock() {
var sheet = SpreadsheetApp.getActiveSheet();
// Copying the value from D3 to G3:
var origin = sheet.getRange("D3").getValue();
var dest = sheet.getRange("G3");
dest.setValue(origin);
// Protecting G3:
var protection = dest.protect();
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
Please take into account that the cell cannot be locked from the current user nor the owner of the spreadsheet, as mentioned here.
I hope this is of any help.

Custom function won't refresh as inputs are changed

I have a custom function that finds the value of another cell and displays it. When the source cell is changed, the function does not reflect.
https://docs.google.com/spreadsheets/d/1wfFe__g0VdXGAAaPthuhmWQo3A2nQtSVUhfGBt6aIQ0/edit?usp=sharing
Refreshing google sheets
function findRate() {
var accountName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(1,1).getValue(); //determine the account name to use in the horizontal search
var rateTab = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Rates'); //hold the name of the rate tab for further dissection
var rateNumColumns =rateTab.getLastColumn(); //count the number of columns on the rate tab so we can later create an array
var rateNumRows = rateTab.getLastRow(); //count the number of rows on the rate tab so we can create an array
var rateSheet = rateTab.getRange(1,1,rateNumRows,rateNumColumns).getValues(); //create an array based on the number of rows & columns on the rate tab
var currentRow = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveCell().getRow(); //gets the current row so we can get the name of the rate to search
var rateToSearch = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(currentRow,1).getValue(); //gets the name of the rate to search on the rates tab
for(rr=0;rr<rateSheet.length;++rr){
if (rateSheet[rr][0]==rateToSearch){break} ;// if we find the name of the
}
for(cc=0;cc<rateNumColumns;++cc){
if (rateSheet[0][cc]==accountName){break};
}
var rate = rateSheet[rr][cc] ; //the value of the rate as specified by rate name and account name
return rate;
}
If I change a rate in the rate tab, I need the custom function to recognize the new rate and update its value
You want to recalculate the custom function of =findRate(), when the cells of the sheet name of Rates are edited.
If my understanding is correct, how about adding the following sample script? Please think of this as just one of several answers.
Solution:
In order to recalculate the custom function, in this answer, the formula of =findRate() is overwritten by the script running with the OnEdit event trigger (in this case, it's the simple trigger.). By this, the recalculate is executed. But, when the formula is directly replaced by the same formula, the recalculate is not executed. So I used the following flow.
Retrieve all ranges of cells which have the formula of =findRate() from the sheet of "Projected Revenue".
Clear the formulas of the ranges.
Put the formulas to the ranges.
By this flow, when the cell of the sheet of "Rates" is edited, the custom function of =findRate() is recalculated by automatically running onEdit().
Sample script:
Please copy and paste the following script to the script editor. Then, please edit the cells of sheet name of Rates. By this, onEdit() is automatically run by the OnEdit event trigger.
function onEdit(e) {
var range = e.range;
if (range.getSheet().getSheetName() == "Rates" && range.rowStart > 1 && range.columnStart > 1) {
var sheetName = "Projected Revenue"; // If you want to change the sheet name, please modify this.
var formula = "=findRate()";// If you want to change the function name, please modify this.
var sheet = e.source.getSheetByName(sheetName);
var ranges = sheet.createTextFinder(formula).matchFormulaText(true).findAll().map(function(e) {return e.getA1Notation()});
sheet.getRangeList(ranges).clearContent();
SpreadsheetApp.flush();
sheet.getRangeList(ranges).setFormula(formula);
}
}
Note:
onEdit(e) is run by the OnEdit event trigger. So when you directly run onEdit(e), an error occurs. Please be careful this.
In this sample script, as a sample, even when the row 1 and column "A" of the sheet of "Rates" are edited, the custom function is not recalculated. If you want to modify this and give the limitation of range you want to edit, please modify the above script.
References:
Simple Triggers
Class TextFinder
Class RangeList
flush()
If I misunderstood your question and this was not the result you want, I apologize.
Added:
The proposal from TheMaster's comment was reflected to the script. When sheet.createTextFinder(formula).matchFormulaText(true).replaceAllWith(formula) can be used, also I think that the process cost will be much reduced. But in my environment, it seemed that the formulas are required to be cleared once to refresh the custom function, even if flush() is used. So I have proposed above flow.
But, now I could notice a workaround using replaceAllWith() of TextFinder. So I would like to add it. The flow of this workaround is as follows.
Replace all values of =findRate() to a value in the sheet of Projected Revenue using replaceAllWith()..
In this case, as a test case, the formulas are replaced to sample.
Replace sample to =findRate() using replaceAllWith().
By this flow, I could confirm that =findRate() is recalculated. And also, it seems that flush() is not required for this situation.
Sample script:
Please copy and paste the following script to the script editor. Then, please edit the cells of sheet name of Rates. By this, onEdit() is automatically run by the OnEdit event trigger.
function onEdit(e) {
var range = e.range;
if (range.getSheet().getSheetName() == "Rates" && range.rowStart > 1 && range.columnStart > 1) {
var sheetName = "Projected Revenue";
var formula = "=findRate()";
var tempValue = "sample";
var sheet = e.source.getSheetByName(sheetName);
sheet.createTextFinder(formula).matchFormulaText(true).replaceAllWith(tempValue);
sheet.createTextFinder(tempValue).matchFormulaText(true).replaceAllWith(formula);
}
}

How can I get a macro to automatically trigger when a cell reaches a certain value in a Google Sheet?

What I need is for a macro I've recorded called SwitchHotSeat to trigger when the value of cell F3 goes above £1,000,000.00 0r 1000000 or the LEN of cell F3 goes over that length.
I can find guides for doing this in Excel, but not for Google Sheets. below is just the code for my macro.
function SwitchHotSeat() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('3:3').activate();
spreadsheet.getActiveSheet().deleteRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
spreadsheet.getActiveRangeList().setBackground('#ff0000')
.setFontColor('#ffffff');
};
The macro works fine. I just need a way of triggering it when that cell goes over the 1000000.
You could use simple or installable triggers. See
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/triggers/installable
Example of using onEdit simple trigger
function onEdit(e){
if(/* add here your conditions */) {
SwitchHotSeat();
}
}
NOTE: on edit and on change triggers are triggered only when an user edit the spreadsheet.
Just in case it helps anyone else with a similar issue, I discovered (by logging) that it was returning an object, rather than a number before, so the following code worked fine in the end.
function onFormSubmit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var millionaire24 = ss.getSheetByName('Millionaire24.');
var cellValue = millionaire24.getRange(3,6,1,1).getValues();
Number(cellValue)
if(cellValue[0] >= 1000000)switchHotSeat();
}