Prechádzať zdrojové kódy

添加新浪财经数据源: 东方财富失败时自动切换到新浪财经获取实时数据

openclaw 3 mesiacov pred
rodič
commit
7bbed2981e
1 zmenil súbory, kde vykonal 116 pridanie a 37 odobranie
  1. 116 37
      cat-fly/auto_report.py

+ 116 - 37
cat-fly/auto_report.py

@@ -71,60 +71,139 @@ class DataFetcher:
     
     @staticmethod
     def fetch_recent_2months():
-        """获取近2个月数据 - 使用实时在线数据"""
+        """获取近2个月数据 - 使用实时在线数据(东方财富+新浪财经双数据源)"""
         end_date = datetime.now()
         start_date = end_date - timedelta(days=70)  # 2个月+10天缓冲
         
         print(f"获取数据: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}")
         
-        # 尝试在线获取(带重试机制)
-        max_retries = 3
-        for attempt in range(max_retries):
-            try:
-                print(f"[尝试 {attempt + 1}/{max_retries}] 正在使用东方财富30分钟K线接口...")
+        # 尝试东方财富数据源
+        df = DataFetcher._fetch_eastmoney_data(start_date, end_date)
+        if df is not None:
+            return df
+        
+        # 东方财富失败,尝试新浪财经
+        print("⚠️ 东方财富数据源失败,尝试新浪财经...")
+        df = DataFetcher._fetch_sina_data(start_date, end_date)
+        if df is not None:
+            return df
+        
+        # 所有数据源都失败
+        raise Exception("无法获取实时数据,东方财富和新浪财经均失败。请检查网络连接或稍后重试。")
+    
+    @staticmethod
+    def _fetch_eastmoney_data(start_date, end_date):
+        """从东方财富获取数据"""
+        try:
+            print("[数据源1] 正在使用东方财富30分钟K线接口...")
+            
+            # 使用东方财富接口获取30分钟K线
+            df = ak.index_zh_a_hist_min_em(symbol="399673", period="30")
+            
+            if df is not None and not df.empty and len(df) >= 50:
+                # 标准化列名
+                df = df.rename(columns={
+                    '时间': 'datetime',
+                    '开盘': 'open',
+                    '收盘': 'close',
+                    '最高': 'high',
+                    '最低': 'low',
+                    '成交量': 'volume'
+                })
                 
-                # 使用东方财富接口获取30分钟K线
-                df = ak.index_zh_a_hist_min_em(symbol="399673", period="30")
+                df['datetime'] = pd.to_datetime(df['datetime'])
+                df = df.set_index('datetime').sort_index()
                 
-                if df is not None and not df.empty and len(df) >= 50:
-                    # 标准化列名
-                    df = df.rename(columns={
-                        '时间': 'datetime',
-                        '开盘': 'open',
-                        '收盘': 'close',
-                        '最高': 'high',
-                        '最低': 'low',
-                        '成交量': 'volume'
-                    })
-                    
+                # 只保留最近2个月的数据用于回测
+                backtest_start = end_date - timedelta(days=60)
+                df_backtest = df[df.index >= backtest_start]
+                
+                print(f"✅ 东方财富数据获取成功: 共{len(df_backtest)}条30分钟K线")
+                print(f"   数据区间: {df_backtest.index[0]} 至 {df_backtest.index[-1]}")
+                
+                # 检查数据时效性
+                latest_time = df_backtest.index[-1]
+                time_delay = end_date - latest_time
+                print(f"   数据延迟: {time_delay}")
+                
+                return df_backtest
+            else:
+                print(f"⚠️ 东方财富数据不足: {len(df) if df is not None else 0}条")
+                return None
+                
+        except Exception as e:
+            print(f"❌ 东方财富数据源失败: {e}")
+            return None
+    
+    @staticmethod
+    def _fetch_sina_data(start_date, end_date):
+        """从新浪财经获取数据"""
+        try:
+            print("[数据源2] 正在使用新浪财经30分钟K线接口...")
+            
+            import requests
+            import json
+            import re
+            
+            symbol = "sz399673"
+            url = f"https://quotes.sina.cn/cn/api/jsonp_v2.php/var_{symbol}_30_/CN_MarketDataService.getKLineData?symbol={symbol}&scale=30&ma=no&datalen=1023"
+            
+            headers = {
+                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
+                'Referer': 'https://finance.sina.com.cn/'
+            }
+            
+            response = requests.get(url, headers=headers, timeout=15)
+            response_text = response.text
+            
+            # 解析JSONP响应
+            json_start = response_text.find('[')
+            json_end = response_text.rfind(']') + 1
+            if json_start >= 0 and json_end > json_start:
+                json_str = response_text[json_start:json_end]
+            else:
+                raise Exception("无法解析JSONP响应")
+            
+            data_dict = json.loads(json_str)
+            
+            if data_dict and isinstance(data_dict, list) and len(data_dict) > 0:
+                data_list = []
+                for item in data_dict:
+                    try:
+                        data_list.append({
+                            'datetime': item.get('day'),
+                            'open': float(item.get('open', 0)),
+                            'high': float(item.get('high', 0)),
+                            'low': float(item.get('low', 0)),
+                            'close': float(item.get('close', 0)),
+                            'volume': float(item.get('volume', 0))
+                        })
+                    except Exception:
+                        continue
+                
+                if data_list:
+                    df = pd.DataFrame(data_list)
                     df['datetime'] = pd.to_datetime(df['datetime'])
                     df = df.set_index('datetime').sort_index()
                     
-                    # 只保留最近2个月的数据用于回测
+                    # 只保留最近2个月的数据
                     backtest_start = end_date - timedelta(days=60)
                     df_backtest = df[df.index >= backtest_start]
                     
-                    print(f"✅ 数据获取成功: 共{len(df_backtest)}条30分钟K线")
+                    print(f"✅ 新浪财经数据获取成功: 共{len(df_backtest)}条30分钟K线")
                     print(f"   数据区间: {df_backtest.index[0]} 至 {df_backtest.index[-1]}")
                     
-                    # 检查数据时效性
-                    latest_time = df_backtest.index[-1]
-                    time_delay = end_date - latest_time
-                    print(f"   数据延迟: {time_delay}")
-                    
                     return df_backtest
                 else:
-                    print(f"⚠️ 获取到的数据不足: {len(df) if df is not None else 0}条")
-                    
-            except Exception as e:
-                print(f"❌ 尝试 {attempt + 1} 失败: {e}")
-                if attempt < max_retries - 1:
-                    import time
-                    print(f"   等待3秒后重试...")
-                    time.sleep(3)
-        
-        # 所有尝试都失败
-        raise Exception("无法获取实时数据,所有数据源均失败。请检查网络连接或稍后重试。")
+                    print("❌ 新浪财经数据解析失败")
+                    return None
+            else:
+                print("❌ 新浪财经返回数据格式错误")
+                return None
+                
+        except Exception as e:
+            print(f"❌ 新浪财经数据源失败: {e}")
+            return None
 
 
 # ==================== 策略类 ====================