From a1e033432b371a3f7f09b6cec659e414088ac729 Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Thu, 22 May 2025 12:38:02 +0800 Subject: [PATCH] fix bugs --- web/DEPLOY_GUIDE.md | 212 ++++++++++++++++++++++++++++++ web/chanlun-web-venv.service | 15 +++ web/chanlun-web.service | 15 +++ web/deploy.sh | 25 ++++ web/deploy_venv.sh | 32 +++++ web/status.sh | 16 +++ web/status_venv.sh | 16 +++ web/stop.sh | 6 + web/stop_venv.sh | 7 + web/templates/index.html | 245 +++++++++++++++++++++++++++++++++-- 10 files changed, 577 insertions(+), 12 deletions(-) create mode 100644 web/DEPLOY_GUIDE.md create mode 100644 web/chanlun-web-venv.service create mode 100644 web/chanlun-web.service create mode 100755 web/deploy.sh create mode 100755 web/deploy_venv.sh create mode 100755 web/status.sh create mode 100755 web/status_venv.sh create mode 100755 web/stop.sh create mode 100755 web/stop_venv.sh diff --git a/web/DEPLOY_GUIDE.md b/web/DEPLOY_GUIDE.md new file mode 100644 index 0000000..14d42ec --- /dev/null +++ b/web/DEPLOY_GUIDE.md @@ -0,0 +1,212 @@ +# 缠论Web应用部署指南 + +本指南提供在服务器上直接部署缠论Web应用的步骤,无需使用Nginx等反向代理。 + +## 注意:Ubuntu 22.04+系统的特殊处理 + +最新版本的Ubuntu系统对Python包管理有额外限制,不允许直接用pip在系统级别安装包。因此,我们提供了使用虚拟环境的部署方法。 + +## 方法一:使用虚拟环境部署脚本(适用于Ubuntu 22.04+,推荐) + +这是最适合现代Ubuntu系统的方法: + +1. 登录到服务器 +2. 进入应用目录: + ``` + cd /path/to/user_data/Chan/web + ``` +3. 给脚本添加执行权限: + ``` + chmod +x deploy_venv.sh stop_venv.sh status_venv.sh + ``` +4. 启动服务: + ``` + ./deploy_venv.sh + ``` +5. 检查服务状态: + ``` + ./status_venv.sh + ``` +6. 如需停止服务: + ``` + ./stop_venv.sh + ``` + +## 方法二:标准部署脚本(适用于旧版Ubuntu或其他系统) + +如果您的系统允许直接安装Python包: + +1. 登录到服务器 +2. 进入应用目录: + ``` + cd /path/to/user_data/Chan/web + ``` +3. 给脚本添加执行权限: + ``` + chmod +x deploy.sh stop.sh status.sh + ``` +4. 启动服务: + ``` + ./deploy.sh + ``` +5. 检查服务状态: + ``` + ./status.sh + ``` +6. 如需停止服务: + ``` + ./stop.sh + ``` + +## 方法三:系统服务(systemd) + +如果希望应用随系统启动自动运行,可以设置systemd服务: + +### 使用虚拟环境的systemd服务(推荐) + +1. 编辑服务文件中的用户名、用户组和路径: + ``` + vi chanlun-web-venv.service + ``` + 修改以下行: + - `User=<用户名>` - 改为您的用户名 + - `Group=<用户组>` - 改为您的用户组 + - 所有包含`/path/to/`的路径 + +2. 将服务文件复制到systemd目录: + ``` + sudo cp chanlun-web-venv.service /etc/systemd/system/ + ``` + +3. 重新加载systemd配置: + ``` + sudo systemctl daemon-reload + ``` + +4. 启用并启动服务: + ``` + sudo systemctl enable chanlun-web-venv + sudo systemctl start chanlun-web-venv + ``` + +5. 检查服务状态: + ``` + sudo systemctl status chanlun-web-venv + ``` + +### 使用系统Python的systemd服务(仅适用于旧版系统) + +1. 编辑服务文件: + ``` + vi chanlun-web.service + ``` + +2. 按照上述相同的步骤配置和启动服务。 + +## 方法四:手动启动 + +如果只需要临时运行,可以手动启动: + +### 使用虚拟环境(推荐) + +1. 创建并激活虚拟环境: + ``` + python3 -m venv venv + source venv/bin/activate + ``` + +2. 安装依赖: + ``` + pip install -r requirements.txt + ``` + +3. 使用gunicorn启动(前台运行): + ``` + venv/bin/gunicorn -w 4 -b 0.0.0.0:8123 app:app + ``` + + 或后台运行: + ``` + venv/bin/gunicorn -w 4 -b 0.0.0.0:8123 --access-logfile logs/access.log --error-logfile logs/error.log --daemon app:app + ``` + +### 直接使用系统Python(仅适用于旧版系统) + +1. 安装依赖: + ``` + pip install -r requirements.txt + ``` + +2. 使用gunicorn启动(前台运行): + ``` + gunicorn -w 4 -b 0.0.0.0:8123 app:app + ``` + +## 防火墙设置 + +请确保服务器防火墙开放了8123端口: + +``` +# 对于使用ufw的系统(如Ubuntu) +sudo ufw allow 8123/tcp + +# 对于使用firewalld的系统(如CentOS) +sudo firewall-cmd --permanent --add-port=8123/tcp +sudo firewall-cmd --reload +``` + +## 访问应用 + +部署完成后,可以通过以下URL访问应用: + +``` +http://服务器IP:8123 +``` + +## 可选:使用screen运行 + +如果SSH连接可能不稳定,可以使用screen在后台会话中运行: + +### 使用虚拟环境的screen会话(推荐) + +``` +screen -S chanlun-web +cd /path/to/user_data/Chan/web +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +python app.py +``` + +然后按下`Ctrl+A`然后按`D`来分离会话。要重新连接会话: + +``` +screen -r chanlun-web +``` + +## 故障排除 + +1. 如果服务不能启动,检查日志: + ``` + cat logs/error.log + ``` + +2. 确保安装了所有依赖: + ``` + # 在虚拟环境中 + source venv/bin/activate + pip install -r requirements.txt + ``` + +3. 检查端口是否被占用: + ``` + netstat -tulpn | grep 8123 + ``` + +4. 如果gunicorn无法找到,确保使用完整路径: + ``` + # 对于虚拟环境 + ./venv/bin/gunicorn -w 4 -b 0.0.0.0:8123 app:app + ``` + +5. 如果出现"externally-managed-environment"错误,这表明您正在使用最新的Ubuntu系统,必须使用虚拟环境方法。 \ No newline at end of file diff --git a/web/chanlun-web-venv.service b/web/chanlun-web-venv.service new file mode 100644 index 0000000..3e8a427 --- /dev/null +++ b/web/chanlun-web-venv.service @@ -0,0 +1,15 @@ +[Unit] +Description=ChanLun Web Application +After=network.target + +[Service] +User=<用户名> +Group=<用户组> +WorkingDirectory=/path/to/user_data/Chan/web +ExecStart=/path/to/user_data/Chan/web/venv/bin/gunicorn -w 4 -b 0.0.0.0:8123 app:app +Restart=on-failure +StandardOutput=file:/path/to/user_data/Chan/web/logs/output.log +StandardError=file:/path/to/user_data/Chan/web/logs/error.log + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/web/chanlun-web.service b/web/chanlun-web.service new file mode 100644 index 0000000..4e39e8e --- /dev/null +++ b/web/chanlun-web.service @@ -0,0 +1,15 @@ +[Unit] +Description=ChanLun Web Application +After=network.target + +[Service] +User=<用户名> +Group=<用户组> +WorkingDirectory=/path/to/user_data/Chan/web +ExecStart=/usr/local/bin/gunicorn -w 4 -b 0.0.0.0:8123 app:app +Restart=on-failure +StandardOutput=file:/path/to/user_data/Chan/web/logs/output.log +StandardError=file:/path/to/user_data/Chan/web/logs/error.log + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/web/deploy.sh b/web/deploy.sh new file mode 100755 index 0000000..ac82536 --- /dev/null +++ b/web/deploy.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# 创建日志目录(如果不存在) +mkdir -p logs + +# 激活虚拟环境(如果使用) +# source venv/bin/activate + +# 安装依赖 +pip install -r requirements.txt + +# 使用gunicorn启动应用 +# 参数说明: +# -w 4: 使用4个工作进程 +# -b 0.0.0.0:8123: 绑定到所有接口的8123端口 +# --access-logfile: 访问日志文件路径 +# --error-logfile: 错误日志文件路径 +# --daemon: 以守护进程(后台)方式运行 +# app:app: app.py中的app变量 + +gunicorn -w 4 -b 0.0.0.0:8123 --access-logfile logs/access.log --error-logfile logs/error.log --daemon app:app + +echo "服务已启动在 http://服务器IP:8123" +echo "查看进程状态: ps aux | grep gunicorn" +echo "停止服务: pkill gunicorn" \ No newline at end of file diff --git a/web/deploy_venv.sh b/web/deploy_venv.sh new file mode 100755 index 0000000..5118eb8 --- /dev/null +++ b/web/deploy_venv.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# 确保安装了虚拟环境工具 +echo "检查并安装虚拟环境工具..." +sudo apt update +sudo apt install -y python3-venv python3-full + +# 创建日志目录(如果不存在) +mkdir -p logs + +# 创建虚拟环境(如果不存在) +if [ ! -d "venv" ]; then + echo "创建虚拟环境..." + python3 -m venv venv +fi + +# 激活虚拟环境 +echo "激活虚拟环境..." +source venv/bin/activate + +# 安装依赖 +echo "安装依赖..." +pip install --upgrade pip +pip install -r requirements.txt + +# 使用gunicorn启动应用 +echo "启动应用..." +venv/bin/gunicorn -w 4 -b 0.0.0.0:8123 --access-logfile logs/access.log --error-logfile logs/error.log --daemon app:app + +echo "服务已启动在 http://服务器IP:8123" +echo "查看进程状态: ps aux | grep gunicorn" +echo "停止服务: ./stop_venv.sh" \ No newline at end of file diff --git a/web/status.sh b/web/status.sh new file mode 100755 index 0000000..768342e --- /dev/null +++ b/web/status.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# 检查gunicorn进程 +echo "Gunicorn进程状态:" +ps aux | grep gunicorn | grep -v grep + +# 检查端口 +echo -e "\n端口8123状态:" +netstat -tulpn 2>/dev/null | grep 8123 || echo "端口8123未被占用" + +# 检查日志文件最后几行 +echo -e "\n访问日志(最后5行):" +tail -n 5 logs/access.log 2>/dev/null || echo "访问日志尚未创建" + +echo -e "\n错误日志(最后5行):" +tail -n 5 logs/error.log 2>/dev/null || echo "错误日志尚未创建" \ No newline at end of file diff --git a/web/status_venv.sh b/web/status_venv.sh new file mode 100755 index 0000000..cf1eabf --- /dev/null +++ b/web/status_venv.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# 检查虚拟环境中的gunicorn进程 +echo "Gunicorn进程状态:" +ps aux | grep "venv/bin/gunicorn" | grep -v grep + +# 检查端口 +echo -e "\n端口8123状态:" +netstat -tulpn 2>/dev/null | grep 8123 || echo "端口8123未被占用" + +# 检查日志文件最后几行 +echo -e "\n访问日志(最后5行):" +tail -n 5 logs/access.log 2>/dev/null || echo "访问日志尚未创建" + +echo -e "\n错误日志(最后5行):" +tail -n 5 logs/error.log 2>/dev/null || echo "错误日志尚未创建" \ No newline at end of file diff --git a/web/stop.sh b/web/stop.sh new file mode 100755 index 0000000..ccac724 --- /dev/null +++ b/web/stop.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# 停止所有gunicorn进程 +pkill gunicorn + +echo "已停止所有gunicorn进程" \ No newline at end of file diff --git a/web/stop_venv.sh b/web/stop_venv.sh new file mode 100755 index 0000000..70c218f --- /dev/null +++ b/web/stop_venv.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# 找到并终止gunicorn进程 +echo "停止gunicorn进程..." +pkill -f "venv/bin/gunicorn" + +echo "已停止所有gunicorn进程" \ No newline at end of file diff --git a/web/templates/index.html b/web/templates/index.html index 577a972..f0245e3 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -224,6 +224,22 @@ border-radius: 4px; overflow: hidden; } + + .crosshair-tooltip { + position: absolute; + background: rgba(40, 40, 40, 0.9); + color: white; + padding: 8px 12px; + border-radius: 4px; + font-size: 12px; + z-index: 1000; + pointer-events: none; + max-width: 300px; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + display: none; + } + + /* 主次周期元素样式区分 */ @@ -729,9 +745,16 @@ } // 从日期字符串获取时间戳,应用时区偏移 - function getAdjustedTimestamp(dateStr) { - // 基础时间戳(秒)- 直接使用UTC时间 - return Math.floor(new Date(dateStr).getTime() / 1000); + function getAdjustedTimestamp(dateStr, applyOffset = true) { + const date = new Date(dateStr); + const timestamp = Math.floor(date.getTime() / 1000); + + if (!applyOffset) { + return timestamp; + } + + // 不再手动调整时区偏移,使用JavaScript的内置时区支持 + return timestamp; } // 添加时区选择器变更事件 @@ -1029,6 +1052,10 @@ const timezone = $('#timezone').val(); const date = new Date(timeStr); + // 添加调试信息 + console.debug('表格时间格式化:', timeStr, '->', + date.toISOString(), '使用时区:', timezone); + // 使用toLocaleString带时区参数 return date.toLocaleString('zh-CN', { timeZone: timezone, @@ -1041,13 +1068,8 @@ }); } catch (e) { console.error('时间格式化错误:', e, timeStr); - // 如果出错,尝试使用简单格式化 - try { - return new Date(timeStr).toLocaleString(); - } catch (e2) { - // 如果还是出错,返回原始字符串 - return timeStr; - } + // 如果格式化失败,返回原始时间字符串 + return timeStr; } } @@ -1077,6 +1099,9 @@ const timezone = $('#timezone').val() || 'Asia/Shanghai'; const elementTimeframe = $('#elementTimeframe').val() || '1m'; + // 确保时区参数有效 + console.log('更新图表使用时区:', timezone); + // 如果symbol为空,不发送请求 if (!symbol) { console.error('交易对不能为空'); @@ -1084,7 +1109,7 @@ return; } - console.log(`更新图表: symbol=${symbol}, timeframe=${timeframe}, elementTimeframe=${elementTimeframe}`); + console.log(`更新图表: symbol=${symbol}, timeframe=${timeframe}, elementTimeframe=${elementTimeframe}, timezone=${timezone}`); // 获取开始和结束时间(如果已设置) let startTimeMs = null; @@ -1117,6 +1142,9 @@ // 保存当前数据 currentData = data; + // 检查和记录服务器返回的时区 + console.log('服务器返回的时区:', data.timezone || '未指定'); + // 刷新图表 refreshChart(data); }, @@ -1238,10 +1266,55 @@ }, crosshair: { mode: LightweightCharts.CrosshairMode.Normal, + // 添加十字线工具提示本地化配置 + horzLine: { + labelVisible: true, + }, + vertLine: { + labelVisible: true, + // 自定义时间格式化 + labelFormatter: (time) => { + const selectedTimezone = $('#timezone').val(); + try { + return new Date(time * 1000).toLocaleString('zh-CN', { + timeZone: selectedTimezone, + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + } catch (e) { + console.error('十字线时间格式化错误:', e); + return new Date(time * 1000).toLocaleString(); + } + }, + }, }, rightPriceScale: { borderColor: '#ddd', }, + // 添加本地化选项,确保所有时间显示都使用选定的时区 + localization: { + timeFormatter: (time) => { + const selectedTimezone = $('#timezone').val(); + try { + return new Date(time * 1000).toLocaleString('zh-CN', { + timeZone: selectedTimezone, + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + } catch (e) { + console.error('全局时间格式化错误:', e); + return new Date(time * 1000).toLocaleString(); + } + } + }, timeScale: { timeVisible: true, secondsVisible: false, @@ -1251,7 +1324,11 @@ tickMarkFormatter: (time) => { const selectedTimezone = $('#timezone').val(); try { - return new Date(time * 1000).toLocaleString('zh-CN', { + // 使用完整的配置确保时区正确应用 + const date = new Date(time * 1000); + console.log('格式化时间:', time, '转换为:', date.toISOString(), '时区:', selectedTimezone); + + return date.toLocaleString('zh-CN', { timeZone: selectedTimezone, month: 'numeric', day: 'numeric', @@ -1287,12 +1364,16 @@ // 输出K线周期选择状态 console.log('K线周期选择:', useElementPeriod ? '小周期' : '主周期'); + console.log('当前选择时区:', $('#timezone').val()); if (useElementPeriod) { // 使用小周期K线数据 candles = currentData.element_kline_data.map((kline) => { + // 使用原始日期字符串创建Date对象 const date = new Date(kline.date); + // 获取时间戳(秒)- 不手动调整时区 const timestamp = date.getTime() / 1000; + return { time: timestamp, open: parseFloat(kline.open), @@ -1304,8 +1385,11 @@ } else { // 使用主周期K线数据 candles = currentData.kline_data.map((kline) => { + // 使用原始日期字符串创建Date对象 const date = new Date(kline.date); + // 获取时间戳(秒)- 不手动调整时区 const timestamp = date.getTime() / 1000; + return { time: timestamp, open: parseFloat(kline.open), @@ -1350,6 +1434,7 @@ // 转换成交量数据 - 始终使用主K线周期数据 const volumes = useElementPeriod ? currentData.element_kline_data.map(kline => { + // 创建日期对象并获取时间戳,不手动调整时区 const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); return { time: timestamp, @@ -1358,6 +1443,7 @@ }; }) : currentData.kline_data.map(kline => { + // 创建日期对象并获取时间戳,不手动调整时区 const timestamp = Math.floor(new Date(kline.date).getTime() / 1000); return { time: timestamp, @@ -2942,17 +3028,65 @@ } function setupTooltip() { + // 调试变量 + window.debugMode = true; + // 添加买卖点悬浮提示元素 const tooltipElement = document.createElement('div'); tooltipElement.className = 'point-tooltip'; document.body.appendChild(tooltipElement); + // 添加自定义十字线信息显示 + const crosshairTooltip = document.createElement('div'); + crosshairTooltip.className = 'crosshair-tooltip'; + crosshairTooltip.style.position = 'absolute'; + crosshairTooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; + crosshairTooltip.style.color = 'white'; + crosshairTooltip.style.padding = '5px 10px'; + crosshairTooltip.style.borderRadius = '4px'; + crosshairTooltip.style.fontSize = '12px'; + crosshairTooltip.style.zIndex = '1000'; + crosshairTooltip.style.pointerEvents = 'none'; + crosshairTooltip.style.display = 'none'; + document.body.appendChild(crosshairTooltip); + // 添加鼠标悬停事件显示提示 mainChart.subscribeCrosshairMove(param => { if (param.time && param.point) { const timeStr = param.time; const markers = [...buyMarkers, ...sellMarkers].filter(m => m.time === timeStr); + // 显示时区调试信息 + if (window.debugMode) { + const timezone = $('#timezone').val(); + const formattedTime = formatTimeWithTimezone(timeStr * 1000, timezone); + + // 获取当前价格 - 通过param.seriesPrices获取 + let priceInfo = ''; + if (param.seriesPrices && param.seriesPrices.size > 0) { + // 尝试从蜡烛图系列获取价格 + if (tvWidget.series.candleSeries && param.seriesPrices.get(tvWidget.series.candleSeries)) { + const price = param.seriesPrices.get(tvWidget.series.candleSeries); + priceInfo = `价格: ${price.toFixed(2)}`; + } + // 如果没有蜡烛图系列价格,尝试从线图系列获取 + else if (tvWidget.series.lineSeries && param.seriesPrices.get(tvWidget.series.lineSeries)) { + const price = param.seriesPrices.get(tvWidget.series.lineSeries); + priceInfo = `价格: ${price.toFixed(2)}`; + } + } + + // 仅记录最简短的调试信息 + console.debug(`十字线: ${timeStr} -> ${formattedTime} (${timezone})`); + + // 显示自定义时区工具提示,包含价格信息 + crosshairTooltip.innerHTML = `
时间: ${formattedTime}
` + + (priceInfo ? `
${priceInfo}
` : ''); + crosshairTooltip.style.display = 'block'; + crosshairTooltip.style.left = (param.point.x + 15) + 'px'; + crosshairTooltip.style.top = (param.point.y - 30) + 'px'; + } + if (markers.length > 0) { // 有买卖点标记,显示自定义提示 const tooltips = markers.map(m => m.tooltip).join('
'); @@ -2967,15 +3101,35 @@ } else { // 隐藏提示 tooltipElement.style.display = 'none'; + crosshairTooltip.style.display = 'none'; } }); // 处理图表缩放、平移等事件,隐藏提示 mainChart.timeScale().subscribeVisibleTimeRangeChange(() => { tooltipElement.style.display = 'none'; + crosshairTooltip.style.display = 'none'; }); } + // 辅助函数:使用指定时区格式化时间戳 + function formatTimeWithTimezone(timestamp, timezone) { + try { + return new Date(timestamp).toLocaleString('zh-CN', { + timeZone: timezone, + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + } catch (e) { + console.error('时区格式化错误:', e); + return new Date(timestamp).toLocaleString(); + } + } + function displayTradePoints() { // 优先使用小周期数据,如果不存在则使用主周期数据 const tradePointsData = currentData.element_trade_points || currentData.trade_points; @@ -3454,6 +3608,13 @@ // 页面加载时初始化 $(document).ready(function() { + // 从本地存储中恢复时区设置 + const savedTimezone = localStorage.getItem('selectedTimezone'); + if (savedTimezone) { + $('#timezone').val(savedTimezone); + console.log('从本地存储恢复时区设置:', savedTimezone); + } + // 初始化交易对下拉菜单 $('#symbol').val('BTC/USDT:USDT'); $('#timeframe').val('5m'); @@ -3485,6 +3646,66 @@ // 初始化自动刷新功能 initAutoRefresh(); + + // 确保在文档加载完成后初始化时区设置 + // 默认设置为Shanghai时区 + if (!$('#timezone').val()) { + $('#timezone').val('Asia/Shanghai'); + } + + // 记录当前时区设置 + console.log('页面加载完成,当前时区设置:', $('#timezone').val()); + + // 添加自定义事件处理 - 让时区选择变更立即生效 + $('#timezone').on('change', function() { + const newTimezone = $(this).val(); + console.log('时区已更改为:', newTimezone); + + // 保存到本地存储,下次访问时自动使用 + localStorage.setItem('selectedTimezone', newTimezone); + + // 如果已有数据,重新渲染图表和表格 + if (currentData) { + // 先销毁现有图表实例 + if (tvWidget.mainChart) { + try { + // 销毁主图表及其关联的线系列 + tvWidget.mainChart = null; + tvWidget.volumeChart = null; + tvWidget.macdChart = null; + // 重置系列数据 + tvWidget.series = { + candleSeries: null, + lineSeries: null, + volumeSeries: null, + macdLineSeries: null, + signalLineSeries: null, + histogramSeries: null, + mainBiSeries: [], + mainSegSeries: [], + mainZsSeries: [], + mainUncompletedZsSeries: [], + elementBiSeries: [], + elementSegSeries: [], + elementZsSeries: [], + elementUncompletedZsSeries: [], + tradePointSeries: [] + }; + } catch (e) { + console.error('销毁图表错误:', e); + } + } + + // 使用新的时区重新初始化图表 + initTradingView($('#symbol').val(), $('#timeframe').val()); + + // 重新渲染图表数据 + renderChart(); + + // 更新表格 + updateTables(currentData); + } + }); }); // 自动刷新相关变量