tv DataFeed rework

This commit is contained in:
tim
2024-08-28 18:57:58 -04:00
parent 55397c2b1c
commit 79a6822fd5
7 changed files with 468 additions and 403 deletions

View File

@@ -1,5 +1,8 @@
import {useStore} from "@/store/store.js";
import {nearestOhlcStart} from "@/charts/chart-misc.js";
import {ohlcStart} from "@/charts/chart-misc.js";
// support for Dexorder OHLC data files
function dailyFile(resName) {
@@ -61,27 +64,32 @@ function never(_timestamp) {
}
// noinspection PointlessArithmeticExpressionJS
const resolutions = [
{ period: 1, tvRes: '1', filename: dailyFile( '1m'), nextStart: nextDay, },
{ period: 3, tvRes: '3', filename: dailyFile( '3m'), nextStart: nextDay, },
{ period: 5, tvRes: '5', filename: dailyFile( '5m'), nextStart: nextDay, },
{ period: 10, tvRes: '10', filename: dailyFile('10m'), nextStart: nextDay, },
{ period: 15, tvRes: '15', filename: dailyFile('15m'), nextStart: nextDay, },
{ period: 30, tvRes: '30', filename: dailyFile('30m'), nextStart: nextDay, },
{ period: 60, tvRes: '60', filename: monthlyFile( '1H'), nextStart: nextMonth, },
{ period: 120, tvRes: '120', filename: monthlyFile( '2H'), nextStart: nextMonth, },
{ period: 240, tvRes: '240', filename: monthlyFile( '4H'), nextStart: nextMonth, },
{ period: 480, tvRes: '480', filename: monthlyFile( '8H'), nextStart: nextMonth, },
{ period: 720, tvRes: '720', filename: monthlyFile('12H'), nextStart: nextMonth, },
{ period: 1440, tvRes: '1D', filename: yearlyFile( '1D'), nextStart: nextYear, },
{ period: 2880, tvRes: '2D', filename: yearlyFile( '2D'), nextStart: nextYear, },
{ period: 4320, tvRes: '3D', filename: yearlyFile( '3D'), nextStart: nextYear, },
{ period: 10080, tvRes: '1W', filename: singleFile( '1W'), nextStart: never, },
{ seconds: 1 * 60, name: '1m', tvRes: '1', filename: dailyFile( '1m'), nextStart: nextDay, },
{ seconds: 3 * 60, name: '3m', tvRes: '3', filename: dailyFile( '3m'), nextStart: nextDay, },
{ seconds: 5 * 60, name: '5m', tvRes: '5', filename: dailyFile( '5m'), nextStart: nextDay, },
{ seconds: 10 * 60, name: '10m', tvRes: '10', filename: dailyFile('10m'), nextStart: nextDay, },
{ seconds: 15 * 60, name: '15m', tvRes: '15', filename: dailyFile('15m'), nextStart: nextDay, },
{ seconds: 30 * 60, name: '30m', tvRes: '30', filename: dailyFile('30m'), nextStart: nextDay, },
{ seconds: 60 * 60, name: '1H', tvRes: '60', filename: monthlyFile( '1H'), nextStart: nextMonth, },
{ seconds: 120 * 60, name: '2H', tvRes: '120', filename: monthlyFile( '2H'), nextStart: nextMonth, },
{ seconds: 240 * 60, name: '4H', tvRes: '240', filename: monthlyFile( '4H'), nextStart: nextMonth, },
{ seconds: 480 * 60, name: '8H', tvRes: '480', filename: monthlyFile( '8H'), nextStart: nextMonth, },
{ seconds: 720 * 60, name: '12H', tvRes: '720', filename: monthlyFile('12H'), nextStart: nextMonth, },
{ seconds: 1440 * 60, name: '1D', tvRes: '1D', filename: yearlyFile( '1D'), nextStart: nextYear, },
{ seconds: 2880 * 60, name: '2D', tvRes: '2D', filename: yearlyFile( '2D'), nextStart: nextYear, },
{ seconds: 4320 * 60, name: '3D', tvRes: '3D', filename: yearlyFile( '3D'), nextStart: nextYear, },
{ seconds: 10080 * 60, name: '1W', tvRes: '1W', filename: singleFile( '1W'), nextStart: never, },
]
const resMap = {}
const tvResMap = {}
for (const res of resolutions)
resMap[res.tvRes] = res
tvResMap[res.tvRes] = res
const dxoResMap = {}
for (const res of resolutions)
dxoResMap[res.name] = res
const seriesStarts = {}
@@ -107,15 +115,19 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
// console.log('loadOHLC', tvRes, new Date(1000*from), new Date(1000*to), symbol, contract);
let chainId
let bars = [];
let inverted = symbol.inverted;
let inverted = false;
let baseURL
let latest = null // latest time, price
function fill(end, period) {
if (latest===null) return
const [start, price] = latest
for (let now=nearestOhlcStart(start, period*60); now < end; now += period )
const periodSecs = period * 60
end = ohlcStart(end, periodSecs)
for (let now=ohlcStart(start+periodSecs, periodSecs); now < end; now += periodSecs ) {
bars.push({time:now * 1000, open:price, high:price, low:price, close:price})
latest = [now, price]
}
}
if (symbol.x?.data) {
@@ -130,7 +142,7 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
}
baseURL += `${chainId}/${contract}/`
const res = resMap[tvRes]
const res = tvResMap[tvRes]
const fetches = []
let start = from
if (!(baseURL in seriesStarts)) {
@@ -164,7 +176,6 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
let lineNum = 0
response.split('\n').forEach((line) => {
lineNum++
// console.log(`processing line ${lineNum}`, line)
const row = line.split(',')
let time, open, high, low, close=null
switch (row.length) {
@@ -204,8 +215,9 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
close = parseFloat(row[4])
if (inverted) {
open = 1/open
high = 1/high
low = 1/low
const h = high
high = 1/low
low = 1/h
close = 1/close
}
break
@@ -214,10 +226,8 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
break
}
if (close!==null) {
// console.log(`filling up to ${time}`)
fill(time, res.period)
fill(time, res.seconds)
const bar = {time:time*1000, open, high, low, close};
// console.log('pushing bar', bar)
bars.push(bar)
latest = [time, close]
}
@@ -226,20 +236,21 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
}
// else { console.log('response was empty') }
}
fill(to, res.period)
// 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!");
// console.log('bars', bars)
return [bars, {noData}];
fill(to, res.seconds)
return bars
}
export function tvResolutionToPeriodString(res) {
return tvResMap[res].name
}
export function convertTvResolution(res) {
return tvResMap[res]
}
export function resForName(name) {
return dxoResMap[name]
}