Close Editor Run Reset Auto Update CJS const lcjsTrader = require('@lightningchart/lcjs-trader')
const lcjs = require('@lightningchart/lcjs')
const { TechnicalAnalysisMethods } = lcjsTrader
const { AxisTickStrategies, ColorRGBA, IndividualPointFill, LinearGradientFill, LUT, PalettedFill } = lcjs
lcjsTrader.trader(TRADER_LICENSE).then(async (trader) => {
const exampleContainer = document.getElementById('chart') || document.body
if (exampleContainer === document.body) {
exampleContainer.style.width = '100vw'
exampleContainer.style.height = '100vh'
exampleContainer.style.margin = '0px'
}
exampleContainer.style.display = 'flex'
exampleContainer.style.flexDirection = 'row'
exampleContainer.style.flexWrap = 'wrap'
const chartPanel = document.createElement('div')
chartPanel.style.width = '50%'
exampleContainer.append(chartPanel)
const containerChart1 = document.createElement('div')
containerChart1.style.height = '50%'
chartPanel.append(containerChart1)
const containerChart2 = document.createElement('div')
containerChart2.style.height = '50%'
chartPanel.append(containerChart2)
const containerBars = document.createElement('div')
containerBars.style.width = '50%'
exampleContainer.append(containerBars)
// Create trading charts.
const taChart1 = trader.tradingChart({ parentElement: containerChart1, loadFromStorage: false })
const taChart2 = trader.tradingChart({ parentElement: containerChart2, loadFromStorage: false })
taChart2.setPositiveBodyColor('#80FF20')
taChart2.setPositiveWickColor('#80FF20')
taChart2.setNegativeBodyColor('#A02000')
taChart2.setNegativeWickColor('#A02000')
const taMethods = new TechnicalAnalysisMethods(taChart1)
// Create 3D-chart with two box series.
const barChart = trader.lightningChart().Chart3D({ container: containerBars, legend: { entries: { lut: null } } })
.setTitle('High-Low range and various oscillators')
.setCameraLocation({ x: -0.3, y: 0.5, z: 1 })
.setCursorFormatting((_, hit, hits) => {
return [
hit.series,
['X', '', hit.x.toString()],
['Y', '', hit.y.toFixed(2)]
]
})
barChart.getDefaultAxisZ().setTickStrategy(AxisTickStrategies.Empty)
const positiveColor = barChart.getTheme().ohlcCandleBodyFillStylePositive.color
const negativeColor = barChart.getTheme().ohlcCandleBodyFillStyleNegative.color
const hlSeries1 = barChart.addBoxSeries()
.setName('High-Low (JNJ)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
const hlSeries2 = barChart.addBoxSeries()
.setName('High-Low (NVO)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
const stochSeries1 = barChart.addBoxSeries()
.setName('Stochastic (JNJ)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
const stochSeries2 = barChart.addBoxSeries()
.setName('Stochastic (NVO)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
const ultSeries1 = barChart.addBoxSeries()
.setName('Ultimate (JNJ)')
.setRoundedEdges(0.4)
.setFillStyle(new PalettedFill({
lookUpProperty: 'y',
lut: new LUT({
steps: [
{ value: 0, color: negativeColor },
{ value: 100, color: positiveColor }
]
})
}))
const ultSeries2 = barChart.addBoxSeries()
.setName('Ultimate (NVO)')
.setRoundedEdges(0.4)
.setFillStyle(new PalettedFill({
lookUpProperty: 'y',
lut: new LUT({
steps: [
{ value: 0, color: ColorRGBA( 160, 32, 0 ) },
{ value: 100, color: ColorRGBA( 128, 255, 32 ) }
]
})
}))
const aroonSeries1 = barChart.addBoxSeries()
.setName('Aroon Osc. (JNJ)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
const aroonSeries2 = barChart.addBoxSeries()
.setName('Aroon Osc. (NVO)')
.setRoundedEdges(0.4)
.setFillStyle(new IndividualPointFill())
// Add datasets for the technical analysis charts.
await fetch(`${document.head.baseURI}examples/assets/2102/Johnson & Johnson (JNJ).csv`).then((res) => res.text()).then((text) => {
taChart1.loadCsvString(text, 'Johnson & Johnson (JNJ)')
const dataset1 = taChart1.getData(false)
fetch(`${document.head.baseURI}examples/assets/2102/Novo Nordisk (NVO).csv`).then((res) => res.text()).then((text) => {
taChart2.loadCsvString(text, 'Novo Nordisk (NVO)')
const dataset2 = taChart2.getData(false)
// Add bars based on Aroon Oscillator values.
const aroonValues1 = taMethods.calculateAroonOscillator(dataset1[2], dataset1[3], 25)
const aroonValues2 = taMethods.calculateAroonOscillator(dataset2[2], dataset2[3], 25)
const boxDataAroon1 = []
const boxDataAroon2 = []
for (let i = 0; i < aroonValues1.length; i++) {
boxDataAroon1.push({
xCenter: i + 25,
yCenter: aroonValues1[i] / 2,
zCenter: 1,
xSize: 1,
ySize: aroonValues1[i],
zSize: 1,
color: aroonValues1[i] >= 0 ? positiveColor : negativeColor
})
boxDataAroon2.push({
xCenter: i + 25,
yCenter: aroonValues2[i] / 2,
zCenter: 0,
xSize: 1,
ySize: aroonValues2[i],
zSize: 1,
color: aroonValues2[i] >= 0 ? ColorRGBA( 128, 255, 32 ) : ColorRGBA( 160, 32, 0 )
})
}
aroonSeries1.invalidateData(boxDataAroon1)
aroonSeries2.invalidateData(boxDataAroon2)
// Add bars based on Ultimate Oscillator values.
const ultValues1 = taMethods.calculateUltimateOscillator(dataset1[4], dataset1[2], dataset1[3], 7, 14, 28)
const ultValues2 = taMethods.calculateUltimateOscillator(dataset2[4], dataset2[2], dataset2[3], 7, 14, 28)
const boxDataUlt1 = []
const boxDataUlt2 = []
for (let i = 0; i < ultValues1.length; i++) {
boxDataUlt1.push({
xCenter: i + 28,
yCenter: ultValues1[i] / 2,
zCenter: 4,
xSize: 1,
ySize: ultValues1[i],
zSize: 1,
color: ultValues1[i] >= 50 ? positiveColor : negativeColor
})
boxDataUlt2.push({
xCenter: i + 28,
yCenter: ultValues2[i] / 2,
zCenter: 3,
xSize: 1,
ySize: ultValues2[i],
zSize: 1,
color: ultValues2[i] >= 50 ? ColorRGBA( 128, 255, 32 ) : ColorRGBA( 160, 32, 0 )
})
}
ultSeries1.invalidateData(boxDataUlt1)
ultSeries2.invalidateData(boxDataUlt2)
// Add bars based on Stochastic Oscillator values.
const stochasticValues1 = taMethods.calculateStochasticOscillator(dataset1[4], dataset1[2], dataset1[3], 14, 3)
const stochasticValues2 = taMethods.calculateStochasticOscillator(dataset2[4], dataset2[2], dataset2[3], 14, 3)
const boxDataStoch1 = []
const boxDataStoch2 = []
for (let i = 0; i < stochasticValues1[0].length; i++) {
boxDataStoch1.push({
xCenter: i + 13,
yCenter: stochasticValues1[0][i] / 2,
zCenter: 7,
xSize: 1,
ySize: stochasticValues1[0][i],
zSize: 1,
color: i < 2 || stochasticValues1[0][i] >= stochasticValues1[1][i - 2] ? positiveColor : negativeColor
})
boxDataStoch2.push({
xCenter: i + 13,
yCenter: stochasticValues2[0][i] / 2,
zCenter: 6,
xSize: 1,
ySize: stochasticValues2[0][i],
zSize: 1,
color: i < 2 || stochasticValues2[0][i] >= stochasticValues2[1][i - 2] ? ColorRGBA( 128, 255, 32 ) : ColorRGBA( 160, 32, 0 )
})
}
stochSeries1.invalidateData(boxDataStoch1)
stochSeries2.invalidateData(boxDataStoch2)
// Add bars based on High-Low range.
const boxData1 = []
const boxData2 = []
for (let i = 0; i < dataset1[2].length; i++) {
boxData1.push({
xCenter: i,
yCenter: dataset1[3][i] + (dataset1[2][i] - dataset1[3][i]) / 2,
zCenter: 9.7,
xSize: 1,
ySize: dataset1[2][i] - dataset1[3][i],
zSize: 0.4,
color: dataset1[4][i] >= dataset1[1][i] ? positiveColor : negativeColor
})
boxData2.push({
xCenter: i,
yCenter: dataset2[3][i] + (dataset2[2][i] - dataset2[3][i]) / 2,
zCenter: 9.3,
xSize: 1,
ySize: dataset2[2][i] - dataset2[3][i],
zSize: 0.4,
color: dataset2[4][i] >= dataset2[1][i] ? ColorRGBA( 128, 255, 32 ) : ColorRGBA( 160, 32, 0 )
})
}
hlSeries1.invalidateData(boxData1)
hlSeries2.invalidateData(boxData2)
barChart.getDefaultAxisX().setInterval({ start: -0.5, end: dataset1[4].length - 0.5 })
barChart.getDefaultAxisY().setInterval({ start: 0, end: 200 })
barChart.getDefaultAxisZ().setInterval({ start: -0.5, end: 10.5 })
barChart.getDefaultAxisZ().addCustomTick().setValue(0.5).setTextFormatter(() => 'Aroon Osc.')
barChart.getDefaultAxisZ().addCustomTick().setValue(3.5).setTextFormatter(() => 'Ultimate Osc.')
barChart.getDefaultAxisZ().addCustomTick().setValue(6.5).setTextFormatter(() => 'Stochastic Osc.')
barChart.getDefaultAxisZ().addCustomTick().setValue(9.5).setTextFormatter(() => 'High-Low Range')
// Configure legend box.
const fill1 = new LinearGradientFill({
angle: 0,
stops: [
{ offset: 0, color: negativeColor },
{ offset: 0.5, color: negativeColor },
{ offset: 0.5, color: positiveColor },
{ offset: 1, color: positiveColor }
]
})
const fill2 = new LinearGradientFill({
angle: 0,
stops: [
{ offset: 0, color: ColorRGBA( 160, 32, 0 ) },
{ offset: 0.5, color: ColorRGBA( 160, 32, 0 ) },
{ offset: 0.5, color: ColorRGBA( 128, 255, 32 ) },
{ offset: 1, color: ColorRGBA( 128, 255, 32 ) }
]
})
barChart.legend.setEntryOptions(hlSeries1, { markerFillStyle: fill1 })
barChart.legend.setEntryOptions(stochSeries1, { markerFillStyle: fill1 })
barChart.legend.setEntryOptions(ultSeries1, { markerFillStyle: fill1 })
barChart.legend.setEntryOptions(aroonSeries1, { markerFillStyle: fill1 })
barChart.legend.setEntryOptions(hlSeries2, { markerFillStyle: fill2 })
barChart.legend.setEntryOptions(stochSeries2, { markerFillStyle: fill2 })
barChart.legend.setEntryOptions(ultSeries2, { markerFillStyle: fill2 })
barChart.legend.setEntryOptions(aroonSeries2, { markerFillStyle: fill2 })
})
})
}) 3D Bars - Editor
Example showing a combination of Technical Analysis Charts and 3D-bars in Lightning JS. Two trading datasets are used to create bars based on High-Low range and various oscillators. Clicking an entry in the legend box will hide and show the respective series.
The example loads data from a csv-file.