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__":
print("正在获取主力合约列表...")
main_contracts = get_main_contracts()
if not main_contracts:
print("无法获取主力合约列表,请检查网络连接")
exit()
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:
print("\n生成可视化图表...")
visualize_data(df)