5. 马科维茨资产组合模型+政策意图AI金融智能体(Qwen-Max)增强方案(理论+Python实战)
目录
- 0. 承前
- 1. AI金融智能体
- 1.1 What is AI金融智能体
- 1.2 Why is AI金融智能体
- 1.3 How to AI金融智能体
- 2. 数据要素&计算流程
- 2.1 参数集设置
- 2.2 数据获取&预处理
- 2.3 收益率计算
- 2.4 因子构建与预期收益率计算
- 2.5 协方差矩阵计算
- 2.6 投资组合优化
- 2.7 持仓筛选
- 2.8 AI金融智能体调仓函数
- 3. 汇总代码
- 4. 反思
- 4.1 不足之处
- 4.2 提升思路
- 5. 启后
0. 承前
本篇博文是对上一篇文章,链接:
4. 马科维茨资产组合模型+Fama-French五因子优化方案(理论+Python实战)
的资产权重进行AI干预。
本文首先使用Fama-French五因子计算出资产组合模型权重,再把权重结合政策信息输入AI模型,目的是:
- 在金融工程中,实现AI功能在金融模型的落地的尝试;
- AI模型对政策信息描述内容,情绪分析等进行分析,实现政策信息对金融模型的主动影响。
本文主要要素:
- 马科维茨资产组合模型;
- Fama-French五因子模型预期收益率;
- AI金融智能体(通义千问:qwen-max),提示词工程;
- 政策信息通过AI转化影响预期收益率。
如果想更加全面清晰地了解金融资产组合模型进化论的体系架构,可参考:
0. 金融资产组合模型进化全图鉴
1. AI金融智能体
1.1 What is AI金融智能体
AI金融智能体是指利用人工智能技术,特别是机器学习、深度学习和自然语言处理等先进技术,来模拟人类分析师的行为,以执行复杂的金融分析任务的软件。本文主要是通过提示词工程,结合政策信息,给予AI一定的范围权限去影响资产组合权重,属于金融工程构建的尝试性实验。
1.2 Why is AI金融智能体
-
自动接入全网,实时搜索并分析海量数据:AI金融智能体能够无缝连接互联网,迅速处理和解析大量的金融市场信息,为用户提供即时的洞察和支持。
-
拥有远超人类的计算能力,揭示潜在的市场盲点:凭借其卓越的计算力,AI智能体可以深入挖掘数据,识别出那些基于常识可能被忽视的市场机会或风险。
-
顺应技术潮流,推动更多AI工具在金融领域的实际应用:随着技术的进步,AI在金融行业的落地已成为必然趋势。金融机构需积极探索和实施更多的AI解决方案,以保持竞争力和服务创新。
1.3 How to AI金融智能体
-
参数集设置:
- ts.set_token:设置Tushare的API访问令牌
- industry:选择目标行业,如"银行"
- end_date:回测结束日期,格式为’YYYYMMDD’
- years:回测年限,默认5年
- risk_free_rate:无风险利率,默认0.03
- top_holdings:投资组合持仓数量,默认10只股票
- index_code:市场指数代码,默认’000300.SH’
- api_key:通义千问API
- character:AI人设提示词工程
- policy_info:政策信息(5条)
-
数据准备:
- 股票行业数据:通过tushare获取指定行业的股票列表
- 历史价格数据:获取指定时间段内的股票日线数据
- 市场指数数据:获取指定时间段内的市场指数数据
- 因子数据:获取市值(Size)和账面市值比(B/M)数据
- 财务数据:获取ROE和资产增长率数据
- 无风险利率:设定无风险利率参数
-
计算流程:
- 数据获取:获取股票、市场指数和因子数据
- 收益率计算:计算月度对数收益率
- 因子构建:构建SMB、HML、RMW和CMA因子
- 因子载荷计算:计算每只股票对五个因子的敏感度
- FF5预期收益:使用五因子模型计算预期收益率
- 组合优化:最大化夏普比率得到最优权重
- 持仓筛选:选取权重最大的N只股票并归一化
- AI函数:结合权重数据、政策信息、提示词工程,对权重实现智能调整
2. 数据要素&计算流程
2.1 参数集设置
设置模型所需的基本参数,包括数据获取、回测区间和优化约束等。
# 参数集
ts.set_token('token')
pro = ts.pro_api()
industry = '银行'
end_date = '20240101'
years = 5 # 数据时长
risk_free_rate = 0.03 # 无风险利率参数
top_holdings = 10 # 持仓数量参数
index_code = '000300.SH' # 市场指数代码参数
api_key='sk-api_key' # 通义千问API# AI人设提示词工程
character = f'''
你是一名专业的金融数据与政策分析师,擅长解读金融市场动态和政策导向,并据此调整资产组合的权重分布,以优化投资策略。你的主要任务是对给定的资产组合进行权重调整,确保:
1. 权重之和精确为1;
2. 每个资产调整后的权重只能在原有基础上增减最多10%;
3. 每个资产调整完毕后,如果权重之和不等于1,则归一化使权重之和精确为1;
4. 数据对应的日期是{end_date},在思考过程中,切勿根据该日期之后的信息进行思考。
5. 输出的数据格式需与输入保持一致,仅提供数据而不做额外解释;当你接收到具体的资产组合及其权重时,请根据最新的金融数据和政策信息对其进行合理调整。
'''# 通过工作流获取的政策信息
policy_info = '''
| 日期 | 政策简述 |
|------|----------|
| 2023-12-29 | 央行发布《关于优化商业银行存款利率监管有关事项的通知》,取消定期存款利率浮动上限,允许银行自主协调存贷款利率 |
| 2023-11-17 | 央行、银保监会联合发布《关于做好当前商业银行房地产贷款投放管理的通知》,优化房地产信贷政策,支持刚性和改善性住房需求 |
| 2023-09-25 | 银保监会发布《关于进一步加强银行业金融机构流动性风险管理的通知》,要求银行加强流动性风险管理,完善风险监测预警机制 |
| 2023-08-31 | 央行、银保监会宣布下调全国首套住房贷款利率下限,各地可自主决定下调幅度,二套房贷款利率政策与首套相同 |
| 2023-07-21 | 十四届全国人大常委会第四次会议表决通过《中华人民共和国金融稳定法》,建立健全金融风险防范化解制度体系 |
'''
2.2 数据获取&预处理
获取股票、市场指数、因子数据和财务数据,并进行必要的数据清洗和格式转换。
def get_industry_stocks(industry):"""获取指定行业的股票列表"""df = pro.stock_basic(fields=["ts_code", "name", "industry"])industry_stocks = df[df["industry"]==industry].copy()industry_stocks.sort_values(by='ts_code', inplace=True)industry_stocks.reset_index(drop=True, inplace=True)return industry_stocks['ts_code'].tolist()def get_data(code_list, end_date, years):"""获取指定行业名称的历史收盘价数据"""ts_code_list = code_listend_date_dt = datetime.strptime(end_date, '%Y%m%d')start_date_dt = end_date_dt - timedelta(days=years*365)start_date = start_date_dt.strftime('%Y%m%d')all_data = []for stock in ts_code_list:df = pro.daily(ts_code=stock, start_date=start_date, end_date=end_date)all_data.append(df)combined_df = pd.concat(all_data).sort_values(by=['ts_code', 'trade_date'])combined_df.reset_index(drop=True, inplace=True)combined_df.rename(columns={'trade_date': 'date'}, inplace=True)return combined_dfdef get_market_data(index_code='000300.SH', start_date=None, end_date=None):"""获取市场指数数据用于计算贝塔"""df_market = pro.index_daily(ts_code=index_code, start_date=start_date, end_date=end_date,fields=['trade_date', 'close'])df_market['date'] = pd.to_datetime(df_market['trade_date'])df_market.set_index('date', inplace=True)df_market = df_market.sort_index()monthly_last_close = df_market['close'].resample('M').last()monthly_log_returns = np.log(monthly_last_close).diff().dropna()return monthly_log_returnsdef get_factor_data(stock_codes, start_date=None, end_date=None):"""获取指定股票的因子数据(市值和PB)"""all_factor_data = []for stock in stock_codes:try:df = pro.daily_basic(ts_code=stock,start_date=start_date,end_date=end_date,fields=['ts_code', 'trade_date', 'total_mv', 'pb'])all_factor_data.append(df)except Exception as e:print(f"获取股票 {stock} 的因子数据失败: {str(e)}")continuefactor_data = pd.concat(all_factor_data, ignore_index=True)factor_data['trade_date'] = pd.to_datetime(factor_data['trade_date'])return factor_datadef get_fina_data(stock_codes, start_date=None, end_date=None):"""获取指定股票的财务指标数据(ROE和资产增长率)"""all_fina_data = []for stock in stock_codes:try:df = pro.fina_indicator(ts_code=stock,start_date=start_date,end_date=end_date,fields=['ts_code', 'end_date', 'roe_dt', 'assets_yoy', 'update_flag'])all_fina_data.append(df)except Exception as e:print(f"获取股票 {stock} 的财务数据失败: {str(e)}")continue# 合并数据fina_data = pd.concat(all_fina_data, ignore_index=True)# 处理update_flag,保留最新数据fina_data = (fina_data.groupby(['ts_code', 'end_date']).agg({'roe_dt': 'first', 'assets_yoy': 'first','update_flag': 'max'}).reset_index())# 将end_date转换为datetimefina_data['end_date'] = pd.to_datetime(fina_data['end_date'])# 创建季度到月度的映射monthly_data = []for _, row in fina_data.iterrows():quarter_end = row['end_date']if quarter_end.month == 3: # Q1months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]elif quarter_end.month == 6: # Q2months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]elif quarter_end.month == 9: # Q3months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]else: # Q4months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]for month in months:monthly_data.append({'ts_code': row['ts_code'],'trade_date': month,'roe_dt': row['roe_dt'],'assets_yoy': row['assets_yoy']})monthly_df = pd.DataFrame(monthly_data)return monthly_df
2.3 收益率计算
计算月度对数收益率,为后续的因子构建和优化计算做准备。
def calculate_monthly_log_returns(df):"""计算每月的对数收益率"""df['date'] = pd.to_datetime(df['date'])monthly_last_close = df.groupby(['ts_code', pd.Grouper(key='date', freq='M')])['close'].last().unstack(level=-1)monthly_log_returns = np.log(monthly_last_close).diff().dropna()return monthly_log_returns.T
2.4 因子构建与预期收益率计算
构建SMB、HML、RMW和CMA因子,并使用五因子模型计算预期收益率。
def calculate_expected_returns(monthly_log_returns):"""使用Fama-French五因子模型计算各股票的预期收益率"""start_date = monthly_log_returns.index.min().strftime('%Y%m%d')end_date = monthly_log_returns.index.max().strftime('%Y%m%d')# 获取财务数据时,将start_date往前推一个季度,以确保有完整的季度数据fina_start_date = (datetime.strptime(start_date, '%Y%m%d') - timedelta(days=90)).strftime('%Y%m%d')# 获取市场收益率market_returns = get_market_data(index_code, start_date, end_date)# 获取股票的市值和PB数据stock_data = get_factor_data(monthly_log_returns.columns.tolist(),start_date,end_date)# 获取财务指标数据,使用提前的start_datefina_data = get_fina_data(monthly_log_returns.columns.tolist(),fina_start_date,end_date)# 确保所有数据的日期对齐aligned_dates = monthly_log_returns.index.intersection(market_returns.index)market_returns = market_returns[aligned_dates]stock_returns = monthly_log_returns.loc[aligned_dates].copy() # 使用copy()避免SettingWithCopyWarningdef calculate_size_factor(date):date_data = stock_data[stock_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_mv = date_data['total_mv'].median()small_returns = stock_returns.loc[date, date_data[date_data['total_mv'] <= median_mv]['ts_code']]big_returns = stock_returns.loc[date, date_data[date_data['total_mv'] > median_mv]['ts_code']]return small_returns.mean() - big_returns.mean()def calculate_value_factor(date):date_data = stock_data[stock_data['trade_date'].dt.to_period('M') == date.to_period('M')]# 创建date_data的副本并计算bm_ratiodate_data = date_data.copy()date_data.loc[:, 'bm_ratio'] = 1 / date_data['pb']median_bm = date_data['bm_ratio'].median()high_returns = stock_returns.loc[date, date_data[date_data['bm_ratio'] > median_bm]['ts_code']]low_returns = stock_returns.loc[date, date_data[date_data['bm_ratio'] <= median_bm]['ts_code']]return high_returns.mean() - low_returns.mean()def calculate_profitability_factor(date):date_data = fina_data[fina_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_roe = date_data['roe_dt'].median()robust_returns = stock_returns.loc[date, date_data[date_data['roe_dt'] > median_roe]['ts_code']]weak_returns = stock_returns.loc[date, date_data[date_data['roe_dt'] <= median_roe]['ts_code']]return robust_returns.mean() - weak_returns.mean()def calculate_investment_factor(date):date_data = fina_data[fina_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_growth = date_data['assets_yoy'].median()conservative_returns = stock_returns.loc[date, date_data[date_data['assets_yoy'] <= median_growth]['ts_code']]aggressive_returns = stock_returns.loc[date, date_data[date_data['assets_yoy'] > median_growth]['ts_code']]return conservative_returns.mean() - aggressive_returns.mean()# 计算每个月的因子收益smb_factor = pd.Series([calculate_size_factor(date) for date in aligned_dates], index=aligned_dates)hml_factor = pd.Series([calculate_value_factor(date) for date in aligned_dates], index=aligned_dates)rmw_factor = pd.Series([calculate_profitability_factor(date) for date in aligned_dates], index=aligned_dates)cma_factor = pd.Series([calculate_investment_factor(date) for date in aligned_dates], index=aligned_dates)# 使用OLS回归计算每个股票的因子载荷factor_loadings = {}for stock in stock_returns.columns:X = sm.add_constant(pd.concat([market_returns - risk_free_rate,smb_factor,hml_factor,rmw_factor,cma_factor], axis=1))y = stock_returns[stock] - risk_free_ratemodel = sm.OLS(y, X).fit()factor_loadings[stock] = model.params[1:]# 计算因子风险溢价market_premium = market_returns.mean() - risk_free_ratesmb_premium = smb_factor.mean()hml_premium = hml_factor.mean()rmw_premium = rmw_factor.mean()cma_premium = cma_factor.mean()# 使用FF5模型计算预期收益率expected_returns = pd.Series({stock: (risk_free_rate + loadings.iloc[0] * market_premium +loadings.iloc[1] * smb_premium + loadings.iloc[2] * hml_premium +loadings.iloc[3] * rmw_premium +loadings.iloc[4] * cma_premium)for stock, loadings in factor_loadings.items()})return expected_returns
2.5 协方差矩阵计算
计算收益率的协方差矩阵,用于评估资产间的相关性和波动性。
def calculate_covariance_matrix(monthly_log_returns):"""计算收益率协方差矩阵"""return monthly_log_returns.cov()
2.6 投资组合优化
通过最大化夏普比率来寻找最优权重配置。
def max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate):"""计算最大夏普比率的投资组合权重"""num_assets = len(mean_returns)args = (mean_returns, cov_matrix, risk_free_rate)constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})bounds = tuple((0, 1) for asset in range(num_assets))result = minimize(negative_sharpe_ratio, num_assets*[1./num_assets], args=args,method='SLSQP', bounds=bounds, constraints=constraints)return result.x
2.7 持仓筛选
选取权重最大的N只股票并重新归一化权重。
def calculate_top_holdings_weights(optimal_weights, monthly_log_returns_columns, top_n):"""计算前N大持仓的权重占比"""result_dict = {asset: weight for asset, weight in zip(monthly_log_returns_columns, optimal_weights)}top_n_holdings = sorted(result_dict.items(), key=lambda item: item[1], reverse=True)[:top_n]top_n_sum = sum(value for _, value in top_n_holdings)updated_result = {key: value / top_n_sum for key, value in top_n_holdings}return updated_result
2.8 AI金融智能体调仓函数
def get_ai_weights(character, policy_info, updated_result, api_key):# 定义发送对话内容messages = [{'role': 'system', 'content': character},{'role': 'user', 'content': policy_info},{'role': 'user', 'content': json.dumps(updated_result, ensure_ascii=False)}]response = dashscope.Generation.call(api_key=api_key,model="qwen-max",messages=messages,result_format='message',enable_search=True,top_p=0.01)# 提取content内容content = response['output']['choices'][0]['message']['content']# 将JSON字符串转换为Python字典portfolio_weights = json.loads(content)# 对AI输出结果进行归一化weights_sum = sum(portfolio_weights.values())portfolio_weights = {key: value/weights_sum for key, value in portfolio_weights.items()}# 将字典中的值修改为6位小数portfolio_weights = {k: round(v, 6) for k, v in portfolio_weights.items()}return portfolio_weights
3. 汇总代码
以下即为全量代码,修改参数集中内容即可跑出个性化数据。
import tushare as ts
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from scipy.optimize import minimize
import backtrader as bt
import statsmodels.api as sm
import os
import json
import dashscope# 参数集##############################################################################
ts.set_token('token')
pro = ts.pro_api()
industry = '银行'
end_date = '20240101'
years = 5 # 数据时长
risk_free_rate = 0.03 # 无风险利率参数
top_holdings = 10 # 持仓数量参数
index_code = '000300.SH' # 市场指数代码参数
api_key='sk-api_key' # 通义千问API# AI人设提示词工程
character = f'''
你是一名专业的金融数据与政策分析师,擅长解读金融市场动态和政策导向,并据此调整资产组合的权重分布,以优化投资策略。你的主要任务是对给定的资产组合进行权重调整,确保:
1. 权重之和精确为1;
2. 每个资产调整后的权重只能在原有基础上增减最多10%;
3. 每个资产调整完毕后,如果权重之和不等于1,则归一化使权重之和精确为1;
4. 数据对应的日期是{end_date},在思考过程中,切勿根据该日期之后的信息进行思考。
5. 输出的数据格式需与输入保持一致,仅提供数据而不做额外解释;当你接收到具体的资产组合及其权重时,请根据最新的金融数据和政策信息对其进行合理调整。
'''# 通过工作流获取的政策信息
policy_info = '''
| 日期 | 政策简述 |
|------|----------|
| 2023-12-29 | 央行发布《关于优化商业银行存款利率监管有关事项的通知》,取消定期存款利率浮动上限,允许银行自主协调存贷款利率 |
| 2023-11-17 | 央行、银保监会联合发布《关于做好当前商业银行房地产贷款投放管理的通知》,优化房地产信贷政策,支持刚性和改善性住房需求 |
| 2023-09-25 | 银保监会发布《关于进一步加强银行业金融机构流动性风险管理的通知》,要求银行加强流动性风险管理,完善风险监测预警机制 |
| 2023-08-31 | 央行、银保监会宣布下调全国首套住房贷款利率下限,各地可自主决定下调幅度,二套房贷款利率政策与首套相同 |
| 2023-07-21 | 十四届全国人大常委会第四次会议表决通过《中华人民共和国金融稳定法》,建立健全金融风险防范化解制度体系 |
'''
# 参数集##############################################################################def get_industry_stocks(industry):"""获取指定行业的股票列表"""df = pro.stock_basic(fields=["ts_code", "name", "industry"])industry_stocks = df[df["industry"]==industry].copy()industry_stocks.sort_values(by='ts_code', inplace=True)industry_stocks.reset_index(drop=True, inplace=True)return industry_stocks['ts_code'].tolist()def get_data(code_list, end_date, years):"""获取指定行业名称的历史收盘价数据"""ts_code_list = code_listend_date_dt = datetime.strptime(end_date, '%Y%m%d')start_date_dt = end_date_dt - timedelta(days=years*365)start_date = start_date_dt.strftime('%Y%m%d')all_data = []for stock in ts_code_list:df = pro.daily(ts_code=stock, start_date=start_date, end_date=end_date)all_data.append(df)combined_df = pd.concat(all_data).sort_values(by=['ts_code', 'trade_date'])combined_df.reset_index(drop=True, inplace=True)combined_df.rename(columns={'trade_date': 'date'}, inplace=True)return combined_dfdef get_market_data(index_code='000300.SH', start_date=None, end_date=None):"""获取市场指数数据用于计算贝塔"""df_market = pro.index_daily(ts_code=index_code, start_date=start_date, end_date=end_date,fields=['trade_date', 'close'])df_market['date'] = pd.to_datetime(df_market['trade_date'])df_market.set_index('date', inplace=True)df_market = df_market.sort_index()monthly_last_close = df_market['close'].resample('M').last()monthly_log_returns = np.log(monthly_last_close).diff().dropna()return monthly_log_returnsdef get_factor_data(stock_codes, start_date=None, end_date=None):"""获取指定股票的因子数据(市值和PB)"""all_factor_data = []for stock in stock_codes:try:df = pro.daily_basic(ts_code=stock,start_date=start_date,end_date=end_date,fields=['ts_code', 'trade_date', 'total_mv', 'pb'])all_factor_data.append(df)except Exception as e:print(f"获取股票 {stock} 的因子数据失败: {str(e)}")continuefactor_data = pd.concat(all_factor_data, ignore_index=True)factor_data['trade_date'] = pd.to_datetime(factor_data['trade_date'])return factor_datadef get_fina_data(stock_codes, start_date=None, end_date=None):"""获取指定股票的财务指标数据(ROE和资产增长率)"""all_fina_data = []for stock in stock_codes:try:df = pro.fina_indicator(ts_code=stock,start_date=start_date,end_date=end_date,fields=['ts_code', 'end_date', 'roe_dt', 'assets_yoy', 'update_flag'])all_fina_data.append(df)except Exception as e:print(f"获取股票 {stock} 的财务数据失败: {str(e)}")continue# 合并数据fina_data = pd.concat(all_fina_data, ignore_index=True)# 处理update_flag,保留最新数据fina_data = (fina_data.groupby(['ts_code', 'end_date']).agg({'roe_dt': 'first', 'assets_yoy': 'first','update_flag': 'max'}).reset_index())# 将end_date转换为datetimefina_data['end_date'] = pd.to_datetime(fina_data['end_date'])# 创建季度到月度的映射monthly_data = []for _, row in fina_data.iterrows():quarter_end = row['end_date']if quarter_end.month == 3: # Q1months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]elif quarter_end.month == 6: # Q2months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]elif quarter_end.month == 9: # Q3months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]else: # Q4months = [quarter_end + pd.DateOffset(months=i) for i in range(1, 4)]for month in months:monthly_data.append({'ts_code': row['ts_code'],'trade_date': month,'roe_dt': row['roe_dt'],'assets_yoy': row['assets_yoy']})monthly_df = pd.DataFrame(monthly_data)return monthly_dfdef calculate_monthly_log_returns(df):"""计算每月的对数收益率"""df['date'] = pd.to_datetime(df['date'])monthly_last_close = df.groupby(['ts_code', pd.Grouper(key='date', freq='M')])['close'].last().unstack(level=-1)monthly_log_returns = np.log(monthly_last_close).diff().dropna()return monthly_log_returns.Tdef calculate_expected_returns(monthly_log_returns):"""使用Fama-French五因子模型计算各股票的预期收益率"""start_date = monthly_log_returns.index.min().strftime('%Y%m%d')end_date = monthly_log_returns.index.max().strftime('%Y%m%d')# 获取财务数据时,将start_date往前推一个季度,以确保有完整的季度数据fina_start_date = (datetime.strptime(start_date, '%Y%m%d') - timedelta(days=90)).strftime('%Y%m%d')# 获取市场收益率market_returns = get_market_data(index_code, start_date, end_date)# 获取股票的市值和PB数据stock_data = get_factor_data(monthly_log_returns.columns.tolist(),start_date,end_date)# 获取财务指标数据,使用提前的start_datefina_data = get_fina_data(monthly_log_returns.columns.tolist(),fina_start_date,end_date)# 确保所有数据的日期对齐aligned_dates = monthly_log_returns.index.intersection(market_returns.index)market_returns = market_returns[aligned_dates]stock_returns = monthly_log_returns.loc[aligned_dates].copy() # 使用copy()避免SettingWithCopyWarningdef calculate_size_factor(date):date_data = stock_data[stock_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_mv = date_data['total_mv'].median()small_returns = stock_returns.loc[date, date_data[date_data['total_mv'] <= median_mv]['ts_code']]big_returns = stock_returns.loc[date, date_data[date_data['total_mv'] > median_mv]['ts_code']]return small_returns.mean() - big_returns.mean()def calculate_value_factor(date):date_data = stock_data[stock_data['trade_date'].dt.to_period('M') == date.to_period('M')]# 创建date_data的副本并计算bm_ratiodate_data = date_data.copy()date_data.loc[:, 'bm_ratio'] = 1 / date_data['pb']median_bm = date_data['bm_ratio'].median()high_returns = stock_returns.loc[date, date_data[date_data['bm_ratio'] > median_bm]['ts_code']]low_returns = stock_returns.loc[date, date_data[date_data['bm_ratio'] <= median_bm]['ts_code']]return high_returns.mean() - low_returns.mean()def calculate_profitability_factor(date):date_data = fina_data[fina_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_roe = date_data['roe_dt'].median()robust_returns = stock_returns.loc[date, date_data[date_data['roe_dt'] > median_roe]['ts_code']]weak_returns = stock_returns.loc[date, date_data[date_data['roe_dt'] <= median_roe]['ts_code']]return robust_returns.mean() - weak_returns.mean()def calculate_investment_factor(date):date_data = fina_data[fina_data['trade_date'].dt.to_period('M') == date.to_period('M')]median_growth = date_data['assets_yoy'].median()conservative_returns = stock_returns.loc[date, date_data[date_data['assets_yoy'] <= median_growth]['ts_code']]aggressive_returns = stock_returns.loc[date, date_data[date_data['assets_yoy'] > median_growth]['ts_code']]return conservative_returns.mean() - aggressive_returns.mean()# 计算每个月的因子收益smb_factor = pd.Series([calculate_size_factor(date) for date in aligned_dates], index=aligned_dates)hml_factor = pd.Series([calculate_value_factor(date) for date in aligned_dates], index=aligned_dates)rmw_factor = pd.Series([calculate_profitability_factor(date) for date in aligned_dates], index=aligned_dates)cma_factor = pd.Series([calculate_investment_factor(date) for date in aligned_dates], index=aligned_dates)# 使用OLS回归计算每个股票的因子载荷factor_loadings = {}for stock in stock_returns.columns:X = sm.add_constant(pd.concat([market_returns - risk_free_rate,smb_factor,hml_factor,rmw_factor,cma_factor], axis=1))y = stock_returns[stock] - risk_free_ratemodel = sm.OLS(y, X).fit()factor_loadings[stock] = model.params[1:]# 计算因子风险溢价market_premium = market_returns.mean() - risk_free_ratesmb_premium = smb_factor.mean()hml_premium = hml_factor.mean()rmw_premium = rmw_factor.mean()cma_premium = cma_factor.mean()# 使用FF5模型计算预期收益率expected_returns = pd.Series({stock: (risk_free_rate + loadings.iloc[0] * market_premium +loadings.iloc[1] * smb_premium + loadings.iloc[2] * hml_premium +loadings.iloc[3] * rmw_premium +loadings.iloc[4] * cma_premium)for stock, loadings in factor_loadings.items()})return expected_returnsdef calculate_covariance_matrix(monthly_log_returns):"""计算收益率协方差矩阵"""return monthly_log_returns.cov()def portfolio_performance(weights, mean_returns, cov_matrix):"""计算投资组合的表现"""returns = np.sum(mean_returns * weights) std_dev = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))return returns, std_devdef negative_sharpe_ratio(weights, mean_returns, cov_matrix, risk_free_rate):"""计算负夏普比率"""p_ret, p_std = portfolio_performance(weights, mean_returns, cov_matrix)sharpe_ratio = (p_ret - risk_free_rate) / p_stdreturn -sharpe_ratiodef max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate):"""计算最大夏普比率的投资组合权重"""num_assets = len(mean_returns)args = (mean_returns, cov_matrix, risk_free_rate)constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})bounds = tuple((0, 1) for asset in range(num_assets))result = minimize(negative_sharpe_ratio, num_assets*[1./num_assets], args=args,method='SLSQP', bounds=bounds, constraints=constraints)return result.xdef calculate_top_holdings_weights(optimal_weights, monthly_log_returns_columns, top_n):"""计算前N大持仓的权重占比"""result_dict = {asset: weight for asset, weight in zip(monthly_log_returns_columns, optimal_weights)}top_n_holdings = sorted(result_dict.items(), key=lambda item: item[1], reverse=True)[:top_n]top_n_sum = sum(value for _, value in top_n_holdings)updated_result = {key: value / top_n_sum for key, value in top_n_holdings}return updated_resultdef get_ai_weights(character, policy_info, updated_result, api_key):# 定义发送对话内容messages = [{'role': 'system', 'content': character},{'role': 'user', 'content': policy_info},{'role': 'user', 'content': json.dumps(updated_result, ensure_ascii=False)}]response = dashscope.Generation.call(api_key=api_key,model="qwen-max",messages=messages,result_format='message',enable_search=True,top_p=0.01)# 提取content内容content = response['output']['choices'][0]['message']['content']# 将JSON字符串转换为Python字典portfolio_weights = json.loads(content)# 对AI输出结果进行归一化weights_sum = sum(portfolio_weights.values())portfolio_weights = {key: value/weights_sum for key, value in portfolio_weights.items()}# 将字典中的值修改为6位小数portfolio_weights = {k: round(v, 6) for k, v in portfolio_weights.items()}return portfolio_weightsdef main():# 获取数据code_list = get_industry_stocks(industry)df = get_data(code_list, end_date, years)# 计算每月的对数收益率monthly_log_returns = calculate_monthly_log_returns(df)# 使用FF5模型计算预期收益率mean_returns = calculate_expected_returns(monthly_log_returns)# 计算收益率协方差矩阵cov_matrix = calculate_covariance_matrix(monthly_log_returns)# 优化权重optimal_weights = max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate)# 计算前N大持仓权重updated_result = calculate_top_holdings_weights(optimal_weights, monthly_log_returns.columns, top_holdings)# 计算AI调仓后的持仓权重updated_result = get_ai_weights(character, policy_info, updated_result, api_key)# 打印更新后的资产占比print(f"\n{end_date}最优资产前{top_holdings}占比:")print(updated_result)if __name__ == "__main__":main()
运行结果:
AI金融智能体调仓前权重:
股票代码 | 占比 |
---|---|
601398.SH | 0.16318772568631026 |
601328.SH | 0.16177476392789242 |
600919.SH | 0.12936894301756055 |
600036.SH | 0.10747174637443846 |
601169.SH | 0.0958427702817229 |
600016.SH | 0.09012906474680284 |
601166.SH | 0.08768928377548085 |
601288.SH | 0.06538512327994642 |
600908.SH | 0.05559150377594274 |
600926.SH | 0.043559075133902475 |
AI金融智能体调仓后权重:
{'601398.SH': 0.163025, '601328.SH': 0.161623, '600919.SH': 0.129252, '600036.SH': 0.107372, '601169.SH': 0.095764,
'600016.SH': 0.090046, '601166.SH': 0.087606, '601288.SH': 0.065323, '600908.SH': 0.055541, '600926.SH': 0.044449}
股票代码 | 占比 |
---|---|
601398.SH | 0.163025 |
601328.SH | 0.161623 |
600919.SH | 0.129252 |
600036.SH | 0.107372 |
601169.SH | 0.095764 |
600016.SH | 0.090046 |
601166.SH | 0.087606 |
601288.SH | 0.065323 |
600908.SH | 0.055541 |
600926.SH | 0.044449 |
可见,AI金融智能体通过对政策信息的了解,加大对银行业投资的信心,特别是对大型国有银行和部分地方性银行。这种调整反映了AI对于市场动态的理解以及对未来收益预期的优化。
我们后验的经验也证明:在2024年银行行业是一个值得投资的行业,如果在20240101投资银行行业,将会获得不俗的收益。
4. 反思
4.1 不足之处
- 政策信息获取:获取政策信息方案仍为半手动
- AI逻辑缜密度:AI可能未能完全按照提示词工程执行
4.2 提升思路
- 更换AI智能体:使用由幻方量化开发的DeepSeek-V3 模型
- 工作流接入金融工程内部,实现真正全自动
5. 启后
-
优化,下一篇文章将会尝试使用由幻方量化开发的DeepSeek_V3模型:,可参考下一篇文章:
6. 马科维茨资产组合模型+政策意图AI金融智能体(DeepSeek-V3)增强方案(理论+Python实战) -
量化回测实现,可参考下一篇文章:
pass
相关文章:

