@amcharts/amcharts5-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,664 @@
1
+ # Stock & Financial Charts
2
+ Build financial stock charts with panels, indicators, and toolbar.
3
+
4
+
5
+ ## Required imports
6
+
7
+ ### ES modules
8
+ ```ts
9
+ import * as am5 from "@amcharts/amcharts5";
10
+ import * as am5xy from "@amcharts/amcharts5/xy";
11
+ import * as am5stock from "@amcharts/amcharts5/stock";
12
+ import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
13
+ ```
14
+
15
+ ### CDN
16
+ ```html
17
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
18
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
19
+ <script src="https://cdn.amcharts.com/lib/5/stock.js"></script>
20
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
21
+ ```
22
+
23
+ ## Core setup
24
+
25
+ ```html
26
+ <div id="chartcontrols"></div> <!-- toolbar container -->
27
+ <div id="chartdiv"></div> <!-- chart container -->
28
+ ```
29
+
30
+ ```js
31
+ const root = am5.Root.new("chartdiv");
32
+ root.setThemes([am5themes_Animated.new(root)]);
33
+
34
+ // 1. Stock chart (wrapper)
35
+ const stockChart = root.container.children.push(
36
+ am5stock.StockChart.new(root, {})
37
+ );
38
+
39
+ // 2. Main panel (is an XYChart)
40
+ const mainPanel = stockChart.panels.push(
41
+ am5stock.StockPanel.new(root, {
42
+ wheelY: "zoomX",
43
+ panX: true,
44
+ panY: true
45
+ })
46
+ );
47
+
48
+ // 3. Axes on the panel
49
+ const dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, {
50
+ baseInterval: { timeUnit: "day", count: 1 },
51
+ renderer: am5xy.AxisRendererX.new(root, {}),
52
+ tooltip: am5.Tooltip.new(root, {})
53
+ }));
54
+
55
+ const valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
56
+ renderer: am5xy.AxisRendererY.new(root, {})
57
+ }));
58
+
59
+ // 4. Main series (candlestick)
60
+ const valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
61
+ name: "STCK",
62
+ xAxis: dateAxis,
63
+ yAxis: valueAxis,
64
+ valueXField: "Date",
65
+ valueYField: "Close",
66
+ highValueYField: "High",
67
+ lowValueYField: "Low",
68
+ openValueYField: "Open",
69
+ calculateAggregates: true,
70
+ legendValueText: "{valueY}"
71
+ }));
72
+
73
+ // 5. Register as main stock series (CRITICAL)
74
+ stockChart.set("stockSeries", valueSeries);
75
+
76
+ // 6. Stock legend
77
+ const legend = mainPanel.plotContainer.children.push(
78
+ am5stock.StockLegend.new(root, { stockChart: stockChart })
79
+ );
80
+
81
+ // 7. Cursor
82
+ mainPanel.set("cursor", am5xy.XYCursor.new(root, {
83
+ yAxis: valueAxis,
84
+ xAxis: dateAxis,
85
+ behavior: "none",
86
+ snapToSeries: [valueSeries]
87
+ }));
88
+
89
+ // 8. Scrollbar with preview series
90
+ const scrollbar = mainPanel.set("scrollbarX",
91
+ am5xy.XYChartScrollbar.new(root, {
92
+ orientation: "horizontal",
93
+ height: 50
94
+ })
95
+ );
96
+
97
+ var sbDateAxis = scrollbar.chart.xAxes.push(am5xy.DateAxis.new(root, {
98
+ baseInterval: { timeUnit: "day", count: 1 },
99
+ renderer: am5xy.AxisRendererX.new(root, {})
100
+ }));
101
+ var sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, {
102
+ renderer: am5xy.AxisRendererY.new(root, {})
103
+ }));
104
+ var sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
105
+ xAxis: sbDateAxis,
106
+ yAxis: sbValueAxis,
107
+ valueYField: "Close",
108
+ valueXField: "Date"
109
+ }));
110
+
111
+ // 9. Data — LAST
112
+ valueSeries.data.setAll(data);
113
+ sbSeries.data.setAll(data);
114
+
115
+ // 10. Toolbar (optional)
116
+ const toolbar = am5stock.StockToolbar.new(root, {
117
+ container: document.getElementById("chartcontrols"),
118
+ stockChart: stockChart,
119
+ controls: [
120
+ am5stock.IndicatorControl.new(root, { stockChart: stockChart }),
121
+ am5stock.DrawingControl.new(root, { stockChart: stockChart }),
122
+ am5stock.PeriodSelector.new(root, {
123
+ stockChart: stockChart,
124
+ periods: [
125
+ { timeUnit: "day", count: 1, name: "1D" },
126
+ { timeUnit: "month", count: 1, name: "1M" },
127
+ { timeUnit: "month", count: 3, name: "3M" },
128
+ { timeUnit: "year", count: 1, name: "1Y" },
129
+ { timeUnit: "max", name: "Max" }
130
+ ]
131
+ }),
132
+ am5stock.SeriesTypeControl.new(root, { stockChart: stockChart }),
133
+ am5stock.SettingsControl.new(root, { stockChart: stockChart }),
134
+ am5stock.ResetControl.new(root, { stockChart: stockChart })
135
+ ]
136
+ });
137
+ ```
138
+
139
+ ## Adding a volume panel
140
+
141
+ ```js
142
+ const volumePanel = stockChart.panels.push(
143
+ am5stock.StockPanel.new(root, {
144
+ wheelY: "zoomX",
145
+ panX: true,
146
+ panY: true,
147
+ height: am5.percent(30)
148
+ })
149
+ );
150
+
151
+ const volDateAxis = volumePanel.xAxes.push(am5xy.DateAxis.new(root, {
152
+ baseInterval: { timeUnit: "day", count: 1 },
153
+ renderer: am5xy.AxisRendererX.new(root, {})
154
+ }));
155
+
156
+ const volValueAxis = volumePanel.yAxes.push(am5xy.ValueAxis.new(root, {
157
+ renderer: am5xy.AxisRendererY.new(root, {})
158
+ }));
159
+
160
+ const volumeSeries = volumePanel.series.push(am5xy.ColumnSeries.new(root, {
161
+ name: "Volume",
162
+ xAxis: volDateAxis,
163
+ yAxis: volValueAxis,
164
+ valueXField: "Date",
165
+ valueYField: "Volume"
166
+ }));
167
+
168
+ stockChart.set("volumeSeries", volumeSeries);
169
+ volumeSeries.data.setAll(data);
170
+ ```
171
+
172
+ ## Adding indicators programmatically
173
+
174
+ ```js
175
+ // Bollinger Bands
176
+ stockChart.indicators.push(am5stock.BollingerBands.new(root, {
177
+ stockChart: stockChart,
178
+ stockSeries: valueSeries,
179
+ legend: legend
180
+ }));
181
+
182
+ // Moving Average (SMA)
183
+ stockChart.indicators.push(am5stock.MovingAverage.new(root, {
184
+ stockChart: stockChart,
185
+ stockSeries: valueSeries,
186
+ legend: legend,
187
+ period: 20,
188
+ type: "simple" // "simple", "weighted", "exponential", "dema", "tema"
189
+ }));
190
+
191
+ // RSI (creates its own panel)
192
+ stockChart.indicators.push(am5stock.RelativeStrengthIndex.new(root, {
193
+ stockChart: stockChart,
194
+ stockSeries: valueSeries,
195
+ legend: legend
196
+ }));
197
+
198
+ // MACD (creates its own panel)
199
+ stockChart.indicators.push(am5stock.MACD.new(root, {
200
+ stockChart: stockChart,
201
+ stockSeries: valueSeries,
202
+ legend: legend
203
+ }));
204
+
205
+ // Volume (requires volumeSeries)
206
+ stockChart.indicators.push(am5stock.Volume.new(root, {
207
+ stockChart: stockChart,
208
+ stockSeries: valueSeries,
209
+ volumeSeries: volumeSeries,
210
+ legend: legend
211
+ }));
212
+ ```
213
+
214
+ ### Available indicators
215
+
216
+ | Indicator | Class | Needs volumeSeries |
217
+ |-----------|-------|--------------------|
218
+ | Moving Average | `MovingAverage` | No |
219
+ | Moving Average Cross | `MovingAverageCross` | No |
220
+ | Moving Average Envelope | `MovingAverageEnvelope` | No |
221
+ | Moving Average Deviation | `MovingAverageDeviation` | No |
222
+ | Bollinger Bands | `BollingerBands` | No |
223
+ | MACD | `MACD` | No |
224
+ | RSI | `RelativeStrengthIndex` | No |
225
+ | Stochastic Oscillator | `StochasticOscillator` | No |
226
+ | Williams %R | `WilliamsR` | No |
227
+ | Aroon | `Aroon` | No |
228
+ | Awesome Oscillator | `AwesomeOscillator` | No |
229
+ | Commodity Channel Index | `CommodityChannelIndex` | No |
230
+ | Standard Deviation | `StandardDeviation` | No |
231
+ | Disparity Index | `DisparityIndex` | No |
232
+ | Trix | `Trix` | No |
233
+ | ZigZag | `ZigZag` | No |
234
+ | Typical Price | `TypicalPrice` | No |
235
+ | Median Price | `MedianPrice` | No |
236
+ | On Balance Volume | `OnBalanceVolume` | Yes |
237
+ | Accumulation Distribution | `AccumulationDistribution` | Yes |
238
+ | Chaikin Money Flow | `ChaikinMoneyFlow` | Yes |
239
+ | Chaikin Oscillator | `ChaikinOscillator` | Yes |
240
+ | Volume Profile | `VolumeProfile` | Yes |
241
+ | VWAP | `VWAP` | Yes |
242
+ | PVT | `PVT` | Yes |
243
+ | Volume | `Volume` | Yes |
244
+
245
+ All classes are under `am5stock.*` (e.g., `am5stock.BollingerBands`).
246
+
247
+ ## Data format
248
+
249
+ ```js
250
+ var data = [
251
+ { Date: new Date(2024, 0, 2).getTime(), Open: 150.0, High: 155.2, Low: 148.5, Close: 153.1, Volume: 1200000 },
252
+ { Date: new Date(2024, 0, 3).getTime(), Open: 153.1, High: 158.0, Low: 151.3, Close: 156.4, Volume: 1350000 },
253
+ { Date: new Date(2024, 0, 4).getTime(), Open: 156.4, High: 160.1, Low: 154.8, Close: 159.7, Volume: 1100000 },
254
+ { Date: new Date(2024, 0, 5).getTime(), Open: 159.7, High: 162.5, Low: 157.2, Close: 158.3, Volume: 980000 },
255
+ { Date: new Date(2024, 0, 8).getTime(), Open: 158.3, High: 163.0, Low: 156.9, Close: 161.8, Volume: 1420000 },
256
+ { Date: new Date(2024, 0, 9).getTime(), Open: 161.8, High: 165.4, Low: 160.1, Close: 164.2, Volume: 1560000 },
257
+ { Date: new Date(2024, 0, 10).getTime(), Open: 164.2, High: 167.8, Low: 162.0, Close: 163.5, Volume: 1180000 },
258
+ { Date: new Date(2024, 0, 11).getTime(), Open: 163.5, High: 166.3, Low: 161.7, Close: 165.9, Volume: 1050000 },
259
+ { Date: new Date(2024, 0, 12).getTime(), Open: 165.9, High: 170.2, Low: 164.5, Close: 169.1, Volume: 1630000 },
260
+ { Date: new Date(2024, 0, 16).getTime(), Open: 169.1, High: 172.0, Low: 167.3, Close: 171.4, Volume: 1470000 },
261
+ // ... more data points
262
+ ];
263
+ ```
264
+
265
+ **All date values must be timestamps (milliseconds).** Data must be sorted ascending by date.
266
+
267
+ ## Toolbar controls
268
+
269
+ | Control | Class | Purpose |
270
+ |---------|-------|---------|
271
+ | Period selector | `am5stock.PeriodSelector` | 1D, 1M, 1Y, Max buttons |
272
+ | Date range | `am5stock.DateRangeSelector` | Date picker for custom range |
273
+ | Series type | `am5stock.SeriesTypeControl` | Switch line/candlestick/OHLC/area |
274
+ | Indicators | `am5stock.IndicatorControl` | Add SMA, EMA, Bollinger, RSI, etc. |
275
+ | Drawing | `am5stock.DrawingControl` | Trend lines, Fibonacci, annotations |
276
+ | Comparison | `am5stock.ComparisonControl` | Compare multiple symbols |
277
+ | Settings | `am5stock.SettingsControl` | Theme, fills, auto-save |
278
+ | Reset | `am5stock.ResetControl` | Reset chart to defaults |
279
+ | Interval | `am5stock.IntervalControl` | Switch time interval |
280
+
281
+ ## Events
282
+
283
+ ```js
284
+ // Period changed
285
+ stockChart.events.on("periodselected", (ev) => {
286
+ console.log("Period:", ev.period);
287
+ });
288
+
289
+ // Series type changed
290
+ valueSeries.events.on("datavalidated", () => {
291
+ console.log("Data updated");
292
+ });
293
+ ```
294
+
295
+ ## Disposal
296
+
297
+ ```js
298
+ root.dispose();
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Example 1: Stock chart with candlesticks and toolbar
304
+
305
+ ```html
306
+ <!DOCTYPE html>
307
+ <html>
308
+ <head>
309
+ <meta charset="UTF-8">
310
+ <title>Stock Chart</title>
311
+ <style>
312
+ body { font-family: -apple-system, sans-serif; margin: 0; padding: 20px; }
313
+ #chartcontrols { height: auto; padding: 5px 0; }
314
+ #chartdiv { width: 100%; height: 500px; }
315
+ </style>
316
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
317
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
318
+ <script src="https://cdn.amcharts.com/lib/5/stock.js"></script>
319
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
320
+ </head>
321
+ <body>
322
+ <div id="chartcontrols"></div>
323
+ <div id="chartdiv"></div>
324
+ <script>
325
+ var root = am5.Root.new("chartdiv");
326
+ root.setThemes([am5themes_Animated.new(root)]);
327
+
328
+ // Stock chart wrapper
329
+ var stockChart = root.container.children.push(
330
+ am5stock.StockChart.new(root, {})
331
+ );
332
+
333
+ // Main panel
334
+ var mainPanel = stockChart.panels.push(
335
+ am5stock.StockPanel.new(root, {
336
+ wheelY: "zoomX",
337
+ panX: true,
338
+ panY: true
339
+ })
340
+ );
341
+
342
+ // Axes
343
+ var dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, {
344
+ baseInterval: { timeUnit: "day", count: 1 },
345
+ renderer: am5xy.AxisRendererX.new(root, {}),
346
+ tooltip: am5.Tooltip.new(root, {})
347
+ }));
348
+
349
+ var valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
350
+ renderer: am5xy.AxisRendererY.new(root, {})
351
+ }));
352
+
353
+ // Candlestick series
354
+ var valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
355
+ name: "ACME",
356
+ xAxis: dateAxis,
357
+ yAxis: valueAxis,
358
+ valueXField: "Date",
359
+ valueYField: "Close",
360
+ highValueYField: "High",
361
+ lowValueYField: "Low",
362
+ openValueYField: "Open",
363
+ calculateAggregates: true,
364
+ legendValueText: "O:{openValueY} H:{highValueY} L:{lowValueY} C:{valueY}"
365
+ }));
366
+
367
+ // CRITICAL: register as stock series
368
+ stockChart.set("stockSeries", valueSeries);
369
+
370
+ // Legend
371
+ var legend = mainPanel.plotContainer.children.push(
372
+ am5stock.StockLegend.new(root, { stockChart: stockChart })
373
+ );
374
+
375
+ // Cursor
376
+ mainPanel.set("cursor", am5xy.XYCursor.new(root, {
377
+ yAxis: valueAxis,
378
+ xAxis: dateAxis,
379
+ behavior: "none",
380
+ snapToSeries: [valueSeries]
381
+ }));
382
+
383
+ // Scrollbar
384
+ var scrollbar = mainPanel.set("scrollbarX",
385
+ am5xy.XYChartScrollbar.new(root, {
386
+ orientation: "horizontal",
387
+ height: 50
388
+ })
389
+ );
390
+
391
+ // Scrollbar preview series
392
+ var sbDateAxis = scrollbar.chart.xAxes.push(am5xy.DateAxis.new(root, {
393
+ baseInterval: { timeUnit: "day", count: 1 },
394
+ renderer: am5xy.AxisRendererX.new(root, {})
395
+ }));
396
+ var sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, {
397
+ renderer: am5xy.AxisRendererY.new(root, {})
398
+ }));
399
+ var sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
400
+ xAxis: sbDateAxis,
401
+ yAxis: sbValueAxis,
402
+ valueYField: "Close",
403
+ valueXField: "Date"
404
+ }));
405
+
406
+ // Toolbar
407
+ am5stock.StockToolbar.new(root, {
408
+ container: document.getElementById("chartcontrols"),
409
+ stockChart: stockChart,
410
+ controls: [
411
+ am5stock.IndicatorControl.new(root, { stockChart: stockChart }),
412
+ am5stock.DrawingControl.new(root, { stockChart: stockChart }),
413
+ am5stock.PeriodSelector.new(root, {
414
+ stockChart: stockChart,
415
+ periods: [
416
+ { timeUnit: "month", count: 1, name: "1M" },
417
+ { timeUnit: "month", count: 3, name: "3M" },
418
+ { timeUnit: "month", count: 6, name: "6M" },
419
+ { timeUnit: "year", count: 1, name: "1Y" },
420
+ { timeUnit: "max", name: "Max" }
421
+ ]
422
+ }),
423
+ am5stock.SeriesTypeControl.new(root, { stockChart: stockChart }),
424
+ am5stock.ResetControl.new(root, { stockChart: stockChart })
425
+ ]
426
+ });
427
+
428
+ // Generate sample OHLCV data
429
+ var data = [];
430
+ var open = 150;
431
+ var date = new Date(2024, 0, 2);
432
+ for (var i = 0; i < 120; i++) {
433
+ // Skip weekends
434
+ if (date.getDay() === 0) date.setDate(date.getDate() + 1);
435
+ if (date.getDay() === 6) date.setDate(date.getDate() + 2);
436
+
437
+ var change = (Math.random() - 0.48) * 4;
438
+ var high = open + Math.random() * 3 + 1;
439
+ var low = open - Math.random() * 3 - 1;
440
+ var close = open + change;
441
+ close = Math.max(low, Math.min(high, close));
442
+
443
+ data.push({
444
+ Date: date.getTime(),
445
+ Open: Math.round(open * 100) / 100,
446
+ High: Math.round(high * 100) / 100,
447
+ Low: Math.round(low * 100) / 100,
448
+ Close: Math.round(close * 100) / 100,
449
+ Volume: Math.round(800000 + Math.random() * 1200000)
450
+ });
451
+
452
+ open = close;
453
+ date = new Date(date);
454
+ date.setDate(date.getDate() + 1);
455
+ }
456
+
457
+ // Set data LAST
458
+ valueSeries.data.setAll(data);
459
+ sbSeries.data.setAll(data);
460
+
461
+ stockChart.appear(1000, 100);
462
+ </script>
463
+ </body>
464
+ </html>
465
+ ```
466
+
467
+ ## Example 2: Stock chart with volume panel and Bollinger Bands indicator
468
+
469
+ ```html
470
+ <!DOCTYPE html>
471
+ <html>
472
+ <head>
473
+ <meta charset="UTF-8">
474
+ <title>Stock Chart with Volume & Indicators</title>
475
+ <style>
476
+ body { font-family: -apple-system, sans-serif; margin: 0; padding: 20px; }
477
+ #chartcontrols { height: auto; padding: 5px 0; }
478
+ #chartdiv { width: 100%; height: 600px; }
479
+ </style>
480
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
481
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
482
+ <script src="https://cdn.amcharts.com/lib/5/stock.js"></script>
483
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
484
+ </head>
485
+ <body>
486
+ <div id="chartcontrols"></div>
487
+ <div id="chartdiv"></div>
488
+ <script>
489
+ var root = am5.Root.new("chartdiv");
490
+ root.setThemes([am5themes_Animated.new(root)]);
491
+
492
+ var stockChart = root.container.children.push(
493
+ am5stock.StockChart.new(root, {})
494
+ );
495
+
496
+ // === Main panel ===
497
+ var mainPanel = stockChart.panels.push(
498
+ am5stock.StockPanel.new(root, {
499
+ wheelY: "zoomX",
500
+ panX: true,
501
+ panY: true
502
+ })
503
+ );
504
+
505
+ var dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, {
506
+ baseInterval: { timeUnit: "day", count: 1 },
507
+ renderer: am5xy.AxisRendererX.new(root, {}),
508
+ tooltip: am5.Tooltip.new(root, {})
509
+ }));
510
+
511
+ var valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
512
+ renderer: am5xy.AxisRendererY.new(root, {})
513
+ }));
514
+
515
+ var valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
516
+ name: "TECH",
517
+ xAxis: dateAxis,
518
+ yAxis: valueAxis,
519
+ valueXField: "Date",
520
+ valueYField: "Close",
521
+ highValueYField: "High",
522
+ lowValueYField: "Low",
523
+ openValueYField: "Open",
524
+ calculateAggregates: true,
525
+ legendValueText: "O:{openValueY} H:{highValueY} L:{lowValueY} C:{valueY}"
526
+ }));
527
+
528
+ stockChart.set("stockSeries", valueSeries);
529
+
530
+ var legend = mainPanel.plotContainer.children.push(
531
+ am5stock.StockLegend.new(root, { stockChart: stockChart })
532
+ );
533
+
534
+ mainPanel.set("cursor", am5xy.XYCursor.new(root, {
535
+ yAxis: valueAxis,
536
+ xAxis: dateAxis,
537
+ behavior: "none",
538
+ snapToSeries: [valueSeries]
539
+ }));
540
+
541
+ // Scrollbar
542
+ mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, {
543
+ orientation: "horizontal",
544
+ height: 50
545
+ }));
546
+
547
+ // === Volume panel ===
548
+ var volumePanel = stockChart.panels.push(
549
+ am5stock.StockPanel.new(root, {
550
+ wheelY: "zoomX",
551
+ panX: true,
552
+ panY: true,
553
+ height: am5.percent(30)
554
+ })
555
+ );
556
+
557
+ var volDateAxis = volumePanel.xAxes.push(am5xy.DateAxis.new(root, {
558
+ baseInterval: { timeUnit: "day", count: 1 },
559
+ renderer: am5xy.AxisRendererX.new(root, {})
560
+ }));
561
+
562
+ var volValueAxis = volumePanel.yAxes.push(am5xy.ValueAxis.new(root, {
563
+ renderer: am5xy.AxisRendererY.new(root, {}),
564
+ numberFormat: "#.#a"
565
+ }));
566
+
567
+ var volumeSeries = volumePanel.series.push(am5xy.ColumnSeries.new(root, {
568
+ name: "Volume",
569
+ xAxis: volDateAxis,
570
+ yAxis: volValueAxis,
571
+ valueXField: "Date",
572
+ valueYField: "Volume",
573
+ tooltip: am5.Tooltip.new(root, { labelText: "Vol: {valueY}" })
574
+ }));
575
+
576
+ // Color volume bars by price direction
577
+ volumeSeries.columns.template.adapters.add("fill", function(fill, target) {
578
+ var dataItem = target.dataItem;
579
+ if (dataItem) {
580
+ var dc = dataItem.dataContext;
581
+ return dc.Close >= dc.Open
582
+ ? am5.color(0x26a69a)
583
+ : am5.color(0xef5350);
584
+ }
585
+ return fill;
586
+ });
587
+ volumeSeries.columns.template.adapters.add("stroke", function(stroke, target) {
588
+ var dataItem = target.dataItem;
589
+ if (dataItem) {
590
+ var dc = dataItem.dataContext;
591
+ return dc.Close >= dc.Open
592
+ ? am5.color(0x26a69a)
593
+ : am5.color(0xef5350);
594
+ }
595
+ return stroke;
596
+ });
597
+
598
+ stockChart.set("volumeSeries", volumeSeries);
599
+
600
+ var volLegend = volumePanel.plotContainer.children.push(
601
+ am5stock.StockLegend.new(root, { stockChart: stockChart })
602
+ );
603
+
604
+ // === Toolbar ===
605
+ am5stock.StockToolbar.new(root, {
606
+ container: document.getElementById("chartcontrols"),
607
+ stockChart: stockChart,
608
+ controls: [
609
+ am5stock.IndicatorControl.new(root, { stockChart: stockChart }),
610
+ am5stock.DrawingControl.new(root, { stockChart: stockChart }),
611
+ am5stock.PeriodSelector.new(root, {
612
+ stockChart: stockChart,
613
+ periods: [
614
+ { timeUnit: "month", count: 1, name: "1M" },
615
+ { timeUnit: "month", count: 3, name: "3M" },
616
+ { timeUnit: "year", count: 1, name: "1Y" },
617
+ { timeUnit: "max", name: "Max" }
618
+ ]
619
+ }),
620
+ am5stock.SeriesTypeControl.new(root, { stockChart: stockChart }),
621
+ am5stock.ResetControl.new(root, { stockChart: stockChart })
622
+ ]
623
+ });
624
+
625
+ // Generate sample data
626
+ var data = [];
627
+ var open = 280;
628
+ var date = new Date(2023, 6, 3);
629
+ for (var i = 0; i < 200; i++) {
630
+ if (date.getDay() === 0) date.setDate(date.getDate() + 1);
631
+ if (date.getDay() === 6) date.setDate(date.getDate() + 2);
632
+ var change = (Math.random() - 0.47) * 6;
633
+ var high = open + Math.random() * 4 + 1;
634
+ var low = open - Math.random() * 4 - 1;
635
+ var close = Math.max(low, Math.min(high, open + change));
636
+ data.push({
637
+ Date: date.getTime(),
638
+ Open: Math.round(open * 100) / 100,
639
+ High: Math.round(high * 100) / 100,
640
+ Low: Math.round(low * 100) / 100,
641
+ Close: Math.round(close * 100) / 100,
642
+ Volume: Math.round(500000 + Math.random() * 2000000)
643
+ });
644
+ open = close;
645
+ date = new Date(date);
646
+ date.setDate(date.getDate() + 1);
647
+ }
648
+
649
+ // Set data LAST
650
+ valueSeries.data.setAll(data);
651
+ volumeSeries.data.setAll(data);
652
+
653
+ // Add Bollinger Bands indicator programmatically
654
+ stockChart.indicators.push(am5stock.BollingerBands.new(root, {
655
+ stockChart: stockChart,
656
+ stockSeries: valueSeries,
657
+ legend: legend
658
+ }));
659
+
660
+ stockChart.appear(1000, 100);
661
+ </script>
662
+ </body>
663
+ </html>
664
+ ```