|
|
@@ -6,11 +6,11 @@
|
|
|
import { defineComponent, ref, watch, PropType } from 'vue';
|
|
|
import { QueryTSDataRsp, QueryQuoteDayRsp } from '@/services/go/quote/interface';
|
|
|
import { QueryTSData } from '@/services/go/quote';
|
|
|
-import { getGoodsByCode } from '@/services/bus/goods';
|
|
|
-import { handleEchart, ChartData } from './setup';
|
|
|
-import EchartBase from '../echart-base/index.vue';
|
|
|
-import { getRangeTime } from '@/utils/time';
|
|
|
+import { debounce, getRangeTime } from '@/utils/time';
|
|
|
import { toDecimalFull } from '@/utils/number';
|
|
|
+import EchartBase from '../echart-base/index.vue';
|
|
|
+import { handleEchart } from './setup';
|
|
|
+import moment from 'moment';
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'EchartTime',
|
|
|
@@ -26,39 +26,50 @@ export default defineComponent({
|
|
|
},
|
|
|
setup(props) {
|
|
|
const loading = ref(true);
|
|
|
+ const historyIndexs: number[] = []; // 行情历史数据中所有非补充数据的索引位置(用于计算均线)
|
|
|
const { chartData, options, updateOptions, initOptions } = handleEchart();
|
|
|
|
|
|
// 处理图表数据
|
|
|
- const handleData = (rawData: QueryTSDataRsp): ChartData => {
|
|
|
- const datas = rawData.historyDatas!.map((item) => item.c),
|
|
|
- startTime = rawData.startTime!,
|
|
|
- endTime = rawData.endTime!,
|
|
|
- times = getRangeTime(startTime, endTime, 'HH:mm', 'm'),
|
|
|
- yestclose = rawData.preSettle!,
|
|
|
- decimal = rawData.decimalPlace!;
|
|
|
+ const handleData = (rawData: QueryTSDataRsp): void => {
|
|
|
+ historyIndexs.length = 0; // 清空数据
|
|
|
+ const datas: number[] = [],
|
|
|
+ times: string[] = [],
|
|
|
+ xAxisTimes: string[] = [],
|
|
|
+ yestclose = rawData.preSettle,
|
|
|
+ decimal = rawData.decimalPlace;
|
|
|
|
|
|
- const { last, lasttime: lastTime } = props.quoteData;
|
|
|
- const { min, max } = calcDataLine(datas, yestclose, last);
|
|
|
+ rawData.historyDatas.forEach((item, index) => {
|
|
|
+ const { c, ts } = item;
|
|
|
+ datas.push(c);
|
|
|
+ times.push(moment(ts).format('MM-DD HH:mm'));
|
|
|
+ if (!item.f) historyIndexs.push(index);
|
|
|
+ });
|
|
|
|
|
|
- return {
|
|
|
+ rawData.runSteps.forEach((item) => {
|
|
|
+ const { start, end } = item;
|
|
|
+ const rangeTime = getRangeTime(start, end, 'HH:mm', 'm');
|
|
|
+ xAxisTimes.push(...rangeTime);
|
|
|
+ });
|
|
|
+
|
|
|
+ chartData.value = {
|
|
|
datas,
|
|
|
times,
|
|
|
+ xAxisTimes,
|
|
|
yestclose,
|
|
|
- last,
|
|
|
- lastTime,
|
|
|
decimal,
|
|
|
- min,
|
|
|
- max,
|
|
|
- ma5: calcMA(rawData, 5),
|
|
|
+ ma5: calcMA(datas, 5, decimal),
|
|
|
+ ...calcDataLine(datas, yestclose),
|
|
|
};
|
|
|
};
|
|
|
|
|
|
// 计算图表最高低指标线
|
|
|
- const calcDataLine = (datas: number[], yestclose: number, last: number) => {
|
|
|
- let max = Math.max(...datas, last); // 取历历史数据最高价
|
|
|
- let min = Math.min(...datas, last); // 取历史数据最低价
|
|
|
- const a = yestclose - min; // 计算收盘价和最低价的差值
|
|
|
- const b = max - yestclose; // 计算收盘价和最高价的差值
|
|
|
+ const calcDataLine = (datas: number[], yestclose: number) => {
|
|
|
+ let max = Math.max(...datas); // 取历史行情最高价
|
|
|
+ let min = Math.min(...datas); // 取历史行情最低价
|
|
|
+
|
|
|
+ const last = datas[datas.length - 1], // 历史行情最后收盘价
|
|
|
+ a = yestclose - min, // 计算收盘价和最低价的差值
|
|
|
+ b = max - yestclose; // 计算收盘价和最高价的差值
|
|
|
|
|
|
// 比较差值大小
|
|
|
if (a > b) {
|
|
|
@@ -84,37 +95,28 @@ export default defineComponent({
|
|
|
};
|
|
|
|
|
|
// 计算平均线
|
|
|
- const calcMA = (rawData: QueryTSDataRsp, count: number) => {
|
|
|
- const datas = rawData.historyDatas!,
|
|
|
- decimal = rawData.decimalPlace!;
|
|
|
-
|
|
|
+ const calcMA = (datas: number[], count: number, decimal: number) => {
|
|
|
const result: string[] = [];
|
|
|
if (datas.length >= count) {
|
|
|
- // 所有非补充数据的索引id
|
|
|
- const dataIndexs = datas.reduce((prev: number[], cur, index) => {
|
|
|
- if (!cur.f) prev.push(index);
|
|
|
- return prev;
|
|
|
- }, []);
|
|
|
// 均线起始位置
|
|
|
- const startIndex = dataIndexs[count - 1];
|
|
|
-
|
|
|
+ const startIndex = historyIndexs[count - 1];
|
|
|
datas.forEach((item, index) => {
|
|
|
if (index < startIndex) {
|
|
|
result.push('-');
|
|
|
} else {
|
|
|
- const j = dataIndexs.findIndex((val) => val === index);
|
|
|
+ const j = historyIndexs.findIndex((val) => val === index);
|
|
|
// 判断是否补充数据
|
|
|
if (j === -1) {
|
|
|
// 取上个平均值
|
|
|
result.push(result[result.length - 1]);
|
|
|
} else {
|
|
|
// 向后取MA数
|
|
|
- const splitIndexs = dataIndexs.slice(j - (count - 1), j + 1);
|
|
|
+ const maIndexs = historyIndexs.slice(j - (count - 1), j + 1);
|
|
|
// 计算总价
|
|
|
- const total = splitIndexs.reduce((sum, val) => sum + datas[val].c, 0);
|
|
|
+ const total = maIndexs.reduce((sum, val) => sum + datas[val], 0);
|
|
|
// 计算均线
|
|
|
- const average = toDecimalFull(total / count, decimal);
|
|
|
- result.push(average);
|
|
|
+ const ma = toDecimalFull(total / count, decimal);
|
|
|
+ result.push(ma);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
@@ -122,21 +124,49 @@ export default defineComponent({
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
+ // 更新图表K线数据
|
|
|
+ const updateChartData = () => {
|
|
|
+ const { datas, times } = chartData.value,
|
|
|
+ lastIndex = datas.length - 1, // 历史行情最后索引位置
|
|
|
+ lastTime = moment(times[times.length - 1]), // 历史行情最后时间
|
|
|
+ newTime = moment(props.quoteData.lasttime), // 实时行情最新时间
|
|
|
+ newPrice = props.quoteData.last; // 实时行情最新价
|
|
|
+
|
|
|
+ const cycleMilliseconds = 60 * 1000; // 周期毫秒数
|
|
|
+
|
|
|
+ const diffTime = newTime.valueOf() - lastTime.valueOf(); // 计算时间差
|
|
|
+ // 判断时间差是否大于周期时间
|
|
|
+ if (diffTime > cycleMilliseconds) {
|
|
|
+ lastTime.add(cycleMilliseconds, 'ms');
|
|
|
+ times.push(lastTime.format('MM-DD HH:mm')); // 添加历史行情时间
|
|
|
+ datas.push(newPrice); // 添加历史行情数据
|
|
|
+ historyIndexs.push(lastIndex + 1); // 添加历史行情索引
|
|
|
+ } else {
|
|
|
+ datas[lastIndex] = newPrice; // 更新历史行情数据
|
|
|
+ }
|
|
|
+
|
|
|
+ // 延迟图表更新,减少卡顿
|
|
|
+ debounce(() => {
|
|
|
+ const { min, max } = calcDataLine(datas, chartData.value.yestclose);
|
|
|
+ chartData.value.ma5 = calcMA(datas, 5, chartData.value.decimal);
|
|
|
+ chartData.value.min = min;
|
|
|
+ chartData.value.max = max;
|
|
|
+
|
|
|
+ updateOptions();
|
|
|
+ }, 1000);
|
|
|
+ };
|
|
|
+
|
|
|
// 查询分时数据
|
|
|
QueryTSData(props.quoteData.goodscode).then((res) => {
|
|
|
- chartData.value = handleData(res);
|
|
|
+ handleData(res);
|
|
|
initOptions();
|
|
|
});
|
|
|
|
|
|
watch(
|
|
|
() => props.quoteData.last,
|
|
|
- (val) => {
|
|
|
+ () => {
|
|
|
if (!loading.value) {
|
|
|
- const { min, max } = calcDataLine(chartData.value.datas, chartData.value.yestclose, val);
|
|
|
- chartData.value.last = val;
|
|
|
- chartData.value.min = min;
|
|
|
- chartData.value.max = max;
|
|
|
- updateOptions();
|
|
|
+ updateChartData();
|
|
|
}
|
|
|
}
|
|
|
);
|