All time selectors work for OHLC
This commit is contained in:
@@ -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"),
|
||||||
|
|||||||
@@ -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);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 (iMonth != iDate.getUTCMonth()) {
|
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 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user