st-comp 0.0.166 → 0.0.168

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "st-comp",
3
3
  "public": true,
4
- "version": "0.0.166",
4
+ "version": "0.0.168",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -4,7 +4,7 @@ import dayjs from "dayjs";
4
4
  import * as echarts from "echarts";
5
5
  import { stMath, debounce, addResizeListener } from "st-func";
6
6
  import { ref, watch, computed, onMounted, onUnmounted, inject } from "vue";
7
- import { loadKlineConfig, getSubOptions, mergeklineData, handleMarkPointTradeLog, handleNetPositionLine, handleMarkPointOffset, normalizeToKlineTimeByMatch } from "./utils.js";
7
+ import { loadKlineConfig, checkTimeInterval, getSubOptions, mergeklineData, handleMarkPointTradeLog, handleNetPositionLine, handleMarkPointOffset, normalizeToKlineTimeByMatch } from "./utils.js";
8
8
  import Tips from "./components/Tips.vue";
9
9
  import SliderChart from "./components/SliderChart.vue";
10
10
 
@@ -174,10 +174,26 @@ const getMainData = async ({ startTime, endTime }) => {
174
174
  contractType: props.varietyStock ? null : props.klineType, // 合约类型
175
175
  mainIndicatorList: props.indicatorStore.getIndicatorParams(props.mainIndicator),
176
176
  subIndicator: subIndicator.value,
177
- startTime: dayjs(startTime).subtract(50, "day").format("YYYY-MM-DD HH:mm:ss"), // 确保缩放, 多请求部分数据, 也可以兼容undefined的情况
178
- endTime: dayjs(endTime).add(50, "day").format("YYYY-MM-DD HH:mm:ss"), // 确保缩放, 多请求部分数据, 也可以兼容undefined的情况
179
177
  deleteFirstNumber: 1, // >> 重要: 绩效后端特殊要求传参 <<
180
178
  };
179
+ // Echarts如果一屏如果正好展示了所有数据, 是无法缩放触发加载更多的
180
+ // 所以在请求中需要对开始和结束时间进行延伸, 但是首屏的展示时间定位还是会以传入的开始结束时间为准
181
+ if (["1", "2", "3", "4", "5"].includes(props.cycle)) {
182
+ Object.assign(params, {
183
+ startTime: dayjs(startTime).subtract(1, "day").format("YYYY-MM-DD HH:mm:ss"),
184
+ endTime: dayjs(endTime).add(1, "day").format("YYYY-MM-DD HH:mm:ss"),
185
+ });
186
+ } else if (["6", "7"].includes(props.cycle)) {
187
+ Object.assign(params, {
188
+ startTime: dayjs(startTime).subtract(50, "day").format("YYYY-MM-DD HH:mm:ss"),
189
+ endTime: dayjs(endTime).add(50, "day").format("YYYY-MM-DD HH:mm:ss"),
190
+ });
191
+ } else {
192
+ Object.assign(params, {
193
+ startTime: dayjs(startTime).subtract(10, "month").format("YYYY-MM-DD HH:mm:ss"),
194
+ endTime: dayjs(endTime).add(10, "month").format("YYYY-MM-DD HH:mm:ss"),
195
+ });
196
+ }
181
197
  const { body } = await request.post("/middleLayer/kline/getKline", params);
182
198
  klineData.value = body ?? { data: [], mainIndicator: [], subIndicator: [], time: [] };
183
199
 
@@ -578,7 +594,11 @@ const draw = (params = { startValue: 0, endValue: 0 }) => {
578
594
 
579
595
  // 拖拽轴: 拖拽回调
580
596
  const handleSliderChange = (params) => {
581
- const { startTime, endTime } = params;
597
+ const [startTime, endTime] = checkTimeInterval({
598
+ startTime: params.startTime,
599
+ endTime: params.endTime,
600
+ cycle: props.cycle,
601
+ });
582
602
  getMainData({ startTime, endTime });
583
603
  };
584
604
  // 键盘控制 [↑↓←→缩放平移]
@@ -659,9 +679,23 @@ watch(
659
679
  },
660
680
  { deep: true }
661
681
  );
