3 changed files with 0 additions and 671 deletions
@ -1,655 +0,0 @@ |
|||
<template> |
|||
<view style="width: 750rpx; height: 750rpx;"> |
|||
<l-echart ref="chartRef" @finished="initChart"></l-echart> |
|||
</view> |
|||
</template> |
|||
<script setup> |
|||
import { ref, computed, onMounted } from 'vue'; |
|||
|
|||
const chartRef = ref(null) |
|||
// 获取系统信息,替代 window.innerWidth |
|||
const systemInfo = uni.getSystemInfoSync() |
|||
const screenWidth = ref(systemInfo.screenWidth || 375) // 默认值 375px |
|||
|
|||
// 生成30天的交易信号数据 |
|||
const generateAIGoldBullData = () => { |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
// 模拟交易信号 [索引, 买入信号, 卖出信号, 持有信号, 强度, 成交量] |
|||
const buySignal = Math.random() > 0.7 ? 1 : 0 // 30%概率买入信号 |
|||
const sellSignal = Math.random() > 0.8 ? 1 : 0 // 20%概率卖出信号 |
|||
const holdSignal = Math.random() > 0.5 ? 1 : 0 // 50%概率持有信号 |
|||
const strength = Math.floor(Math.random() * 3) + 1 // 信号强度1-3 |
|||
const volume = Math.floor(Math.random() * 2000) + 500 // 成交量500-2500 |
|||
|
|||
data.push([i, buySignal, sellSignal, holdSignal, strength, volume]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 添加缺失的变量定义 |
|||
var option |
|||
const AIGoldBull = ref({ |
|||
JN: generateAIGoldBullData() |
|||
}) |
|||
|
|||
// 模拟多语言数据 |
|||
const t = ref({ |
|||
suoxie: 'zh', |
|||
tianxian: '天线', |
|||
feixian: '飞线', |
|||
zhoongxian: '中线', |
|||
liuxian: '流线', |
|||
Klinetext_5: 'K线5', |
|||
Klinetext_6: 'K线6', |
|||
maipan: '买盘', |
|||
maipan1: '卖盘' |
|||
}) |
|||
|
|||
// 生成30天的模拟K线数据 [日期, 开盘, 最高, 最低, 收盘] |
|||
const generateKLineData = () => { |
|||
const data = [] |
|||
let basePrice = 2450 // 黄金基础价格 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0] |
|||
|
|||
// 模拟价格波动 |
|||
const volatility = (Math.random() - 0.5) * 50 // ±25的波动 |
|||
const open = basePrice + volatility |
|||
|
|||
const highVolatility = Math.random() * 30 + 10 // 10-40的向上波动 |
|||
const lowVolatility = Math.random() * 30 + 10 // 10-40的向下波动 |
|||
|
|||
const high = Math.max(open, open + highVolatility) |
|||
const low = Math.min(open, open - lowVolatility) |
|||
|
|||
const closeVolatility = (Math.random() - 0.5) * 20 |
|||
const close = Math.max(low, Math.min(high, open + closeVolatility)) |
|||
|
|||
data.push([date, |
|||
Math.round(open * 100) / 100, |
|||
Math.round(high * 100) / 100, |
|||
Math.round(low * 100) / 100, |
|||
Math.round(close * 100) / 100 |
|||
]) |
|||
|
|||
basePrice = close // 下一天的基础价格 |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成30天的成交量和技术指标数据 [日期, 成交量1, 成交量2, 指标1, 指标2, 指标3] |
|||
const generateWaveVolData = () => { |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0] |
|||
|
|||
// 模拟成交量数据 |
|||
const vol1 = Math.floor(Math.random() * 2000) + 800 // 800-2800 |
|||
const vol2 = Math.floor(Math.random() * 1500) + 600 // 600-2100 |
|||
|
|||
// 模拟技术指标 |
|||
const indicator1 = Math.floor(Math.random() * 30) + 40 // 40-70 |
|||
const indicator2 = Math.floor(Math.random() * 40) + 50 // 50-90 |
|||
const indicator3 = Math.floor(Math.random() * 35) + 60 // 60-95 |
|||
|
|||
data.push([date, vol1, vol2, indicator1, indicator2, indicator3]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成30天的移动平均线数据 [MA5, MA10, MA20, MA30] |
|||
const generateFTLineData = () => { |
|||
const data = [] |
|||
let ma5Base = 2450 |
|||
let ma10Base = 2445 |
|||
let ma20Base = 2440 |
|||
let ma30Base = 2435 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
// 模拟移动平均线的平滑变化 |
|||
ma5Base += (Math.random() - 0.5) * 10 |
|||
ma10Base += (Math.random() - 0.5) * 8 |
|||
ma20Base += (Math.random() - 0.5) * 6 |
|||
ma30Base += (Math.random() - 0.5) * 4 |
|||
|
|||
data.push([ |
|||
Math.round(ma5Base * 100) / 100, |
|||
Math.round(ma10Base * 100) / 100, |
|||
Math.round(ma20Base * 100) / 100, |
|||
Math.round(ma30Base * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成模拟数据 |
|||
const mockKLineData = generateKLineData() |
|||
const mockWaveVolData = generateWaveVolData() |
|||
const mockFTLineData = generateFTLineData() |
|||
|
|||
// 生成RSI指标数据 (相对强弱指数) |
|||
const generateRSIData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const rsi = Math.random() * 60 + 20 // RSI值在20-80之间 |
|||
data.push(Math.round(rsi * 100) / 100) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成MACD指标数据 |
|||
const generateMACDData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const macd = (Math.random() - 0.5) * 20 // MACD值在-10到10之间 |
|||
const signal = (Math.random() - 0.5) * 15 // 信号线 |
|||
const histogram = macd - signal // 柱状图 |
|||
|
|||
data.push([ |
|||
Math.round(macd * 100) / 100, |
|||
Math.round(signal * 100) / 100, |
|||
Math.round(histogram * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成布林带数据 |
|||
const generateBollingerData = () => { |
|||
const data = [] |
|||
let middleLine = 2450 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
middleLine += (Math.random() - 0.5) * 10 |
|||
const upperBand = middleLine + Math.random() * 30 + 20 // 上轨 |
|||
const lowerBand = middleLine - Math.random() * 30 - 20 // 下轨 |
|||
|
|||
data.push([ |
|||
Math.round(upperBand * 100) / 100, |
|||
Math.round(middleLine * 100) / 100, |
|||
Math.round(lowerBand * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成成交量分析数据 |
|||
const generateVolumeAnalysisData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const buyVolume = Math.floor(Math.random() * 1500) + 500 // 买入量 |
|||
const sellVolume = Math.floor(Math.random() * 1500) + 500 // 卖出量 |
|||
const netVolume = buyVolume - sellVolume // 净买入量 |
|||
|
|||
data.push([buyVolume, sellVolume, netVolume]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成市场情绪数据 |
|||
const generateMarketSentimentData = () => { |
|||
const sentiments = ['极度恐慌', '恐慌', '中性', '贪婪', '极度贪婪'] |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const sentimentIndex = Math.floor(Math.random() * 100) // 0-100的情绪指数 |
|||
const sentimentLabel = sentiments[Math.floor(sentimentIndex / 20)] |
|||
|
|||
data.push({ |
|||
date: new Date(2024, 0, i + 1).toISOString().split('T')[0], |
|||
index: sentimentIndex, |
|||
label: sentimentLabel, |
|||
fearGreedRatio: Math.random() * 100 |
|||
}) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成重要新闻事件数据 |
|||
const generateNewsEventsData = () => { |
|||
const events = [ |
|||
'美联储利率决议', |
|||
'非农就业数据发布', |
|||
'通胀数据公布', |
|||
'地缘政治紧张', |
|||
'央行政策变化', |
|||
'经济数据超预期', |
|||
'市场技术突破', |
|||
'大宗商品价格波动' |
|||
] |
|||
|
|||
const data = [] |
|||
for (let i = 0; i < 10; i++) { // 生成10个随机事件 |
|||
const randomDay = Math.floor(Math.random() * 30) + 1 |
|||
const event = events[Math.floor(Math.random() * events.length)] |
|||
const impact = Math.floor(Math.random() * 5) + 1 // 影响力1-5 |
|||
|
|||
data.push({ |
|||
date: new Date(2024, 0, randomDay).toISOString().split('T')[0], |
|||
event: event, |
|||
impact: impact, |
|||
type: Math.random() > 0.5 ? 'positive' : 'negative' |
|||
}) |
|||
} |
|||
return data.sort((a, b) => new Date(a.date) - new Date(b.date)) |
|||
} |
|||
|
|||
// 生成价格预测数据 |
|||
const generatePricePredictionData = () => { |
|||
const data = [] |
|||
let currentPrice = 2450 |
|||
|
|||
for (let i = 0; i < 7; i++) { // 未来7天预测 |
|||
const date = new Date(2024, 1, i + 1).toISOString().split('T')[0] // 2月份 |
|||
|
|||
// 模拟AI预测的价格区间 |
|||
const prediction = currentPrice + (Math.random() - 0.5) * 100 |
|||
const confidence = Math.random() * 40 + 60 // 60-100%的置信度 |
|||
const upperBound = prediction + Math.random() * 50 |
|||
const lowerBound = prediction - Math.random() * 50 |
|||
|
|||
data.push({ |
|||
date: date, |
|||
predicted_price: Math.round(prediction * 100) / 100, |
|||
confidence: Math.round(confidence), |
|||
upper_bound: Math.round(upperBound * 100) / 100, |
|||
lower_bound: Math.round(lowerBound * 100) / 100 |
|||
}) |
|||
|
|||
currentPrice = prediction |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 模拟提取的绘图数据 |
|||
const extractedDrawData = { |
|||
KLine20: mockKLineData, |
|||
WAVEVOL: mockWaveVolData, |
|||
FTLINE: mockFTLineData, |
|||
RSI: generateRSIData(), |
|||
MACD: generateMACDData(), |
|||
BOLLINGER: generateBollingerData(), |
|||
VOLUME_ANALYSIS: generateVolumeAnalysisData(), |
|||
MARKET_SENTIMENT: generateMarketSentimentData(), |
|||
NEWS_EVENTS: generateNewsEventsData(), |
|||
PRICE_PREDICTION: generatePricePredictionData() |
|||
} |
|||
|
|||
const fnShowEcharts4 = (extractedDrawData) => { |
|||
const splitData = (b) => { |
|||
const a = JSON.parse(JSON.stringify(b)) |
|||
let categoryData = [] |
|||
let values = [] |
|||
for (let i = 0; i < a.length; i++) { |
|||
categoryData.push(a[i].splice(0, 1)[0]) |
|||
values.push(a[i]) |
|||
} |
|||
return { |
|||
categoryData, |
|||
values |
|||
} |
|||
} |
|||
var bodongliang = splitData(extractedDrawData.WAVEVOL) |
|||
function bodongliangData(values, i) { |
|||
return values.map((subArray) => subArray[i]) |
|||
} |
|||
function calculateMA(index, data) { |
|||
let result = [] |
|||
if (data.FTLINE) { |
|||
data.FTLINE.forEach((item) => { |
|||
result.push(item[index]) |
|||
}) |
|||
} |
|||
return result |
|||
} |
|||
function vwToPx(vw) { |
|||
return (screenWidth.value * vw) / 100 |
|||
} |
|||
var dealData = splitData(extractedDrawData.KLine20) |
|||
var dealGnBullData = AIGoldBull.value.JN |
|||
const textEcharts = t.value |
|||
const firstLegend = computed(() => { |
|||
if (screenWidth.value < 768) { |
|||
if (textEcharts.suoxie === 'en' || textEcharts.suoxie === 'th') { |
|||
return '2%' |
|||
} else if (textEcharts.suoxie === 'kr') { |
|||
return '2%' |
|||
} else { |
|||
return '2%' |
|||
} |
|||
} else { |
|||
return textEcharts.suoxie === 'en' || |
|||
textEcharts.suoxie === 'th' || |
|||
textEcharts.suoxie === 'kr' |
|||
? '9%' |
|||
: '9%' |
|||
} |
|||
}) |
|||
const processBarData = (data) => { |
|||
const barData = [] |
|||
data.forEach((item) => { |
|||
let color |
|||
switch (item[4]) { |
|||
case 1: |
|||
color = '#13E113' |
|||
break |
|||
case 2: |
|||
color = '#FF0E00' |
|||
break |
|||
case 3: |
|||
color = '#0000FE' |
|||
break |
|||
case 4: |
|||
color = '#1397FF' |
|||
break |
|||
} |
|||
barData.push({ |
|||
value: item[5], |
|||
itemStyle: { |
|||
normal: { |
|||
color: color |
|||
} |
|||
} |
|||
}) |
|||
}) |
|||
return { barData } |
|||
} |
|||
const { barData } = processBarData(dealGnBullData) |
|||
option = { |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { |
|||
type: 'cross' |
|||
}, |
|||
backgroundColor: 'rgba(119, 120, 125, 0.6)', |
|||
borderWidth: 1, |
|||
borderColor: '#77787D', |
|||
padding: 10, |
|||
textStyle: { |
|||
color: '#fff' |
|||
} |
|||
}, |
|||
axisPointer: { |
|||
link: [ |
|||
{ |
|||
xAxisIndex: 'all' |
|||
} |
|||
], |
|||
label: { |
|||
backgroundColor: '#77787D' |
|||
} |
|||
}, |
|||
toolbox: { |
|||
show: false |
|||
}, |
|||
grid: [ |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '10%' : '12%', |
|||
height: screenWidth.value > 768 ? '35%' : '34%', |
|||
containLabel: false |
|||
}, |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '48%' : '48%', |
|||
height: screenWidth.value > 768 ? '19%' : '21%', |
|||
containLabel: false |
|||
}, |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '70%' : '71%', |
|||
height: screenWidth.value > 768 ? '19%' : '21%', |
|||
containLabel: false |
|||
} |
|||
], |
|||
xAxis: [ |
|||
{ |
|||
type: 'category', |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisLine: { onZero: false }, |
|||
splitLine: { show: false }, |
|||
min: 'dataMin', |
|||
max: 'dataMax', |
|||
axisPointer: { |
|||
z: 100, |
|||
label: { |
|||
show: false // 不显示标签 |
|||
} |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'black' |
|||
} |
|||
}, // |
|||
axisLabel: { show: false }, |
|||
axisTick: { show: false } |
|||
}, |
|||
{ |
|||
type: 'category', |
|||
gridIndex: 1, |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisPointer: { |
|||
z: 100, |
|||
label: { |
|||
show: false // 不显示标签 |
|||
} |
|||
}, |
|||
axisLine: { lineStyle: { color: 'black' } }, |
|||
axisLabel: { |
|||
show: false, |
|||
interval: 'auto' |
|||
}, |
|||
axisTick: { show: false } |
|||
}, |
|||
{ |
|||
type: 'category', |
|||
gridIndex: 2, |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisLine: { lineStyle: { color: 'black' } }, |
|||
axisLabel: { |
|||
show: true, |
|||
interval: 'auto', |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisTick: { show: false } |
|||
} |
|||
], |
|||
yAxis: [ |
|||
{ |
|||
scale: true, |
|||
gridIndex: 0, |
|||
position: 'left', |
|||
axisLabel: { |
|||
inside: false, |
|||
align: 'right', |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisLine: { |
|||
show: true, |
|||
lineStyle: { |
|||
fontSize: '', |
|||
color: 'black' |
|||
} |
|||
}, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: false } |
|||
}, |
|||
{ |
|||
scale: true, |
|||
gridIndex: 1, |
|||
splitNumber: 4, |
|||
min: 0, |
|||
minInterval: 1, |
|||
axisLabel: { |
|||
show: true, |
|||
fontSize: screenWidth.value > 768 ? 15 : 9, |
|||
margin: 8, |
|||
}, |
|||
axisLine: { show: true, lineStyle: { color: 'black' } }, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: true, lineStyle: { type: 'dashed' } }, |
|||
boundaryGap: ['20%', '20%'] |
|||
}, |
|||
{ |
|||
scale: true, |
|||
gridIndex: 2, |
|||
splitNumber: 2, |
|||
axisLabel: { |
|||
show: true, |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisLine: { show: true, lineStyle: { color: 'black' } }, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: false } |
|||
} |
|||
], |
|||
dataZoom: [ |
|||
{ |
|||
type: 'inside', |
|||
xAxisIndex: [0, 1, 2], |
|||
start: 50, |
|||
end: 100 |
|||
}, |
|||
{ |
|||
show: true, |
|||
xAxisIndex: [0, 1, 2], |
|||
type: 'slider', |
|||
start: 50, |
|||
end: 100 |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'candlestick', |
|||
name: '日K', |
|||
xAxisIndex: 0, |
|||
yAxisIndex: 0, |
|||
data: dealData.values, |
|||
itemStyle: { |
|||
normal: { |
|||
color0: 'red', |
|||
color: 'green', |
|||
borderColor0: 'red', |
|||
borderColor: 'green' |
|||
} |
|||
}, |
|||
gridIndex: 1 |
|||
}, |
|||
{ |
|||
name: '成交量', |
|||
type: 'bar', |
|||
barWidth: '70%', |
|||
xAxisIndex: 1, |
|||
yAxisIndex: 1, |
|||
data: barData, |
|||
}, |
|||
// { |
|||
// name: textEcharts.feixian, |
|||
// type: 'line', |
|||
// data: calculateMA(1, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#00a32e', |
|||
// lineStyle: { |
|||
// color: '#00a32e', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.zhoongxian, |
|||
// type: 'line', |
|||
// data: calculateMA(2, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#de0000', |
|||
// lineStyle: { |
|||
// color: '#de0000', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.tianxian, |
|||
// type: 'line', |
|||
// data: calculateMA(3, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#ffb300', |
|||
// lineStyle: { |
|||
// color: '#ffb300', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.liuxian, |
|||
// type: 'line', |
|||
// data: calculateMA(4, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#00c8ff', |
|||
// lineStyle: { |
|||
// color: '#00c8ff', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
] |
|||
} |
|||
initChart() |
|||
} |
|||
|
|||
// 组件挂载时初始化图表 |
|||
onMounted(() => { |
|||
// 调用图表初始化函数 |
|||
fnShowEcharts4(extractedDrawData) |
|||
}) |
|||
|
|||
|
|||
// 初始化图表 |
|||
const initChart = async () => { |
|||
if (!chartRef.value) return |
|||
|
|||
try { |
|||
const chart = await chartRef.value.init(echarts) |
|||
chart.setOption(option) |
|||
} catch (error) { |
|||
console.error('图表初始化失败:', error) |
|||
} |
|||
} |
|||
</script> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue