candlestick-chart.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. import { Component, Input } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { BaseChartComponent } from './base-chart.component';
  4. import * as echarts from 'echarts';
  5. @Component({
  6. selector: 'lib-candlestick-chart-basic',
  7. standalone: true,
  8. imports: [CommonModule, BaseChartComponent],
  9. template: '<lib-base-chart [width]="width" [height]="height" [options]="options"></lib-base-chart>',
  10. styles: [':host { display: block; }']
  11. })
  12. export class CandlestickChartBasicComponent extends BaseChartComponent {
  13. @Input() data: any[] = [
  14. ['2023-01-01', 2320.26, 2320.26, 2287.3, 2362.94],
  15. ['2023-01-02', 2300, 2291.3, 2288.26, 2308.38],
  16. ['2023-01-03', 2295.35, 2346.5, 2295.35, 2346.92],
  17. ['2023-01-04', 2347.22, 2358.98, 2337.35, 2363.8],
  18. ['2023-01-05', 2360.75, 2382.48, 2347.89, 2383.76],
  19. ['2023-01-06', 2383.43, 2385.42, 2371.23, 2391.82],
  20. ['2023-01-07', 2377.41, 2419.02, 2369.57, 2421.15],
  21. ['2023-01-08', 2425.92, 2428.15, 2417.58, 2440.38],
  22. ['2023-01-09', 2411, 2433.13, 2403.3, 2437.42],
  23. ['2023-01-10', 2432.68, 2434.48, 2427.7, 2441.73]
  24. ];
  25. @Input() override width = 600;
  26. @Input() override height = 400;
  27. override ngOnInit(): void {
  28. this.options = {
  29. title: {
  30. text: '基础K线图',
  31. left: 'center'
  32. },
  33. tooltip: {
  34. trigger: 'axis',
  35. axisPointer: {
  36. type: 'cross'
  37. }
  38. },
  39. grid: {
  40. left: '10%',
  41. right: '10%',
  42. bottom: '15%'
  43. },
  44. xAxis: {
  45. data: this.data.map((item: any) => item[0]),
  46. scale: true,
  47. boundaryGap: false,
  48. axisLine: { onZero: false },
  49. splitLine: { show: false },
  50. min: 'dataMin',
  51. max: 'dataMax'
  52. },
  53. yAxis: {
  54. scale: true,
  55. splitArea: {
  56. show: true
  57. }
  58. },
  59. dataZoom: [
  60. {
  61. type: 'inside',
  62. start: 50,
  63. end: 100
  64. },
  65. {
  66. show: true,
  67. type: 'slider',
  68. top: '90%',
  69. start: 50,
  70. end: 100
  71. }
  72. ],
  73. series: [
  74. {
  75. name: '日K',
  76. type: 'candlestick',
  77. data: this.data.map((item: any) => [item[1], item[2], item[3], item[4]]),
  78. itemStyle: {
  79. color: '#ec0000',
  80. color0: '#00da3c',
  81. borderColor: '#8A0000',
  82. borderColor0: '#008F28'
  83. }
  84. }
  85. ]
  86. };
  87. }
  88. }
  89. @Component({
  90. selector: 'lib-candlestick-chart-ma',
  91. standalone: true,
  92. imports: [CommonModule, BaseChartComponent],
  93. template: '<lib-base-chart [width]="width" [height]="height" [options]="options"></lib-base-chart>',
  94. styles: [':host { display: block; }']
  95. })
  96. export class CandlestickChartMAComponent extends BaseChartComponent {
  97. @Input() data: any[] = [
  98. ['2023-01-01', 2320.26, 2320.26, 2287.3, 2362.94],
  99. ['2023-01-02', 2300, 2291.3, 2288.26, 2308.38],
  100. ['2023-01-03', 2295.35, 2346.5, 2295.35, 2346.92],
  101. ['2023-01-04', 2347.22, 2358.98, 2337.35, 2363.8],
  102. ['2023-01-05', 2360.75, 2382.48, 2347.89, 2383.76],
  103. ['2023-01-06', 2383.43, 2385.42, 2371.23, 2391.82],
  104. ['2023-01-07', 2377.41, 2419.02, 2369.57, 2421.15],
  105. ['2023-01-08', 2425.92, 2428.15, 2417.58, 2440.38],
  106. ['2023-01-09', 2411, 2433.13, 2403.3, 2437.42],
  107. ['2023-01-10', 2432.68, 2434.48, 2427.7, 2441.73]
  108. ];
  109. @Input() override width = 600;
  110. @Input() override height = 400;
  111. calculateMA(dayCount: number): number[] {
  112. const result: number[] = [];
  113. for (let i = 0, len = this.data.length; i < len; i++) {
  114. if (i < dayCount) {
  115. result.push(NaN);
  116. continue;
  117. }
  118. let sum = 0;
  119. for (let j = 0; j < dayCount; j++) {
  120. sum += this.data[i - j][4];
  121. }
  122. result.push(+(sum / dayCount).toFixed(3));
  123. }
  124. return result;
  125. }
  126. override ngOnInit(): void {
  127. const dates = this.data.map((item: any) => item[0]);
  128. const values = this.data.map((item: any) => [item[1], item[2], item[3], item[4]]);
  129. const ma5 = this.calculateMA(5);
  130. const ma10 = this.calculateMA(10);
  131. const ma20 = this.calculateMA(20);
  132. this.options = {
  133. title: {
  134. text: 'K线图+均线',
  135. left: 'center'
  136. },
  137. tooltip: {
  138. trigger: 'axis',
  139. axisPointer: {
  140. type: 'cross'
  141. }
  142. },
  143. legend: {
  144. data: ['日K', 'MA5', 'MA10', 'MA20'],
  145. top: 30
  146. },
  147. grid: {
  148. left: '10%',
  149. right: '10%',
  150. bottom: '15%'
  151. },
  152. xAxis: {
  153. data: dates,
  154. scale: true,
  155. boundaryGap: false,
  156. axisLine: { onZero: false },
  157. splitLine: { show: false },
  158. min: 'dataMin',
  159. max: 'dataMax'
  160. },
  161. yAxis: {
  162. scale: true,
  163. splitArea: {
  164. show: true
  165. }
  166. },
  167. dataZoom: [
  168. {
  169. type: 'inside',
  170. start: 50,
  171. end: 100
  172. },
  173. {
  174. show: true,
  175. type: 'slider',
  176. top: '90%',
  177. start: 50,
  178. end: 100
  179. }
  180. ],
  181. series: [
  182. {
  183. name: '日K',
  184. type: 'candlestick',
  185. data: values,
  186. itemStyle: {
  187. color: '#ec0000',
  188. color0: '#00da3c',
  189. borderColor: '#8A0000',
  190. borderColor0: '#008F28'
  191. }
  192. },
  193. {
  194. name: 'MA5',
  195. type: 'line',
  196. data: ma5,
  197. smooth: true,
  198. lineStyle: {
  199. opacity: 0.5
  200. }
  201. },
  202. {
  203. name: 'MA10',
  204. type: 'line',
  205. data: ma10,
  206. smooth: true,
  207. lineStyle: {
  208. opacity: 0.5
  209. }
  210. },
  211. {
  212. name: 'MA20',
  213. type: 'line',
  214. data: ma20,
  215. smooth: true,
  216. lineStyle: {
  217. opacity: 0.5
  218. }
  219. }
  220. ]
  221. };
  222. }
  223. }
  224. @Component({
  225. selector: 'lib-candlestick-chart-volume',
  226. standalone: true,
  227. imports: [CommonModule, BaseChartComponent],
  228. template: '<lib-base-chart [width]="width" [height]="height" [options]="options"></lib-base-chart>',
  229. styles: [':host { display: block; }']
  230. })
  231. export class CandlestickChartVolumeComponent extends BaseChartComponent {
  232. @Input() data: any[] = [
  233. ['2023-01-01', 2320.26, 2320.26, 2287.3, 2362.94, 5000],
  234. ['2023-01-02', 2300, 2291.3, 2288.26, 2308.38, 4500],
  235. ['2023-01-03', 2295.35, 2346.5, 2295.35, 2346.92, 6000],
  236. ['2023-01-04', 2347.22, 2358.98, 2337.35, 2363.8, 5500],
  237. ['2023-01-05', 2360.75, 2382.48, 2347.89, 2383.76, 7000],
  238. ['2023-01-06', 2383.43, 2385.42, 2371.23, 2391.82, 6500],
  239. ['2023-01-07', 2377.41, 2419.02, 2369.57, 2421.15, 8000],
  240. ['2023-01-08', 2425.92, 2428.15, 2417.58, 2440.38, 7500],
  241. ['2023-01-09', 2411, 2433.13, 2403.3, 2437.42, 9000],
  242. ['2023-01-10', 2432.68, 2434.48, 2427.7, 2441.73, 8500]
  243. ];
  244. @Input() override width = 600;
  245. @Input() override height = 400;
  246. override ngOnInit(): void {
  247. const dates = this.data.map((item: any) => item[0]);
  248. const values = this.data.map((item: any) => [item[1], item[2], item[3], item[4]]);
  249. const volumes = this.data.map((item: any) => item[5]);
  250. this.options = {
  251. title: {
  252. text: 'K线图+成交量',
  253. left: 'center'
  254. },
  255. tooltip: {
  256. trigger: 'axis',
  257. axisPointer: {
  258. type: 'cross'
  259. }
  260. },
  261. grid: [
  262. {
  263. left: '10%',
  264. right: '8%',
  265. height: '50%'
  266. },
  267. {
  268. left: '10%',
  269. right: '8%',
  270. top: '63%',
  271. height: '16%'
  272. }
  273. ],
  274. xAxis: [
  275. {
  276. type: 'category',
  277. data: dates,
  278. scale: true,
  279. boundaryGap: false,
  280. axisLine: { onZero: false },
  281. splitLine: { show: false },
  282. min: 'dataMin',
  283. max: 'dataMax'
  284. },
  285. {
  286. type: 'category',
  287. gridIndex: 1,
  288. data: dates,
  289. scale: true,
  290. boundaryGap: false,
  291. axisLine: { onZero: false },
  292. axisTick: { show: false },
  293. splitLine: { show: false },
  294. axisLabel: { show: false },
  295. min: 'dataMin',
  296. max: 'dataMax'
  297. }
  298. ],
  299. yAxis: [
  300. {
  301. scale: true,
  302. splitArea: {
  303. show: true
  304. }
  305. },
  306. {
  307. scale: true,
  308. gridIndex: 1,
  309. splitNumber: 2,
  310. axisLabel: { show: false },
  311. axisLine: { show: false },
  312. axisTick: { show: false },
  313. splitLine: { show: false }
  314. }
  315. ],
  316. dataZoom: [
  317. {
  318. type: 'inside',
  319. xAxisIndex: [0, 1],
  320. start: 50,
  321. end: 100
  322. },
  323. {
  324. show: true,
  325. xAxisIndex: [0, 1],
  326. type: 'slider',
  327. top: '85%',
  328. start: 50,
  329. end: 100
  330. }
  331. ],
  332. series: [
  333. {
  334. name: '日K',
  335. type: 'candlestick',
  336. data: values,
  337. itemStyle: {
  338. color: '#ec0000',
  339. color0: '#00da3c',
  340. borderColor: '#8A0000',
  341. borderColor0: '#008F28'
  342. }
  343. },
  344. {
  345. name: '成交量',
  346. type: 'bar',
  347. xAxisIndex: 1,
  348. yAxisIndex: 1,
  349. data: volumes,
  350. itemStyle: {
  351. color: (params: any) => {
  352. const colorList = ['#ec0000', '#00da3c'];
  353. return colorList[params.dataIndex % 2];
  354. }
  355. }
  356. }
  357. ]
  358. };
  359. }
  360. }
  361. @Component({
  362. selector: 'lib-candlestick-chart-brush',
  363. standalone: true,
  364. imports: [CommonModule, BaseChartComponent],
  365. template: '<lib-base-chart [width]="width" [height]="height" [options]="options"></lib-base-chart>',
  366. styles: [':host { display: block; }']
  367. })
  368. export class CandlestickChartBrushComponent extends BaseChartComponent {
  369. @Input() data: any[] = [
  370. ['2023-01-01', 2320.26, 2320.26, 2287.3, 2362.94],
  371. ['2023-01-02', 2300, 2291.3, 2288.26, 2308.38],
  372. ['2023-01-03', 2295.35, 2346.5, 2295.35, 2346.92],
  373. ['2023-01-04', 2347.22, 2358.98, 2337.35, 2363.8],
  374. ['2023-01-05', 2360.75, 2382.48, 2347.89, 2383.76],
  375. ['2023-01-06', 2383.43, 2385.42, 2371.23, 2391.82],
  376. ['2023-01-07', 2377.41, 2419.02, 2369.57, 2421.15],
  377. ['2023-01-08', 2425.92, 2428.15, 2417.58, 2440.38],
  378. ['2023-01-09', 2411, 2433.13, 2403.3, 2437.42],
  379. ['2023-01-10', 2432.68, 2434.48, 2427.7, 2441.73]
  380. ];
  381. @Input() override width = 600;
  382. @Input() override height = 400;
  383. override ngOnInit(): void {
  384. this.options = {
  385. title: {
  386. text: 'K线图+刷选',
  387. left: 'center'
  388. },
  389. tooltip: {
  390. trigger: 'axis',
  391. axisPointer: {
  392. type: 'cross'
  393. }
  394. },
  395. grid: {
  396. left: '10%',
  397. right: '10%',
  398. bottom: '15%'
  399. },
  400. xAxis: {
  401. data: this.data.map((item: any) => item[0]),
  402. scale: true,
  403. boundaryGap: false,
  404. axisLine: { onZero: false },
  405. splitLine: { show: false },
  406. min: 'dataMin',
  407. max: 'dataMax'
  408. },
  409. yAxis: {
  410. scale: true,
  411. splitArea: {
  412. show: true
  413. }
  414. },
  415. dataZoom: [
  416. {
  417. type: 'inside',
  418. start: 50,
  419. end: 100
  420. },
  421. {
  422. show: true,
  423. type: 'slider',
  424. top: '90%',
  425. start: 50,
  426. end: 100
  427. }
  428. ],
  429. brush: {
  430. xAxisIndex: 'all',
  431. brushLink: 'all',
  432. toolbox: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],
  433. outOfBrush: {
  434. colorAlpha: 0.1
  435. }
  436. },
  437. series: [
  438. {
  439. name: '日K',
  440. type: 'candlestick',
  441. data: this.data.map((item: any) => [item[1], item[2], item[3], item[4]]),
  442. itemStyle: {
  443. color: '#ec0000',
  444. color0: '#00da3c',
  445. borderColor: '#8A0000',
  446. borderColor0: '#008F28'
  447. }
  448. }
  449. ]
  450. };
  451. }
  452. }
  453. @Component({
  454. selector: 'lib-candlestick-chart-dynamic',
  455. standalone: true,
  456. imports: [CommonModule, BaseChartComponent],
  457. template: '<lib-base-chart [width]="width" [height]="height" [options]="options"></lib-base-chart>',
  458. styles: [':host { display: block; }']
  459. })
  460. export class CandlestickChartDynamicComponent extends BaseChartComponent {
  461. @Input() data: any[] = [
  462. ['2023-01-01', 2320.26, 2320.26, 2287.3, 2362.94],
  463. ['2023-01-02', 2300, 2291.3, 2288.26, 2308.38],
  464. ['2023-01-03', 2295.35, 2346.5, 2295.35, 2346.92],
  465. ['2023-01-04', 2347.22, 2358.98, 2337.35, 2363.8],
  466. ['2023-01-05', 2360.75, 2382.48, 2347.89, 2383.76],
  467. ['2023-01-06', 2383.43, 2385.42, 2371.23, 2391.82],
  468. ['2023-01-07', 2377.41, 2419.02, 2369.57, 2421.15],
  469. ['2023-01-08', 2425.92, 2428.15, 2417.58, 2440.38],
  470. ['2023-01-09', 2411, 2433.13, 2403.3, 2437.42],
  471. ['2023-01-10', 2432.68, 2434.48, 2427.7, 2441.73]
  472. ];
  473. @Input() override width = 600;
  474. @Input() override height = 400;
  475. override ngOnInit(): void {
  476. this.options = {
  477. title: {
  478. text: '动态K线图',
  479. left: 'center'
  480. },
  481. tooltip: {
  482. trigger: 'axis',
  483. axisPointer: {
  484. type: 'cross'
  485. }
  486. },
  487. animation: true,
  488. animationDuration: 1000,
  489. animationEasing: 'cubicOut',
  490. animationDelay: function (idx: number) {
  491. return idx * 10;
  492. },
  493. grid: {
  494. left: '10%',
  495. right: '10%',
  496. bottom: '15%'
  497. },
  498. xAxis: {
  499. data: this.data.map((item: any) => item[0]),
  500. scale: true,
  501. boundaryGap: false,
  502. axisLine: { onZero: false },
  503. splitLine: { show: false },
  504. min: 'dataMin',
  505. max: 'dataMax'
  506. },
  507. yAxis: {
  508. scale: true,
  509. splitArea: {
  510. show: true
  511. }
  512. },
  513. dataZoom: [
  514. {
  515. type: 'inside',
  516. start: 50,
  517. end: 100
  518. },
  519. {
  520. show: true,
  521. type: 'slider',
  522. top: '90%',
  523. start: 50,
  524. end: 100
  525. }
  526. ],
  527. series: [
  528. {
  529. name: '日K',
  530. type: 'candlestick',
  531. data: this.data.map((item: any) => [item[1], item[2], item[3], item[4]]),
  532. itemStyle: {
  533. color: '#ec0000',
  534. color0: '#00da3c',
  535. borderColor: '#8A0000',
  536. borderColor0: '#008F28'
  537. },
  538. emphasis: {
  539. itemStyle: {
  540. shadowBlur: 10,
  541. shadowOffsetX: 0,
  542. shadowColor: 'rgba(0, 0, 0, 0.5)'
  543. }
  544. }
  545. }
  546. ]
  547. };
  548. }
  549. }