@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.
- package/.gitmodules +3 -0
- package/README.md +82 -0
- package/amcharts5-skill/README.md +50 -0
- package/amcharts5-skill/amcharts5-skill/SKILL.md +667 -0
- package/amcharts5-skill/amcharts5-skill/references/flow.md +523 -0
- package/amcharts5-skill/amcharts5-skill/references/gantt.md +410 -0
- package/amcharts5-skill/amcharts5-skill/references/hierarchy.md +568 -0
- package/amcharts5-skill/amcharts5-skill/references/map.md +574 -0
- package/amcharts5-skill/amcharts5-skill/references/pie.md +663 -0
- package/amcharts5-skill/amcharts5-skill/references/radar.md +584 -0
- package/amcharts5-skill/amcharts5-skill/references/stock.md +664 -0
- package/amcharts5-skill/amcharts5-skill/references/timeline.md +449 -0
- package/amcharts5-skill/amcharts5-skill/references/ui-elements.md +393 -0
- package/amcharts5-skill/amcharts5-skill/references/venn.md +368 -0
- package/amcharts5-skill/amcharts5-skill/references/wordcloud.md +339 -0
- package/amcharts5-skill/amcharts5-skill/references/xy.md +1150 -0
- package/amcharts5-skill/cursorrules +820 -0
- package/package.json +27 -0
- package/src/index.js +329 -0
- package/test.js +153 -0
|
@@ -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
|
+
```
|