# -*- coding: utf-8 -*-
"""
获取某只股票的数据绘制K线图、计算日收益率、绘制收益率直方图、计算VaR
并绘制VaR图
Created on Sun Sep 15 13:15:50 2024
@author: 24384
"""
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import akshare as ak
import numpy as np
import pandas as pd
import mplfinance as mpf # 需先 pip install mplfinance
import seaborn as sns
import time
from requests.exceptions import ConnectionError, Timeout, TooManyRedirects
# # 列出系统所有可用字体
# fonts = fm.findSystemFonts()
# font_names = [fm.FontProperties(fname=font).get_name() for font in fonts]
# print("系统可用字体:")
# for font_name in font_names:
# print(font_name)
# 手动选择一个支持中文的字体
font_name = 'Microsoft YaHei' # 根据输出结果修改
try:
plt.rcParams['font.family'] = font_name
plt.rcParams['axes.unicode_minus'] = False # 负号正常显示
print(f"成功使用字体: {font_name}")
except Exception as e:
print(f"加载字体时发生错误: {e},使用默认字体。")
def get_stock_data(stock_code, start_date, end_date, max_retries=3, retry_delay=5):
"""获取股票数据,添加重试机制和错误处理"""
for attempt in range(max_retries):
try:
print(f"尝试获取 {stock_code} 的数据,尝试次数: {attempt + 1}/{max_retries}")
stock_df = ak.stock_zh_a_hist_tx(
symbol=stock_code,
start_date=start_date,
end_date=end_date,
adjust=""
)
if stock_df is None or stock_df.empty:
print(f"警告:获取到的 {stock_code} 数据为空")
return None
if 'date' in stock_df.columns:
stock_df = stock_df.set_index('date')
stock_df.index = pd.to_datetime(stock_df.index)
else:
print(f"错误:未找到日期列。可用列名: {stock_df.columns.tolist()}")
return None
return stock_df['close']
except (ConnectionError, Timeout, TooManyRedirects) as e:
print(f"网络连接错误: {e}")
if attempt < max_retries - 1:
print(f"将在 {retry_delay} 秒后重试...")
time.sleep(retry_delay)
else:
print("达到最大重试次数,获取数据失败")
return None
except Exception as e:
print(f"发生未知错误: {e}")
return None
def plot_kline(stock_code, start_date, end_date):
try:
stock_df = ak.stock_zh_a_hist_tx(
symbol=stock_code,
start_date=start_date,
end_date=end_date,
adjust=""
)
if stock_df is None or stock_df.empty:
print("K线数据为空,无法绘制K线图")
return
stock_df = stock_df.rename(columns={'date': 'Date', 'open': 'Open', 'high': 'High', 'low': 'Low', 'close': 'Close', 'amount': 'Volume'})
stock_df['Date'] = pd.to_datetime(stock_df['Date'])
stock_df.set_index('Date', inplace=True)
title = f'{stock_code} K线图'
mpf.plot(stock_df[['Open', 'High', 'Low', 'Close', 'Volume']], type='candle', volume=True, style='yahoo', title=title)
except RequestException as e:
print(f"获取数据时发生网络请求错误: {e}")
except Exception as e:
print(f"绘制K线图时发生错误: {e}")
def monte_carlo_simulations(close_prices, num_simulations=10000, days=1):
"""返回蒙特卡洛模拟的所有收益率数组"""
returns = close_prices.pct_change().dropna()
mean_return = returns.mean()
std_return = returns.std()
simulations = np.zeros(num_simulations)
for i in range(num_simulations):
daily_returns = np.random.normal(mean_return, std_return, days)
final_return = np.prod(1 + daily_returns) - 1
simulations[i] = final_return
return simulations
def monte_carlo_var(simulations, confidence_level=0.95):
"""根据模拟结果计算VaR"""
var = np.percentile(simulations, 100 * (1 - confidence_level))
return var
def plot_var_results(simulations, var_value, confidence_level=0.95, days=1):
"""绘制蒙特卡洛模拟收益率分布和VaR"""
plt.figure(figsize=(10, 6))
sns.histplot(simulations, bins=30, kde=True, stat="density", color='skyblue')
plt.axvline(x=var_value, color='red', linestyle='--',
label=f"{int(confidence_level*100)}% VaR: {var_value:.2%}")
plt.title(f"蒙特卡洛模拟股票收益率分布与VaR({days}天)")
plt.xlabel("收益率")
plt.ylabel("密度")
plt.legend()
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
def plot_price_history(stock_prices):
plt.figure(figsize=(10, 4))
sns.lineplot(data=stock_prices)
plt.title("历史股票价格走势")
plt.xlabel("日期")
plt.ylabel("价格")
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
# 参数设置
stock_code = 'sh600938' # 中国海油
start_date = '20240101'
end_date = '20250521'
num_simulations = 10000
days = 10
confidence_level = 0.95
# 获取股票数据
close_prices = get_stock_data(stock_code, start_date, end_date)
if close_prices is None:
print("无法获取股票数据,程序退出")
exit()
# 绘制历史价格
plot_price_history(close_prices)
# 蒙特卡洛模拟
simulations = monte_carlo_simulations(close_prices, num_simulations, days)
var = monte_carlo_var(simulations, confidence_level)
print(f"单只股票 {stock_code} 在 {confidence_level * 100:.0f}% 置信水平下,{days} 天的 VaR 为: {var:.2%}")
# 绘制模拟结果与VaR
plot_var_results(simulations, var, confidence_level, days)
# 绘制K线图
plot_kline(stock_code, start_date, end_date)