gpt4 book ai didi

Python:如何优化函数参数?

转载 作者:太空狗 更新时间:2023-10-30 01:31:46 24 4
gpt4 key购买 nike

背景:
我想解决各种优化问题,例如投资组合中的 Assets 权重和交易策略中的参数 其中变量被传递给包含一堆其他变量的函数 .
到目前为止,我已经能够使用 Solver Add-In 在 Excel 中轻松完成这些事情。但我认为使用 Python 会更高效,更广泛地适用。为了清楚起见,我将把问题归结为投资组合优化的本质。
我的问题(简短版):
这是一个数据框和一个带有 Assets 返回的相应图。
数据框 1:

                A1      A2
2017-01-01 0.0075 0.0096
2017-01-02 -0.0075 -0.0033
.
.
2017-01-10 0.0027 0.0035
图 1 - Assets 返回
enter image description here
基于此,我想找到关于 risk / return (Sharpe ratio) 的最佳投资组合的权重。 ,由下图中的绿点表示(红点是所谓的最小方差投资组合,代表另一个优化问题)。
图 2 - 有效边界和最优投资组合:
enter image description here
我怎样才能用 numpy 或 scipy 做到这一点?
详情:
以下代码部分包含函数 returns()为两个 Assets 构建一个具有随机返回的数据框,以及一个函数 pf_sharpe计算 yield 组合的两个给定权重的夏普比率。
# imports
import pandas as pd
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt

np.random.seed(1234)

# Reproducible data sample
def returns(rows, names):
''' Function to create data sample with random returns

Parameters
==========
rows : number of rows in the dataframe
names: list of names to represent assets

Example
=======

>>> returns(rows = 2, names = ['A', 'B'])

A B
2017-01-01 0.0027 0.0075
2017-01-02 -0.0050 -0.0024
'''
listVars= names
rng = pd.date_range('1/1/2017', periods=rows, freq='D')
df_temp = pd.DataFrame(np.random.randint(-100,100,size=(rows, len(listVars))), columns=listVars)
df_temp = df_temp.set_index(rng)
df_temp = df_temp / 10000

return df_temp


# Sharpe ratio
def pf_sharpe(df, w1, w2):
''' Function to calculate risk / reward ratio
based on a pandas dataframe with two return series

Parameters
==========
df : pandas dataframe
w1 : portfolio weight for asset 1
w2 : portfolio weight for asset 2

'''

weights = [w1,w2]

# Calculate portfolio returns and volatility
pf_returns = (np.sum(df.mean() * weights) * 252)
pf_volatility = (np.sqrt(np.dot(np.asarray(weights).T, np.dot(df.cov() * 252, weights))))

# Calculate sharpe ratio
pf_sharpe = pf_returns / pf_volatility

return pf_sharpe

# Make df with random returns and calculate
# sharpe ratio for a 80/20 split between assets
df_returns = returns(rows = 10, names = ['A1', 'A2'])
df_returns.plot(kind = 'bar')

sharpe = pf_sharpe(df = df_returns, w1 = 0.8, w2 = 0.2)
print(sharpe)

# Output:
# 5.09477512073
现在我想找到优化夏普比率的投资组合权重。我认为您可以将优化问题表达如下:
maximize:
pf_sharpe()

by changing:
w1, w2

under the constraints:
0 < w1 < 1
0 < w2 < 1
w1 + w2 = 1
到目前为止我尝试过的:
我在帖子 Python Scipy Optimization.minimize using SLSQP showing maximized results 中找到了一个可能的设置.以下是我到目前为止所拥有的,它直接解决了我的问题的一个核心方面:

[...]where the variables are passed to functions containing a bunch of other variables as well.


如您所见,我最初的挑战甚至阻止我测试我的边界和约束是否会被函数 optimize.minimize() 接受。 .我什至没有考虑到这是一个最大化而不是最小化问题(希望可以通过更改函数的符号来修正)这一事实。
尝试:
# bounds
b = (0,1)
bnds = (b,b)

