如何基于动态参数创建动态过滤器?

时间:2019-04-06 03:22:24

标签: javascript google-apps-script

我很难想出一种解决方案来基于动态过滤生成必要的逻辑和输出。我正在使用Google Apps脚本中的脚本,正在使用doGet()来充当Webhook。将参数发送到该Webhook,然后根据提供的参数从电子表格中过滤数据。这意味着我必须根据发送的参数创建自己的过滤器。最初,我开始尝试手动创建条件。但是,我意识到可选参数的组合超过250个,这将使我永远!流程如下:

以下是所有可接受的参数:(exch,base,dir,durmin,durmax,drawmin,drawmax,askmin,askmax,excessmin,excessmax,maxdcalvl,maxdcapercent,numcalls)

其中,有6个必需的参数: (exch,base,dir,durmax,drawmax,maxdcalvl)

这些是可选的: (durmin,drawmin,askmin,askmax,excessmin,excessmax,maxdcapercent,numcalls)

每个参数所需的逻辑遵循以下模式: exch == exchange && base == baseC && dir == direction

duration >= durmin && duration <= durmax drawdown <= drawmin && drawdown >= drawmax

这里要注意的重要事情是这些参数基本上只是帮助在工作表exch == exchange && base == baseC && dir == direction上定位数据,并且实际上只是返回了这些参数。这些没有其他比较。

其他参数遵循以下模式: duration >= durmin && duration <= durmax drawdown <= drawmin && drawdown >= drawmax 其中第一个变量是需要过滤的来自for循环的数据,而min / max变量是用户发送的min和max参数,这些参数用于实际过滤诸如askSpread (for loop data) >= askmin (user input) && askSpread (for loop data) <= askmax (user input)之类的数据。同样,这些参数中的每一个都是可选参数,因此用户最终只能发送askmin,因此我只需要askSpread >= askmin而不是askSpread (for loop data) >= askmin (user input) && askSpread (for loop data) <= askmax (user input),反之亦然。

所以有一个简化的解释-如果必需参数或可选参数都没有最小/最大值,那么我只是确保要调用的数据来自表单AKA上的正确位置:exch == binance && base == btc && dir == long < / p>

任何具有最小值/最大值的东西,我正在使用它们来创建最小值和最大值条件 duration >= durmin && duration <= durmax-过滤数据,其中数据> = durmin(例如1),数据是<= durmax(例如4)

这是我的代码的片段,返回正确的值。但是,此方法需要我根据if语句键入所有250多个参数组合。我认为.filter()是更好的解决方案。但是我不熟悉如何正确使用它。任何帮助将不胜感激,因为我此刻完全陷入困境。 PS。如果您不熟悉Google Apps脚本,那么我在Javascript的某些功能上会受到限制。

  

Apps Script是用于G Suite平台中轻量级应用程序开发的脚本语言。它基于JavaScript 1.6,具有部分> 1.7和1.8,并提供ECMAScript 5 API的子集,[2]但是,它不是在客户端上运行,而是在Google Cloud中执行。根据Google的说法,Apps Script“提供了跨Google产品和第三方服务自动执行任务的简便方法。” [3] Apps Script也是为Google Docs,表格和幻灯片的附加组件提供动力的工具。[4 ]

https://en.wikipedia.org/wiki/Google_Apps_Script

function test() {
  //  exch,base,dir,durmin,durmax,drawmin,drawmax,askmin,askmax,excessmin,excessmax
  var d = data('binance','bnb','long',0.5,3,-1,-3,0,0,5,0);
  Logger.log(d)

}

