Convert chartOptions from getter to property

This will give us more control over repainting
This commit is contained in:
Matthias 2020-12-21 20:37:11 +01:00
parent 1ed52ef6a1
commit 45e167265f

View File

@ -52,6 +52,8 @@ export default class CandleChart extends Vue {
sellData = [] as Array<number>[]; sellData = [] as Array<number>[];
chartOptions: echarts.EChartOption = {};
@Watch('timeframe') @Watch('timeframe')
timeframeChanged() { timeframeChanged() {
this.signalsCalculated = false; this.signalsCalculated = false;
@ -60,6 +62,7 @@ export default class CandleChart extends Vue {
@Watch('dataset') @Watch('dataset')
datasetChanged() { datasetChanged() {
this.signalsCalculated = false; this.signalsCalculated = false;
this.updateChart();
} }
get strategy() { get strategy() {
@ -90,40 +93,18 @@ export default class CandleChart extends Vue {
return this.trades.filter((item: Trade) => item.pair === this.pair); return this.trades.filter((item: Trade) => item.pair === this.pair);
} }
get chartOptions() { mounted() {
if (!this.hasData) { this.initializeChartOptions();
return {}; }
}
// console.log(`Available Columns: ${this.dataset.columns}`); initializeChartOptions() {
// Find default columns (sequence might be different, depending on the strategy) this.chartOptions = {
const colDate = this.dataset.columns.findIndex((el) => el === '__date_ts');
const colOpen = this.dataset.columns.findIndex((el) => el === 'open');
const colHigh = this.dataset.columns.findIndex((el) => el === 'high');
const colLow = this.dataset.columns.findIndex((el) => el === 'low');
const colClose = this.dataset.columns.findIndex((el) => el === 'close');
const colVolume = this.dataset.columns.findIndex((el) => el === 'volume');
const colBuyData = this.dataset.columns.findIndex((el) => el === '_buy_signal_open');
const colSellData = this.dataset.columns.findIndex((el) => el === '_sell_signal_open');
const subplotCount =
'subplots' in this.plotConfig ? Object.keys(this.plotConfig.subplots).length : 0;
// console.log(`subplotcount: ${subplotCount}`);
// Always show ~250 candles max as starting point
const startingZoom = (1 - 250 / this.dataset.length) * 100;
const options: echarts.EChartOption = {
title: { title: {
text: `${this.strategy} - ${this.pair} - ${this.timeframe}`, text: `${this.strategy} - ${this.pair} - ${this.timeframe}`,
show: true, show: true,
}, },
backgroundColor: '#1b1b1b', backgroundColor: '#1b1b1b',
useUTC: this.useUTC, useUTC: this.useUTC,
dataset: {
source: this.dataset.data,
},
animation: false, animation: false,
legend: { legend: {
data: ['Candles', 'Volume', 'Buy', 'Sell'], data: ['Candles', 'Volume', 'Buy', 'Sell'],
@ -189,6 +170,47 @@ export default class CandleChart extends Vue {
splitLine: { show: false }, splitLine: { show: false },
}, },
], ],
// visualMap: {
// // TODO: this would allow to colorize volume bars (if we'd want this)
// // Needs green / red indicator column in data.
// show: true,
// seriesIndex: 1,
// dimension: 5,
// pieces: [
// {
// max: 500000.0,
// color: downColor,
// },
// {
// min: 500000.0,
// color: upColor,
// },
// ],
// },
};
this.updateChart();
}
updateChart() {
if (!this.hasData) {
return;
}
const colDate = this.dataset.columns.findIndex((el) => el === '__date_ts');
const colOpen = this.dataset.columns.findIndex((el) => el === 'open');
const colHigh = this.dataset.columns.findIndex((el) => el === 'high');
const colLow = this.dataset.columns.findIndex((el) => el === 'low');
const colClose = this.dataset.columns.findIndex((el) => el === 'close');
const colVolume = this.dataset.columns.findIndex((el) => el === 'volume');
const colBuyData = this.dataset.columns.findIndex((el) => el === '_buy_signal_open');
const colSellData = this.dataset.columns.findIndex((el) => el === '_sell_signal_open');
const subplotCount =
'subplots' in this.plotConfig ? Object.keys(this.plotConfig.subplots).length : 0;
const startingZoom = (1 - 250 / this.dataset.length) * 100;
const options: echarts.EChartOption = {
dataset: {
source: this.dataset.data,
},
grid: [ grid: [
{ {
left: MARGINLEFT, left: MARGINLEFT,
@ -221,23 +243,6 @@ export default class CandleChart extends Vue {
end: 100, end: 100,
}, },
], ],
// visualMap: {
// // TODO: this would allow to colorize volume bars (if we'd want this)
// // Needs green / red indicator column in data.
// show: true,
// seriesIndex: 1,
// dimension: 5,
// pieces: [
// {
// max: 500000.0,
// color: downColor,
// },
// {
// min: 500000.0,
// color: upColor,
// },
// ],
// },
series: [ series: [
{ {
name: 'Candles', name: 'Candles',
@ -302,24 +307,15 @@ export default class CandleChart extends Vue {
], ],
}; };
// this.createSignalData(colDate, colOpen, colBuy, colSell); // Merge this into original data
Object.assign(this.chartOptions, options);
// This will be merged into final plot config
// const subPlots = {
// legend: [] as string[],
// grid: [] as object[],
// yaxis: [] as object[],
// xaxis: [] as object[],
// xaxisIndex: [] as number[],
// series: [] as object[],
// };
if ('main_plot' in this.plotConfig) { if ('main_plot' in this.plotConfig) {
Object.entries(this.plotConfig.main_plot).forEach(([key, value]) => { Object.entries(this.plotConfig.main_plot).forEach(([key, value]) => {
const col = this.dataset.columns.findIndex((el) => el === key); const col = this.dataset.columns.findIndex((el) => el === key);
if (col > 1) { if (col > 1) {
if (options.legend && options.legend.data) { if (this.chartOptions.legend && this.chartOptions.legend.data) {
options.legend.data.push(key); this.chartOptions.legend.data.push(key);
} }
const sp: echarts.EChartOption.Series = { const sp: echarts.EChartOption.Series = {
name: key, name: key,
@ -335,8 +331,8 @@ export default class CandleChart extends Vue {
}, },
showSymbol: false, showSymbol: false,
}; };
if (options.series) { if (this.chartOptions.series) {
options.series.push(sp); this.chartOptions.series.push(sp);
} }
} else { } else {
console.log(`element ${key} for main plot not found in columns.`); console.log(`element ${key} for main plot not found in columns.`);
@ -349,8 +345,8 @@ export default class CandleChart extends Vue {
let plotIndex = 2; let plotIndex = 2;
Object.entries(this.plotConfig.subplots).forEach(([key, value]) => { Object.entries(this.plotConfig.subplots).forEach(([key, value]) => {
// define yaxis // define yaxis
if (options.yAxis && Array.isArray(options.yAxis)) { if (this.chartOptions.yAxis && Array.isArray(this.chartOptions.yAxis)) {
options.yAxis.push({ this.chartOptions.yAxis.push({
scale: true, scale: true,
gridIndex: plotIndex, gridIndex: plotIndex,
name: key, name: key,
@ -362,8 +358,8 @@ export default class CandleChart extends Vue {
splitLine: { show: false }, splitLine: { show: false },
}); });
} }
if (options.xAxis && Array.isArray(options.xAxis)) { if (this.chartOptions.xAxis && Array.isArray(this.chartOptions.xAxis)) {
options.xAxis.push({ this.chartOptions.xAxis.push({
type: 'time', type: 'time',
scale: true, scale: true,
gridIndex: plotIndex, gridIndex: plotIndex,
@ -375,13 +371,13 @@ export default class CandleChart extends Vue {
splitNumber: 20, splitNumber: 20,
}); });
} }
if (options.dataZoom) { if (this.chartOptions.dataZoom) {
options.dataZoom.forEach((el) => this.chartOptions.dataZoom.forEach((el) =>
el.xAxisIndex && Array.isArray(el.xAxisIndex) ? el.xAxisIndex.push(plotIndex) : null, el.xAxisIndex && Array.isArray(el.xAxisIndex) ? el.xAxisIndex.push(plotIndex) : null,
); );
} }
if (options.grid && Array.isArray(options.grid)) { if (this.chartOptions.grid && Array.isArray(this.chartOptions.grid)) {
options.grid.push({ this.chartOptions.grid.push({
left: MARGINLEFT, left: MARGINLEFT,
right: MARGINRIGHT, right: MARGINRIGHT,
bottom: `${plotIndex * 8}%`, bottom: `${plotIndex * 8}%`,
@ -389,8 +385,12 @@ export default class CandleChart extends Vue {
}); });
} }
Object.entries(value).forEach(([sk, sv]) => { Object.entries(value).forEach(([sk, sv]) => {
if (options.legend && options.legend.data && Array.isArray(options.legend.data)) { if (
options.legend.data.push(sk); this.chartOptions.legend &&
this.chartOptions.legend.data &&
Array.isArray(this.chartOptions.legend.data)
) {
this.chartOptions.legend.data.push(sk);
} }
// entries per subplot // entries per subplot
const col = this.dataset.columns.findIndex((el) => el === sk); const col = this.dataset.columns.findIndex((el) => el === sk);
@ -409,8 +409,8 @@ export default class CandleChart extends Vue {
}, },
showSymbol: false, showSymbol: false,
}; };
if (options.series && Array.isArray(options.series)) { if (this.chartOptions.series && Array.isArray(this.chartOptions.series)) {
options.series.push(sp); this.chartOptions.series.push(sp);
} }
} else { } else {
console.log(`element ${sk} was not found in the columns.`); console.log(`element ${sk} was not found in the columns.`);
@ -426,12 +426,11 @@ export default class CandleChart extends Vue {
// options.xAxis[options.xAxis.length - 1].axisLabel.show = true; // options.xAxis[options.xAxis.length - 1].axisLabel.show = true;
// options.xAxis[options.xAxis.length - 1].axisTick.show = true; // options.xAxis[options.xAxis.length - 1].axisTick.show = true;
// } // }
if (options.grid && Array.isArray(options.grid)) { if (this.chartOptions.grid && Array.isArray(this.chartOptions.grid)) {
// Last subplot is bottom // Last subplot is bottom
options.grid[options.grid.length - 1].bottom = '50px'; this.chartOptions.grid[this.chartOptions.grid.length - 1].bottom = '50px';
delete options.grid[options.grid.length - 1].top; delete this.chartOptions.grid[this.chartOptions.grid.length - 1].top;
} }
if (this.filteredTrades.length > 0) { if (this.filteredTrades.length > 0) {
// Show trades // Show trades
const trades: Array<string | number>[] = []; const trades: Array<string | number>[] = [];
@ -464,8 +463,8 @@ export default class CandleChart extends Vue {
const name = 'Trades'; const name = 'Trades';
const nameClose = 'Trades Close'; const nameClose = 'Trades Close';
if (options.legend && options.legend.data) { if (this.chartOptions.legend && this.chartOptions.legend.data) {
options.legend.data.push(name); this.chartOptions.legend.data.push(name);
} }
const sp: echarts.EChartOption.SeriesScatter = { const sp: echarts.EChartOption.SeriesScatter = {
name, name,
@ -477,11 +476,11 @@ export default class CandleChart extends Vue {
}, },
data: trades, data: trades,
}; };
if (options.series) { if (this.chartOptions.series) {
options.series.push(sp); this.chartOptions.series.push(sp);
} }
if (options.legend && options.legend.data) { if (this.chartOptions.legend && this.chartOptions.legend.data) {
options.legend.data.push(nameClose); this.chartOptions.legend.data.push(nameClose);
} }
const closeSeries: echarts.EChartOption.SeriesScatter = { const closeSeries: echarts.EChartOption.SeriesScatter = {
name: nameClose, name: nameClose,
@ -493,14 +492,12 @@ export default class CandleChart extends Vue {
}, },
data: tradesClose, data: tradesClose,
}; };
if (options.series) { if (this.chartOptions.series) {
options.series.push(closeSeries); this.chartOptions.series.push(closeSeries);
} }
} }
// console.log(options); console.log('chartOptions', this.chartOptions);
// TODO: Rebuilding this causes a full redraw for every new step
return options;
} }
// createSignalData(colDate: number, colOpen: number, colBuy: number, colSell: number): void { // createSignalData(colDate: number, colOpen: number, colBuy: number, colSell: number): void {