All time selectors work for OHLC

This commit is contained in:
7400
2024-02-11 11:34:09 -08:00
parent 16cce66fba
commit 00ac45dafc
3 changed files with 94 additions and 86 deletions

View File

@@ -30,7 +30,7 @@ export function initWidget(el) {
// debug: true, // debug: true,
autosize: true, autosize: true,
symbol: 'AAPL', symbol: 'AAPL',
// symbol: 'Bitfinex:BTC/USD', // use this for ohlc // symbol: 'Uniswap:WETH/USD', // use this for ohlc
interval: '1D', interval: '1D',
container: el, container: el,
datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"), datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"),

View File

@@ -1,12 +1,3 @@
// import {
// makeApiRequest,
// generateSymbol,
// parseFullSymbol,
// } from './helpers.js';
// import {
// subscribeOnStream,
// unsubscribeFromStream,
// } from './streaming.js';
import {jBars} from './jBars.js'; import {jBars} from './jBars.js';
const lastBarsCache = new Map(); const lastBarsCache = new Map();
@@ -14,14 +5,14 @@ const lastBarsCache = new Map();
// DatafeedConfiguration implementation // DatafeedConfiguration implementation
const configurationData = { const configurationData = {
// Represents the resolutions for bars supported by your datafeed // Represents the resolutions for bars supported by your datafeed
// supported_resolutions: ['1D', '1W', '1M'], supported_resolutions:
supported_resolutions: ['1D'], ['1', '3', '5', '10', '15', '30', '60', '120', '240', '480', '720', '1D', '2D', '3D', '1W'],
// The `exchanges` arguments are used for the `searchSymbols` method if a user selects the exchange // The `exchanges` arguments are used for the `searchSymbols` method if a user selects the exchange
exchanges: [{ exchanges: [{
value: 'Bitfinex', value: 'Uniswap',
name: 'Bitfinex', name: 'Uniswap',
desc: 'Bitfinex', desc: 'Uniswap',
}, },
], ],
// The `symbols_types` arguments are used for the `searchSymbols` method if a user selects this symbol type // The `symbols_types` arguments are used for the `searchSymbols` method if a user selects this symbol type
@@ -34,13 +25,11 @@ const configurationData = {
// Obtains all symbols for all exchanges supported by CryptoCompare API // Obtains all symbols for all exchanges supported by CryptoCompare API
async function getAllSymbols() { async function getAllSymbols() {
// const data = await makeApiRequest('data/v3/all/exchanges');
// let allSymbols = [];
return [{ return [{
symbol: 'BTC/USD', symbol: 'WETH/USD',
full_name: 'Bitfinex:BTC/USD', full_name: 'Uniswap:WETH/USD',
description: 'BTC/USD', description: 'WETH/USD 42161/0xC31E54c7a869B9Fc',
exchange: 'Bitfinex', exchange: 'Uniswap',
type: 'crypto'} type: 'crypto'}
]; ];
} }
@@ -96,9 +85,9 @@ export default {
exchange: symbolItem.exchange, exchange: symbolItem.exchange,
minmov: 1, minmov: 1,
pricescale: 100, pricescale: 100,
has_intraday: false, has_intraday: true, // Added to allow less than one day to work
has_no_volume: true, has_no_volume: true,
has_weekly_and_monthly: false, has_weekly_and_monthly: true, // Added to allow greater than one day to work
supported_resolutions: configurationData.supported_resolutions, supported_resolutions: configurationData.supported_resolutions,
volume_precision: 2, volume_precision: 2,
data_status: 'streaming', data_status: 'streaming',
@@ -112,17 +101,8 @@ export default {
const { from, to, firstDataRequest } = periodParams; const { from, to, firstDataRequest } = periodParams;
console.log('[getBars]: Method call', symbolInfo, resolution, from, to); console.log('[getBars]: Method call', symbolInfo, resolution, from, to);
// const parsedSymbol = parseFullSymbol(symbolInfo.full_name);
// const urlParameters = {
// e: parsedSymbol.exchange,
// fsym: parsedSymbol.fromSymbol,
// tsym: parsedSymbol.toSymbol,
// toTs: to,
// limit: 2000,
// };
try { try {
var bars = await jBars(from, to, resolution); var bars = await jBars(from, to, resolution); // This is the one that does all the work
if (firstDataRequest) { if (firstDataRequest) {
lastBarsCache.set(symbolInfo.full_name, { lastBarsCache.set(symbolInfo.full_name, {
@@ -147,20 +127,9 @@ export default {
onResetCacheNeededCallback, onResetCacheNeededCallback,
) => { ) => {
console.log('[subscribeBars]: Method call with subscriberUID:', subscriberUID); console.log('[subscribeBars]: Method call with subscriberUID:', subscriberUID);
// throw Error('subscribeBars unimplemented');
// subscribeOnStream(
// symbolInfo,
// resolution,
// onRealtimeCallback,
// subscriberUID,
// onResetCacheNeededCallback,
// lastBarsCache.get(symbolInfo.full_name),
// );
}, },
unsubscribeBars: (subscriberUID) => { unsubscribeBars: (subscriberUID) => {
console.log('[unsubscribeBars]: Method call with subscriberUID:', subscriberUID); console.log('[unsubscribeBars]: Method call with subscriberUID:', subscriberUID);
// throw Error('unsubscribeBars unimplemented');
// unsubscribeFromStream(subscriberUID);
}, },
}; };

View File

@@ -10,97 +10,136 @@ export async function jBars (from, to, res) {
const contract = "0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"; const contract = "0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443";
// check parameters // check parameters
// console.assert(fromDate.getUTCHours() == 0, "hours should be zero");
if (res != "1D") throw Error("Only 1D resolution currently supported"); // console.assert(fromDate.getUTCMinutes() == 0, "minutes should be zero");
// console.assert(fromDate.getUTCSeconds() == 0, "seconds should be zero");
console.assert(fromDate.getUTCHours() == 0, "hours should be zero"); // console.assert(fromDate.getUTCMilliseconds() == 0, "milliseconds should be zero");
console.assert(fromDate.getUTCMinutes() == 0, "minutes should be zero");
console.assert(fromDate.getUTCSeconds() == 0, "seconds should be zero");
console.assert(fromDate.getUTCMilliseconds() == 0, "milliseconds should be zero");
// Spoof data // Spoof data
var spoof; // var spoof;
{ // {
const yr = "2022"; // const yr = "2022";
const mo = "01"; // const mo = "01";
const url = `/ohlc/42161/${contract}/${res}/${yr}/${contract}-${res}-${yr}${mo}.json` // const url = `/ohlc/42161/${contract}/${res}/${yr}/${contract}-${res}-${yr}${mo}.json`
const response = await fetch(url); // const response = await fetch(url);
spoof = await response.json(); // spoof = await response.json();
} // }
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;
var bars = []; var bars = [];
for ( // Once around for each sample in from-to range for ( // Once around for each sample in from-to range
let iDate = fromDate, let iDate = fromDate,
// loop state // loop state
iMonth = -1, iFile = undefined,
iolhc = 0, iohlc = 0,
ohlc; ohlc;
iDate < toDate; iDate < toDate;
iDate.setUTCDate(iDate.getUTCDate()+1)
) { ) {
let bar = undefined; let bar = undefined;
// Fetch one sample file as needed // 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
) {
if (iMonth != iDate.getUTCMonth()) { const fres = file_res[supported_res.indexOf(res)]
const yr = iDate.getUTCFullYear(); const yr = iDate.getUTCFullYear();
const mo = String(iDate.getUTCMonth()+1).padStart(2, '0'); const yrdir = is_single_res ? "" : `/${yr}`;
const url = `/ohlc/42161/${contract}/${res}/${yr}/${contract}-${res}-${yr}${mo}.json` 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}` : "";
let url = `/ohlc/42161/${contract}/${fres}${yrdir}/${contract}-${fres}${yrmo}${date}.json`;
let response = await fetch(url); let response = await fetch(url);
if (response.ok) { if (response.ok) {
ohlc = await response.json(); ohlc = await response.json();
} else { } else {
ohlc = []; // no file, then empty data ohlc = []; // no file, then empty data
} }
iMonth = iDate.getUTCMonth(); iFile = new Date(iDate);
iolhc = 0; iohlc = 0;
} }
let ohlcDate = iolhc >= ohlc.length ? undefined : new Date(ohlc[iolhc][0]+'Z'); // Skip samples not for our time
// no ohlc sample, insert a visible sample for(; iohlc < ohlc.length; iohlc++ ) {
if ( new Date(ohlc[iohlc][0]+'Z').getTime() >= iDate.getTime() ) break;
}
let ohlcDate = iohlc >= ohlc.length ? undefined : new Date(ohlc[iohlc][0]+'Z');
// no ohlc sample file, insert missing sample
const visible_missing_samples = true;
if (ohlcDate == undefined) { if (ohlcDate == undefined) {
bar = { bar = {
time: iDate.getTime(), time: iDate.getTime(),
open: 50,
high: 50,
low: 0,
close: 0,
} }
if (visible_missing_samples) bar = Object.assign(bar, {
// Comment these to make invisible
open: 50,
high: 50,
low: 0,
close: 0,
});
} }
// ohlc sample not for this time, insert invisible sample // file exists, but ohlc sample not for this time, insert missing sample
else if ( iDate.getTime() != ohlcDate.getTime() ) { else if ( iDate.getTime() != ohlcDate.getTime() ) {
bar = { bar = {
time: iDate.getTime(), time: iDate.getTime(),
// open: 100,
// high: 100,
// low: 0,
// close: 0,
} }
if (visible_missing_samples) bar = Object.assign(bar, {
open: 100,
high: 100,
low: 0,
close: 0,
});
// Copy ohlc sample // Copy ohlc sample
} else { } else {
bar = { bar = {
time: iDate.getTime(), time: iDate.getTime(),
open: ohlc[iolhc][1], open: ohlc[iohlc][1] ?? ohlc[iohlc][4], // open
high: ohlc[iolhc][2], high: ohlc[iohlc][2] ?? ohlc[iohlc][4], // high
low: ohlc[iolhc][3], low: ohlc[iohlc][3] ?? ohlc[iohlc][4], // low
close: ohlc[iolhc][4], close: ohlc[iohlc][4], // close
} }
iolhc++; iohlc++;
} }
if (bar==undefined) throw "bar==undefined"; if (bar != undefined) bars.push(bar);
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);
}
} }
return bars; return bars;