5. 马科维茨资产组合模型+政策意图AI金融智能体(Qwen-Max)增强方案(理论+Python实战)
目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…...

Centos类型服务器等保测评整/etc/pam.d/system-auth
修改服务器配置文件/etc/pam.d/system-auth,但是,把一下配置放在password的配置第一行才会生效 执行命令:配置口令要求:大小写字母、数字、特殊字符组合、至少8位,包括强制设置root口令! sed -i 14a pas…...

从工厂到桌面:3D打印制造潮玩手办
传统潮玩手办的制造过程复杂且成本高昂。从设计到成品,需要经过多道工序,包括手工建模、模具制作、注塑成型等。这一过程不仅耗时耗力,而且难以满足消费者日益增长的个性化需求。此外,传统制造方式对于小批量生产或定制化产品的经…...

Java高频面试之SE-16
hello啊,各位观众姥爷们!!!本牛马baby今天又来了!哈哈哈哈哈嗝🐶 Java中异常的处理方式有哪些? 在 Java 中,异常的处理方式主要有以下几种: 1. 使用 try-catch 语句 …...

三分钟简单了解一些HTML的标签和语法_01
1.图片建议建立一个文件夹如下图所示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"keywords"><title>魔神羽落</title><style>.testone{background-color: #ff53e…...
缓存-Redis-数据结构-redis哪些数据结构是跳表实现的?
在 Redis 中,跳表(Skip List) 被用于实现 有序集合(Sorted Set) 数据结构。以下是对此实现的详细解释: Redis中的有序集合(Sorted Set) 有序集合(Sorted Set࿰…...
Linux 系统错误处理简介
Linux 系统错误处理简介 1. errno:错误代码的载体2. strerror():错误信息的翻译官3. perror():便捷的错误信息输出4. 系统调用与库函数的区别5. 错误处理的最佳实践 在 C/C 程序开发中,我们经常需要处理各种错误情况 Linux 系统提…...
逐笔成交逐笔委托Level2高频数据下载和分析:20250122
逐笔委托逐笔成交下载 链接: https://pan.baidu.com/s/1WP6eGLip3gAbt7yFKg4XqA?pwd7qtx 提取码: 7qtx Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交和逐笔委托这种每一笔的毫秒级别的数据可以分析出很多有用的点,包括主力意图,虚假动作&…...

第18个项目:微信开发入门:获取access_token的Python源码
源码下载地址:https://download.csdn.net/download/mosquito_lover1/90301829 功能特点: 输入AppID和AppSecret,点击按钮后异步获取access_token 1、自动保存功能: 当用户输入或修改 AppID 和 AppSecret 时自动保存 获取到新的 access_token 时自动保存 所有数据都保存在…...

如何将自己本地项目开源到github上?
环境: LLMB项目 问题描述: 如何将自己本地项目开源到github上? 解决方案: 步骤 1: 准备本地项目 确保项目整洁 确认所有的文件都在合适的位置,并且项目的 README.md 文件已经完善。检查是否有敏感信息࿰…...

Windows远程连接Docker服务
问题背景 本地开发了一个SpringBoot项目,想通过Docker部署起来,我本地是Window11系统,由于某些原因不能虚拟化并且未安装Docker-Desktop,所以我在想有没有办法本地不需要虚拟化也不需要安装Docker-Desktop来实现支持Docker命令远…...

在Qt中实现点击一个界面上的按钮弹窗到另一个界面
文章目录 步骤 1:创建新窗口类步骤 2:设计窗口的 UI步骤 3:设计响应函数 以下是一个完整的示例,展示在Qt中如何实现在一个窗口中通过点击按钮弹出一个新窗口。 步骤 1:创建新窗口类 假设你要创建一个名为 WelcomeWidg…...

嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础
嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础 目录 1.NAND FLASH 和NOR FLASH异同 ? 2.CPU,MPU,MCU,SOC,SOPC联系与差别? 3.什么是交叉编译? 4.为什么要交叉编译? 5.描述一下嵌入式基于ROM的运行方式和基于RAM的运行方式有什么区别? 1…...

全氟醚橡胶发展前景:高性能密封材料的璀璨之星
在当今科技飞速发展的时代,各类高性能材料不断涌现,全氟醚橡胶便是其中一颗闪耀的明珠。它以其卓越的性能和广泛的应用领域,在众多关键行业中发挥着不可或缺的作用,展现出巨大的市场潜力和发展前景。 一、引言 全氟醚橡胶&#…...

Android程序中使用FFmpeg库
目录 前言 一、环境 二、创建APP 三. 添加FFmpeg库文件到app中 1. 复制ffmpeg头文件和so库到app中 2. 修改CMakeLists.txt文件内容. 3. 修改ffmpeglib.cpp 文件内容 4. 修改NativeLib.kt 文件添加方法和加载库 5. 调用 四. 增加解析视频文件信息功能 总结 前言 前面…...
Spring 依赖注入详解:创建 Bean 和注入依赖是一回事吗?
1. 什么是依赖注入(Dependency Injection,DI)? 依赖注入 是 Spring IoC(控制反转)容器的核心功能。它的目标是将对象的依赖(如其他对象或配置)从对象本身中剥离,由容器负…...

【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题
本篇博客给大家带来的是01背包问题之动态规划解法技巧. 🐎文章专栏: 动态规划 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺便…...

浅说树上差分——点差分
我们前面也学过差分,现在的话我们就把他放到树上来做。因为这是树,所以会有点和边之分,所以树上差分也会分为 点差分 和 边差分 。 引入 树上差分其实和线性差分没有什么区别,只不过是放到了树上的两点,而他们之间的…...

All in大模型!智能座舱语音交互决胜2025
大模型加速上车,AI智能座舱竞争更显白热化。 诚然,在语言大模型为核心的多模态能力加持下,智能语音助理能够理解复杂的语言指令,实现知识问答、文本生成等,以及根据上下文进行逻辑推理,提供更智能、准确的…...

windows git bash 使用zsh 并集成 oh my zsh
参考了 这篇文章 进行配置,记录了自己的踩坑过程,并增加了 zsh-autosuggestions 插件的集成。 主要步骤: 1. git bash 这个就不说了,自己去网上下,windows 使用git时候 命令行基本都有它。 主要也是用它不方便&…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...