首页 > 解决方案 > 从 API 查询到 Google 电子表格/G Apps 脚本并获得过滤结果

问题描述

我正在尝试基于DataDT 的1 分钟外汇数据优秀 API 构建一个电子表格。我正在尝试构建一个函数,它 1)从单元格中读取一个值(“日期时间”) 2)从上述 API 的给定 URL 中搜索该值 3)打印 2 个其他属性(开盘价和收盘价)同一个日期。

当前电子表格状态

换句话说,它将从 N 行和 O 行获取输入,并在 H 和 I 行输出相关值(来自 API 的 OPEN 和 CLOSE)。

(链接到当前的GSpreadsheet

该电子表格将宏观经济新闻和历史价格联系起来,并可能为外汇用户提供有用的见解。

我已经设法有效地从 API 查询数据,但我找不到一种方法来仅过滤我所询问的日期时间。不同日期的迭代要少得多!在用户@Cooper 的帮助下,我得到了以下代码,它可以从 API 查询整个页面,但还不能有效地过滤。我将不胜感激您可能提供的任何帮助。

这是 Appscript 中代码的当前状态:

(代码.gs)

function searchOnEdit(e) {
  //e.source.toast('Entry');// I use these lines for debugging
  var sh=e.range.getSheet();
  if(sh.getName()!='API') return;
  var checkedValue='TRUE';//these are the defaults if you install the checkboxes from the Insert Menu
  var uncheckedValue='FALSE';
  if(e.range.columnStart==17 && e.range.rowStart>1 && e.value==checkedValue) {
    e.range.setValue(uncheckedValue);//this was commented out it should not have been sorry for that Cooper
    //e.source.toast('flag1');
    var r=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
    var obj={datetime:r[14],url:r[13],event:e};
    var dObj=getDataDT1(obj);
    //Logger.log(dObj);
    sh.getRange(e.range.rowStart,4).setValue(dObj.OPEN);//loading OPEN on your spreadsheet
    sh.getRange(e.range.rowStart,5).setValue(dObj.CLOSE);//loadding CLOSE on your spreadsheet
  }
}

//{datetime:'',url:'',event:e}
function getDataDT1(obj) {
  Logger.log(JSON.stringify(obj));//I need to see this
  var r=UrlFetchApp.fetch(obj.url);
  var data=JSON.parse(r.getContentText("UTF-8"));
  //Logger.log(data);
  var pair='USDJPY';
  var dat=new Date(obj.datetime);
  var dtv=new Date(dat.getFullYear(),dat.getMonth(),dat.getDate(),dat.getHours(),dat.getMinutes()).valueOf();
  for(var i=0;i<data.length;i++) {
    var dt=data[i].DATE_TIME.split(' ');
    var sd=new Date(data[i].DATE_TIME);
    var sdv=new Date(sd.getFullYear(),sd.getMonth(),sd.getDate(),sd.getHours(),sd.getMinutes()).valueOf();
    if(sdv==dtv) {
      var d=dt[0].split('-');
      var t=dt[1].split(':');
      var datestring=Utilities.formatString('%s/%s/%s',d[1],d[2],d[0]);
      var timestring=Utilities.formatString('%s:%s',t[0],t[1]);
      var rObj={DATE:datestring,TIME:timestring,PAIR:pair,OPEN:data[i].OPEN.toFixed(3),CLOSE:data[i].CLOSE.toFixed(3)};
      break;
    }
  }
  //Logger.log(rObj);
  return rObj;
}

(应用脚本.json)

{
  "timeZone": "America/Caracas",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes":  ["https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/script.external_request","https://www.googleapis.com/auth/script.scriptapp","https://www.googleapis.com/auth/spreadsheets"]
}

(触发器.js)

function createSearchOnEditTrigger() {
  var ss=SpreadsheetApp.getActive();
  ScriptApp.newTrigger('searchOnEdit').forSpreadsheet(ss.getId()).onEdit().create();
}

标签: javascriptgoogle-apps-scriptgoogle-sheetsforex

解决方案


onEdit 搜索

您需要将一列复选框添加到第 17 列,并创建一个可安装的 onEdit 触发器。您可以使用提供的代码或通过“编辑/项目触发器”菜单手动执行。使用触发器创建代码时,请检查以确保只创建了一个触发器,因为多个触发器可能会导致问题。

此外,不要错误地将可安装触发器命名为 onEdit(e),因为它会响应简单触发器和导致问题的可安装触发器。

我在下面有一个动画向您展示它是如何运作的,您也可以看到电子表格的布局。请注意隐藏的列。我必须这样做以使动画尽可能小。但我没有删除你的任何专栏。

最好等待复选框重置为关闭,然后再选中另一个复选框。有可能检查它们的速度如此之快以至于脚本跟不上并且可能会错过一些搜索。

我还必须手动添加这些范围:

"oauthScopes":[" https://www.googleapis.com/auth/userinfo.email "," https://www.googleapis.com/auth/script.external_request "," https://www.googleapis. com/auth/电子表格"]

您可以将它们放入您的 appsscript.json 文件中,该文件可使用查看/显示清单文件查看。这是一个参考,几乎没有向您展示它们的外观。但基本思想是在右括号之前的最后一个条目之后放置一个逗号并添加所需的行。

创建触发器后,最好进入查看/当前项目触发器并将通知设置为立即。如果您遇到范围界定错误,它会告诉您要添加哪些错误。您添加它们,然后运行一个函数,您可以使用其他范围重新授权访问。您甚至可以运行 null 函数,例如function dummy(){};.

这是 onEdit 函数:

function searchOnEdit(e) {
  //e.source.toast('Entry');// I use these lines for debugging
  var sh=e.range.getSheet();
  if(sh.getName()!='API') return;
  var checkedValue='TRUE';//these are the defaults if you install the checkboxes from the Insert Menu
  var uncheckedValue='FALSE';
  if(e.range.columnStart==17 && e.range.rowStart>1 && e.value==checkedValue) {
    e.range.setValue(uncheckedValue);
    //e.source.toast('flag1');
    var r=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
    var obj={datetime:r[14],url:r[13],event:e};//you dont really need e here
    var dObj=getDataDT1(obj);
    //Logger.log(dObj);
    sh.getRange(e.range.rowStart,4).setValue(dObj.OPEN);//loading OPEN on your spreadsheet
    sh.getRange(e.range.rowStart,5).setValue(dObj.CLOSE);//loadding CLOSE on your spreadsheet
  }
}

这就是搜索功能。我尝试缓存数据,但它太大了。因此,如果您可以显着减小大小,这将有助于加快连续搜索的速度。

//{datetime:'',url:'',event:e}
function getDataDT1(obj) {
  var r=UrlFetchApp.fetch(obj.url);
  var data=JSON.parse(r.getContentText("UTF-8"));
  //Logger.log(data);
  var pair='USDJPY';
  var dat=new Date(obj.datetime);
  var dtv=new Date(dat.getFullYear(),dat.getMonth(),dat.getDate(),dat.getHours(),dat.getMinutes()).valueOf();
  for(var i=0;i<data.length;i++) {
    var dt=data[i].DATE_TIME.split(' ');
    var sd=new Date(data[i].DATE_TIME);
    var sdv=new Date(sd.getFullYear(),sd.getMonth(),sd.getDate(),sd.getHours(),sd.getMinutes()).valueOf();
    if(sdv==dtv) {
      var d=dt[0].split('-');
      var t=dt[1].split(':');
      var datestring=Utilities.formatString('%s/%s/%s',d[1],d[2],d[0]);
      var timestring=Utilities.formatString('%s:%s',t[0],t[1]);
      var rObj={DATE:datestring,TIME:timestring,PAIR:pair,OPEN:data[i].OPEN.toFixed(3),CLOSE:data[i].CLOSE.toFixed(3)};
      break;
    }
  }
  //Logger.log(rObj);
  return rObj;
}

这是创建触发器功能。请注意不要多次运行此程序,并始终检查是否只有一个,并在您第一次打开它时将通知设置为立即通知,以便在发生错误后很快收到电子邮件。

function createSearchOnEditTrigger() {
  var ss=SpreadsheetApp.getActive();
  ScriptApp.newTrigger('searchOnEdit').forSpreadsheet(ss.getId()).onEdit().create();
}

动画片:

在此处输入图像描述

这是带有复选框的电子表格的副本。

在此处输入图像描述

如果您有任何困难,请随时回来寻求帮助。我知道其中一些东西听起来有点令人生畏,但它有点像公制。一旦您测量并称量了一些东西,它就会开始听起来和感觉自然。

这是我的代码,与我现在正在运行的脚本中的代码完全相同。由于在评论中编辑,我可能有错字。这有一些调试行,其中运行 Logger 并显示您可能应该注释掉的 toast。

function searchOnEdit(e) {
  e.source.toast('Entry');
  var sh=e.range.getSheet();
  if(sh.getName()!='API') return;
  var checkedValue='TRUE';
  var uncheckedValue='FALSE';
  if(e.range.columnStart==17 && e.range.rowStart>1 && e.value==checkedValue) {
    e.range.setValue(uncheckedValue);
    e.source.toast('flag1');
    var r=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
    var obj={datetime:r[14],url:r[13],event:e};
    var dObj=getDataDT1(obj);
    Logger.log(dObj);
    sh.getRange(e.range.rowStart,4).setValue(dObj.OPEN);
    sh.getRange(e.range.rowStart,5).setValue(dObj.CLOSE);
  }
}

//{datetime:'',url:''}
function getDataDT1(obj) {
  var r=UrlFetchApp.fetch(obj.url);
  var data=JSON.parse(r.getContentText("UTF-8"));
  //Logger.log(data);
  var pair='USDJPY';
  var dat=new Date(obj.datetime);
  var dtv=new Date(dat.getFullYear(),dat.getMonth(),dat.getDate(),dat.getHours(),dat.getMinutes()).valueOf();
  for(var i=0;i<data.length;i++) {
    var dt=data[i].DATE_TIME.split(' ');
    var sd=new Date(data[i].DATE_TIME);
    var sdv=new Date(sd.getFullYear(),sd.getMonth(),sd.getDate(),sd.getHours(),sd.getMinutes()).valueOf();
    if(sdv==dtv) {
      var d=dt[0].split('-');
      var t=dt[1].split(':');
      var datestring=Utilities.formatString('%s/%s/%s',d[1],d[2],d[0]);
      var timestring=Utilities.formatString('%s:%s',t[0],t[1]);
      var rObj={DATE:datestring,TIME:timestring,PAIR:pair,OPEN:data[i].OPEN.toFixed(3),CLOSE:data[i].CLOSE.toFixed(3)};
      break;
    }
  }
  //Logger.log(rObj);
  return rObj;
}

function createSearchOnEditTrigger() {
  var ss=SpreadsheetApp.getActive();
  ScriptApp.newTrigger('searchOnEdit').forSpreadsheet(ss.getId()).onEdit().create();
}

推荐阅读