From 3f5bb5ca844af1f7c06569b9ae6b77284542490a Mon Sep 17 00:00:00 2001 From: ZhouYongyou <128128010+zhouyongyou@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:54:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(market):=20resolve=20price=20staleness=20is?= =?UTF-8?q?sue=20in=20GetCurrentKlines=20##=20Problem=20GetCurrentKlines?= =?UTF-8?q?=20had=20two=20critical=20bugs=20causing=20price=20data=20to=20?= =?UTF-8?q?become=20stale:=201.=20Incorrect=20return=20logic:=20returned?= =?UTF-8?q?=20error=20even=20when=20data=20fetch=20succeeded=202.=20Race?= =?UTF-8?q?=20condition:=20returned=20slice=20reference=20instead=20of=20d?= =?UTF-8?q?eep=20copy,=20causing=20concurrent=20data=20corruption=20##=20I?= =?UTF-8?q?mpact=20-=20BTC=20price=20stuck=20at=20106xxx=20while=20actual?= =?UTF-8?q?=20market=20price=20was=20107xxx+=20-=20LLM=20calculated=20take?= =?UTF-8?q?-profit=20based=20on=20stale=20prices=20=E2=86=92=20orders=20fa?= =?UTF-8?q?iled=20validation=20-=20Statistics=20showed=20incorrect=20P&L?= =?UTF-8?q?=20(0.00%)=20due=20to=20corrupted=20historical=20data=20-=20Alt?= =?UTF-8?q?-coins=20filtered=20out=20due=20to=20failed=20market=20data=20f?= =?UTF-8?q?etch=20##=20Solution=201.=20Fixed=20return=20logic:=20only=20re?= =?UTF-8?q?turn=20error=20when=20actual=20failure=20occurs=202.=20Return?= =?UTF-8?q?=20deep=20copy=20instead=20of=20reference=20to=20prevent=20race?= =?UTF-8?q?=20conditions=203.=20Downgrade=20subscription=20errors=20to=20w?= =?UTF-8?q?arnings=20(non-blocking)=20##=20Test=20Results=20=E2=9C=85=20Pr?= =?UTF-8?q?ice=20updates=20in=20real-time=20=E2=9C=85=20Take-profit=20orde?= =?UTF-8?q?rs=20execute=20successfully=20=E2=9C=85=20P&L=20calculations=20?= =?UTF-8?q?accurate=20=E2=9C=85=20Alt-coins=20now=20tradeable=20Related:?= =?UTF-8?q?=20Price=20feed=20mechanism,=20concurrent=20data=20access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- market/monitor.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/market/monitor.go b/market/monitor.go index 23e126d9..a09763e8 100644 --- a/market/monitor.go +++ b/market/monitor.go @@ -239,19 +239,32 @@ func (m *WSMonitor) GetCurrentKlines(symbol string, _time string) ([]Kline, erro // 如果Ws数据未初始化完成时,单独使用api获取 - 兼容性代码 (防止在未初始化完成是,已经有交易员运行) apiClient := NewAPIClient() klines, err := apiClient.GetKlines(symbol, _time, 100) - m.getKlineDataMap(_time).Store(strings.ToUpper(symbol), klines) //动态缓存进缓存 + if err != nil { + return nil, fmt.Errorf("获取%v分钟K线失败: %v", _time, err) + } + + // 动态缓存进缓存 + m.getKlineDataMap(_time).Store(strings.ToUpper(symbol), klines) + + // 订阅 WebSocket 流 subStr := m.subscribeSymbol(symbol, _time) subErr := m.combinedClient.subscribeStreams(subStr) log.Printf("动态订阅流: %v", subStr) if subErr != nil { - return nil, fmt.Errorf("动态订阅%v分钟K线失败: %v", _time, subErr) + log.Printf("警告: 动态订阅%v分钟K线失败: %v (使用API数据)", _time, subErr) } - if err != nil { - return nil, fmt.Errorf("获取%v分钟K线失败: %v", _time, err) - } - return klines, fmt.Errorf("symbol不存在") + + // ✅ FIX: 返回深拷贝而非引用 + result := make([]Kline, len(klines)) + copy(result, klines) + return result, nil } - return value.([]Kline), nil + + // ✅ FIX: 返回深拷贝而非引用,避免并发竞态条件 + klines := value.([]Kline) + result := make([]Kline, len(klines)) + copy(result, klines) + return result, nil } func (m *WSMonitor) Close() {