| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- A50期货 - 30分钟K线数据获取(多方案尝试)
- 标的:富时中国A50指数期货 (CN0Y, XIN9)
- """
- import pandas as pd
- import numpy as np
- import akshare as ak
- import requests
- import json
- import re
- from datetime import datetime, timedelta
- import warnings
- warnings.filterwarnings('ignore')
- class A50FuturesFetcher:
- """A50期货数据获取器 - 多方案"""
-
- def __init__(self):
- print("="*70)
- print("A50期货30分钟K线数据获取工具")
- print("="*70)
-
- def fetch_data(self, days=40):
- """获取数据 - 尝试多种方案"""
- end_date = datetime.now()
- start_date = end_date - timedelta(days=days+5)
-
- print(f"\n目标: 获取近{days}天30分钟K线")
- print(f"时间范围: {start_date.strftime('%Y-%m-%d')} ~ {end_date.strftime('%Y-%m-%d')}")
-
- # 方案1: AKShare期货分钟数据
- print("\n" + "-"*70)
- print("[方案1] AKShare期货分钟数据...")
- df = self._try_akshare_futures(start_date, end_date)
- if df is not None: return df
-
- # 方案2: AKShare股指期货
- print("\n" + "-"*70)
- print("[方案2] AKShare股指期货(CN0Y)...")
- df = self._try_akshare_cn0y(start_date, end_date)
- if df is not None: return df
-
- # 方案3: 新浪财经期货
- print("\n" + "-"*70)
- print("[方案3] 新浪财经期货接口...")
- df = self._try_sina_futures(days)
- if df is not None: return df
-
- # 方案4: 东方财富期货
- print("\n" + "-"*70)
- print("[方案4] 东方财富期货接口...")
- df = self._try_eastmoney_futures()
- if df is not None: return df
-
- # 方案5: 使用相关ETF作为替代
- print("\n" + "-"*70)
- print("[方案5] A50相关ETF数据...")
- df = self._try_a50_etf(start_date, end_date)
- if df is not None: return df
-
- # 方案6: 上证50指数作为替代
- print("\n" + "-"*70)
- print("[方案6] 上证50指数(000016)作为替代...")
- df = self._try_sz50_index(start_date, end_date)
- if df is not None: return df
-
- print("\n❌ 所有方案均失败")
- return None
-
- def _try_akshare_futures(self, start_date, end_date):
- """方案1: AKShare期货分钟数据"""
- try:
- # 尝试获取富时A50期货分钟数据
- print(" 尝试: futures_zh_minute_sina...")
-
- # 富时中国A50期货代码
- symbol = "CN0Y"
- df = ak.futures_zh_minute_sina(symbol=symbol, period="30")
-
- if df is not None and len(df) > 0:
- df['datetime'] = pd.to_datetime(df['datetime'])
- df = df.set_index('datetime').sort_index()
- df = df[(df.index >= start_date) & (df.index <= end_date)]
-
- if len(df) > 10:
- print(f" ✅ 成功: {len(df)}条")
- return df
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def _try_akshare_cn0y(self, start_date, end_date):
- """方案2: AKShare股指期货数据"""
- try:
- print(" 尝试: futures_zh_realtime...")
-
- # 获取股指期货实时数据(包含历史)
- df = ak.futures_zh_realtime(symbol="富时A50")
-
- if df is not None and len(df) > 0:
- print(f" 获取到实时数据: {len(df)}条")
- # 注意:这是实时报价,不是K线
- return None
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def _try_sina_futures(self, days):
- """方案3: 新浪财经期货K线"""
- try:
- print(" 尝试: 新浪财经期货K线接口...")
-
- # 新浪财经A50连续合约
- url = "https://stock.finance.sina.com.cn/futures/api/jsonp.php/var_CN0Y=/InnerFuturesNewService.getMinLine?symbol=CN0Y"
-
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
- 'Referer': 'https://finance.sina.com.cn/'
- }
-
- response = requests.get(url, headers=headers, timeout=10)
-
- # 解析JSONP
- text = response.text
- json_start = text.find('[')
- json_end = text.rfind(']') + 1
-
- if json_start > 0 and json_end > json_start:
- json_str = text[json_start:json_end]
- data = json.loads(json_str)
-
- if data and len(data) > 0:
- df_list = []
- for item in data:
- df_list.append({
- 'datetime': item.get('time'),
- '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))
- })
-
- df = pd.DataFrame(df_list)
- df['datetime'] = pd.to_datetime(df['datetime'])
- df = df.set_index('datetime').sort_index()
-
- # 只保留近N天
- start = datetime.now() - timedelta(days=days)
- df = df[df.index >= start]
-
- if len(df) > 10:
- print(f" ✅ 成功: {len(df)}条")
- return df
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def _try_eastmoney_futures(self):
- """方案4: 东方财富期货数据"""
- try:
- print(" 尝试: 东方财富期货接口...")
-
- # 东方财富A50期货
- # 使用股指期货分钟数据接口
- df = ak.futures_zh_minute_sina(symbol="XIN9", period="30")
-
- if df is not None and len(df) > 0:
- df['datetime'] = pd.to_datetime(df['datetime'])
- df = df.set_index('datetime').sort_index()
-
- if len(df) > 10:
- print(f" ✅ 成功: {len(df)}条")
- return df
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def _try_a50_etf(self, start_date, end_date):
- """方案5: A50 ETF数据"""
- try:
- print(" 尝试: 华夏A50ETF(159601)...")
-
- df = ak.fund_etf_hist_min_em(symbol="159601", period="30",
- start_date=start_date.strftime('%Y%m%d%H%M%S'),
- end_date=end_date.strftime('%Y%m%d%H%M%S'))
-
- if df is not None and len(df) > 10:
- df = df.rename(columns={
- '时间': 'datetime', '开盘': 'open', '收盘': 'close',
- '最高': 'high', '最低': 'low', '成交量': 'volume'
- })
- df['datetime'] = pd.to_datetime(df['datetime'])
- df = df.set_index('datetime').sort_index()
-
- print(f" ✅ 成功: {len(df)}条 (ETF替代数据)")
- return df
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def _try_sz50_index(self, start_date, end_date):
- """方案6: 上证50指数"""
- try:
- print(" 尝试: 上证50指数(000016)...")
-
- df = ak.index_zh_a_hist_min_em(symbol="000016", period="30",
- start_date=start_date.strftime('%Y%m%d%H%M%S'),
- end_date=end_date.strftime('%Y%m%d%H%M%S'))
-
- if df is not None and len(df) > 10:
- df = df.rename(columns={
- '时间': 'datetime', '开盘': 'open', '收盘': 'close',
- '最高': 'high', '最低': 'low', '成交量': 'volume'
- })
- df['datetime'] = pd.to_datetime(df['datetime'])
- df = df.set_index('datetime').sort_index()
-
- print(f" ✅ 成功: {len(df)}条 (上证50替代数据)")
- return df
-
- except Exception as e:
- print(f" 失败: {str(e)[:80]}")
- return None
-
- def save_and_show(self, df, filename=None):
- """保存并显示数据"""
- if df is None or len(df) == 0:
- print("\n❌ 无数据")
- return
-
- # 保存
- if filename is None:
- filename = f"A50_30min_{datetime.now().strftime('%Y%m%d_%H%M')}.csv"
-
- df.to_csv(filename)
- print(f"\n💾 已保存: {filename}")
-
- # 统计
- print(f"\n📊 数据统计:")
- print(f" 数据条数: {len(df)}")
- print(f" 时间区间: {df.index[0]} ~ {df.index[-1]}")
- print(f" 价格区间: {df['low'].min():.2f} ~ {df['high'].max():.2f}")
- print(f" 最新价格: {df['close'].iloc[-1]:.2f}")
-
- # 显示最新10条
- print(f"\n📋 最新10条数据:")
- print(df.tail(10)[['open', 'high', 'low', 'close', 'volume']].to_string())
- def main():
- fetcher = A50FuturesFetcher()
- df = fetcher.fetch_data(days=40)
-
- if df is not None:
- fetcher.save_and_show(df)
- print("\n✅ 完成!")
- else:
- print("\n❌ 获取失败,请检查网络连接")
-
- print("="*70)
- if __name__ == "__main__":
- main()
|