本期代码预览
后台回复27代码获得本文参考文献及完整代码。
# 获取所有数据
dataframes = {
"nationwide_blast_furnace_operating_rate_weekly": nationwide_blast_furnace_operating_rate_weekly,
"tangshan_blast_furnace_operating_rate_weekly": tangshan_blast_furnace_operating_rate_weekly,
"China_Capacity_Utilization_Electric_Furnace_weekly": China_Capacity_Utilization_Electric_Furnace_weekly,
"key_enterprises_daily_crude_steel_production_ten_days": key_enterprises_daily_crude_steel_production_weekly,
"nationwide_estimated_daily_crude_steel_production_ten_days": nationwide_estimated_daily_crude_steel_production_ten_days,
"automotive_semi_steel_tire_operating_rate_weekly": automotive_semi_steel_tire_operating_rate_weekly,
"automotive_full_steel_tire_operating_rate_weekly": automotive_full_steel_tire_operating_rate_weekly,
"PTA_factory_industry_chain_load_rate_daily": PTA_factory_industry_chain_load_rate_daily,
"jiangsu_zhejiang_weaving_machine_operating_rate_weekly": jiangsu_zhejiang_weaving_machine_operating_rate_weekly,
"pmi_product_monthly": pmi_product_monthly
}
# 将所有高频数据转换为月度数据
monthly_data = {}
for key, df in dataframes.items():
# 确保索引是DatetimeIndex
if not isinstance(df.index, pd.DatetimeIndex):
# 将索引转换为DatetimeIndex
df.index = pd.to_datetime(df.index)
if "weekly" in key:
monthly_data[key] = df.resample('M').mean()
elif "ten_days" in key:
monthly_data[key] = df.resample('M').mean()
elif "daily" in key:
monthly_data[key] = df.resample('M').mean()
else:
monthly_data[key] = df
# 根据频率进行重采样,并进行填充
if "weekly" in key or "ten_days" in key or "daily" in key:
monthly_data[key] = df.resample('M').mean().ffill().bfill()
else:
monthly_data[key] = df
写在前面
宏观研究中离不开PMI,比如依靠3月份制造业PMI的超预期景气度,铜相关行情起飞,相关投资者获得超额收益。
制造业PMI由五个关键分指数按权重汇总而成,公式如下:PMI=新订单指数x30%+生产指数x25%+从业人员指数x20%+(100-供应商配送时间指数)x15%+主要原材料库存x10%
,其中每项得分来源于主观调研。
所以探索出一种能够高频跟踪并预测PMI的方法显得尤为重要,旨在数据官方披露前(如月中),提前得知PMI值以辅助决策制定。
因此,我们尝试进行了PMI高频数据预测模型的编制,最终结果详见如下,相比于参考文献效果 更好些,以及因子选取更具经济学逻辑。.
编写过程
有了idea,首先做的就是找文献,果然在慧博平台上找到了相关文献,这里我参考的是国君研报《宏观分析手册之一:PMI分析与预测》,后台回复27代码获得本文参考文献,其思路如下:
选取两个一级因子:新订单指数和生产指数,正如上文公式,PMI=新订单指数x30%+生产指数x25%+从业人员指数x20%+(100-供应商配送时间指数)x15%+主要原材料库存x10%
,这两个一级因子可以解释55%。
选取二级因子进行分别拟合:对于新订单指数和生产指数进行高频数据预测,采用基础的OLS模型,采取逐步回归的方式
采用预测的一级因子进行再拟合:采取相同的OLS方法,进行模型重新训练与预测
接下来进行详细介绍。
一、因子选择
广选因子,为捕捉经济活动的细微变化,广泛搜集各类高频经济指标作为潜在预测因子,包括但不限于“唐山钢厂高炉开工率”、“唐山钢厂高炉开工率”“30 大中城市商品房成交面积”等指标;同时注意因子的时效性,一定是至今持续披露的,否则效果好也用不上;最后注意对因子进行缩放,确保计算结果在PMI范围,相关代码如下:
# 新订单高频因子
china_30_city_housing_sales_area_code = "S2707380" # 中国:30大中城市:商品房成交面积(每日)
china_100_city_land_transactions_area_code = "S2726992" # 中国:100大中城市:成交土地占地面积(每周)
china_daily_passenger_car_sales_retail_code = "S6126413" # 中国:日均销量(厂家零售):乘用车(每日)
china_daily_passenger_car_sales_wholesale_code = "S6126411" # 中国:日均销量(厂家批发):乘用车(每日)
futures_settlement_price_coking_coal_code = "S0181379" # 期货结算价(活跃合约):焦煤(每日)
futures_settlement_price_coke_code = "S0181380" # 期货结算价(活跃合约):焦炭(每日)
futures_settlement_price_thermal_coal_code = "S0182141" # 期货结算价(活跃合约):动力煤(每日)
china_rebar_market_price_code = "S0033227" # 中国:市场价:螺纹钢(HRB400,Φ16-25mm)(每日)
china_cement_price_index_code = "S5914515" # 中国:水泥价格指数(每日)
china_concrete_price_index_code = "S5319531" # 中国:混凝土价格指数(每周)
china_export_price_index_cement_concrete_artificial_stone_code = "S5914490" # 中国出口价格指数:HS4:水泥、混凝土或人造石制品(每月)
baltic_dry_index_code = "S0031550" # 波罗的海干散货指数(每日)
china_export_containerized_freight_index_code = "S0000066" # 中国出口集装箱运价指数(每周)
shanghai_export_containerized_freight_index_code = "S0114089" # 上海出口集装箱运价指数(每周)
china_pmi_new_orders_code = "M0017128" # 中国:制造业PMI:新订单(每月)
# 生产高频因子
nationwide_blast_furnace_operating_rate_weekly = get_wind_data(nationwide_blast_furnace_code, start_date, end_date, "Fill=Previous;usedf=True")
tangshan_blast_furnace_operating_rate_weekly = get_wind_data(tangshan_blast_furnace_code, start_date, end_date, "Fill=Previous;usedf=True")
China_Capacity_Utilization_Electric_Furnace_weekly = get_wind_data(China_Capacity_Utilization_Electric_Furnace, start_date, end_date, "Fill=Previous;usedf=True")
key_enterprises_daily_crude_steel_production_weekly = get_wind_data(key_enterprises_crude_steel_code, start_date, end_date, "Fill=Previous;usedf=True")
nationwide_estimated_daily_crude_steel_production_ten_days = get_wind_data(nationwide_crude_steel_code, start_date, end_date, "Fill=Previous;usedf=True")
automotive_semi_steel_tire_operating_rate_weekly = get_wind_data(semi_steel_tire_code, start_date, end_date, "Fill=Previous;usedf=True")
automotive_full_steel_tire_operating_rate_weekly = get_wind_data(full_steel_tire_code, start_date, end_date, "Fill=Previous;usedf=True")
PTA_factory_industry_chain_load_rate_daily = get_wind_data(PTA_factory_load_code, start_date, end_date, "Fill=Previous;usedf=True")
jiangsu_zhejiang_weaving_machine_operating_rate_weekly = get_wind_data(weaving_machine_code, start_date, end_date, "Fill=Previous;usedf=True")
pmi_product_monthly = get_wind_data(pmi_product, start_date, end_date, "Fill=Previous;usedf=True")
import pandas as pd
# 读取 CSV 文件
df = pd.read_csv('pmi_product_new.csv', index_col=0, parse_dates=True)
# 提取 PMI 生产指数
pmi_product_monthly = df['pmi_product_monthly']
# 获取 PMI 生产指数的最小值和最大值
pmi_min = pmi_product_monthly.min()
pmi_max = pmi_product_monthly.max()
# 剔除 PMI 生产指数,其他变量进行范围调整
other_vars = df.drop(columns=['pmi_product_monthly'])
# 定义一个函数,将其他变量按 PMI 的范围进行缩放
def scale_to_pmi_range(series, pmi_min, pmi_max):
series_min = series.min()
series_max = series.max()
scaled_series = (series - series_min) / (series_max - series_min) * (pmi_max - pmi_min) + pmi_min
return scaled_series
# 对其他变量进行范围调整
scaled_other_vars = other_vars.apply(scale_to_pmi_range, args=(pmi_min, pmi_max))
# 合并 PMI 生产指数和调整范围后的其他变量
scaled_df = pd.concat([pmi_product_monthly, scaled_other_vars], axis=1)
# 查看结果
print(scaled_df.head())
# 保存调整范围后的数据
scaled_df.to_csv('pmi_product_standardized.csv')
二、逐步回归
(一)计算VIF
计算VIF,在下面的代码处理中如果大于10予以剔除。
import pandas as pd
import statsmodels.api as sm
from statsmodels.stats.outliers_influence import variance_inflation_factor
def calculate_vif(X):
"""计算方差膨胀因子(VIF)"""
vif = pd.DataFrame()
vif["variables"] = X.columns
vif["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
return vif
(二)逐步回归,保留显著的变量
def stepwise_regression(X, y, p_threshold=0.1):
"""逐步回归,保留显著的变量"""
selected_vars = X.columns.tolist()
while True:
X_temp = X[selected_vars]
model = sm.OLS(y, X_temp).fit()
p_values = model.pvalues.drop('const')
if p_values.max() > p_threshold: # 剔除 p 值大于阈值的变量
excluded_var = p_values.idxmax()
selected_vars.remove(excluded_var)
else:
break
return selected_vars
(三)输出结果及拟合方程
检测并剔除多重共线性严重的变量,并且显示显著的变量,输出拟合结果和拟合方程
def remove_multicollinearity(X, selected_vars, vif_threshold=10):
"""检测并剔除多重共线性严重的变量"""
while True:
X_temp = X[selected_vars]
vif = calculate_vif(X_temp)
max_vif = vif['VIF'].max()
if max_vif > vif_threshold:
excluded_var = vif.loc[vif['VIF'].idxmax(), 'variables']
if excluded_var == 'const': # 不剔除常数项
break
selected_vars.remove(excluded_var)
else:
break
return selected_vars
def display_model_equation(model):
"""显示拟合的模型方程"""
params = model.params
equation = "PMI 生产指数 = "
for param, value in params.items():
if param == 'const':
equation += f"{value:.4f} "
else:
equation += f"{'+' if value >= 0 else '-'} {abs(value):.4f} * {param} "
return equation
# 读取标准化后的 CSV 文件
df = pd.read_csv('pmi_product_standardized.csv', index_col=0, parse_dates=True)
# 提取 PMI 生产指数和其他变量
pmi_product_monthly = df['pmi_product_monthly']
other_vars = df.drop(columns=['pmi_product_monthly'])
# 自变量(高频指标)和因变量(PMI 生产指数)
X = sm.add_constant(other_vars)
y = pmi_product_monthly
# 逐步回归,保留显著的变量
selected_vars = stepwise_regression(X, y)
# 检测并剔除多重共线性严重的变量
selected_vars = remove_multicollinearity(X, selected_vars)
# 最终选择的变量
X_selected = X[selected_vars]
# 最终模型拟合
final_model = sm.OLS(y, X_selected).fit()
print(final_model.summary())
# 输出模型方程
model_equation = display_model_equation(final_model)
print("\n拟合的模型方程:")
print(model_equation)
另一个因子重复相同步骤,最终两个二级因子重复相同步骤,结果如下,展示了较好的预测性,并且后续可以选择更多因子&模型进行优化。
四、代码优点
(一)程序自动抓取数据,无需手工调整
只要任意一个因子数据有更新,即会自动抓取并计算,无需手工调整。
# 定义获取数据的函数
def get_wind_data(codes, begin_time, end_time, options):
data = w.edb(codes, begin_time, end_time, options)
if data.ErrorCode != 0:
print(f"Error in fetching data for {codes}: {data.ErrorCode}")
return None
df = pd.DataFrame(data.Data[0], index=data.Times, columns=[codes] if isinstance(codes, str) else codes)
return df
# 变量代码字典
variable_codes = {
"nationwide_blast_furnace_operating_rate_weekly": "C1925068",
"tangshan_blast_furnace_operating_rate_weekly": "S5711217",
"China_Capacity_Utilization_Electric_Furnace_weekly": "S5715660",
"key_enterprises_daily_crude_steel_production_weekly": "S5704502",
"nationwide_estimated_daily_crude_steel_production_ten_days": "S5708247",
"automotive_semi_steel_tire_operating_rate_weekly": "S6124651",
"automotive_full_steel_tire_operating_rate_weekly": "S6124650",
"PTA_factory_industry_chain_load_rate_daily": "S5446173",
"jiangsu_zhejiang_weaving_machine_operating_rate_weekly": "S5417019"
}
(二)可以任意增删因子
一级因子放在一起了,可以任意增删,后面的模型训练是既定的,省时省力。
# 最新指标和Wind代码
variable_codes = {
"china_30_city_housing_sales_area_daily": "S2707380", # 中国:30大中城市:商品房成交面积(每日)
"china_100_city_land_transactions_area_weekly": "S2726992", # 中国:100大中城市:成交土地占地面积(每周)
"china_daily_passenger_car_sales_retail_daily": "S6126413", # 中国:日均销量(厂家零售):乘用车(每日)
"china_daily_passenger_car_sales_wholesale_daily": "S6126411", # 中国:日均销量(厂家批发):乘用车(每日)
"futures_settlement_price_coking_coal_daily": "S0181379", # 期货结算价(活跃合约):焦煤(每日)
"futures_settlement_price_coke_daily": "S0181380", # 期货结算价(活跃合约):焦炭(每日)
"futures_settlement_price_thermal_coal_daily": "S0182141", # 期货结算价(活跃合约):动力煤(每日)
"china_rebar_market_price_daily": "S0033227", # 中国:市场价:螺纹钢(HRB400,Φ16-25mm)(每日)
"china_cement_price_index_daily": "S5914515", # 中国:水泥价格指数(每日)
"china_concrete_price_index_weekly": "S5319531", # 中国:混凝土价格指数(每周)
"china_export_price_index_cement_concrete_artificial_stone_monthly": "S5914490", # 中国出口价格指数:HS4:水泥、混凝土或人造石制品(每月)
"baltic_dry_index_daily": "S0031550", # 波罗的海干散货指数(每日)
"china_export_containerized_freight_index_weekly": "S0000066", # 中国出口集装箱运价指数(每周)
"shanghai_export_containerized_freight_index_weekly": "S0114089", # 上海出口集装箱运价指数(每周)
"china_pmi_new_orders_monthly": "M0017128" # 中国:制造业PMI:新订单(每月)
}
# 读取 CSV 文件,并根据 end_date 过滤数据
df = pd.read_csv('pmi_product_new1.csv', index_col=0, parse_dates=True)
df = df.loc[start_date:end_date] # 过滤数据,确保只使用 start_date 到 end_date 之间的数据
关注我们
资源获取
后台回复【27代码】即可得到【详细代码及参考文献】。
知识星球
知识星球全面升级,本代码及文献早于普通公众号发布,
近期星球推出了每日价值信息汇总,将最新的一级二级信息进行每日汇总,相关说明如下:
(1)转融通利好名单,今日已得到结果兑现
(2)萝卜快跑拟商业化运营,成功推票百度,上涨8%
(3)成功预测半导体本轮行情
...
<<< 左右滑动见更多 >>>
并且对于暑期和校招生来说,星球内定期发布从数千人群聊中沉淀的一手校招价值信息。
(1)证券今年有无hc,及往年留用比例
(2)证券进度-信采
(3)银行第一批offer
(4)基金拒了是不是会拉黑
...
<<< 左右滑动见更多 >>>
需要的朋友扫码获取或者微店购买(2选1即可)
欢迎点赞与在看,感谢支持!