Python:将列表形式的股票模拟数据转为多列或多重索引DataFrame
股票价格模拟与期权指标的DataFrame高效存储方案
问题现状
原代码生成的DataFrame将二维数组(股票路径、Delta值)直接存入单个单元格,无法直接进行后续数据分析、计算操作,需调整存储结构以适配业务需求。
解决方案实现
先补全缺失的股票路径生成函数(几何布朗运动实现),确保代码可运行:
import numpy as np import pandas as pd from scipy import stats from math import exp def simpath(S0, sigma, ttm, numSteps, numPaths): dt = ttm / numSteps paths = np.zeros((numSteps, numPaths)) paths[0] = S0 for t in range(1, numSteps): paths[t] = paths[t-1] * np.exp((r - 0.5 * sigma**2)*dt + sigma*np.sqrt(dt)*np.random.normal(0,1,numPaths)) return paths # 修正原期权定价与Delta计算函数的参数一致性问题 def bscall_val(S0, strike, sigma, ttm, rf): d1 = (np.log(S0/strike) + 0.5 * np.power(sigma, 2) * ttm )/(sigma * np.power(ttm, 0.5)) d2 = d1 - sigma * np.power(ttm, 0.5) bs_call = S0 * stats.norm.cdf(d1, 0, 1) - strike * exp(-rf * ttm) * stats.norm.cdf(d2, 0, 1) return bs_call def bscall_delta(S0, strike, sigma, ttm, rf): d1 = (np.log(S0/strike) + 0.5 * np.power(sigma, 2) * ttm )/(sigma * np.power(ttm, 0.5)) bscall_delta = stats.norm.cdf(d1, 0, 1) return bscall_delta
方案1:将变量分别转为DataFrame后合并
先把股票路径和Delta各自转为带行列索引的DataFrame,再通过标识列合并,形成规整的长表格式。
def sim_results(strike, sigma, ttm, r, numSteps, numPaths, quantity): # 生成股票路径 path = simpath(S0, sigma, ttm, numSteps, numPaths) # 计算每一步的剩余期限,确保Delta计算的时间参数准确 remaining_ttm = ttm - np.arange(numSteps)*(ttm/numSteps) # 计算每个时点每个路径的Delta delta = bscall_delta(path, strike, sigma, remaining_ttm[:, np.newaxis], r) # 路径转DataFrame并规整格式 path_df = pd.DataFrame(path, columns=[f"path_{i}" for i in range(numPaths)]) path_df["step"] = path_df.index path_df = path_df.melt(id_vars="step", var_name="indicator", value_name="value") # Delta转DataFrame并规整格式 delta_df = pd.DataFrame(delta, columns=[f"delta_{i}" for i in range(numPaths)]) delta_df["step"] = delta_df.index delta_df = delta_df.melt(id_vars="step", var_name="indicator", value_name="value") # 合并两个DataFrame combined_df = pd.concat([path_df, delta_df], ignore_index=True) return combined_df
说明:长表格式适合后续分组统计、可视化操作,可快速筛选指定指标或步数的数据。
方案2:拆分为动态列(列数随路径数变化)
直接将每个路径的股票价格和Delta作为单独列,步数作为行索引,结构直观,适合快速查看单步数据。
def sim_results(strike, sigma, ttm, r, numSteps, numPaths, quantity): path = simpath(S0, sigma, ttm, numSteps, numPaths) remaining_ttm = ttm - np.arange(numSteps)*(ttm/numSteps) delta = bscall_delta(path, strike, sigma, remaining_ttm[:, np.newaxis], r) # 生成动态列名 path_cols = [f"path_{i}" for i in range(numPaths)] delta_cols = [f"delta_{i}" for i in range(numPaths)] # 合并路径与Delta数据 result_df = pd.DataFrame(path, columns=path_cols) result_df[delta_cols] = delta result_df.index.name = "step" return result_df
说明:宽表格式可直接查看某一步所有路径的价格与Delta值,列数随numPaths自动调整,操作简单高效。
方案3:多重索引(MultiIndex)存储
使用三层索引(步数、路径编号、指标类型),是最结构化的存储方式,适配复杂多维数据分析需求。
def sim_results(strike, sigma, ttm, r, numSteps, numPaths, quantity): path = simpath(S0, sigma, ttm, numSteps, numPaths) remaining_ttm = ttm - np.arange(numSteps)*(ttm/numSteps) delta = bscall_delta(path, strike, sigma, remaining_ttm[:, np.newaxis], r) # 创建多层索引 index = pd.MultiIndex.from_product( [range(numSteps), range(numPaths), ["path", "delta"]], names=["step", "path_id", "indicator"] ) # 扁平化数据并生成DataFrame data = np.concatenate([path.flatten(), delta.flatten()]) result_df = pd.DataFrame(data, index=index, columns=["value"]) return result_df
说明:可通过索引快速筛选指定数据,例如result_df.loc[(5, 1, "delta")]可直接获取第5步第2个路径的Delta值,适合精细化分析场景。
内容的提问来源于stack exchange,提问作者user3654852
相关产品推荐
相关产品推荐

