|
@@ -251,47 +251,85 @@ export function categoryContribOption(categoryWeighted) {
|
|
|
|
|
|
|
|
// ===== 4.2.1 新增板块 =====
|
|
// ===== 4.2.1 新增板块 =====
|
|
|
|
|
|
|
|
-// ===== 政治经济不确定性指数(单折线) =====
|
|
|
|
|
-export function epuLineOption(series) {
|
|
|
|
|
- const dates = series.map((s) => s[0])
|
|
|
|
|
- const values = series.map((s) => s[1])
|
|
|
|
|
|
|
+// ===== 政治经济不确定性标准指数(双折线) =====
|
|
|
|
|
+// 1) 全球:地缘政治风险指数 → geoSeries
|
|
|
|
|
+// 2) 全球:经济政策不确定性指数:按GDP现价加权平均 → epuSeries
|
|
|
|
|
+export function epuLineOption(geoSeries, epuSeries) {
|
|
|
|
|
+ const dates = geoSeries.map((s) => s[0])
|
|
|
|
|
+ const geoValues = geoSeries.map((s) => s[1])
|
|
|
|
|
+ const epuValues = epuSeries.map((s) => s[1])
|
|
|
|
|
+ const lastDate = dates[dates.length - 1]
|
|
|
|
|
+ const lastGeo = geoValues[geoValues.length - 1]
|
|
|
|
|
+ const lastEpu = epuValues[epuValues.length - 1]
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
|
trigger: 'axis',
|
|
trigger: 'axis',
|
|
|
- axisPointer: { type: 'line', lineStyle: { color: C.warn, type: 'dashed' } },
|
|
|
|
|
- valueFormatter: (v) => v.toFixed(1),
|
|
|
|
|
|
|
+ axisPointer: { type: 'line', lineStyle: { color: C.mut, type: 'dashed' } },
|
|
|
|
|
+ valueFormatter: (v) => (v == null ? '—' : v.toFixed(1)),
|
|
|
|
|
+ },
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ data: [
|
|
|
|
|
+ { name: '全球:地缘政治风险指数', itemStyle: { color: C.warn } },
|
|
|
|
|
+ { name: '全球:经济政策不确定性指数(GDP加权)', itemStyle: { color: C.brand } },
|
|
|
|
|
+ ],
|
|
|
|
|
+ top: 4,
|
|
|
|
|
+ textStyle: { color: C.mut, fontSize: 11 },
|
|
|
|
|
+ itemWidth: 14,
|
|
|
},
|
|
},
|
|
|
- grid: { top: 28, left: 50, right: 24, bottom: 32, containLabel: true },
|
|
|
|
|
|
|
+ grid: { top: 36, left: 50, right: 56, bottom: 32, containLabel: true },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
data: dates,
|
|
data: dates,
|
|
|
...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }),
|
|
...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }),
|
|
|
},
|
|
},
|
|
|
- yAxis: { type: 'value', ...axisStyle() },
|
|
|
|
|
|
|
+ yAxis: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ name: '地缘政治',
|
|
|
|
|
+ nameTextStyle: { color: C.warn, fontSize: 10.5, padding: [0, 0, 0, -28] },
|
|
|
|
|
+ position: 'left',
|
|
|
|
|
+ ...axisStyle(),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ name: '经济政策不确定性',
|
|
|
|
|
+ nameTextStyle: { color: C.brand, fontSize: 10.5, padding: [0, -28, 0, 0] },
|
|
|
|
|
+ position: 'right',
|
|
|
|
|
+ ...axisStyle({ splitLine: { show: false } }),
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
- name: 'EPU 指数',
|
|
|
|
|
|
|
+ name: '全球:地缘政治风险指数',
|
|
|
type: 'line',
|
|
type: 'line',
|
|
|
- data: values,
|
|
|
|
|
|
|
+ yAxisIndex: 0,
|
|
|
|
|
+ data: geoValues,
|
|
|
symbol: 'none',
|
|
symbol: 'none',
|
|
|
smooth: true,
|
|
smooth: true,
|
|
|
- lineStyle: { color: C.warn, width: 2.4 },
|
|
|
|
|
- areaStyle: {
|
|
|
|
|
- color: {
|
|
|
|
|
- type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
|
|
|
|
|
- colorStops: [
|
|
|
|
|
- { offset: 0, color: 'rgba(232,145,45,0.30)' },
|
|
|
|
|
- { offset: 1, color: 'rgba(232,145,45,0.02)' },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 2.2 },
|
|
|
markPoint: {
|
|
markPoint: {
|
|
|
symbol: 'circle',
|
|
symbol: 'circle',
|
|
|
symbolSize: 8,
|
|
symbolSize: 8,
|
|
|
itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
label: { formatter: (p) => p.value.toFixed(1), color: C.warn, fontSize: 10.5, position: 'top', fontWeight: 600 },
|
|
label: { formatter: (p) => p.value.toFixed(1), color: C.warn, fontSize: 10.5, position: 'top', fontWeight: 600 },
|
|
|
- data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
|
|
|
|
|
+ data: [{ name: '当前', value: lastGeo, xAxis: lastDate, yAxis: lastGeo }],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '全球:经济政策不确定性指数(GDP加权)',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: epuValues,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.brand, width: 2.2 },
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 8,
|
|
|
|
|
+ itemStyle: { color: C.brand, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(1), color: C.brand, fontSize: 10.5, position: 'top', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前', value: lastEpu, xAxis: lastDate, yAxis: lastEpu }],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
@@ -347,7 +385,7 @@ export function revenueProfitLineOption(series) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== PE / PB 估值带 =====
|
|
// ===== PE / PB 估值带 =====
|
|
|
-function priceBandOption(series, opts) {
|
|
|
|
|
|
|
+function priceBandOption(series, opts, closeSeries) {
|
|
|
const dates = series.map((s) => s[0])
|
|
const dates = series.map((s) => s[0])
|
|
|
const mid = series.map((s) => s[1])
|
|
const mid = series.map((s) => s[1])
|
|
|
const up = series.map((s) => s[2])
|
|
const up = series.map((s) => s[2])
|
|
@@ -355,6 +393,17 @@ function priceBandOption(series, opts) {
|
|
|
const cur = series.map((s) => s[4])
|
|
const cur = series.map((s) => s[4])
|
|
|
const upperBand = up.map((v, i) => v - mid[i])
|
|
const upperBand = up.map((v, i) => v - mid[i])
|
|
|
const lowerBand = dn.map((v, i) => dn[i] - mid[i])
|
|
const lowerBand = dn.map((v, i) => dn[i] - mid[i])
|
|
|
|
|
+ const hasClose = Array.isArray(closeSeries) && closeSeries.length > 0
|
|
|
|
|
+ const closeMap = hasClose ? new Map(closeSeries.map(([d, v]) => [d, v])) : null
|
|
|
|
|
+ const closeAligned = hasClose ? dates.map((d) => (closeMap.has(d) ? closeMap.get(d) : null)) : []
|
|
|
|
|
+ const lastClose = hasClose ? (closeSeries[closeSeries.length - 1][1]) : null
|
|
|
|
|
+ const legendData = [
|
|
|
|
|
+ { name: '当前', itemStyle: { color: opts.curColor } },
|
|
|
|
|
+ { name: '上轨', itemStyle: { color: C.faint } },
|
|
|
|
|
+ { name: '中枢', itemStyle: { color: C.mut } },
|
|
|
|
|
+ { name: '下轨', itemStyle: { color: C.faint } },
|
|
|
|
|
+ ]
|
|
|
|
|
+ if (hasClose) legendData.push({ name: '指数走势', itemStyle: { color: C.warn } })
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
@@ -363,19 +412,19 @@ function priceBandOption(series, opts) {
|
|
|
valueFormatter: (v) => v.toFixed(opts.toFixed || 2),
|
|
valueFormatter: (v) => v.toFixed(opts.toFixed || 2),
|
|
|
},
|
|
},
|
|
|
legend: {
|
|
legend: {
|
|
|
- data: [
|
|
|
|
|
- { name: '当前', itemStyle: { color: opts.curColor } },
|
|
|
|
|
- { name: '上轨', itemStyle: { color: C.faint } },
|
|
|
|
|
- { name: '中枢', itemStyle: { color: C.mut } },
|
|
|
|
|
- { name: '下轨', itemStyle: { color: C.faint } },
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ data: legendData,
|
|
|
top: 4,
|
|
top: 4,
|
|
|
textStyle: { color: C.mut, fontSize: 11 },
|
|
textStyle: { color: C.mut, fontSize: 11 },
|
|
|
itemWidth: 14,
|
|
itemWidth: 14,
|
|
|
},
|
|
},
|
|
|
- grid: { top: 36, left: 50, right: 24, bottom: 32, containLabel: true },
|
|
|
|
|
|
|
+ grid: { top: 36, left: 50, right: hasClose ? 60 : 24, bottom: 32, containLabel: true },
|
|
|
xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
- yAxis: { type: 'value', ...axisStyle() },
|
|
|
|
|
|
|
+ yAxis: hasClose
|
|
|
|
|
+ ? [
|
|
|
|
|
+ { type: 'value', name: opts.toFixed === 3 ? 'PB' : 'PE', nameTextStyle: { color: opts.curColor, fontSize: 10.5, padding: [0, 0, 0, -28] }, position: 'left', ...axisStyle() },
|
|
|
|
|
+ { type: 'value', name: '指数走势', nameTextStyle: { color: C.warn, fontSize: 10.5, padding: [0, -28, 0, 0] }, position: 'right', ...axisStyle({ splitLine: { show: false } }) },
|
|
|
|
|
+ ]
|
|
|
|
|
+ : { type: 'value', ...axisStyle() },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: '下轨',
|
|
name: '下轨',
|
|
@@ -429,20 +478,44 @@ function priceBandOption(series, opts) {
|
|
|
data: [{ name: '当前', value: cur[cur.length - 1], xAxis: dates[dates.length - 1], yAxis: cur[cur.length - 1] }],
|
|
data: [{ name: '当前', value: cur[cur.length - 1], xAxis: dates[dates.length - 1], yAxis: cur[cur.length - 1] }],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
|
|
+ ...(hasClose ? [{
|
|
|
|
|
+ name: '指数走势',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: closeAligned,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 1.6 },
|
|
|
|
|
+ z: 4,
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 7,
|
|
|
|
|
+ itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(0), color: C.warn, fontSize: 10, position: 'bottom', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前指数走势', value: lastClose, xAxis: closeSeries[closeSeries.length - 1][0], yAxis: lastClose }],
|
|
|
|
|
+ },
|
|
|
|
|
+ }] : []),
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-export function peBandOption(series) {
|
|
|
|
|
- return priceBandOption(series, { curColor: C.brand, toFixed: 2 })
|
|
|
|
|
|
|
+export function peBandOption(series, closeSeries) {
|
|
|
|
|
+ return priceBandOption(series, { curColor: C.brand, toFixed: 2 }, closeSeries)
|
|
|
}
|
|
}
|
|
|
-export function pbBandOption(series) {
|
|
|
|
|
- return priceBandOption(series, { curColor: C.brandD, toFixed: 3 })
|
|
|
|
|
|
|
+export function pbBandOption(series, closeSeries) {
|
|
|
|
|
+ return priceBandOption(series, { curColor: C.brandD, toFixed: 3 }, closeSeries)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 风险溢价 ERP =====
|
|
// ===== 风险溢价 ERP =====
|
|
|
-export function erpLineOption(series) {
|
|
|
|
|
|
|
+export function erpLineOption(series, closeSeries) {
|
|
|
const dates = series.map((s) => s[0])
|
|
const dates = series.map((s) => s[0])
|
|
|
const values = series.map((s) => s[1])
|
|
const values = series.map((s) => s[1])
|
|
|
|
|
+ const hasClose = Array.isArray(closeSeries) && closeSeries.length > 0
|
|
|
|
|
+ const closeMap = hasClose ? new Map(closeSeries.map(([d, v]) => [d, v])) : null
|
|
|
|
|
+ const closeAligned = hasClose ? dates.map((d) => (closeMap.has(d) ? closeMap.get(d) : null)) : []
|
|
|
|
|
+ const lastClose = hasClose ? closeSeries[closeSeries.length - 1][1] : null
|
|
|
|
|
+ const lastCloseDate = hasClose ? closeSeries[closeSeries.length - 1][0] : null
|
|
|
|
|
+ const legendData = [{ name: 'ERP', itemStyle: { color: C.brandD } }]
|
|
|
|
|
+ if (hasClose) legendData.push({ name: '指数走势', itemStyle: { color: C.warn } })
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
@@ -450,12 +523,23 @@ export function erpLineOption(series) {
|
|
|
axisPointer: { type: 'line' },
|
|
axisPointer: { type: 'line' },
|
|
|
valueFormatter: (v) => `${v.toFixed(2)}%`,
|
|
valueFormatter: (v) => `${v.toFixed(2)}%`,
|
|
|
},
|
|
},
|
|
|
- grid: { top: 28, left: 50, right: 24, bottom: 32, containLabel: true },
|
|
|
|
|
- xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
|
|
- yAxis: {
|
|
|
|
|
- type: 'value',
|
|
|
|
|
- ...axisStyle({ axisLabel: { color: C.mut, fontSize: 11, formatter: '{value}%' } }),
|
|
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ data: legendData,
|
|
|
|
|
+ top: 4,
|
|
|
|
|
+ textStyle: { color: C.mut, fontSize: 11 },
|
|
|
|
|
+ itemWidth: 14,
|
|
|
},
|
|
},
|
|
|
|
|
+ grid: { top: 36, left: 50, right: hasClose ? 60 : 24, bottom: 32, containLabel: true },
|
|
|
|
|
+ xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
|
|
+ yAxis: hasClose
|
|
|
|
|
+ ? [
|
|
|
|
|
+ { type: 'value', name: 'ERP', nameTextStyle: { color: C.brandD, fontSize: 10.5, padding: [0, 0, 0, -28] }, position: 'left', ...axisStyle({ axisLabel: { color: C.mut, fontSize: 11, formatter: '{value}%' } }) },
|
|
|
|
|
+ { type: 'value', name: '指数走势', nameTextStyle: { color: C.warn, fontSize: 10.5, padding: [0, -28, 0, 0] }, position: 'right', ...axisStyle({ splitLine: { show: false } }) },
|
|
|
|
|
+ ]
|
|
|
|
|
+ : {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ ...axisStyle({ axisLabel: { color: C.mut, fontSize: 11, formatter: '{value}%' } }),
|
|
|
|
|
+ },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: 'ERP',
|
|
name: 'ERP',
|
|
@@ -473,12 +557,12 @@ export function erpLineOption(series) {
|
|
|
],
|
|
],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
- markLine: {
|
|
|
|
|
- symbol: ['none', 'none'],
|
|
|
|
|
- data: [
|
|
|
|
|
- { yAxis: 2.5, lineStyle: { color: C.mut, type: 'dashed', width: 1 }, label: { show: true, position: 'end', formatter: '历史中枢', color: C.mut, fontSize: 10 } },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ // markLine: {
|
|
|
|
|
+ // symbol: ['none', 'none'],
|
|
|
|
|
+ // data: [
|
|
|
|
|
+ // { yAxis: 2.5, lineStyle: { color: C.mut, type: 'dashed', width: 1 }, label: { show: true, position: 'end', formatter: '历史中枢', color: C.mut, fontSize: 10 } },
|
|
|
|
|
+ // ],
|
|
|
|
|
+ // },
|
|
|
markPoint: {
|
|
markPoint: {
|
|
|
symbol: 'circle',
|
|
symbol: 'circle',
|
|
|
symbolSize: 8,
|
|
symbolSize: 8,
|
|
@@ -487,15 +571,41 @@ export function erpLineOption(series) {
|
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
|
|
+ ...(hasClose ? [{
|
|
|
|
|
+ name: '指数走势',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: closeAligned,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 1.6 },
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 7,
|
|
|
|
|
+ itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(0), color: C.warn, fontSize: 10, position: 'bottom', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前指数走势', value: lastClose, xAxis: lastCloseDate, yAxis: lastClose }],
|
|
|
|
|
+ },
|
|
|
|
|
+ }] : []),
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== 换手率 + 成交额 双轴 =====
|
|
// ===== 换手率 + 成交额 双轴 =====
|
|
|
-export function liquidityBarLineOption(series) {
|
|
|
|
|
|
|
+export function liquidityBarLineOption(series, closeSeries) {
|
|
|
const dates = series.map((s) => s[0])
|
|
const dates = series.map((s) => s[0])
|
|
|
const turnover = series.map((s) => s[1])
|
|
const turnover = series.map((s) => s[1])
|
|
|
const volume = series.map((s) => s[2])
|
|
const volume = series.map((s) => s[2])
|
|
|
|
|
+ const hasClose = Array.isArray(closeSeries) && closeSeries.length > 0
|
|
|
|
|
+ const closeMap = hasClose ? new Map(closeSeries.map(([d, v]) => [d, v])) : null
|
|
|
|
|
+ const closeAligned = hasClose ? dates.map((d) => (closeMap.has(d) ? closeMap.get(d) : null)) : []
|
|
|
|
|
+ const lastClose = hasClose ? closeSeries[closeSeries.length - 1][1] : null
|
|
|
|
|
+ const lastCloseDate = hasClose ? closeSeries[closeSeries.length - 1][0] : null
|
|
|
|
|
+ const legendData = [
|
|
|
|
|
+ { name: '换手率', itemStyle: { color: C.brand } },
|
|
|
|
|
+ { name: '成交额(万亿)', itemStyle: { color: C.up } },
|
|
|
|
|
+ ]
|
|
|
|
|
+ if (hasClose) legendData.push({ name: '指数走势', itemStyle: { color: C.warn } })
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
@@ -503,10 +613,7 @@ export function liquidityBarLineOption(series) {
|
|
|
axisPointer: { type: 'shadow' },
|
|
axisPointer: { type: 'shadow' },
|
|
|
},
|
|
},
|
|
|
legend: {
|
|
legend: {
|
|
|
- data: [
|
|
|
|
|
- { name: '换手率', itemStyle: { color: C.brand } },
|
|
|
|
|
- { name: '成交额(万亿)', itemStyle: { color: C.up } },
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ data: legendData,
|
|
|
top: 4,
|
|
top: 4,
|
|
|
textStyle: { color: C.mut, fontSize: 11 },
|
|
textStyle: { color: C.mut, fontSize: 11 },
|
|
|
itemWidth: 14,
|
|
itemWidth: 14,
|
|
@@ -521,7 +628,7 @@ export function liquidityBarLineOption(series) {
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
type: 'value',
|
|
type: 'value',
|
|
|
- name: '成交额(万亿)',
|
|
|
|
|
|
|
+ name: hasClose ? '成交额(万亿) / 指数走势' : '成交额(万亿)',
|
|
|
...axisStyle({ axisLabel: { color: C.mut, fontSize: 11 }, nameTextStyle: { color: C.mut, fontSize: 10 } }),
|
|
...axisStyle({ axisLabel: { color: C.mut, fontSize: 11 }, nameTextStyle: { color: C.mut, fontSize: 10 } }),
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
@@ -542,14 +649,37 @@ export function liquidityBarLineOption(series) {
|
|
|
smooth: true,
|
|
smooth: true,
|
|
|
lineStyle: { color: C.up, width: 2.2 },
|
|
lineStyle: { color: C.up, width: 2.2 },
|
|
|
},
|
|
},
|
|
|
|
|
+ ...(hasClose ? [{
|
|
|
|
|
+ name: '指数走势',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: closeAligned,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 1.6 },
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 7,
|
|
|
|
|
+ itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(0), color: C.warn, fontSize: 10, position: 'bottom', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前指数走势', value: lastClose, xAxis: lastCloseDate, yAxis: lastClose }],
|
|
|
|
|
+ },
|
|
|
|
|
+ }] : []),
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== RSI 单线 =====
|
|
// ===== RSI 单线 =====
|
|
|
-export function rsiLineOption(series) {
|
|
|
|
|
|
|
+export function rsiLineOption(series, closeSeries) {
|
|
|
const dates = series.map((s) => s[0])
|
|
const dates = series.map((s) => s[0])
|
|
|
const values = series.map((s) => s[1])
|
|
const values = series.map((s) => s[1])
|
|
|
|
|
+ const hasClose = Array.isArray(closeSeries) && closeSeries.length > 0
|
|
|
|
|
+ const closeMap = hasClose ? new Map(closeSeries.map(([d, v]) => [d, v])) : null
|
|
|
|
|
+ const closeAligned = hasClose ? dates.map((d) => (closeMap.has(d) ? closeMap.get(d) : null)) : []
|
|
|
|
|
+ const lastClose = hasClose ? closeSeries[closeSeries.length - 1][1] : null
|
|
|
|
|
+ const lastCloseDate = hasClose ? closeSeries[closeSeries.length - 1][0] : null
|
|
|
|
|
+ const legendData = [{ name: 'RSI', itemStyle: { color: C.brand } }]
|
|
|
|
|
+ if (hasClose) legendData.push({ name: '指数走势', itemStyle: { color: C.warn } })
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
@@ -557,15 +687,20 @@ export function rsiLineOption(series) {
|
|
|
axisPointer: { type: 'line' },
|
|
axisPointer: { type: 'line' },
|
|
|
valueFormatter: (v) => v.toFixed(2),
|
|
valueFormatter: (v) => v.toFixed(2),
|
|
|
},
|
|
},
|
|
|
- grid: { top: 28, left: 50, right: 24, bottom: 32, containLabel: true },
|
|
|
|
|
- xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
|
|
- yAxis: {
|
|
|
|
|
- type: 'value',
|
|
|
|
|
- min: 0,
|
|
|
|
|
- max: 100,
|
|
|
|
|
- interval: 25,
|
|
|
|
|
- ...axisStyle(),
|
|
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ data: legendData,
|
|
|
|
|
+ top: 4,
|
|
|
|
|
+ textStyle: { color: C.mut, fontSize: 11 },
|
|
|
|
|
+ itemWidth: 14,
|
|
|
},
|
|
},
|
|
|
|
|
+ grid: { top: 36, left: 50, right: hasClose ? 60 : 24, bottom: 32, containLabel: true },
|
|
|
|
|
+ xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
|
|
+ yAxis: hasClose
|
|
|
|
|
+ ? [
|
|
|
|
|
+ { type: 'value', min: 0, max: 100, interval: 25, ...axisStyle() },
|
|
|
|
|
+ { type: 'value', name: '指数走势', position: 'right', ...axisStyle({ splitLine: { show: false }, nameTextStyle: { color: C.warn, fontSize: 10 } }) },
|
|
|
|
|
+ ]
|
|
|
|
|
+ : { type: 'value', min: 0, max: 100, interval: 25, ...axisStyle() },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: 'RSI',
|
|
name: 'RSI',
|
|
@@ -599,14 +734,37 @@ export function rsiLineOption(series) {
|
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
|
|
+ ...(hasClose ? [{
|
|
|
|
|
+ name: '指数走势',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: closeAligned,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 1.6 },
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 7,
|
|
|
|
|
+ itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(0), color: C.warn, fontSize: 10, position: 'bottom', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前指数走势', value: lastClose, xAxis: lastCloseDate, yAxis: lastClose }],
|
|
|
|
|
+ },
|
|
|
|
|
+ }] : []),
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ===== VOSC 单线 =====
|
|
// ===== VOSC 单线 =====
|
|
|
-export function voscLineOption(series) {
|
|
|
|
|
|
|
+export function voscLineOption(series, closeSeries) {
|
|
|
const dates = series.map((s) => s[0])
|
|
const dates = series.map((s) => s[0])
|
|
|
const values = series.map((s) => s[1])
|
|
const values = series.map((s) => s[1])
|
|
|
|
|
+ const hasClose = Array.isArray(closeSeries) && closeSeries.length > 0
|
|
|
|
|
+ const closeMap = hasClose ? new Map(closeSeries.map(([d, v]) => [d, v])) : null
|
|
|
|
|
+ const closeAligned = hasClose ? dates.map((d) => (closeMap.has(d) ? closeMap.get(d) : null)) : []
|
|
|
|
|
+ const lastClose = hasClose ? closeSeries[closeSeries.length - 1][1] : null
|
|
|
|
|
+ const lastCloseDate = hasClose ? closeSeries[closeSeries.length - 1][0] : null
|
|
|
|
|
+ const legendData = [{ name: 'VOSC', itemStyle: { color: C.up } }]
|
|
|
|
|
+ if (hasClose) legendData.push({ name: '指数走势', itemStyle: { color: C.warn } })
|
|
|
return {
|
|
return {
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
...tipOpt,
|
|
...tipOpt,
|
|
@@ -614,9 +772,20 @@ export function voscLineOption(series) {
|
|
|
axisPointer: { type: 'line' },
|
|
axisPointer: { type: 'line' },
|
|
|
valueFormatter: (v) => v.toFixed(3),
|
|
valueFormatter: (v) => v.toFixed(3),
|
|
|
},
|
|
},
|
|
|
- grid: { top: 28, left: 50, right: 24, bottom: 32, containLabel: true },
|
|
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ data: legendData,
|
|
|
|
|
+ top: 4,
|
|
|
|
|
+ textStyle: { color: C.mut, fontSize: 11 },
|
|
|
|
|
+ itemWidth: 14,
|
|
|
|
|
+ },
|
|
|
|
|
+ grid: { top: 36, left: 50, right: hasClose ? 60 : 24, bottom: 32, containLabel: true },
|
|
|
xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
xAxis: { type: 'category', data: dates, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10.5 } }) },
|
|
|
- yAxis: { type: 'value', ...axisStyle() },
|
|
|
|
|
|
|
+ yAxis: hasClose
|
|
|
|
|
+ ? [
|
|
|
|
|
+ { type: 'value', ...axisStyle() },
|
|
|
|
|
+ { type: 'value', name: '指数走势', position: 'right', ...axisStyle({ splitLine: { show: false }, nameTextStyle: { color: C.warn, fontSize: 10 } }) },
|
|
|
|
|
+ ]
|
|
|
|
|
+ : { type: 'value', ...axisStyle() },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: 'VOSC',
|
|
name: 'VOSC',
|
|
@@ -634,12 +803,6 @@ export function voscLineOption(series) {
|
|
|
],
|
|
],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
- markLine: {
|
|
|
|
|
- symbol: ['none', 'none'],
|
|
|
|
|
- data: [
|
|
|
|
|
- { yAxis: 0, lineStyle: { color: C.mut, type: 'dashed' }, label: { show: true, position: 'end', formatter: '零轴', color: C.mut, fontSize: 10 } },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
markPoint: {
|
|
markPoint: {
|
|
|
symbol: 'circle',
|
|
symbol: 'circle',
|
|
|
symbolSize: 8,
|
|
symbolSize: 8,
|
|
@@ -648,6 +811,22 @@ export function voscLineOption(series) {
|
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
data: [{ name: '当前', value: values[values.length - 1], xAxis: dates[dates.length - 1], yAxis: values[values.length - 1] }],
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
|
|
+ ...(hasClose ? [{
|
|
|
|
|
+ name: '指数走势',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ yAxisIndex: 1,
|
|
|
|
|
+ data: closeAligned,
|
|
|
|
|
+ symbol: 'none',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ lineStyle: { color: C.warn, width: 1.6 },
|
|
|
|
|
+ markPoint: {
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: 7,
|
|
|
|
|
+ itemStyle: { color: C.warn, borderColor: '#fff', borderWidth: 2 },
|
|
|
|
|
+ label: { formatter: (p) => p.value.toFixed(0), color: C.warn, fontSize: 10, position: 'bottom', fontWeight: 600 },
|
|
|
|
|
+ data: [{ name: '当前指数走势', value: lastClose, xAxis: lastCloseDate, yAxis: lastClose }],
|
|
|
|
|
+ },
|
|
|
|
|
+ }] : []),
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|