Files
web/src/charts/jBars.js
2024-03-02 11:04:24 -08:00

175 lines
6.7 KiB
JavaScript

export async function jBars (from, to, res) {
console.log('[jBars]: Method call', res, from, to);
var toDate = new Date(to*1000);
var fromDate = new Date(from*1000);
if (res=="1W") { // for 1W, day must be Sunday
const day = fromDate.getUTCDay(); // 0<=day<7
fromDate.setDate(fromDate.getDate() + (7-day)%7 );
}
// Set fromDate to be compatible with Tim's datafiles.
// This potentially increases number of samples returned.
if (res.endsWith("W") || res.endsWith("D")) { // Days/Weeks -- set to midnight
fromDate.setUTCHours(0, 0, 0);
} else {
let minutesRes = parseInt(res);
if (minutesRes >= 60) { // Hours
let hoursRes = Math.floor(minutesRes/60);
let fromHours = fromDate.getUTCHours();
fromDate.setUTCHours(fromHours - fromHours % hoursRes, 0, 0, 0);
} else { // Minutes
let fromMinutes = fromDate.getUTCMinutes();
fromDate.setUTCMinutes(fromMinutes - fromMinutes % minutesRes, 0, 0);
}
}
console.log("fromDate:", fromDate.toUTCString());
console.log("toDate: ", toDate.toUTCString());
const contract = "0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443";
// const contract = "0xC6962004f452bE9203591991D15f6b388e09E8D0";
const file_res = ['1m', '3m', '5m', '10m', '15m', '30m', '1H', '2H', '4H', '8H', '12H', '1D', '2D', '3D', '1W',];
const supported_res = ['1', '3', '5', '10', '15', '30', '60', '120', '240', '480', '720', '1D', '2D', '3D', '1W',];
const daily_res = ['1', '3', '5', '10', '15', '30'];
const single_res = ['1W'];
if (!supported_res.includes(res)) throw Error(`resolution ${res} not supported.`);
const is_daily_res = daily_res.includes(res);
const is_single_res = single_res.includes(res);
const is_monthly_res = !is_single_res && !is_daily_res;
let bars = [];
for ( // Once around for each sample in from-to range
let iDate = fromDate,
// loop state
iFile = undefined,
iohlc = 0,
ohlc;
iDate < toDate;
) {
let bar = undefined;
// Fetch one sample file as needed
if (iFile == undefined ? true :
is_monthly_res ? iFile.getUTCMonth() != iDate.getUTCMonth() :
is_daily_res ? iFile.getUTCDate() != iDate.getUTCDate() :
false // is_single_res
) {
const fres = file_res[supported_res.indexOf(res)]
const yr = iDate.getUTCFullYear();
const yrdir = is_single_res ? "" : `/${yr}`;
const mo = String(iDate.getUTCMonth()+1).padStart(2, '0'); // January is month 0 in Date object
const date = is_daily_res ? String(iDate.getUTCDate()).padStart(2, '0') : "";
const yrmo = !is_single_res ? `-${yr}${mo}` : "";
const server = "https://alpha.dexorder.trade"
let url = `${server}/ohlc/42161/${contract}/${fres}${yrdir}/${contract}-${fres}${yrmo}${date}.json`;
let response = await fetch(url);
if (response.ok) {
ohlc = await response.json();
console.log(`Fetch: ${ohlc.length} resolution ${res} samples from ${url}`)
console.log(`first: ${new Date(ohlc[0][0]*1000).toUTCString()}`)
console.log(`last: ${new Date(ohlc[ohlc.length-1][0]*1000).toUTCString()}`)
} else {
console.log(`Fetch: file not found: ${url}`)
ohlc = []; // no file, then empty data
}
iFile = new Date(iDate);
iohlc = 0;
}
// Skip samples not for our time
for(; iohlc < ohlc.length; iohlc++ ) {
// if ( new Date(ohlc[iohlc][0]+'Z').getTime() >= iDate.getTime() ) break;
if ( ohlc[iohlc][0]*1000 >= iDate.getTime() ) break;
}
// console.log(`iohlc: ${iohlc}`);
// let ohlcDate = iohlc >= ohlc.length ? undefined : new Date(ohlc[iohlc][0]+'Z');
let ohlcDate = iohlc >= ohlc.length ? undefined : new Date(ohlc[iohlc][0]*1000);
// no ohlc sample file, or sample file exists and asking for sample beyond last sample, insert missing sample
const insert_missing_samples = false;
const visible_missing_samples = false;
if (ohlcDate == undefined) {
bar = {
time: iDate.getTime(),
}
if (visible_missing_samples) bar = Object.assign(bar, {
// Comment these to make invisible
open: 50,
high: 50,
low: 0,
close: 0,
});
if (!insert_missing_samples) bar = undefined;
}
// file exists, but ohlc sample not for this time, insert missing sample
else if ( iDate.getTime() != ohlcDate.getTime() ) {
bar = {
time: iDate.getTime(),
}
if (visible_missing_samples) bar = Object.assign(bar, {
open: 100,
high: 100,
low: 0,
close: 0,
});
if (!insert_missing_samples) bar = undefined;
}
// Copy ohlc sample
else {
bar = {
time: iDate.getTime(),
open: ohlc[iohlc][1] ?? ohlc[iohlc][4], // open
high: ohlc[iohlc][2] ?? ohlc[iohlc][4], // high
low: ohlc[iohlc][3] ?? ohlc[iohlc][4], // low
close: ohlc[iohlc][4], // close
}
iohlc++;
}
if (bar != undefined) bars.push(bar);
// Increment loop variable
if (supported_res.indexOf(res)<supported_res.indexOf('1D')) { // <1day
const mins = parseInt(res);
iDate.setUTCMinutes(iDate.getUTCMinutes()+mins)
} else if (res=='1W') { // 1W
iDate.setUTCDate(iDate.getUTCDate()+7);
} else { // <1W >1day
iDate.setUTCDate(iDate.getUTCDate()+1);
}
}
// noData should be set only if no bars are in the requested period and earlier.
// In our case, we are guaranteed to have contiguous samples.
// So we only return no bars (bars.length==0) if:
// 1. period is entirely before first data available.
// 2. period is entirely after last data available.
// Returning noData based on bars.length works perfectly assuming that TV never asks for case 2.
// This is probably not a safe assumption. The alternative would be to search
// backward to find beginning of history. How far to search?
let noData = bars.length == 0;
if (noData) console.log("noData == true!");
return [bars, {noData}];
}