function data(exch,base,dir,durmin,durmax,drawmin,drawmax,askmin,askmax,excessmin,excessmax){
  var exch = exch.toLowerCase();
  var base = base.toUpperCase();
  var dir = dir.toUpperCase();

  var s = SpreadsheetApp;
  var ss = s.getActiveSpreadsheet();
  var saved = ss.getSheetByName('Signals');
  var lastRow = saved.getLastRow();
  var data = saved.getRange(2, 1, lastRow, 12).getValues();

  if (drawmin > 0) {    
   var drawmin = drawmin/100
  }
  if (drawmax > 0) {  
   var drawmax = drawmax/100
  }
  if (askmin > 0) {
   var askmin = askmin/100
  }
  if (askmax > 0) {
   var askmax = askmax/100
  }
  if (excessmin > 0) {
   var excessmin = excessmin/100
  }
  if (excessmax > 0) {
    var excessmax = excessmax/100
  }

  var array = []
  for (var i = 0; i < data.length; i++) {

    var exchange = data[i][0];
    var baseC = data[i][1];
    var direction = data[i][2];
    var coin = data[i][3];
    var duration = data[i][4];
    var drawdown = data[i][5];
    var askSpread = data[i][6];
    var excess = data[i][7];

    if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown <= drawmin && drawdown >= drawmax && askSpread >= askmin && askSpread <= askmax && excess >= excessmin && excess <= excessmax) {
      Logger.log('1')  
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))

          }
        )
    } else if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown <= drawmin && drawdown >= drawmax && askSpread >= askmin && askSpread <= askmax && excess >= excessmin && excess <= excessmax) {
      Logger.log('2')   
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )
    } else if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown <= drawmin && drawdown >= drawmax && askSpread >= askmin && askSpread <= askmax && excess >= excessmin) {
      Logger.log('3')  
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )
    } else if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown <= drawmin && drawdown >= drawmax && askSpread >= askmin && askSpread <= askmax) {
      Logger.log('4')  
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )
    } else if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown <= drawmin && drawdown >= drawmax && askSpread >= askmin) {
      Logger.log('5')   
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )
    } else if(exch == exchange && base == baseC && dir == direction && duration >= durmin && duration <= durmax && drawdown >= drawmax && askSpread >= askmin) {
      Logger.log('6')    
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )
    } else if (exch == exchange && base == baseC && dir == direction && duration <= durmax && drawdown >= drawmax && askSpread >= askmin) {
      Logger.log('7')  
      array.push(
          {
            "exchange": exchange,
            "base": baseC,
            "direction": direction,
            "coin": coin,
            "duration": Number(duration.toPrecision(2)),
            "draw_down": Number((drawdown*100).toPrecision(2)),
            "ask_highest_spread": Number((askSpread*100).toPrecision(2)),
            "excess_above_target": Number((excess*100).toPrecision(2))
          }
        )

    }
  }
  return array
}

2 个答案:

答案 0 :(得分:2)

在解析查询字符串时,请为可选参数1(如果不存在)设置默认值。

摘要:

function doGet(f){
  const e = f.parameter;
  const durmin = e.durmin || -Infinity;
  const durmax = e.durmax || Infinity;

答案 1 :(得分:1)

在处理2D数组时,从索引符号转换为带注释的对象,展平对象并将索引访问替换为属性访问会有所帮助:

const relationship = {
  // array index: property name
  0: "exchange",
  ...
};
var annotated = data.map(function (row) {
  // row is an array, lets make it an object:
  return row.reduce(function (obj, value, idx) {
    var prop = relationship[idx];
    obj[prop] = value;
    return obj;
  }, {});
});
// `annotated` is now an array of objects with usefully named properties instead of an array of arrays of values

下一步是开始过滤。您似乎有两种测试-相等测试和“在范围内”,并且这些测试可能最容易单独处理。假设您创建了一个具有用户指定键的对象(而不是使用大量单独的变量,而是使用一个将这些变量作为属性的对象),我们可以简化相等性检查:

const requestedInfo = {
  "exchange": exchange,
  "base": base,
  "direction": direction,
  ...
};

// some request parameters denote "ranges," not equality; they don't go in here.
const requiredEqualKeys = ["exchange", "base", ... ];
var meetsEqualityCriteria = annotated.filter(function (obj) {
  return requiredEqualKeys.every(function (key) { return requestedInfo[key] === undefined || obj[key] === requestedInfo[key]; });
});

如果为该数组(Array#every)中的每个值调用的函数返回true,则true方法将仅返回Array#filter(因此告诉requiredEqualKeys保留该对象) 。我们的相等性检查首先确定是否甚至已将该参数指定为输入,并且仅当该参数要求的值必须与被过滤对象中的值相同时(例如,如果请求中不包含base ,则不会对base进行排除)。您可能应该为请求的属性null添加一个检查;我把它留给读者。 (如果您不对data进行注释,则只能按数组索引访问这些值,并且当数据更改格式/顺序时,很容易弄错这一点!)

将对象简化为仅满足要求的相等性的对象后,就可以应用其他测试,例如属性是否在请求的范围内。定义requestedInfo时,对于范围值,您应该创建一个嵌套对象,例如

const requestedInfo = {
  ...
  "ask": {
    "min": askMin, // can set defaults per @TheMaster's answer here too
    "max": askMax
  },
  ...
}

这允许您测试属性以及对象的值是否在范围内:

const rangeKeys = [ "ask", "duration", ... ];
var meetsEQandRangeCriteria = meetsEqualityCriteria.filter(function (obj) {
  return rangeKeys.every(function (prop) {
    var rqProp = requestedInfo[prop];
    if (rqProp === undefined)
      return true; // property not present in request
    if (!obj.hasOwnProperty(prop) || obj[prop] < rqProp.min || obj[prop] > rqProp.max)
      return false; // not present in object but was requested, or out-of-range 
    else
      return true;
  });
});

现在,剩下的对象数组满足了您要求的所有相等性和基于范围的条件。您可以按原样返回它,也可以按照帖子中的代码返回格式化的等效项:

return meetsEQandRangeCriteria.map(function (obj) {
  return {
    "base": obj.base,
    ...
    "excess_above_target": Number((obj.excess * 100).toPrecision(2))
  };
});

参考文献: