我很难想出一种解决方案来基于动态过滤生成必要的逻辑和输出。我正在使用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
}
答案 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))
};
});
参考文献: