hi i want charting stock data in web page.
i found sample project in github
https://github.com/tvjsx/tvjs-xp
i change code and connect the binance and receive and charting real time data.
i have some problem after add online receive data chart lagend bouttun not work and i cant add layer.
please help me.
thanks
<trading-vue :data="dc" :width="this.width" :height="this.height"
title-txt="TVJS XP" :key="resetkey"
:chart-config="{DEFAULT_LEN:70}"
ref="tvjs"
:legend-buttons="['display', 'settings', 'up', 'down', 'add', 'remove']"
:toolbar="true"
:index-based="index_based"
:color-back="colors.colorBack"
:color-grid="colors.colorGrid"
:color-text="colors.colorText"
:extensions="ext"
:overlays="ovs"
:x-settings="xsett">
</trading-vue>
<span class="gc-mode">
<input type="checkbox" v-model="index_based">
<label>Index Based</label>
</span>
export default {
name: 'DataHelper',
icon: '⚡',
description: 'Real-time updates. Play with DataCube in the console',
props: ['night', 'ext', 'resetkey'],
components: {
TradingVue
},
mounted() {
window.addEventListener('resize', this.onResize)
this.onResize()
// Load the last data chunk & init DataCube:
let now = Utils.now()
this.load_chunk([now - Const.HOUR4, now]).then(data => {
this.dc = new DataCube({
ohlcv: data['dc.data'],
// onchart: [{
// type: 'EMAx6',
// name: 'Multiple EMA',
// data: []
// }],
offchart: [
// {
// type: 'BuySellBalance',
// name: 'Buy/Sell Balance, $lookback',
// data: [],
// settings: {}
// },
{
name: "RSI, 20",
type: "Range",
data: [],
settings: {
"upper": 70,
"lower": 30,
"backColor": "#9b9ba316",
"bandColor": "#666"
}
},
],
datasets: [{
type: 'Trades',
id: 'binance-btcusdt',
data: []
}]
}, { aggregation: 100 })
// Register onrange callback & And a stream of trades
this.dc.onrange(this.load_chunk)
this.$refs.tvjs.resetChart()
this.stream = new Stream(WSS)
this.stream.ontrades = this.on_trades
window.dc = this.dc // Debug
window.tv = this.$refs.tvjs // Debug
})
},
methods: {
onResize(event) {
this.width = window.innerWidth
this.height = window.innerHeight - 50
},
// New data handler. Should return Promise, or
// use callback: load_chunk(range, tf, callback)
async load_chunk(range) {
let [t1, t2] = range
let x = 'BTCUSDT'
let q = `${x}&interval=1m&startTime=${t1}&endTime=${t2}`
let r = await fetch(URL + q).then(r => r.json())
return this.format(this.parse_binance(r))
},
// Parse a specific exchange format
parse_binance(data) {
if (!Array.isArray(data)) return []
return data.map(x => {
for (var i = 0; i < x.length; i++) {
x[i] = parseFloat(x[i])
}
return x.slice(0,6)
})
},
format(data) {
// Each query sets data to a corresponding overlay
return {
'dc.data': data
// other onchart/offchart overlays can be added here,
// but we are using Script Engine to calculate some:
// see EMAx6 & BuySellBalance
}
},
on_trades(trade) {
this.dc.update({
t: trade.T, // Exchange time (optional)
price: parseFloat(trade.p), // Trade price
volume: parseFloat(trade.q), // Trade amount
'datasets.binance-btcusdt': [ // Update dataset
trade.T,
trade.m ? 0 : 1, // Sell or Buy
parseFloat(trade.q),
parseFloat(trade.p)
],
// ... other onchart/offchart updates
})
}
},
beforeDestroy() {
window.removeEventListener('resize', this.onResize)
if (this.stream) this.stream.off()
},
computed: {
colors() {
return this.$props.night ? {} : {
colorBack: '#fff',
colorGrid: '#eee',
colorText: '#333'
}
},
},
data() {
return {
dc: {},
width: window.innerWidth,
height: window.innerHeight,
index_based: false,
xsett: {
'grid-resize': { min_height: 30 }
},
ovs: Object.values(Overlays),
}
}
}
Related
Actual behaviour Now a series of all days of the week is being built on the X-axis. like now: 2022-5-30 2022-5-31 2022-6-1 2022-6-2 2022-6-3 2022-6-4 2022-6-5 2022-6-6
Live demo with steps to reproduce
https://jsfiddle.net/5z1b9xnp/
let globalData = []; let finRez = [];
let chart;
let duration = 500; // Determines how long the animation between new points should be take
let startIterator = 1; // Determines how many points will be rendered on chart's init
let currentIterator = startIterator;
let maxIterator = 1;
let guiButton = document.getElementById('start');
let guiButtonState = 'Start';
let intervalId;
// Fetch data:
fetch('https://raw.githubusercontent.com/veleg/trade/main/trade.json')
.then(response => response.json())
.then(data => {
parseData(data);
createChart();
initEvents();
});
function initEvents() {
guiButton.addEventListener('click', function() {
if (guiButtonState === 'Stop') {
// User clicked "Stop" -> stop animation and allow to resume
intervalId = clearInterval(intervalId);
guiButton.innerText = guiButtonState = 'Resume';
} else {
// If animation has finished, recreate chart
if (guiButtonState === 'Restart') {
createChart();
}
guiButton.innerText = guiButtonState = 'Stop';
// Start animation:
redrawChart(currentIterator += 1);
intervalId = setInterval(function() {
// If we reached last available point, stop animation:
if (currentIterator === maxIterator) {
intervalId = clearInterval(intervalId);
currentIterator = startIterator;
guiButton.innerText = guiButtonState = 'Restart';
} else {
redrawChart(currentIterator += 1);
}
}, duration);
}
});
}
function redrawChart(index) {
// Set new subtitle on every redraw
chart.setTitle(null, {
text: ' Заработано: ' + globalData[0].data[index][1]
}, false);
const newValues = globalData.map(series => series.data[index][1]);
const maxIndex = newValues.indexOf(Math.max.apply(null, newValues));
// To each series, add a point:
chart.series.forEach(
(series, seriesIndex) => {
const enabled = maxIndex === seriesIndex && ((index < 5) || (index % 5 === 0));
series.addPoint(
{
x: globalData[seriesIndex].data[index][0],
y: globalData[seriesIndex].data[index][1]
<!-- dataLabels: { -->
<!-- enabled -->
<!-- }, -->
<!-- marker: { -->
<!-- enabled -->
<!-- } -->
},
false,
false,
false
);
}
);
// Now, once everything is updated, redraw chart:
chart.redraw({
duration
});
}
function parseData(data) {
Highcharts.objectEach(
data,
// Prepare Highcharts data-format:
// series: [{
// data: [ [x, y], [x, y], ..., [x, y]]
// }]
(countryData, country) => {
if (country !== 'Diamond Princess' && country !== 'Holy See') {
globalData.push({
name: country,
data: countryData.map(p => [Date.parse(p.date), p.recovered / getCountryPopulation(country)])
<!-- data: countryData.map(p => [p.date, p.recovered / getCountryPopulation(country)]), -->
<!-- datas: countryData.date, -->
<!-- datass: countryData.map(p => [p.date, p.date]) -->
});
}
}
);
// Sort and limit dataset:
globalData = globalData
.sort((countryA, countryB) => {
let countryALen,
countryBLen;
if (!countryA || !countryA.data || countryA.data.length === 0) {
return 1;
}
if (!countryB || !countryB.data || countryB.data.length === 0) {
return -1;
}
return countryB.data[countryB.data.length - 1][1] - countryA.data[countryA.data.length - 1][1];
})
.splice(0, 8);
maxIterator = Math.max.apply(null, globalData.map(series => series.data.length - 1));
}
function createChart() {
function format(y) {
return y.toFixed(2);
}
chart = Highcharts.chart('container', {
chart: {
type: 'spline',
marginLeft: 100
},
legend: {
layout: 'proximate',
align: 'right'
},
title: {
floating: true,
align: 'left',
x: 93,
y: 20,
text: 'Confirmed cases per country per 1000 inhabitants'
},
subtitle: {
floating: true,
align: 'left',
y: 60,
x: 90,
text: ' Заработано: ' + globalData[0].data[0][1],
style: {
fontSize: '20px'
}
},
tooltip: {
split: true,
pointFormatter: function() {
<!-- var value = format(this.y); -->
<!-- return `<span style="color:${this.color}">●</span> ${this.series.name}: <b>${value}</b><br/>`; -->
}
},
yAxis: {
title: {
text: ''
},
maxPadding: 0.2,
softMax: 1
},
xAxis: {
gridLineWidth: 2,
min: globalData[0].data[0][0],
minRange: 7 * 24 * 3600 * 1000,
type: 'datetime'
<!-- categories: [1] -->
},
plotOptions: {
series: {
animation: {
duration
},
<!-- marker: { -->
<!-- symbol: 'circle' -->
<!-- }, -->
dataLabels: {
formatter: function() {
return format(this.y);
}
}
}
},
series: globalData.map(series => {
return {
name: series.name,
data: series.data.slice(0, startIterator).map(point => {
return { x: point[0], y: point[1] }
})
}
})
});
}
function getCountryPopulation(country) {
return {
"Заработано": 1,
"Финансовый результат": 1
}[country];
}
Product version Highcharts JS v10.3.2 (2022-11-28)
It is necessary to skip days on the X axis that are not in the JSON file. need: 2022-5-30 2022-5-31 2022-6-1 2022-6-2 2022-6-3 2022-6-6
I don't need to filter JSON. The JSON file just indicates what I need, but the script itself substitutes dates that are not in JSON.
Be careful, dates are skipped in JSON, and the library inserts missing dates. I need only those dates that are specified in JSON, it can be weekends or two days a week.
uplot is used to dislay timeseries data from VictoriaMetrics database.
For the backend Node-Red is used to forward and recieve the query with node-red-contrib-uibuilder.
It works basically and is very fast.
The problem is, when I try to zoom into the uplot graph, my browser (Chrome, Firefox, Edge) freezes. It seems to run out of memory.
Here are parts of my code, using svelte.
<script>
import { onMount } from "svelte";
import { query } from "../lib/uibStore";
import { transformToUplot } from "../lib/helper";
// import uPlot from "uplot";
import Browsebar from "../components/Browsebar.svelte";
import TimerangeSelect from "../components/TimerangeSelect.svelte";
let uplotdiv; //
let opts = {
title: "Temperaturen1",
id: "chart1",
class: "my-chart",
width: 1000,
height: 600,
series: [
{},
{
show: true, // initial toggled state (optional)
spanGaps: true,
label: "RT",
stroke: "red", // series style
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
{
show: true,
spanGaps: true,
label: "KT",
stroke: "green",
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
{
show: true,
spanGaps: true,
label: "VT",
stroke: "blue",
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
],
scales: {
x: { time: true },
Temperature: {
auto: true,
// range: [-10, 20],
side: 3,
},
},
axes: [
{},
{
scale: "Temperature",
values: (self, ticks) => ticks.map((rawValue) => rawValue.toFixed(1) + "°C"),
},
],
cursor: { drag: { x: true, y: true } },
};
let plot; // = new uPlot(opts);
let uPlot;
let d = [[0], [0], [0], [0]];
let resolved = false;
$: uisend($query); //use uibilder.send, if query changes which occurs when timerange or nav index changes
//send a victoriametrics query to the backend, _q is part of query
function uisend(_q) {
// Example 'uvr_prozess_celsius{ort="1"}&start=-3d&step=60s'
uibuilder.send({ topic: "getVMetrics", payload: _q });
}
onMount(async () => {
uisend($query);
const uplotModule = await import("https://unpkg.com/uplot#1.6.22/dist/uPlot.esm.js");
uPlot = uplotModule.default;
plot = new uPlot(opts, [[0], [0], [0], [0]], uplotdiv);
});
uibuilder.onChange("msg", function (msg) {
// load Metrics via Node-Red's uibuilder, serverside
if (msg.topic === "getVMetrics") {
resolved = true;
if (msg.payload.data.result.length > 0) {
d = transformToUplot(msg.payload.data);
plot.setData(d);
}
}
});
</script>
<svelte:head>
<link rel="stylesheet" href="https://unpkg.com/uplot#1.6.22/dist/uPlot.min.css" />
</svelte:head>
<Browsebar>
<TimerangeSelect />
</Browsebar>
<hr />
<div bind:this={uplotdiv} />
{#if resolved}
<code>{$query}</code>
{:else}
<h4>lade Metriken... {$query}</h4>
{/if}
<hr />
Has anyone experienced freezing with uplot? What did you do?
Lucky me, I found the problem. It had to do with the way I transformed the victoriametrics data. On every timestamp I did Number(timestamp).toFixed(0). Without toFixed(0) it is working now. :)
//transform raw data from metrics query to the uplot format
export function transformToUplot(dt) {
let udata = []; //2d data array, conforming uPlot
let tsd = []; //timestamp array
//from first result take only the timestamps
for (let t of dt.result[0].values) {
// tsd.push(Number(t[0]).toFixed(0)); //this was bad!!!!, it lead to freezing
tsd.push(Number(t[0]));
}
udata.push(tsd);
//then the values
for (let r of dt.result) {
let sd = [];
for (let d of r.values) {
let val = Number(d[1]);
sd.push(val);
}
udata.push(sd);
}
return udata;
}
Thanks for your interest!
I have this Vue component BarChart.vue which is from
https://github.com/apexcharts/vue3-apexcharts
The script portion of this component is as follows;
<script>
/* eslint-disable */
export default {
name: "BarExample",
data: function() {
return {
chartOptions: {
plotOptions: {
bar: {
horizontal: true
}
},
xaxis: {
categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
}
},
series: [
{
name: "series-1",
data: [30, 40, 45, 50, 49, 60, 70, 91]
}
]
};
},
methods: {
updateChart() {
const max = 90;
const min = 20;
const newData = this.series[0].data.map(() => {
return Math.floor(Math.random() * (max - min + 1)) + min;
});
const colors = ["#008FFB", "#00E396", "#FEB019", "#FF4560", "#775DD0"];
// Make sure to update the whole options config and not just a single property to allow the Vue watch catch the change.
this.chartOptions = {
colors: [colors[Math.floor(Math.random() * colors.length)]]
};
// In the same way, update the series option
this.series = [
{
data: newData
}
];
}
}
};
</script>
I want to bring updateChart() out of methods such that it is a separate function by itself.
This is what I did;
<script>
/* eslint-disable */
export default {
name: "BarExample",
data: function() {
return {
chartOptions: {
plotOptions: {
bar: {
horizontal: true
}
},
xaxis: {
categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
}
},
series: [
{
name: "series-1",
data: [30, 40, 45, 50, 49, 60, 70, 91]
}
]
};
},
methods: {
updateChart(),
}
};
updateChart() {
const max = 90;
const min = 20;
const newData = this.series[0].data.map(() => {
return Math.floor(Math.random() * (max - min + 1)) + min;
});
const colors = ["#008FFB", "#00E396", "#FEB019", "#FF4560", "#775DD0"];
// Make sure to update the whole options config and not just a single property to allow the Vue watch catch the change.
this.chartOptions = {
colors: [colors[Math.floor(Math.random() * colors.length)]]
};
// In the same way, update the series option
this.series = [
{
data: newData
}
];
}
}
</script>
I received an error Parsing error: Unexpected token ,
I am using vue3 and apexcharts.
Remove the () like since that means that you're running the method:
methods: {
updateChart,
}
or
methods: {
updateChart : updateChart,
}
I would like to answer my own question for the sake of completion as there were other syntax errors to be fixed.
I credit my answer to #Thomas in the comments section.
<script>
/* eslint-disable */
export default {
name: "BarExample",
data: function() {
return {
chartOptions: {
plotOptions: {
bar: {
horizontal: true
}
},
xaxis: {
categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
}
},
series: [
{
name: "series-1",
data: [30, 40, 45, 50, 49, 60, 70, 91]
}
]
};
},
methods: {
updateChart,
}
};
function updateChart() {
const max = 90;
const min = 20;
const newData = this.series[0].data.map(() => {
return Math.floor(Math.random() * (max - min + 1)) + min;
});
const colors = ["#008FFB", "#00E396", "#FEB019", "#FF4560", "#775DD0"];
// Make sure to update the whole options config and not just a single property to allow the Vue watch catch the change.
this.chartOptions = {
colors: [colors[Math.floor(Math.random() * colors.length)]]
};
// In the same way, update the series option
this.series = [
{
data: newData
}
];
}
</script>
I am trying to draw a chart fetching data from a Web Api. I can see some data is getting through but I still can not get the chart drawn. Pls let me know if I am doing something wrong.
import React, { Component } from 'react';
import './main.styles.scss';
import { createChart } from 'lightweight-charts';
async function getData() {
const response = await fetch(`http://localhost:3500/stock/app/RY`);
const data = await response.json();
return data.webApiData;
}
class Main extends Component {
ref = React.createRef();
componentDidMount() {
const chart = createChart(this.ref.current, {
width: 1400,
height: 550,
timeScale: {
timeVisible: true,
secondsVisible: false,
},
});
const candleSeries = chart.addCandlestickSeries();
const chartData = getData().then((data) => {
console.log(data);
candleSeries.setData(data);
});
}
render() {
return (
<div className="main">
<div className="trading">
<div className="box one">1</div>
<div className="box two" ref={this.ref}></div>
</div>
</div>
);
}
}
export default Main;
Here is the data on the console.log
Here is the error I am getting
It's because the format of the time attribute is not in the correct style.
It should be in YYYY-MM-DD style.
For example, you can try
const chartData = getData().then((data) => {
console.log(data);
candleSeries.setData(data.map((sD) => {
return {time: `${sD.time.year}-${sD.month > 9 ? sD.month : `0${sD.time.month}`}-${sD.day > 9 ? sD.day : `0${sD.day}`}`, ...sD}
}));
});
It is because time format is incorrect. It should be a date string.
From the candlestick chart docs:
Each item of the candlestick series is either an OHLC or a whitespace item.
So time must be in the following format.
const ohlcItem = {
time: '2018-06-25',
open: 10,
high: 12,
low: 9,
close: 11,
};
OR
// note it might be any type of series here
const series = chart.addHistogramSeries();
series.setData([
{ time: '2018-12-01', value: 32.51 },
{ time: '2018-12-02', value: 31.11 },
{ time: '2018-12-03', value: 27.02 },
{ time: '2018-12-04' }, // whitespace
{ time: '2018-12-05' }, // whitespace
{ time: '2018-12-06' }, // whitespace
{ time: '2018-12-07' }, // whitespace
{ time: '2018-12-08', value: 23.92 },
{ time: '2018-12-09', value: 22.68 },
{ time: '2018-12-10', value: 22.67 },
{ time: '2018-12-11', value: 27.57 },
{ time: '2018-12-12', value: 24.11 },
{ time: '2018-12-13', value: 30.74 },
]);
Using echarts how can I have a horizontal stack bar chart taking in consideration the following scenario, I have groups and group has employees of different categories: freelance, permanent, student...
I want to show per group: divided stacks of employee categories but is not clear in this case how do I handle the code
import echarts from 'echarts';
let groupChart = echarts.init(document.getElementById('chartGroups'));
axios.get('/chart')
.then(function (response) {
// handle success
let stack = {}
let re = response.data
let categories = Object.keys(re.stacks).map(function(key, index) {
return key
})
let arr = re.labels.map(item => ({
name: item,
type: 'bar',
stack: item,
label: {
normal: {
show: true,
position: 'insideRight'
}
},
data: []
}))
console.log(arr)
let app = {}
app.title = 'Employees';
let option = {
tooltip : {
trigger: 'axis',
axisPointer : {
type : 'shadow'
}
},
legend: {
data: re.labels
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: categories
},
series: arr
}
groupChart.setOption(option, true);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
})
and here is my codepen
I'm not sure but is this you want? here is jsFiddle
get data of each series by :
let data = [];
categories.forEach((category) => {
let index = re.stacks[category].findIndex(item => {
return item[label];
})
if (index !== -1) {
data.push(re.stacks[category][index][label]);
} else {
data.push(null)
}
})
and if you want stack on each category, the series.stack should remain the same, you can use any string like below:
{
name: label,
type: 'bar',
stack: 'anyString',
label: {
normal: {
show: true,
position: 'insideRight'
}
},
data: data
}