662
- // 监控: [主指标, 副指标, 指标配置, 周期选项, 复权选项, 常用选项] => 重加载K线 (缩放不变)
682
+ // 监控: [周期选项] => 重加载K线 (缩放不变+校验时间间隔)
683
+ watch(
684
+ () => [props.cycle],
685
+ () => {
686
+ const { startValue, endValue } = mainChartIns.getOption()?.dataZoom[0] ?? {};
687
+ const [startTime, endTime] = checkTimeInterval({
688
+ startTime: klineData.value.time[startValue],
689
+ endTime: klineData.value.time[endValue],
690
+ cycle: props.cycle,
691
+ });
692
+ getMainData({ startTime, endTime });
693
+ },
694
+ { deep: true }
695
+ );
696
+ // 监控: [主指标, 副指标, 指标配置, 复权选项, 常用选项] => 重加载K线 (缩放不变)
663
697
  watch(
664
- () => [props.mainIndicator, subIndicator.value, props.indicatorStore?.filterIndicator, props.indicatorStore?.customIndicator, props.cycle, props.rightType, props.klineType],
698
+ () => [props.mainIndicator, subIndicator.value, props.indicatorStore?.filterIndicator, props.indicatorStore?.customIndicator, props.rightType, props.klineType],
665
699
  () => {
666
700
  const { startValue, endValue } = mainChartIns.getOption()?.dataZoom[0] ?? {};
667
701
  const [startTime, endTime] = [klineData.value.time[startValue], klineData.value.time[endValue]];
@@ -14,6 +14,29 @@ export const loadKlineConfig = {
14
14
  loadAddCount: 2000,
15
15
  };
16
16
 
17
+ // 前端估算K线根数的周期分布
18
+ export const dayBarsNumByCycle = {
19
+ 1: 240, // 每天240根(4小时×60分钟)
20
+ 2: 48, // 每天48根(4小时×12根)
21
+ 3: 16, // 每天16根(4小时×4根)
22
+ 4: 8, // 每天8根(4小时×2根)
23
+ 5: 4, // 每天4根(4小时×1根)
24
+ 6: 1, // 每天1根
25
+ 7: 0.2, // 每周1根(按5个交易日算)
26
+ 8: 0.033, // 每月1根(按21个交易日算)
27
+ };
28
+
29
+ // 校验时间间隔, 避免开始和结束时间过大, 超过一屏根数上限
30
+ export const checkTimeInterval = ({ startTime, endTime, cycle }) => {
31
+ // 大切小时可能会出现请求超过一屏上限的数据量, 进行时间间隔校验, 由于是估算, 所以计算时可以比一屏上限根数多一些
32
+ const { maxValueSpan } = loadKlineConfig;
33
+ const N = Math.ceil((maxValueSpan + 1000) / dayBarsNumByCycle[cycle]);
34
+ const d1 = dayjs(startTime);
35
+ const d2 = dayjs(endTime);
36
+ const diff = d2.diff(d1, "day");
37
+ return [diff <= N ? startTime : dayjs(endTime).subtract(N, "day").format("YYYY-MM-DD HH:mm:ss"), endTime];
38
+ };
39
+
17
40
  // 获取副图配置
18
41
  const getSubBarStyle = (data, index) => {
19
42
  const itemData = data[index];
@@ -446,7 +469,7 @@ export const normalizeToKlineTimeByMatch = (klineTimeArray, timeRange, cycle) =>
446
469
  klineEnd = klineTimeArray.findLast((t) => new Date(t).getTime() <= new Date(end).getTime());
447
470
  }
448
471
  }
449
- return [klineStart, klineEnd]
472
+ return [klineStart, klineEnd];
450
473
  };
451
474
 
452
475
  // 统一处理markPoint标记点的偏移量
@@ -4,7 +4,6 @@ import { nextTick, ref, watch } from "vue";
4
4
  import { Plus, CircleCloseFilled, InfoFilled } from "@element-plus/icons-vue";
