@sunrise1002/tats
Version:
Techincal Indicators written in javascript
166 lines (165 loc) • 6.84 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Indicator, IndicatorInput } from '../indicator/indicator';
// import * as tf from '@tensorflow/tfjs';
var isNodeEnvironment = false;
var model;
var oneHotMap = ['IHS', 'TU', 'DB', 'HS', 'TD', 'DT'];
var tf;
try {
isNodeEnvironment = Object.prototype.toString.call(global.process) === '[object process]';
}
catch (e) { }
export class PatternDetectorInput extends IndicatorInput {
constructor(values) {
super();
this.values = values;
}
}
export var AvailablePatterns;
(function (AvailablePatterns) {
AvailablePatterns[AvailablePatterns["IHS"] = 0] = "IHS";
AvailablePatterns[AvailablePatterns["TU"] = 1] = "TU";
AvailablePatterns[AvailablePatterns["DB"] = 2] = "DB";
AvailablePatterns[AvailablePatterns["HS"] = 3] = "HS";
AvailablePatterns[AvailablePatterns["TD"] = 4] = "TD";
AvailablePatterns[AvailablePatterns["DT"] = 5] = "DT";
})(AvailablePatterns || (AvailablePatterns = {}));
function interpolateArray(data, fitCount) {
var linearInterpolate = function (before, after, atPoint) {
return before + (after - before) * atPoint;
};
var newData = new Array();
var springFactor = new Number((data.length - 1) / (fitCount - 1));
newData[0] = data[0]; // for new allocation
for (var i = 1; i < fitCount - 1; i++) {
var tmp = i * springFactor;
var before = new Number(Math.floor(tmp)).toFixed();
var after = new Number(Math.ceil(tmp)).toFixed();
var atPoint = tmp - before;
newData[i] = linearInterpolate(data[before], data[after], atPoint);
}
newData[fitCount - 1] = data[data.length - 1]; // for new allocation
return newData;
}
;
function l2Normalize(arr) {
var sum = arr.reduce((cum, value) => { return cum + (value * value); }, 0);
var norm = Math.sqrt(sum);
return arr.map((v) => v / norm);
}
export class PatternDetectorOutput {
}
var modelLoaded = false;
var laodingModel = false;
var loadingPromise;
function loadModel() {
return __awaiter(this, void 0, void 0, function* () {
if (modelLoaded)
return Promise.resolve(true);
if (laodingModel)
return loadingPromise;
laodingModel = true;
loadingPromise = new Promise(function (resolve, reject) {
return __awaiter(this, void 0, void 0, function* () {
if (isNodeEnvironment) {
tf = require('@tensorflow/tfjs');
console.log('Nodejs Environment detected ');
var tfnode = require('@tensorflow/tfjs-node');
var modelPath = require('path').resolve(__dirname, '../tf_model/model.json');
model = yield tf.loadModel(tfnode.io.fileSystem(modelPath));
}
else {
if (typeof window.tf == "undefined") {
modelLoaded = false;
laodingModel = false;
console.log('Tensorflow js not imported, pattern detection may not work');
resolve(void 0);
return;
}
tf = window.tf;
console.log('Browser Environment detected ', tf);
console.log('Loading model ....');
model = yield tf.loadModel('/tf_model/model.json');
modelLoaded = true;
laodingModel = false;
setTimeout(resolve, 1000);
console.log('Loaded model');
return;
}
modelLoaded = true;
laodingModel = false;
resolve(void 0);
return;
});
});
yield loadingPromise;
return;
});
}
loadModel();
export function predictPattern(input) {
return __awaiter(this, void 0, void 0, function* () {
yield loadModel();
if (input.values.length < 300) {
console.warn('Pattern detector requires atleast 300 data points for a reliable prediction, received just ', input.values.length);
}
Indicator.reverseInputs(input);
var values = input.values;
var output = yield model.predict(tf.tensor2d([l2Normalize(interpolateArray(values, 400))]));
var index = tf.argMax(output, 1).get(0);
Indicator.reverseInputs(input);
return { patternId: index, pattern: oneHotMap[index], probability: output.get(0, 4) * 100 };
});
}
export function hasDoubleBottom(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.DB);
});
}
export function hasDoubleTop(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.DT);
});
}
export function hasHeadAndShoulder(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.HS);
});
}
export function hasInverseHeadAndShoulder(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.IHS);
});
}
export function isTrendingUp(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.TU);
});
}
export function isTrendingDown(input) {
return __awaiter(this, void 0, void 0, function* () {
var result = yield predictPattern(input);
return (result.patternId === AvailablePatterns.TD);
});
}
export class PatternDetector extends Indicator {
}
PatternDetector.predictPattern = predictPattern;
PatternDetector.hasDoubleBottom = hasDoubleBottom;
PatternDetector.hasDoubleTop = hasDoubleTop;
PatternDetector.hasHeadAndShoulder = hasHeadAndShoulder;
PatternDetector.hasInverseHeadAndShoulder = hasInverseHeadAndShoulder;
PatternDetector.isTrendingUp = isTrendingUp;
PatternDetector.isTrendingDown = isTrendingDown;