brighter-trading/src/static/charts.js

224 lines
8.8 KiB
JavaScript

class Charts {
constructor(idata) {
// Unpack the initialization data.
this.chart1_id = idata.chart1_id;
this.chart2_id = idata.chart2_id;
this.chart3_id = idata.chart3_id;
this.chart4_id = idata.chart4_id;
this.trading_pair = idata.trading_pair;
this.price_history = idata.price_history;
/* A list of bound charts this is necessary for maintaining a dynamic
number of charts with their position and zoom factors bound.*/
this.bound_charts=[];
// Only the main chart is created by default.
this.create_main_chart();
}
create_main_chart() {
// Pass the id of the element to create the main chart in.
// This function returns the main chart object.
this.chart_1 = this.create_chart(this.chart1_id);
// Display the trading pair as a watermark overlaying the chart.
this.addWatermark(this.chart_1, this.trading_pair);
// - Create the candle stick series for our chart
this.candleSeries = this.chart_1.addCandlestickSeries();
// Initialize the candlestick series if price_history is available
if (this.price_history && this.price_history.length > 0) {
this.candleSeries.setData(this.price_history);
console.log('Candle series init:', this.price_history);
} else {
console.error('Price history is not available or is empty.');
}
this.bind_charts(this.chart_1);
}
update_main_chart(new_candle){
// Update candlestick series
this.candleSeries.update(new_candle);
}
create_RSI_chart(){
this.chart2 = this.create_chart(this.chart2_id, 100);
this.set_priceScale(this.chart2, 0.3, 0.0);
// Put the name of the chart in a watermark in the chart.
this.addWatermark(this.chart2, 'RSI');
// Todo: Not sure how to set this
//this.chart2.applyOptions({ priceRange: {minValue:0,maxValue:100} });
this.bind_charts(this.chart2);
}
create_MACD_chart(){
this.chart3 = this.create_chart(this.chart3_id, 100);
this.addWatermark(this.chart3, 'MACD');
this.bind_charts(this.chart3);
}
create_PercentB_chart(){
this.chart4 = this.create_chart(this.chart4_id, 100);
this.set_priceScale(this.chart4, 0.3, 0.0);
// Put the name of the chart in a watermark
this.addWatermark(this.chart4, '%B');
this.bind_charts(this.chart4);
}
create_chart(target_id, height=500){
// Accepts a target element to place the chart in.
// Returns the chart object.
let container = document.getElementById(target_id);
//Create a lightweight chart object.
let chart = LightweightCharts.createChart(container, {
width: 1000,
height: height,
crosshair: {
mode: LightweightCharts.CrosshairMode.Normal,
},
priceScale: {
borderColor: 'rgba(197, 203, 206, 0.8)',
},
timeScale: {
borderColor: 'rgba(197, 203, 206, 0.8)',
timeVisible: true,
secondsVisible: false,
barSpacing: 6
},
handleScroll: true
});
return chart;
}
set_priceScale(chart, top, bottom){
chart.priceScale('right').applyOptions({
scaleMargins: {
top: top,
bottom: bottom,
},
});
}
addWatermark(chart,text){
chart.applyOptions({
watermark: {visible: true,
color: '#DBC29E',
text: text,
fontSize: 30,
fontFamily: 'Roboto',
fontStyle: 'bold',
vertAlign: 'center'
}
});
}
bind_charts(chart){
// keep a list of charts and bind all their position and spacing.
// Add (arg1) to bound_charts
this.add_to_list(chart);
// Get the number of objects in bound_charts
let bcl = Object.keys(this.bound_charts).length;
// if bound_charts has two element in it bind them
if (bcl == 2) { this.bind2charts(); }
// if bound_charts has three elements in it bind them
if (bcl == 3) { this.bind3charts(); }
// if bound_charts has four elements in it bind them
if (bcl == 4) { this.bind4charts(); }
return;
}
add_to_list(chart){
// If the chart isn't already included in the list, add it.
if ( !this.bound_charts.includes(chart) ){
this.bound_charts.push(chart);
}
}
bind2charts(){
//On change in chart 1 change chart 2
let syncHandler1 = (e) => {
// Get the barSpacing(zoom) and position of 1st chart.
let barSpacing1 = this.bound_charts[0].timeScale().getBarSpacing();
let scrollPosition1 = this.bound_charts[0].timeScale().scrollPosition();
// Apply barSpacing(zoom) and position to 2nd chart.
this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 });
}
this.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler1);
//On change in chart 2 change chart 1
let syncHandler2 = (e) => {
// Get the barSpacing(zoom) and position of chart 2
let barSpacing2 = this.bound_charts[1].timeScale().getBarSpacing();
let scrollPosition2 = this.bound_charts[1].timeScale().scrollPosition();
// Apply barSpacing(zoom) and position to chart 1
this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 });
}
this.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2);
}
bind3charts(){
//On change to chart 1 change chart 2 and 3
let syncHandler = (e) => {
// Get the barSpacing(zoom) and position of chart 1
let barSpacing1 = this.bound_charts[0].timeScale().getBarSpacing();
let scrollPosition1 = this.bound_charts[0].timeScale().scrollPosition();
// Apply barSpacing(zoom) and position to new chart
this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 });
this.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition1, barSpacing: barSpacing1 });
}
this.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncHandler);
//On change to chart 2 change chart 1 and 3
let syncHandler2 = (e) => {
// Get the barSpacing(zoom) and position of chart 2
let barSpacing2 = this.bound_charts[1].timeScale().getBarSpacing();
let scrollPosition2 = this.bound_charts[1].timeScale().scrollPosition();
// Apply barSpacing(zoom) and position to chart 1 and 3
this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 });
this.bound_charts[2].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 });
}
this.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncHandler2);
//On change to chart 3 change chart 1 and 2
let syncHandler3 = (e) => {
// Get the barSpacing(zoom) and position of new chart
let barSpacing2 = this.bound_charts[2].timeScale().getBarSpacing();
let scrollPosition2 = this.bound_charts[2].timeScale().scrollPosition();
// Apply barSpacing(zoom) and position to parent chart
this.bound_charts[0].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 });
this.bound_charts[1].timeScale().applyOptions({ rightOffset: scrollPosition2, barSpacing: barSpacing2 });
}
this.bound_charts[2].timeScale().subscribeVisibleTimeRangeChange(syncHandler3);
}
bind4charts(){
// Sync all 4 charts together
let syncFromChart = (sourceIndex) => {
return (e) => {
let barSpacing = this.bound_charts[sourceIndex].timeScale().getBarSpacing();
let scrollPosition = this.bound_charts[sourceIndex].timeScale().scrollPosition();
for (let i = 0; i < 4; i++) {
if (i !== sourceIndex) {
this.bound_charts[i].timeScale().applyOptions({ rightOffset: scrollPosition, barSpacing: barSpacing });
}
}
}
}
this.bound_charts[0].timeScale().subscribeVisibleTimeRangeChange(syncFromChart(0));
this.bound_charts[1].timeScale().subscribeVisibleTimeRangeChange(syncFromChart(1));
this.bound_charts[2].timeScale().subscribeVisibleTimeRangeChange(syncFromChart(2));
this.bound_charts[3].timeScale().subscribeVisibleTimeRangeChange(syncFromChart(3));
}
}