5
5
  import { handleVerifyScore, extractConditionDetails } from "./tools.js";
6
6
  import FactorDescription from "./FactorDescription.vue";
7
- import ScriptSelect from "./ScriptSelect.vue";
8
7
  import MonacoEditor from "../../../MonacoEditor/index.vue"
9
8
 
10
9
  const props = defineProps({
@@ -29,7 +28,7 @@ const data = defineModel("data", {
29
28
  });
30
29
 
31
30
  const monacoEditorRef = ref();
32
- const scriptSelectRef = ref();
31
+ const stVarSelectDialogRef = ref();
33
32
  // 弹窗开关
34
33
  const visible = ref(false);
35
34
  const visibleDescriptions = ref(false);
@@ -55,7 +54,7 @@ const dialogForm = ref({
55
54
 
56
55
  watch(() => [factorType.value, visible.value], () => {
57
56
  if (factorType.value === '模版' || visible.value === false) {
58
- scriptSelectRef.value.close();
57
+ stVarSelectDialogRef.value.close();
59
58
  }
60
59
  }, { deep: true })
61
60
 
@@ -236,7 +235,7 @@ const handleDeleteTag = (aciton, index) => {
236
235
  const open = () => {
237
236
  const zIndex = document.getElementsByClassName('factor-dialog')?.[0]?.style?.zIndex;
238
237
  console.log(zIndex)
239
- scriptSelectRef.value.open(monacoEditorRef.value, zIndex);
238
+ stVarSelectDialogRef.value.open(monacoEditorRef.value, zIndex);
240
239
  }
241
240
  </script>
242
241
 
@@ -605,7 +604,7 @@ const open = () => {
605
604
  :data="config.factorDescriptions?.filter((item) => [1, 3].includes(item.type))"
606
605
  />
607
606
  <!-- 变量选择器 -->
608
- <ScriptSelect ref="scriptSelectRef" />
607
+ <st-varSelectDialog ref="stVarSelectDialogRef" />
609
608
  </template>
610
609
 
611
610
  <style lang="scss" scoped>
@@ -1,11 +1,19 @@
1
1
  <template>
2
2
  <div>
3
- <el-button @click="stKlineConfigRef?.open">打开K线自定义配置</el-button>
4
- <st-klineConfig
5
- ref="stKlineConfigRef"
6
- :indicatorStore="indicatorStore"
7
- @callBack="(formJson) => handleUserKlineConfig('update', formJson)"
8
- />
3
+ <div style="display: flex; align-items: center; gap: 10px">
4
+ <el-button @click="stKlineConfigRef?.open">打开K线自定义配置</el-button>
5
+ <el-select
6
+ v-model="cycle"
7
+ style="width: 100px"
8
+ >
9
+ <el-option
10
+ v-for="item in cycleOptions"
11
+ :key="item.value"
12
+ :value="item.value"
13
+ :label="item.label"
14
+ />
15
+ </el-select>
16
+ </div>
9
17
  <div class="main">
10
18
  <template v-if="!loading">
11
19
  <st-klinePlus
@@ -25,6 +33,11 @@
25
33
  />
26
34
  </template>
27
35
  </div>
36
+ <st-klineConfig
37
+ ref="stKlineConfigRef"
38
+ :indicatorStore="indicatorStore"
39
+ @callBack="(formJson) => handleUserKlineConfig('update', formJson)"
40
+ />
28
41
  </div>
29
42
  </template>
30
43
 
@@ -39,6 +52,12 @@ const loading = ref(true);
39
52
  const userKlineConfig = reactive({});
40
53
  provide("userKlineConfig", userKlineConfig);
41
54
 
55
+ const cycleOptions = [
56
+ { label: "1m", value: "1" },
57
+ { label: "1d", value: "6" },
58
+ { label: "1mon", value: "8" },
59
+ ];
60
+
42
61
  const varietyName = ref(null);
43
62
  const varietyCode = ref("000016");
44
63
  const varietyStock = ref(1); // 0: 期货, 1: 股票, 2: 期权