talib-wasm
Version:
ta-lib.org package parsed with emscripten, that can be added to browser
230 lines (191 loc) • 6.84 kB
JavaScript
const taReturnCodes = require('../constants/ta-return-codes');
const ARRAY_TYPES = [
'Double Array',
'High',
'Low',
'Close',
'Volume',
'Open',
'Integer Array'
];
function cArray(Module, sizeOrData) {
const size = Array.isArray(sizeOrData) ? sizeOrData.length : sizeOrData;
const offset = Module._malloc(size * 8);
Module.HEAPF64.set(new Float64Array(sizeOrData), offset / 8);
return {
"data": Module.HEAPF64.subarray(offset / 8, offset / 8 + size),
"offset": offset
}
}
module.exports = (Module, functionDescr) => {
let wrappedFunction;
let wrappedFunctionLookback;
const Abbreviation = functionDescr.Abbreviation[0];
const callCwrapArgs = [];
const callCwrapArgsLookback = [];
const RequiredInputArguments = ((functionDescr.RequiredInputArguments || [])[0] || {
RequiredInputArgument: []
})
.RequiredInputArgument
.map((current) => {
const typeIsArray = ARRAY_TYPES.indexOf(current.Type) !== -1;
if (typeIsArray) {
callCwrapArgs.push('[number]')
} else {
callCwrapArgs.push('number')
}
return {
name: current.Name[0].replace(' ', ''),
defaultValue: null,
// typeIsArray
};
});
const OptionalInputArguments = ((functionDescr.OptionalInputArguments || [])[0] || {
OptionalInputArgument: []
}).OptionalInputArgument
.map((current) => {
const typeIsArray = ARRAY_TYPES.indexOf(current.Type) !== -1;
if (typeIsArray) {
callCwrapArgs.push('[number]');
callCwrapArgsLookback.push('[number]');
} else {
callCwrapArgs.push('number');
callCwrapArgsLookback.push('number');
}
return {
name: 'optIn' + current.Name[0].replace(' ', ''),
defaultValue: +current.DefaultValue[0],
// typeIsArray
};
});
callCwrapArgs.push('number'); // outBegIdx
callCwrapArgs.push('number'); // outNBElement
const OutputArguments = ((functionDescr.OutputArguments || [])[0] || {
OutputArgument: []
}).OutputArgument
.map((current) => {
const typeIsArray = ARRAY_TYPES.indexOf(current.Type) !== -1;
if (typeIsArray) {
callCwrapArgs.push('[number]')
} else {
callCwrapArgs.push('number')
}
return {
name: current.Name[0].replace(' ', ''),
// typeIsArray
};
});
const cwrapFunction = Module.cwrap(`TA_${Abbreviation}`,
'number',
callCwrapArgs
);
const cwrapFunctionLookback = Module.cwrap(`TA_${Abbreviation}_Lookback`,
'number',
callCwrapArgsLookback
);
wrappedFunction = (optionsToCall) => {
const dataToCallFunction = {
...optionsToCall
};
//Check required input arguments
RequiredInputArguments
.forEach((ria) => {
if (!optionsToCall[ria.name]) {
throw new Error(`Not passed required argument ${ria.name}`);
}
});
OptionalInputArguments
.forEach((oia) => {
if (!dataToCallFunction[oia.name]) {
dataToCallFunction[oia.name] = oia.defaultValue;
}
});
let {startIdx, endIdx} = optionsToCall;
if (typeof startIdx === 'undefined') {
startIdx = 0;
}
if (typeof endIdx === 'undefined') {
endIdx = optionsToCall[
RequiredInputArguments[0].name
].length - 1;
}
let argsToCall = [startIdx, endIdx];
const argsToCallLookback = [];
const arraysToRelease = [];
RequiredInputArguments
.forEach((ria) => {
const dataToCall = dataToCallFunction[ria.name].slice(startIdx, endIdx + 1);
let argArray = cArray(Module, dataToCall);
// dataToCall.forEach((v, i) => argArray.data[i] = v);
arraysToRelease.push(argArray);
argsToCall.push(argArray.offset);
});
OptionalInputArguments
.forEach((oia) => {
argsToCall.push(
dataToCallFunction[oia.name]
);
argsToCallLookback.push(
dataToCallFunction[oia.name]
);
});
const outBegIdxPointer = Module._malloc(8);
const outNBElementPointer = Module._malloc(8);
argsToCall.push(outBegIdxPointer); // outBegIdx
argsToCall.push(outNBElementPointer); // outNBElement
const outputArrays = OutputArguments
.map((oa) => {
let argArray = cArray(Module, endIdx - startIdx);
arraysToRelease.push(argArray);
argsToCall.push(argArray.offset);
return {
array: argArray,
name: oa.name
}
});
const returnCode = cwrapFunction(...argsToCall);
const lookback = cwrapFunctionLookback(...argsToCallLookback);
arraysToRelease.forEach((arr) => {
Module._free(arr.offset / 8);
});
Module._free(outBegIdxPointer);
Module._free(outNBElementPointer);
const result = outputArrays
.reduce((result, current) => {
result[current.name] = Array.prototype.slice.call(current.array.data, 0, endIdx - lookback + 1);
return result;
}, {});
result.returnCode = returnCode;
result.returnCodeName = taReturnCodes[returnCode];
return result;
};
wrappedFunctionLookback = (optionsToCall) => {
const dataToCallFunction = {
...optionsToCall
};
OptionalInputArguments
.forEach((oia) => {
if (!dataToCallFunction[oia.name]) {
dataToCallFunction[oia.name] = oia.defaultValue;
}
});
const argsToCallLookback = [];
OptionalInputArguments
.forEach((oia) => {
argsToCallLookback.push(
dataToCallFunction[oia.name]
);
});
return cwrapFunctionLookback(...argsToCallLookback);
};
return {
funcName: Abbreviation,
wrappedFunction,
wrappedFunctionLookback,
description: {
RequiredInputArguments,
OptionalInputArguments,
OutputArguments
}
}
};