
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import * as am5stock from "@amcharts/amcharts5/stock";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import "./data/AAPL_day.js";
import "./data/AMD_day.js";
import "./data/AMZN_day.js";
import "./data/GOOG_day.js";
import "./data/MSFT_day.js";
import "./data/NFLX_day.js";
import "./data/NVDA_day.js";
import "./data/TSLA_day.js";
// Create root element
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
let root = am5.Root.new("chartdiv");
// Set themes
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root)
]);
// Create a stock chart
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Instantiating_the_chart
let stockChart = root.container.children.push(am5stock.StockChart.new(root, {
}));
// Set global number format
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/
root.numberFormatter.set("numberFormat", "#,###.00");
// Create a main stock panel (chart)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Adding_panels
let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, {
wheelY: "zoomX",
panX: true,
panY: true
}));
// Create value axis
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
let valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
pan: "zoom"
}),
extraMin: 0.1, // adds some space for for main series
tooltip: am5.Tooltip.new(root, {}),
numberFormat: "#,###.00",
extraTooltipPrecision: 2
}));
let dateAxis = mainPanel.xAxes.push(am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "day",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {
minorGridEnabled: true
}),
tooltip: am5.Tooltip.new(root, {})
}));
// Add series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
let valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
name: "MSFT",
clustered: false,
valueXField: "Date",
valueYField: "Close",
highValueYField: "High",
lowValueYField: "Low",
openValueYField: "Open",
calculateAggregates: true,
xAxis: dateAxis,
yAxis: valueAxis,
legendValueText: "open: [bold]{openValueY}[/] high: [bold]{highValueY}[/] low: [bold]{lowValueY}[/] close: [bold]{valueY}[/]",
legendRangeValueText: ""
}));
// Set main value series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
stockChart.set("stockSeries", valueSeries);
// Add a stock legend
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/stock-legend/
let valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, {
stockChart: stockChart
}));
// Create volume axis
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
let volumeAxisRenderer = am5xy.AxisRendererY.new(root, {
inside: true
});
volumeAxisRenderer.labels.template.set("forceHidden", true);
volumeAxisRenderer.grid.template.set("forceHidden", true);
let volumeValueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
numberFormat: "#.#a",
height: am5.percent(20),
y: am5.percent(100),
centerY: am5.percent(100),
renderer: volumeAxisRenderer
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
let volumeSeries = mainPanel.series.push(am5xy.ColumnSeries.new(root, {
name: "Volume",
clustered: false,
valueXField: "Date",
valueYField: "Volume",
xAxis: dateAxis,
yAxis: volumeValueAxis,
legendValueText: "[bold]{valueY.formatNumber('#,###.0a')}[/]"
}));
volumeSeries.columns.template.setAll({
strokeOpacity: 0,
fillOpacity: 0.5
});
// color columns by stock rules
volumeSeries.columns.template.adapters.add("fill", function(fill, target) {
let dataItem = target.dataItem;
if (dataItem) {
return stockChart.getVolumeColor(dataItem);
}
return fill;
})
// Set main series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
stockChart.set("volumeSeries", volumeSeries);
valueLegend.data.setAll([valueSeries, volumeSeries]);
// Add cursor(s)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
mainPanel.set("cursor", am5xy.XYCursor.new(root, {
yAxis: valueAxis,
xAxis: dateAxis,
snapToSeries: [valueSeries],
snapToSeriesBy: "y!"
}));
// Add scrollbar
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
let scrollbar = mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, {
orientation: "horizontal",
height: 50
}));
stockChart.toolsContainer.children.push(scrollbar);
let sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "day",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {})
}));
let sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
let sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
valueYField: "Close",
valueXField: "Date",
xAxis: sbDateAxis,
yAxis: sbValueAxis
}));
sbSeries.fills.template.setAll({
visible: true,
fillOpacity: 0.3
});
// Function that dynamically loads data
function loadData(ticker, series, granularity) {
let data = (window)[ticker + "_" + granularity];
am5.array.each(series, function(item) {
item.data.setAll(data);
});
}
// Load initial data for the first series
let currentGranularity = "day";
loadData("MSFT", [valueSeries, volumeSeries, sbSeries], currentGranularity);
// Add comparing series
addComparingSeries("AAPL");
// Set up main indices selector
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/comparison-control/
var mainSeriesControl = am5stock.DropdownListControl.new(root, {
stockChart: stockChart,
name: valueSeries.get("name"),
icon: am5stock.StockIcons.getIcon("Search"),
fixedLabel: true,
searchable: true,
searchCallback: function(query) {
var mainSeries = stockChart.get("stockSeries");
var mainSeriesID = mainSeries ? mainSeries.get("name") : "";
var list = getTicker(query);
am5.array.each(list, function(item) {
if (item.id == mainSeriesID) {
item.disabled = true;
}
})
return list;
}
});
mainSeriesControl.events.on("selected", function(ev) {
var valueSeries = stockChart.get("stockSeries");
var volumeSeries = stockChart.get("volumeSeries");
mainSeriesControl.set("name", ev.item.subLabel);
valueSeries.set("name", ev.item.subLabel);
loadData(ev.item.subLabel, [valueSeries, volumeSeries, sbSeries], currentGranularity);
});
// Set up comparison control
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/comparison-control/
let comparisonControl = am5stock.ComparisonControl.new(root, {
stockChart: stockChart,
searchable: true,
searchCallback: (query) => {
var compared = stockChart.getPrivate("comparedSeries", []);
var main = stockChart.get("stockSeries");
if (compared.length > 4) {
return [{
label: "A maximum of 5 comparisons is already selected. Remove some to add new ones.",
id: "count",
info: true
}];
};
var comparedIds = [];
am5.array.each(compared, function(series) {
comparedIds.push(series.get("name"));
});
var list = getTicker(query);
am5.array.each(list, function(item) {
if (comparedIds.indexOf(item.id) !== -1 || main.get("name") == item.id) {
item.disabled = true;
}
})
return list;
}
});
comparisonControl.events.on("selected", function(ev) {
addComparingSeries(ev.item.subLabel);
});
function addComparingSeries(label) {
let series = am5xy.LineSeries.new(root, {
name: label,
valueYField: "Close",
calculateAggregates: true,
valueXField: "Date",
xAxis: dateAxis,
yAxis: valueAxis,
legendValueText: "{valueY.formatNumber('#.00')}"
});
let comparingSeries = stockChart.addComparingSeries(series);
loadData(label, [comparingSeries], currentGranularity);
}
function getTicker(search) {
search = search.toLowerCase();
let tickers = [
{ label: "Apple", subLabel: "AAPL", id: "AAPL" },
{ label: "Advanced Micro Devices", subLabel: "AMD", id: "AMD" },
{ label: "Microsoft", subLabel: "MSFT", id: "MSFT" },
{ label: "Alphabet (Google)", subLabel: "GOOG", id: "GOOG" },
{ label: "Amazon", subLabel: "AMZN", id: "AMZN" },
{ label: "Tesla", subLabel: "TSLA", id: "TSLA" },
{ label: "NVIDIA", subLabel: "NVDA", id: "NVDA" },
{ label: "Netflix", subLabel: "NFLX", id: "NFLX" }
];
return tickers.filter((item) => {
return item.label.toLowerCase().match(search) || item.subLabel.toLowerCase().match(search);
});
}
// Set up series type switcher
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/series-type-control/
let seriesSwitcher = am5stock.SeriesTypeControl.new(root, {
stockChart: stockChart
});
seriesSwitcher.events.on("selected", function(ev) {
setSeriesType(ev.item.id);
});
function getNewSettings(series) {
let newSettings = [];
am5.array.each(["name", "valueYField", "highValueYField", "lowValueYField", "openValueYField", "calculateAggregates", "valueXField", "xAxis", "yAxis", "legendValueText", "stroke", "fill"], function(setting) {
newSettings[setting] = series.get(setting);
});
return newSettings;
}
function setSeriesType(seriesType) {
// Get current series and its settings
let currentSeries = stockChart.get("stockSeries");
let newSettings = getNewSettings(currentSeries);
// Remove previous series
let data = currentSeries.data.values;
mainPanel.series.removeValue(currentSeries);
// Create new series
let series;
switch (seriesType) {
case "line":
series = mainPanel.series.push(am5xy.LineSeries.new(root, newSettings));
break;
case "candlestick":
case "procandlestick":
newSettings.clustered = false;
series = mainPanel.series.push(am5xy.CandlestickSeries.new(root, newSettings));
if (seriesType == "procandlestick") {
series.columns.template.get("themeTags").push("pro");
}
break;
case "ohlc":
newSettings.clustered = false;
series = mainPanel.series.push(am5xy.OHLCSeries.new(root, newSettings));
break;
}
// Set new series as stockSeries
if (series) {
valueLegend.data.removeValue(currentSeries);
series.data.setAll(data);
stockChart.set("stockSeries", series);
let cursor = mainPanel.get("cursor");
if (cursor) {
cursor.set("snapToSeries", [series]);
}
valueLegend.data.insertIndex(0, series);
}
}
// Stock toolbar
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/
let toolbar = am5stock.StockToolbar.new(root, {
container: document.getElementById("chartcontrols"),
stockChart: stockChart,
controls: [
mainSeriesControl,
comparisonControl,
am5stock.IndicatorControl.new(root, {
stockChart: stockChart,
legend: valueLegend
}),
am5stock.DateRangeSelector.new(root, {
stockChart: stockChart
}),
am5stock.PeriodSelector.new(root, {
stockChart: stockChart
}),
seriesSwitcher,
am5stock.DrawingControl.new(root, {
stockChart: stockChart
}),
am5stock.ResetControl.new(root, {
stockChart: stockChart
}),
am5stock.SettingsControl.new(root, {
stockChart: stockChart
})
]
})