Creating a range of floats based on the values in an existing pandas dataframe

  dataframe, finance, numpy, pandas, python

Context

I am currently trying to build a function to select a portfolio based on a set of parameters. The dataframe has a group of portfolios based on the below function:

for x in range (10000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    Portfolio_returns_earnings_1.append(np.sum(weights * Portfolio_rtns_earnings_1.mean() * 250)) # expected returns
    Portfolio_Volatilities_earnings_1.append(np.sqrt(np.dot(weights.T,np.dot(Portfolio_rtns_earnings_1.cov() * 250, weights)))) # standard deviation 
    Portfolio_sharpe_ratio_1.append(np.sum(weights * ed.sharpe_ratio_annual(Portfolio_rtns_earnings_1, 0.0085, 250)))
    Portfolio_sortino_ratio_1.append(np.sum(ed.sortino_ratio_annual(Portfolio_rtns_earnings_1, 0.0085, 250) * weights))
    Portfolio_kurtosis_1.append(np.sum(ed.kurtosis(Portfolio_rtns_earnings_1) * weights))                               
    Portfolio_skewness_1.append(np.sum(ed.skewness(Portfolio_rtns_earnings_1) * weights))
    Portfolio_var_gaussian_1.append(np.sum(ed.var_gaussian(Portfolio_rtns_earnings_1, level=5, modified=False) * weights))
    Portfolio_cvar_historic_1.append(np.sum(ed.cvar_historic(Portfolio_rtns_earnings_1, level=5) * weights))
    Portfolio_drawdown_1.append(np.sum(ed.drawdown_Portfolio(Portfolio_rtns_earnings_1)['Drawdown'] * weights))
    Northgate_Returns_weight_earnings_1.append(weights[0])
    Quartix_Returns_weight_earnings_1.append(weights[1])  
    Rockwell_Returns_weight_earnings_1.append(weights[2])

 ...

#Creating a table of the results
Portfolios = pd.DataFrame({'Return': Portfolio_returns_earnings_1, 
                                   'Volatility': Portfolio_Volatilities_earnings_1,
                                   'Sharpe Ratio': Portfolio_sharpe_ratio_1,
                                   'Sortino Ratio': Portfolio_sortino_ratio_1,
                                   'Portfolio Kurtosis': Portfolio_kurtosis_1,
                                   'Portfolio Skewness':Portfolio_skewness_1,
                                   'Portfolio Var Gaussian': Portfolio_var_gaussian_1,
                                   'Portfolio CVAR historic': Portfolio_cvar_historic_1,
                                   'Portfolio Drawdown':Portfolio_drawdown_1,
                                   'Northgate Weight': Northgate_Returns_weight_earnings_1,
                                   'Quartix Weight': Quartix_Returns_weight_earnings_1, 
                                   'Rockwell Weight': Rockwell_Returns_weight_earnings_1,
                                    })


Return  Volatility  Sharpe Ratio    Sortino Ratio   Portfolio Kurtosis  Portfolio Skewness  Portfolio Var Gaussian  Portfolio CVAR historic Portfolio Drawdown  Northgate Weight    Quartix Weight  Rockwell Weight
0   0.157144    0.008917    10.743102   14.443058   2.367912    0.005490    0.000951    0.001024    -0.000201   0.240870    0.422511    0.336619
1   0.129853    0.009276    7.988633    5.868966    2.418320    0.312885    0.001163    0.001118    -0.000256   0.366644    0.599671    0.033684
2   0.135209    0.014865    8.240307    17.646808   2.002489    -0.155758   0.001275    0.001254    -0.000405   0.680641    0.056276    0.263083
3   0.152637    0.011010    10.135540   18.359734   2.161798    -0.159434   0.001067    0.001121    -0.000295   0.440554    0.183086    0.376360
4   0.180362    0.010065    13.122746   20.467785   2.376077    -0.204672   0.000751    0.000925    -0.000135   0.091280    0.335758    0.572963
... ... ... ... ... ... ... ... ... ... ... ... ...
9995    0.188837    0.012406    13.828527   28.357812   2.150223    -0.511562   0.000765    0.000975    -0.000200   0.227595    0.017368    0.755038
9996    0.162845    0.011783    11.153250   22.005659   2.125295    -0.292163   0.000995    0.001092    -0.000281   0.408235    0.094708    0.497057
9997    0.146355    0.009434    9.569746    14.002218   2.269262    0.007745    0.001080    0.001106    -0.000270   0.389526    0.343976    0.266498
9998    0.153782    0.011364    10.239199   19.134432   2.142994    -0.189115   0.001065    0.001123    -0.000299   0.449203    0.154743    0.396054
9999    0.149577    0.008857    9.955576    12.897889   2.348428    0.057063    0.001022    0.001063    -0.000230   0.303659    0.429706    0.266634

From this, I am able to choose a portfolio option (row) based on the column parameters. An example includes:

#Find the min and max range of the portfolio volatility to use to extract custom portfolio from dataframe
min(Portfolios['Volatility']), max(Portfolios['Volatility'])

# Custom Portfolios
# Within this range of volatility maximized, what is is the Portfolio Return? 
Max_Volatility_Return = Portfolios[(Portfolios['Volatility']>=0.008813526) & (Portfolios['Volatility']<=0.019963162)].max()['Return']
# Find the row in the dataframe where the return equals the above return - to derive weights
Portfolio_1 = Portfolios.iloc[np.where(Portfolios['Return']==Max_Volatility_Return)]

Though how I generate the range is a bit tedious and I am having to to go back, create new ranges that are in between these two min and max functions. I would like to create a range of values starting from the min, within the range of min and max that is within the dataframe. Thus far, I have discovered the below, though the link does not seem to be exactly what I want.

def range_float(start, stop, step):
    x = start 
    while x <= stop:
        yield x
        x = x + step

rf = range_float(min(Portfolios['Volatility']), 1000, .001)

for i in rf:
    print(i)

The issue with this method is the range goes beyond the max of the column factor in the dataframe. When I used the max, it just gave me one value. When appended to a blank list, just the two values were generated.

Alternative method is from this link. The issue here is I can’t seem to control the number of values generated if its not in the dataframe. Using for loop with range did not seem to help matters.

The logic I want to create is as follows:

  1. Start and end from min and max of the factor column
  2. Iterate over it x number of times but generate numbers that are within the dataframe range (min and max of the factor column
  3. Choose the number of steps/decimal points to produce these range from
  4. Create a for loop whereby for each of these ranges, the optimal portfolio is derived from the dataframe as illustrated above.
  5. Create an average of all these values to construct the optimal portfolio

Any help would be much appreciated.

Source: Python Questions

LEAVE A COMMENT