# constraints
def constraint1(w1,w2):
return w1 - w2

cons = ({'type': 'eq', 'fun':constraint1})

# initial guess
x0 = [0.5, 0.5]

# Testing the initial guess
print(pf_sharpe(df = df_returns, weights = x0))

# Optimization attempts

attempt1 = optimize.minimize(pf_sharpe(), x0, method = 'SLSQP', bounds = bnds, constraints = cons)
attempt2 = optimize.minimize(pf_sharpe(df = df_returns, weights), x0, method = 'SLSQP', bounds = bnds, constraints = cons)
attempt3 = optimize.minimize(pf_sharpe(weights, df = df_returns), x0, method = 'SLSQP', bounds = bnds, constraints = cons)
结果:
  • Attempt1 最接近 scipy 设置 here ,但可以理解失败,因为 df也不是 weights已被指定。
  • Attempt2 失败,出现 SyntaxError: positional argument follows keyword argument
  • 尝试 3 失败,出现 NameError: name 'weights' is not defined

  • 我的印象是 df可以自由指定,并且 x0optimize.minimize将被视为要测试的变量作为 pf_sharpe() 指定的函数中权重的“代表” .
    正如您肯定理解的那样,我在这方面从 Excel 到 Python 的过渡并不是最容易的,这里有很多我不明白的地方。无论如何,我希望你们中的一些人可以提供一些建议或澄清!
    谢谢!
    附录 1 - 模拟方法 :
    这个特殊的投资组合优化问题可以通过模拟一堆投资组合权重来轻松解决。我正是这样做的,以生成上面的投资组合图。如果有人感兴趣,这是整个功能:
    # Portfolio simulation
    def portfolioSim(df, simRuns):
    ''' Function to take a df with asset returns,
    runs a number of simulated portfolio weights,
    plots return and risk for those weights,
    and finds minimum risk portfolio
    and max risk / return portfolio

    Parameters
    ==========
    df : pandas dataframe with returns
    simRuns : number of simulations

    '''
    prets = []
    pvols = []
    pwgts = []
    names = list(df_returns)

    for p in range (simRuns):

    # Assign random weights
    weights = np.random.random(len(list(df_returns)))
    weights /= np.sum(weights)
    weights = np.asarray(weights)

    # Calculate risk and returns with random weights
    prets.append(np.sum(df_returns.mean() * weights) * 252)
    pvols.append(np.sqrt(np.dot(weights.T, np.dot(df_returns.cov() * 252, weights))))
    pwgts.append(weights)

    prets = np.array(prets)
    pvols = np.array(pvols)
    pwgts = np.array(pwgts)
    pshrp = prets / pvols

    # Store calculations in a df
    df1 = pd.DataFrame({'return':prets})
    df2 = pd.DataFrame({'risk':pvols})
    df3 = pd.DataFrame(pwgts)
    df3.columns = names
    df4 = pd.DataFrame({'sharpe':pshrp})
    df_temp = pd.concat([df1, df2, df3, df4], axis = 1)

    # Plot resulst
    plt.figure(figsize=(8, 4))
    plt.scatter(pvols, prets, c=prets / pvols, cmap = 'viridis', marker='o')

    # Min risk
    min_vol_port = df_temp.iloc[df_temp['risk'].idxmin()]
    plt.plot([min_vol_port['risk']], [min_vol_port['return']], marker='o', markersize=12, color="red")

    # Max sharpe
    max_sharpe_port = df_temp.iloc[df_temp['sharpe'].idxmax()]
    plt.plot([max_sharpe_port['risk']], [max_sharpe_port['return']], marker='o', markersize=12, color="green")

    # Test run
    portfolioSim(df = df_returns, simRuns = 250)
    附录 2 - Excel 求解器方法 :
    以下是我将如何使用 Excel Solver 解决问题。我没有链接到文件,而是仅附上了屏幕截图并在代码部分中包含了最重要的公式。我猜你们中没有多少人会对复制这个感兴趣。但我将它包括在内只是为了表明它可以在 Excel 中轻松完成。
    灰色范围代表公式。可以更改并用作优化问题中的参数的范围以黄色突出显示。绿色范围是目标函数。
    这是工作表和求解器设置的图像:
    enter image description here
    Excel 公式:
    C3  =AVERAGE(C7:C16)
    C4 =AVERAGE(D7:D16)
    H4 =COVARIANCE.P(C7:C16;D7:D16)
    G5 =COVARIANCE.P(C7:C16;D7:D16)
    G10 =G8+G9
    G13 =MMULT(TRANSPOSE(G8:G9);C3:C4)
    G14 =SQRT(MMULT(TRANSPOSE(G8:G9);MMULT(G4:H5;G8:G9)))
    H13 =G12/G13
    H14 =G13*252
    G16 =G13/G14
    H16 =H13/H14
    尾注:
    从截图中可以看出,Excel 求解器建议使用 47% / 53%在 A1 和 A2 之间拆分以获得 5,6 的最佳夏普比率。运行 Python 函数 sr_opt = portfolioSim(df = df_returns, simRuns = 25000)产生 5,3 的夏普比率,相应的权重为 46% and 53%对于 A1 和 A2:
    print(sr_opt)
    #Output
    #return 0.361439
    #risk 0.067851
    #A1 0.465550
    #A2 0.534450
    #sharpe 5.326933
    Excel中应用的方法是 GRG Nonlinear .我了解更改 SLSQP非线性方法的论点会让我找到某个地方,我研究了 Nonlinear solvers in scipy同样,但收效甚微。
    也许 Scipy 甚至不是这里的最佳选择?

    最佳答案

    更详细的答案,代码的第一部分保持不变

    import pandas as pd
    import numpy as np
    from scipy.optimize import minimize
    import matplotlib.pyplot as plt

    np.random.seed(1234)

    # Reproducible data sample
    def returns(rows, names):
    ''' Function to create data sample with random returns

    Parameters
    ==========
    rows : number of rows in the dataframe
    names: list of names to represent assets

    Example
    =======

    >>> returns(rows = 2, names = ['A', 'B'])

    A B
    2017-01-01 0.0027 0.0075
    2017-01-02 -0.0050 -0.0024
    '''
    listVars= names
    rng = pd.date_range('1/1/2017', periods=rows, freq='D')
    df_temp = pd.DataFrame(np.random.randint(-100,100,size=(rows, len(listVars))), columns=listVars)
    df_temp = df_temp.set_index(rng)
    df_temp = df_temp / 10000

    return df_temp

    函数 pf_sharpe被修改,第一个输入是权重之一,要优化的参数。而不是输入约束 w1 + w2 = 1 ,我们可以定义 w21-w1pf_sharpe ,这是完全等效的,但更简单、更快。另外, minimize将尝试最小化 pf_sharpe ,而你实际上想要最大化它,所以现在输出 pf_sharpe乘以-1。
    # Sharpe ratio
    def pf_sharpe(weight, df):
    ''' Function to calculate risk / reward ratio
    based on a pandas dataframe with two return series
    '''
    weights = [weight[0], 1-weight[0]]
    # Calculate portfolio returns and volatility
    pf_returns = (np.sum(df.mean() * weights) * 252)
    pf_volatility = (np.sqrt(np.dot(np.asarray(weights).T, np.dot(df.cov() * 252, weights))))

    # Calculate sharpe ratio
    pf_sharpe = pf_returns / pf_volatility

    return -pf_sharpe

    # initial guess
    x0 = [0.5]

    df_returns = returns(rows = 10, names = ['A1', 'A2'])

    # Optimization attempts

    out = minimize(pf_sharpe, x0, method='SLSQP', bounds=[(0, 1)], args=(df_returns,))

    optimal_weights = [out.x, 1-out.x]
    print(optimal_weights)
    print(-pf_sharpe(out.x, df_returns))

    这将返回优化的夏普比率 6.16(优于 5.3),w1 几乎为 1,w2 几乎为 0

    关于Python:如何优化函数参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49731383/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com