fix: 修复主站自动刷新内存泄漏,并完善 chan_tv 图表体验
主站重建前完整 dispose、去掉重复 sync 监听,自动刷新默认增量更新;顺带消除首屏重复 analyze、复用 ChanMACD,以及全版 TV 指标/未完成中枢/布局本地缓存。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,20 +1,27 @@
|
||||
/**
|
||||
* TradingView Datafeed — 对接 Data Provider 微服务
|
||||
*
|
||||
* 数据源: http://103.179.242.166
|
||||
* - GET /timeframes → 可用周期
|
||||
* - GET /api/candles → 历史 OHLCV
|
||||
* - WS /ws → 实时 K 线推送
|
||||
* REST: https://provider.jackyu66.com
|
||||
* WS: wss://jackyu66.com/ws (可通过 window.DATA_SERVICE_* 或 URL 参数覆盖)
|
||||
*
|
||||
* 实现 IDatafeedChartApi 核心接口:
|
||||
* onReady, resolveSymbol, getBars, subscribeBars, unsubscribeBars
|
||||
* 实时:subscribeBars → 收到 kline 后调用 onTick(由 Charting Library 增量更新,不重置缩放)
|
||||
*/
|
||||
|
||||
var ChanTVDatafeed = (function () {
|
||||
'use strict'
|
||||
|
||||
// 默认 data_provider 地址,可通过 URL param 覆盖
|
||||
var DATA_HOST = 'http://103.179.242.166'
|
||||
function getParam(name) {
|
||||
try {
|
||||
var m = (new RegExp('[?&]' + name + '=([^&]*)')).exec(location.search)
|
||||
return m ? decodeURIComponent(m[1]) : ''
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// REST 与 WS 可分离(nginx 反代)
|
||||
var DATA_HOST = (window.DATA_SERVICE_URL || getParam('data_host') || 'https://provider.jackyu66.com').replace(/\/$/, '')
|
||||
var WS_URL = (window.DATA_SERVICE_WS_URL || getParam('ws_url') || 'wss://jackyu66.com/ws').replace(/\/$/, '')
|
||||
|
||||
// ---- resolution <-> timeframe 转换 ----
|
||||
var RES_TO_TF = {
|
||||
@@ -36,13 +43,12 @@ var ChanTVDatafeed = (function () {
|
||||
var ws = null
|
||||
var wsReconnectTimer = null
|
||||
var wsSubs = {} // listenerGuid -> { symbol, tf, onTick, lastTickTime }
|
||||
var wsUrl = DATA_HOST.replace(/^http/, 'ws') + '/ws'
|
||||
|
||||
function wsConnect() {
|
||||
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return
|
||||
|
||||
try {
|
||||
ws = new WebSocket(wsUrl)
|
||||
ws = new WebSocket(WS_URL)
|
||||
} catch (e) {
|
||||
console.warn('[TV Datafeed] WS 连接失败', e)
|
||||
scheduleReconnect()
|
||||
@@ -50,7 +56,7 @@ var ChanTVDatafeed = (function () {
|
||||
}
|
||||
|
||||
ws.onopen = function () {
|
||||
console.log('[TV Datafeed] WS 已连接')
|
||||
console.log('[TV Datafeed] WS 已连接', WS_URL)
|
||||
// 重新订阅
|
||||
Object.keys(wsSubs).forEach(function (guid) {
|
||||
var sub = wsSubs[guid]
|
||||
@@ -62,28 +68,35 @@ var ChanTVDatafeed = (function () {
|
||||
try {
|
||||
var msg = JSON.parse(evt.data)
|
||||
var bars = msg.data || msg.bars // data_provider 用 'data' 字段
|
||||
// 历史快照交给 getBars;实时只走 kline → onTick,避免冲掉缩放
|
||||
if (msg.type === 'snapshot' || msg.type === 'subscribed') return
|
||||
if ((msg.type === 'kline' || msg.type === 'candles') && bars && bars.length > 0) {
|
||||
// 只推送最新一根 bar,避免历史快照造成时间顺序冲突
|
||||
// 按时间升序排列取最后一个
|
||||
var sorted = bars.slice().sort(function (a, b) { return (a.timestamp || 0) - (b.timestamp || 0) })
|
||||
var latest = sorted[sorted.length - 1]
|
||||
// 广播给所有匹配的 subscriber
|
||||
if (!latest || latest.timestamp == null) return
|
||||
Object.keys(wsSubs).forEach(function (guid) {
|
||||
var sub = wsSubs[guid]
|
||||
if (sub.symbol === msg.symbol && sub.tf === msg.timeframe) {
|
||||
// 跳过已处理过的时间戳
|
||||
if (sub.lastTickTime && latest.timestamp <= sub.lastTickTime) return
|
||||
// 允许同 timestamp 更新未收盘棒(用 < 而不是 <=)
|
||||
if (sub.lastTickTime != null && latest.timestamp < sub.lastTickTime) return
|
||||
var tick = {
|
||||
time: latest.timestamp,
|
||||
open: latest.open,
|
||||
high: latest.high,
|
||||
low: latest.low,
|
||||
close: latest.close,
|
||||
volume: latest.volume,
|
||||
}
|
||||
try {
|
||||
sub.onTick({
|
||||
time: latest.timestamp,
|
||||
open: latest.open,
|
||||
high: latest.high,
|
||||
low: latest.low,
|
||||
close: latest.close,
|
||||
volume: latest.volume,
|
||||
})
|
||||
sub.onTick(tick)
|
||||
sub.lastTickTime = latest.timestamp
|
||||
} catch (e) { /* ignore */ }
|
||||
// 通知页面:更新缠论缓存(K 线由 TV onTick 处理,不重置缩放)
|
||||
try {
|
||||
if (window.ChanTvRealtime && typeof window.ChanTvRealtime.onBar === 'function') {
|
||||
window.ChanTvRealtime.onBar(msg.symbol, msg.timeframe, latest)
|
||||
}
|
||||
} catch (e2) { /* ignore */ }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user