east-analysistools
Version:
description: Tools to analyze the performance of Crypto Currencies
357 lines (323 loc) • 10.6 kB
JavaScript
import { abs, min, max, sum, ceil , log, exp} from "mathjs";
import { MongoClient } from "mongodb";
import uTools from "updatetools";
import wt from "discrete-wavelets";
async function refactorData(crypt, timeSpan) {
// take data in hour format and create dataset for longer time perid
// right now the data is hours
// longer time periods needed are 6hr, days, weeks
// 6hr = 6 data points
// 1day= 24 data points
// 7 days= 168 data points
// Example:
// for 24 refactor
// period = 24
// for the latest of each 24 data points we get the date and close values
// for open we use the earliest of the 24 data points
// volume = sum of the volumes for all 24 data points
// low = minimum(all the lows for all 24 points)
// high = maximum ( all the highs for all 24 datapoints)
var validTimeSpans = [6, 24, 168];
if (!validTimeSpans.includes(timeSpan)) {
throw new Error("Invalid timespan");
}
try {
var dataSet = [];
var dataPoint;
var high = crypt.map((x) => x.high);
var low = crypt.map((x) => x.low);
var volume = crypt.map((x) => x.volume);
var lastPoint;
var ts1 = timeSpan - 1;
for (let i = 0; i < crypt.length - timeSpan; i++) {
lastPoint = i + timeSpan;
dataPoint = {};
dataPoint["date_time"] = crypt[i].date_time;
dataPoint["low" + timeSpan] = min(...low.slice(i, lastPoint));
dataPoint["high" + timeSpan] = max(...high.slice(i, lastPoint));
dataPoint["close" + timeSpan] = crypt[i + ts1].close;
dataPoint["volume" + timeSpan] = sum(volume.slice(i, lastPoint));
dataSet.push(dataPoint);
}
return dataSet;
} catch (err) {
throw err;
}
}
async function refactorSet(MDBURI, exch, product, timeSpan, Force) {
var force = Force || false;
const client = await MongoClient.connect(MDBURI);
var crypto;
var closeTime = "close" + timeSpan;
try {
// get latest entry of "close" + timeSpan
var closeTime = "close" + timeSpan;
var mostRecent = await client
.db(exch)
.collection(product)
.aggregate([
{ $project: { _id: 0, date_time: 1, [closeTime]: 1 } },
{ $match: { [closeTime]: { $exists: false } } },
{ $sort: { date_time: 1 } },
{ $limit: 1 },
])
.toArray();
if ((mostRecent.length == 0) || force) {
// there is no "closeTime" data, so get all of it
crypto = await client
.db(exch)
.collection(product)
.find()
.sort({ date_time: 1 })
.toArray();
} else {
crypto = await client
.db(exch)
.collection(product)
.find({ date_time: { $gte: new Date(mostRecent[0].date_time) } })
.sort({ date_time: 1 })
.toArray();
}
var dh = await refactorData(crypto, timeSpan);
} catch (err) {
console.log(err);
} finally {
client.close();
}
console.log(
"Update ",
dh.length,
" records for ",
product,
" With time spacing of ",
timeSpan,
" hours"
);
if (dh.length > 0) uTools.DBupdateSet(MDBURI, exch, product, dh);
}
async function WTIfilter(dataArray, N) {
var coeffs = await wt.wavedec(dataArray, "D16");
// console.log("coeffs:", coeffs)
var slevel = coeffs.length - 1;
if (N > slevel) N = slevel;
for (let i = N; i < coeffs.length; i++) {
coeffs[i].fill(0);
}
return await wt.waverec(coeffs, "D16");
}
async function WTSmooth(dataSet, smoothLevel) {
var spacing = 2048,
overlap = 64;
var workSet = [];
var transition = [];
var revtransition = [];
var setSmooth, dataSnip, lastData;
for (let j = 0; j < overlap; j++) {
transition.push(j / overlap);
revtransition.push(1 - transition[j]);
}
dataSnip = await dataSet.slice(0, spacing);
setSmooth = await WTIfilter(dataSnip, smoothLevel);
lastData = setSmooth.slice(0, overlap);
if (dataSet.length < spacing + 1) workSet = [...setSmooth];
else
for (let i = 0; i < dataSet.length - spacing + 1; i += spacing - overlap) {
dataSnip = await dataSet.slice(i, i + spacing);
setSmooth = await WTIfilter(dataSnip, smoothLevel);
for (let j = 0; j < overlap; j++) {
setSmooth[j] =
lastData[j] * revtransition[j] + setSmooth[j] * transition[j];
}
lastData = setSmooth.slice(-overlap);
workSet.push(...setSmooth.slice(0, -overlap));
}
if (workSet.length < dataSet.length) workSet.push(...lastData);
return workSet;
}
async function smoothPadded(dSet, smoothLevel) {
const setLength = dSet.length;
const wtLength = 2048,
overlap = 128;
const wtl1 = wtLength - overlap;
// prepend data to beginning so that it is always doing the last 2 sets
// all prepended data is the same as the first element of the dataset
var fillNumber = dSet[0];
var workingSet = await Array(wtl1).fill(fillNumber);
await workingSet.push(...dSet);
// postPend data to make each dataset have a length of
// length = wtL1* N + wtLength
// filled with last digit of set
var requiredLength =
ceil((workingSet.length - wtLength) / wtl1) * wtl1 + wtLength;
fillNumber = workingSet.at(-1);
var postLength = requiredLength - workingSet.length;
var postSet = await Array(postLength).fill(fillNumber);
workingSet.push(...postSet);
// smooth the data and then chop
var smoothSet = await WTSmooth(workingSet, smoothLevel);
if (postLength < 1) postLength = 1;
smoothSet = await smoothSet.slice(wtl1, -postLength);
return smoothSet;
}
async function DBfirstRecord(MDBURI, exch, product) {
const client = await MongoClient.connect(MDBURI);
var crypto;
try {
// get latest entry of "close" + timeSpan
crypto = await client
.db(exch)
.collection(product)
.aggregate([
{ $project: { _id: 0, date_time: 1, open: 1, volume24: 1 } },
{ $match: {} },
{ $sort: { date_time: 1 } },
{ $limit: 1 },
])
.sort({ date_time: 1 })
.toArray();
return crypto[0].date_time;
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
async function DBsmoothAll(MDBURI, exch, product) {
const client = await MongoClient.connect(MDBURI);
var crypto;
try {
// get latest entry of "close" + timeSpan
crypto = await client
.db(exch)
.collection(product)
.aggregate([
{ $project: { _id: 0, date_time: 1, open: 1, volume24: 1 } },
{ $match: {} },
])
.sort({ date_time: 1 })
.toArray();
var dSet = await crypto.map(({ open }) => open);
var tSet = await crypto.map(({ date_time }) => date_time);
var vSet = await crypto.map(({ volume24 }) => volume24);
var i = vSet.length;
var setLength = vSet.length;
while (vSet[i] == undefined) i--;
for (let j = i; j < setLength; j++) {
vSet[j] = vSet[i];
}
var smoothData = await smoothPadded(dSet, 2);
// keep smoothed volumes from going negative
// when data is missing for longer time periods
for (let i = 0; i < vSet.length; i++) {
if ((vSet[i]< 0.0001)) {
vSet[i]= vSet[i-1]
}
}
vSet= vSet.map((x) =>log(x));
var smoothVolume = await smoothPadded(vSet, 1);
smoothVolume= smoothVolume.map((x) => exp(x));
var items = tSet.map((date_time, index) => {
return {
date_time: date_time,
opensmooth: smoothData[index],
volumesmooth: smoothVolume[index],
};
});
console.log("Update smooth data for: ", product);
await uTools.DBupdateSet(MDBURI, exch, product, items);
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
async function DBsmoothUpdate(MDBURI, exch, product) {
var firstDate = await DBfirstRecord(MDBURI, exch, product);
var lastDate = await uTools.DBmostRecentDate(MDBURI, exch, product);
var totalHours =
(new Date(lastDate).getTime() - new Date(firstDate).getTime()) / 3600000;
var wtLength = 2048,
overlap = 128,
wtl1 = wtLength - overlap;
var workingLength = totalHours + wtl1;
var totalLength = ceil((workingLength - wtLength) / wtl1) * wtl1 + wtLength;
var grabLength = wtLength + wtl1;
var postPendLength = totalLength - wtl1 - totalHours;
var getDataStartOffset = wtLength + wtl1 - postPendLength;
var sampleStartDate = new Date(
new Date(lastDate).getTime() - getDataStartOffset * 3600000
);
var dataPoints =
(new Date(sampleStartDate).getTime() - new Date(firstDate).getTime()) /
3600000;
if (dataPoints < 0) sampleStartDate = new Date(firstDate);
console.log("sampleStartDate:", sampleStartDate);
const client = await MongoClient.connect(MDBURI);
var crypto;
try {
// get latest entry of "close" + timeSpan
crypto = await client
.db(exch)
.collection(product)
.aggregate([
{ $project: { _id: 0, date_time: 1, open: 1, volume24: 1 } },
{ $match: { date_time: { $gte: sampleStartDate } } },
])
.sort({ date_time: 1 })
.toArray();
var tSet = await crypto.map(({ date_time }) => date_time);
var dSet = await crypto.map(({ open }) => open);
var vSet = await crypto.map(({ volume24 }) => volume24);
var i = vSet.length;
var setLength = vSet.length;
while (vSet[i] == undefined) i--;
for (let j = i; j < setLength; j++) {
vSet[j] = vSet[i];
}
for (let i = 0; i < vSet.length; i++) {
if ((vSet[i]< 0.0001)) {
vSet[i]= vSet[i-1]
}
}
vSet= vSet.map((x) =>log(x));
var smoothData = await smoothPadded(dSet, 2);
var smoothVolume = await smoothPadded(vSet, 1);
smoothVolume= smoothVolume.map((x) => exp(x));
var items = tSet.map((date_time, index) => {
return {
date_time: date_time,
opensmooth: smoothData[index],
volumesmooth: smoothVolume[index],
};
});
if (dataPoints > 128) items.slice(128, -1);
console.log("Update smooth data for: ", product);
await uTools.DBupdateSet(MDBURI, exch, product, items);
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
async function MRI(dSet) {
var closeSmooth = await WTSmooth(dSet, 2048, 64);
var ratioSet = [];
var ratioPower = 7.0 / 90;
if (dSet.length > 2160) {
for (let i = 2160; i < dSet.length; i++) {
ratioSet.push((dSet[i] / closeSmooth[i - 2160]) ** ratioPower);
}
const ratioSmooth = await WTSmooth(ratioSet, 512, 32);
return ratioSmooth;
}
}
const analysistools = {
refactorSet,
WTIfilter,
WTSmooth,
smoothPadded,
DBsmoothAll,
DBsmoothUpdate,
MRI,
};
export default analysistools;