|
@@ -13,193 +13,193 @@ import { handleEchart } from './setup';
|
|
|
import moment from 'moment';
|
|
import moment from 'moment';
|
|
|
|
|
|
|
|
export default defineComponent({
|
|
export default defineComponent({
|
|
|
- name: 'EchartTime',
|
|
|
|
|
- emits: ['change'],
|
|
|
|
|
- components: {
|
|
|
|
|
- EchartBase,
|
|
|
|
|
|
|
+ name: 'EchartTime',
|
|
|
|
|
+ emits: ['change'],
|
|
|
|
|
+ components: {
|
|
|
|
|
+ EchartBase,
|
|
|
|
|
+ },
|
|
|
|
|
+ props: {
|
|
|
|
|
+ // 实时行情数据
|
|
|
|
|
+ quoteData: {
|
|
|
|
|
+ type: Object as PropType<QueryQuoteDayRsp>,
|
|
|
|
|
+ required: true,
|
|
|
},
|
|
},
|
|
|
- props: {
|
|
|
|
|
- // 实时行情数据
|
|
|
|
|
- quoteData: {
|
|
|
|
|
- type: Object as PropType<QueryQuoteDayRsp>,
|
|
|
|
|
- required: true,
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ setup(props, { emit }) {
|
|
|
|
|
+ const loading = ref(false);
|
|
|
|
|
+ const isEmpty = ref(false);
|
|
|
|
|
+ const historyIndexs: number[] = []; // 行情历史数据中所有非补充数据的索引位置(用于计算均线)
|
|
|
|
|
+ const { chartData, options, updateOptions, initOptions } = handleEchart();
|
|
|
|
|
+
|
|
|
|
|
+ // 处理图表数据
|
|
|
|
|
+ const handleData = (rawData: QueryTSDataRsp): void => {
|
|
|
|
|
+ historyIndexs.length = 0; // 清空数据
|
|
|
|
|
+ const datas: number[] = [],
|
|
|
|
|
+ times: string[] = [],
|
|
|
|
|
+ xAxisTimes: string[] = [],
|
|
|
|
|
+ yestclose = rawData.preSettle,
|
|
|
|
|
+ decimal = rawData.decimalPlace;
|
|
|
|
|
+
|
|
|
|
|
+ // 历史行情日期
|
|
|
|
|
+ rawData.historyDatas.forEach((item, index) => {
|
|
|
|
|
+ const { c, ts } = item;
|
|
|
|
|
+ datas.push(c);
|
|
|
|
|
+ times.push(moment(ts).format('YYYY-MM-DD HH:mm:ss'));
|
|
|
|
|
+ if (!item.f) historyIndexs.push(index);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 时间轴(开盘交易时间)
|
|
|
|
|
+ rawData.runSteps.forEach((item) => {
|
|
|
|
|
+ const { start, end } = item;
|
|
|
|
|
+ const rangeTime = getRangeTime(start, end, 'HH:mm', 'm');
|
|
|
|
|
+ xAxisTimes.push(...rangeTime);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ chartData.value = {
|
|
|
|
|
+ yestclose,
|
|
|
|
|
+ decimal,
|
|
|
|
|
+ rawTime: times,
|
|
|
|
|
+ ...calcDataLine(datas, yestclose),
|
|
|
|
|
+ source: {
|
|
|
|
|
+ time: xAxisTimes,
|
|
|
|
|
+ data: datas,
|
|
|
|
|
+ ma5: calcMA(datas, 5, decimal),
|
|
|
},
|
|
},
|
|
|
- },
|
|
|
|
|
- setup(props, { emit }) {
|
|
|
|
|
- const loading = ref(false);
|
|
|
|
|
- const isEmpty = ref(false);
|
|
|
|
|
- const historyIndexs: number[] = []; // 行情历史数据中所有非补充数据的索引位置(用于计算均线)
|
|
|
|
|
- const { chartData, options, updateOptions, initOptions } = handleEchart();
|
|
|
|
|
-
|
|
|
|
|
- // 处理图表数据
|
|
|
|
|
- const handleData = (rawData: QueryTSDataRsp): void => {
|
|
|
|
|
- historyIndexs.length = 0; // 清空数据
|
|
|
|
|
- const datas: number[] = [],
|
|
|
|
|
- times: string[] = [],
|
|
|
|
|
- xAxisTimes: string[] = [],
|
|
|
|
|
- yestclose = rawData.preSettle,
|
|
|
|
|
- decimal = rawData.decimalPlace;
|
|
|
|
|
-
|
|
|
|
|
- // 历史行情日期
|
|
|
|
|
- rawData.historyDatas.forEach((item, index) => {
|
|
|
|
|
- const { c, ts } = item;
|
|
|
|
|
- datas.push(c);
|
|
|
|
|
- times.push(moment(ts).format('YYYY-MM-DD HH:mm:ss'));
|
|
|
|
|
- if (!item.f) historyIndexs.push(index);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // 时间轴(开盘交易时间)
|
|
|
|
|
- rawData.runSteps.forEach((item) => {
|
|
|
|
|
- const { start, end } = item;
|
|
|
|
|
- const rangeTime = getRangeTime(start, end, 'HH:mm', 'm');
|
|
|
|
|
- xAxisTimes.push(...rangeTime);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- chartData.value = {
|
|
|
|
|
- yestclose,
|
|
|
|
|
- decimal,
|
|
|
|
|
- rawTime: times,
|
|
|
|
|
- ...calcDataLine(datas, yestclose),
|
|
|
|
|
- source: {
|
|
|
|
|
- time: xAxisTimes,
|
|
|
|
|
- data: datas,
|
|
|
|
|
- ma5: calcMA(datas, 5, decimal),
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 计算图表最高低指标线
|
|
|
|
|
- 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) {
|
|
|
|
|
- max = yestclose + a;
|
|
|
|
|
- if (last > max) {
|
|
|
|
|
- const c = last - max;
|
|
|
|
|
- max += c;
|
|
|
|
|
- min -= c;
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- min = min - (b - a);
|
|
|
|
|
- if (min > last) {
|
|
|
|
|
- const c = min - last;
|
|
|
|
|
- max += c;
|
|
|
|
|
- min -= c;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- max: max + max * 0.01,
|
|
|
|
|
- min: min - min * 0.01,
|
|
|
|
|
- };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 计算平均线
|
|
|
|
|
- const calcMA = (data: number[], count: number, decimal: number) => {
|
|
|
|
|
- const result: string[] = [];
|
|
|
|
|
- if (data.length >= count) {
|
|
|
|
|
- // 均线起始位置
|
|
|
|
|
- const startIndex = historyIndexs[count - 1];
|
|
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
|
|
- if (startIndex === undefined || i < startIndex) {
|
|
|
|
|
- result.push('-');
|
|
|
|
|
- } else {
|
|
|
|
|
- const j = historyIndexs.findIndex((val) => val === i);
|
|
|
|
|
- // 判断是否补充数据
|
|
|
|
|
- if (j === -1) {
|
|
|
|
|
- // 取上个平均值
|
|
|
|
|
- result.push(result[result.length - 1]);
|
|
|
|
|
- } else {
|
|
|
|
|
- // 向后取MA数
|
|
|
|
|
- const maIndexs = historyIndexs.slice(j - (count - 1), j + 1);
|
|
|
|
|
- // 计算总价
|
|
|
|
|
- const total = maIndexs.reduce((sum, val) => sum + data[val], 0);
|
|
|
|
|
- // 计算均线
|
|
|
|
|
- const ma = toDecimalFull(total / count, decimal);
|
|
|
|
|
- result.push(ma);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 更新分时数据
|
|
|
|
|
- const updateChartData = () => {
|
|
|
|
|
- const { source, rawTime } = chartData.value,
|
|
|
|
|
- lastIndex = source.data.length - 1, // 历史行情最后索引位置
|
|
|
|
|
- lastTime = moment(rawTime[rawTime.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');
|
|
|
|
|
- rawTime.push(lastTime.format('YYYY-MM-DD HH:mm:ss')); // 添加历史行情时间
|
|
|
|
|
- source.data.push(newPrice); // 添加历史行情数据
|
|
|
|
|
- historyIndexs.push(lastIndex + 1); // 添加历史行情索引
|
|
|
|
|
|
|
+ };
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 计算图表最高低指标线
|
|
|
|
|
+ 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) {
|
|
|
|
|
+ max = yestclose + a;
|
|
|
|
|
+ if (last > max) {
|
|
|
|
|
+ const c = last - max;
|
|
|
|
|
+ max += c;
|
|
|
|
|
+ min -= c;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ min = min - (b - a);
|
|
|
|
|
+ if (min > last) {
|
|
|
|
|
+ const c = min - last;
|
|
|
|
|
+ max += c;
|
|
|
|
|
+ min -= c;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ max: max + max * 0.01,
|
|
|
|
|
+ min: min - min * 0.01,
|
|
|
|
|
+ };
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 计算平均线
|
|
|
|
|
+ const calcMA = (data: number[], count: number, decimal: number) => {
|
|
|
|
|
+ const result: string[] = [];
|
|
|
|
|
+ if (data.length >= count) {
|
|
|
|
|
+ // 均线起始位置
|
|
|
|
|
+ const startIndex = historyIndexs[count - 1];
|
|
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
|
|
+ if (startIndex === undefined || i < startIndex) {
|
|
|
|
|
+ result.push('-');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const j = historyIndexs.findIndex((val) => val === i);
|
|
|
|
|
+ // 判断是否补充数据
|
|
|
|
|
+ if (j === -1) {
|
|
|
|
|
+ // 取上个平均值
|
|
|
|
|
+ result.push(result[result.length - 1]);
|
|
|
} else {
|
|
} else {
|
|
|
- source.data[lastIndex] = newPrice; // 更新历史行情数据
|
|
|
|
|
|
|
+ // 向后取MA数
|
|
|
|
|
+ const maIndexs = historyIndexs.slice(j - (count - 1), j + 1);
|
|
|
|
|
+ // 计算总价
|
|
|
|
|
+ const total = maIndexs.reduce((sum, val) => sum + data[val], 0);
|
|
|
|
|
+ // 计算均线
|
|
|
|
|
+ const ma = toDecimalFull(total / count, decimal);
|
|
|
|
|
+ result.push(ma);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- source.ma5 = calcMA(source.data, 5, chartData.value.decimal);
|
|
|
|
|
-
|
|
|
|
|
- const { min, max } = calcDataLine(source.data, chartData.value.yestclose);
|
|
|
|
|
- chartData.value.min = min;
|
|
|
|
|
- chartData.value.max = max;
|
|
|
|
|
-
|
|
|
|
|
- // 延迟图表更新,减少卡顿
|
|
|
|
|
- debounce(() => {
|
|
|
|
|
- updateOptions();
|
|
|
|
|
- }, 1000);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- onMounted(() => {
|
|
|
|
|
- loading.value = true;
|
|
|
|
|
- // 查询分时数据
|
|
|
|
|
- QueryTSData(props.quoteData.goodscode)
|
|
|
|
|
- .then((res) => {
|
|
|
|
|
- if (res.historyDatas.length) {
|
|
|
|
|
- isEmpty.value = false;
|
|
|
|
|
- handleData(res);
|
|
|
|
|
- // 调用父级函数查询tik数据 (不合理的逻辑处理,待优化)
|
|
|
|
|
- emit('change', res.startTime, res.endTime);
|
|
|
|
|
- } else {
|
|
|
|
|
- isEmpty.value = true;
|
|
|
|
|
- }
|
|
|
|
|
- initOptions();
|
|
|
|
|
- })
|
|
|
|
|
- .catch(() => {
|
|
|
|
|
- isEmpty.value = true;
|
|
|
|
|
- })
|
|
|
|
|
- .finally(() => {
|
|
|
|
|
- loading.value = false;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 更新分时数据
|
|
|
|
|
+ const updateChartData = () => {
|
|
|
|
|
+ const { source, rawTime } = chartData.value,
|
|
|
|
|
+ lastIndex = source.data.length - 1, // 历史行情最后索引位置
|
|
|
|
|
+ lastTime = moment(rawTime[rawTime.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');
|
|
|
|
|
+ rawTime.push(lastTime.format('YYYY-MM-DD HH:mm:ss')); // 添加历史行情时间
|
|
|
|
|
+ source.data.push(newPrice); // 添加历史行情数据
|
|
|
|
|
+ historyIndexs.push(lastIndex + 1); // 添加历史行情索引
|
|
|
|
|
+ } else {
|
|
|
|
|
+ source.data[lastIndex] = newPrice; // 更新历史行情数据
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ source.ma5 = calcMA(source.data, 5, chartData.value.decimal);
|
|
|
|
|
+
|
|
|
|
|
+ const { min, max } = calcDataLine(source.data, chartData.value.yestclose);
|
|
|
|
|
+ chartData.value.min = min;
|
|
|
|
|
+ chartData.value.max = max;
|
|
|
|
|
+
|
|
|
|
|
+ // 延迟图表更新,减少卡顿
|
|
|
|
|
+ debounce(() => {
|
|
|
|
|
+ updateOptions();
|
|
|
|
|
+ }, 1000);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ // 查询分时数据
|
|
|
|
|
+ QueryTSData(props.quoteData.goodscode)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ if (res.historyDatas.length) {
|
|
|
|
|
+ isEmpty.value = false;
|
|
|
|
|
+ handleData(res);
|
|
|
|
|
+ // 调用父级函数查询tik数据 (不合理的逻辑处理,待优化)
|
|
|
|
|
+ emit('change', res.startTime, res.endTime);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ isEmpty.value = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ initOptions();
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ isEmpty.value = true;
|
|
|
|
|
+ })
|
|
|
|
|
+ .finally(() => {
|
|
|
|
|
+ loading.value = false;
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- watch(
|
|
|
|
|
- () => props.quoteData.last,
|
|
|
|
|
- () => {
|
|
|
|
|
- if (!loading.value) {
|
|
|
|
|
- updateChartData();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- loading,
|
|
|
|
|
- isEmpty,
|
|
|
|
|
- options,
|
|
|
|
|
- };
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ watch(
|
|
|
|
|
+ () => props.quoteData.last,
|
|
|
|
|
+ () => {
|
|
|
|
|
+ if (!loading.value) {
|
|
|
|
|
+ updateChartData();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ loading,
|
|
|
|
|
+ isEmpty,
|
|
|
|
|
+ options,
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|