编辑代码


import akshare as ak
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
import time

# 配置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def get_main_contracts():
    """自动获取四大交易所主力合约"""
    markets = {
        "上海期货交易所": {"market": "FF", "suffix": "9999"},
        "大连商品交易所": {"market": "DF", "suffix": "9999"},
        "郑州商品交易所": {"market": "ZF", "suffix": "999"},
        "中国金融期货交易所": {"market": "CF", "suffix": "9999"}
    }
    
    main_contracts = []
    
    for market_name, config in markets.items():
        try:
            # 获取该交易所所有合约
            df = ak.futures_main_sina(symbol=config["suffix"], market=config["market"])
            # 提取主力合约信息
            if not df.empty:
                main_contracts.extend([
                    {"symbol": row['symbol'], 
                     "market": config["market"],
                     "name": row['name']}
                    for _, row in df.iterrows()
                ])
                print(f"成功获取 {market_name} 主力合约")
        except Exception as e:
            print(f"获取 {market_name} 数据异常: {str(e)}")
            continue
        time.sleep(1)
        
    return main_contracts

def get_realtime_data(contract_list):
    """批量获取实时行情数据"""
    all_data = []
    
    for contract in contract_list:
        try:
            df = ak.futures_zh_spot(
                symbol=contract["symbol"],
                market=contract["market"]
            )
            if not df.empty:
                # 统一数据格式
                data = {
                    "合约代码": contract["symbol"],
                    "合约名称": contract["name"],
                    "最新价": df['current_price'].iloc[0],
                    "结算价": df['settlement'].iloc[0],
                    "更新时间": df['time'].iloc[0]
                }
                data["涨跌幅"] = round(
                    (data["最新价"] - data["结算价"]) / data["结算价"] * 100, 2
                )
                all_data.append(data)
                print(f"已获取 {contract['name']} 数据")
        except Exception as e:
            print(f"获取 {contract['name']} 失败: {str(e)}")
            continue
        time.sleep(0.5)
    
    return pd.DataFrame(all_data)

def visualize_data(df):
    """专业级可视化"""
    plt.figure(figsize=(16, 10))
    df = df.sort_values('涨跌幅', ascending=True)
    
    # 创建颜色映射
    colors = ['#FF6B6B' if x >=0 else '#4ECDC4' for x in df['涨跌幅']]
    
    # 绘制水平条形图
    bars = plt.barh(
        df['合约名称'] + '\n(' + df['合约代码'] + ')',
        df['涨跌幅'],
        color=colors,
        height=0.7
    )
    
    # 添加数据标签
    for bar in bars:
        width = bar.get_width()
        label_pos = width if width > 0 else width - 0.8
        plt.text(
            label_pos, 
            bar.get_y() + bar.get_height()/2,
            f'{width:.2f}%',
            va='center',
            ha='right' if width < 0 else 'left',
            fontsize=10,
            color='black'
        )
    
    # 图表装饰
    plt.title(
        f"期货主力合约实时行情\n数据截止时间:{datetime.now().strftime('%Y-%m-%d %H:%M')}",
        fontsize=14,
        pad=20
    )
    plt.xlabel('涨跌幅 (%)', fontsize=12)
    plt.xticks(fontsize=10)
    plt.yticks(fontsize=10)
    plt.grid(axis='x', linestyle='--', alpha=0.6)
    
    # 添加水印
    plt.text(
        0.5, 0.5, '数据来源: Sina Finance',
        fontsize=40, color='gray', alpha=0.2,
        ha='center', va='center', rotation=30,
        transform=plt.gca().transAxes
    )
    
    plt.tight_layout()
    plt.savefig('futures_ranking_pro.png', dpi=300, bbox_inches='tight')
    plt.show()

if __name__ == "__main__":
    # 步骤1:获取最新主力合约
    print("正在获取主力合约列表...")
    main_contracts = get_main_contracts()
    
    if not main_contracts:
        print("无法获取主力合约列表,请检查网络连接")
        exit()
        
    # 步骤2:获取实时数据
    print("\n正在获取实时行情...")
    df = get_realtime_data(main_contracts)
    
    if df.empty:
        print("数据获取失败,建议:")
        print("1. 检查网络连接")
        print("2. 升级AKShare: pip install akshare --upgrade")
        print("3. 等待10分钟后重试")
    else:
        # 步骤3:可视化展示
        print("\n生成可视化图表...")
        visualize_data(df)