Based on the Portfolio Optimization Algorithm (POA) discussed earlier and the related portfolio management, let’s run the Bear vs. Bull QC test of the portfolio P=[MSFT, AAPL, NDAQ] in terms of the Risk/Return Ratio (RRR).
Content:
- Stock prices are rising in a bull market and declining in a bear market. The stock market under bullish conditions is consistently gaining value, even with some brief market corrections. The stock market under bearish conditions is losing value or holding steady at depressed prices.
- Low interest rates typically accompany bull markets, while high interest rates are associated with bear markets. Low interest rates make it more affordable for businesses to borrow money and grow, while high interest rates tend to slow companies’ expansions.
- MSFT
- AAPL
- NDAQ
- Barchart Opinion
- Portfolio Allocation
- Portfolio Optimization
- Summary
- Conclusions
- Explore More

MSFT
- The bears believe Microsoft’s business is still exposed to macroeconomic headwinds.
- Wall Street remains overwhelmingly bullish on Microsoft. Analysts expect its revenue and adjusted earnings per share (EPS) to rise 19% and 16%, respectively, in fiscal 2022.
- In fiscal 2023, they expect its revenue to increase 14% as its adjusted EPS grows another 16%.
AAPL
- Bull case: Innovation spanning decades.
- While Apple has done an excellent job creating sought-after consumer electronics like the iPod, iPad, AirPods, Apple Watch, etc., it’s still largely dependent on the iPhone.
- In its most recent quarter, the iPhone comprised 52% of the company’s overall sales. That’s not even including all the attachments that go along with it. The risk is that if Apple doesn’t continue its iPhone success, revenue growth could stall or even reverse.
NDAQ
- All three of the major U.S. stock indexes are now entrenched in a bear market.
- While there’s no denying that bear markets can test the resolve of both tenured and new investors, history also shows that they’re the ideal opportunity to go hunting for bargains. No matter how bad things may appear for the leading indexes, a bull market rally eventually recoups all that was lost.
Barchart Opinion
Price Information
Company | Microsoft Corp | Apple Inc | Nasdaq Inc |
Change | +8.57 | +3.37 | +0.47 |
% Change | +3.80% | +2.44% | +0.82% |
Weighted Alpha | -27.20 | -9.20 | -10.80 |
Today’s Opinion | 100% Sell | 72% Sell | 24% Buy |
Performance 1-Month
%Chg | -7.51% since 09/13/22 | -8.48% since 09/13/22 | -6.11% since 09/13/22 |
Ratios
Price/Earnings ttm | 24.50 | 22.93 | 22.49 |

Portfolio Allocation
Let’s set the working directory YOURPATH and import the key libraries
import os
os.chdir(‘C:/Users/adrou/OneDrive/Documents/PORTFOLIOJAYA’) # Set working directory
os. getcwd()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import pandas_datareader.data as web
import datetime
Let’s define the time interval
start = datetime.datetime(2020,1,1)
end = datetime.datetime(2022,10,10)
and the 3 stock datasets
data1 = web.DataReader(‘MSFT’,’yahoo’,start,end)
data2 = web.DataReader(‘AAPL’,’yahoo’,start,end)
data3 = web.DataReader(‘NDAQ’,’yahoo’,start,end)
data1.tail()

Let’s estimate normalized returns
for s_df in (data1,data2,data3):
s_df[‘Normalized Return’] = s_df[‘Adj Close’]/s_df.iloc[0][‘Adj Close’]
data1.tail()

Allocations are as follows:
for s_df, allocation in zip((data1,data2,data3),[0.5,0.3,0.2]):
s_df[‘Allocation’] = s_df[‘Normalized Return’]*allocation
data1.tail()

Let’s set
investment = 100000
and get the position value based on allocations
for s_df in (data1,data2,data3):
s_df[‘Position value’] = s_df[‘Allocation’] * investment
data1.tail()

Now let’s look at the position values for all the stocks
position_values = pd.concat([data1[‘Position value’],
data2[‘Position value’],data3[‘Position value’]],axis=1)
position_values.columns = [‘MSFT position values’,’AAPL position values’,
‘NDAQ position values’]
position_values.tail()

The total position can now be calculated by summing the values of all stocks position values
position_values[‘Total position value’] = position_values.sum(axis=1)
position_values.tail()

position_values[‘Total position value’].plot(figsize=(10,8))
plt.title(‘Total portfolio value’)

position_values.drop(‘Total position value’,axis=1).plot(figsize=(10,8))

Portfolio statistics:
position_values[‘Daily return’] = position_values[‘Total position value’].pct_change(1)
position_values.tail()

The mean daily return is given by
position_values[‘Daily return’].mean()
0.0009057958832049809
The Sharpe ratio is
sharpe_r = position_values[‘Daily return’].mean()/position_values[‘Daily return’].std()
sharpe_r
0.04543968353367672
and the annual Sharpe ratio is
annual_sharpe_r = sharpe_r * (252**0.5)
annual_sharpe_r
0.7213326137015117
Recall that A Sharpe ratio of less than one is considered unacceptable or bad. The risk your portfolio encounters isn’t being offset well enough by its return. The higher the Sharpe ratio, the better.
Portfolio Optimization
Let’s apply the revised portfolio management algorithm to our stocks. Firstly, the return will be plotted against volatility based on the Sharpe ratio. Secondly, the Python SciPy module will be used to create the return-volatility plot using the SLSQP optimization scheme.
Let’s continue the story by combining Adj Close columns of our 3 datasets
df1=data1[‘Adj Close’]
df2=data2[‘Adj Close’]
df3=data3[‘Adj Close’]
df = pd.concat([df1,df2,df3],axis=1)
df.columns = [‘MSFT’,’AAPL’,’NDAQ’]
df.tail()

Let’s check statistics.
Mean daily return:
Using the percent change function, the mean daily return of the stocks is
df.pct_change(1).mean()
MSFT 0.000780 AAPL 0.001190 NDAQ 0.000929 dtype: float64
The mean daily return yields the degree of correlation between the stocks
df.pct_change(1).corr()

The percentage change method also gives the arithmetic return

or in log scale
log_returns = np.log(df/df.shift(1))
log_returns.head()

Hence, the covariance matrix is
log_returns.cov()

Optimization via Randomization – Allocation of random weights to the stocks. The weights are randomly allocated to the stocks and made sure that they all add up to 1. To make sure they add up to 1, the weights are rebalanced by dividing it by the sum of weights:
print(‘The stocks are: ‘,df.columns)
np.random.seed(200)
weights = np.array(np.random.random(3)) #random weights
weights = weights/np.sum(weights)
print(‘Random weights: ‘,weights)
The stocks are: Index(['MSFT', 'AAPL', 'NDAQ'], dtype='object') Random weights: [0.53580931 0.12809422 0.33609646]
The annual expected return is
expected_return = np.sum((log_returns.mean()* weights) * 252)
expected_return
0.16570984130750205
The annual expected volatility is
expected_vol = np.sqrt(np.dot(weights.T,np.dot(log_returns.cov()*252,weights)))
expected_vol
0.3059477823851022
Hence, the Sharpe ratio is
sharpe_r = expected_return/expected_vol
sharpe_r
0.541627855628383
Let’s run the random optimization algorithm
np.random.seed(200)
Initalization of variables
portfolio_number = 7000
weights_total = np.zeros((portfolio_number,len(df.columns)))
returns = np.zeros(portfolio_number)
volatility = np.zeros(portfolio_number)
sharpe = np.zeros(portfolio_number)
for i in range(portfolio_number):
# Random weights
weights = np.array(np.random.random(3))
weights = weights/np.sum(weights)
# Append weight
weights_total[i,:] = weights
# Expected return
returns[i] = np.sum((log_returns.mean()* weights) * 252)
# Expected volume
volatility[i] = np.sqrt(np.dot(weights.T,np.dot(log_returns.cov()*252,weights)))
# Sharpe ratio
sharpe[i] = returns[i]/volatility[i]
Let’s calculate the max Sharpe ratio
max_sharpe = sharpe.max()
max_sharpe
0.6818731773912419
max_sharpe_index = sharpe.argmax()
max_sharpe_index
6708
max_sharpe_weights = weights_total[343,:]
max_sharpe_weights
array([6.71707148e-01, 2.83931652e-04, 3.28008920e-01])
Let’s calculate the corresponding max expected return and volatility
max_sharpe_return = returns[max_sharpe_index]
max_sharpe_return
0.21046030001983235
max_sharpe_vol = volatility[max_sharpe_index]
max_sharpe_vol
0.3086502109160916
Let’s plot the Return-Volatility map as the scatter plot
plt.figure(figsize=(12,8))
plt.scatter(volatility,returns,c=sharpe)
plt.colorbar(label=’Sharpe Ratio’)
plt.xlabel(‘Volatility’)
plt.ylabel(‘Return’)
plt.scatter(max_sharpe_vol,max_sharpe_return,c=’red’,s=50)

Let’s apply the SLSQP minimization algorithm from scipy.optimize (with constraints, bounds, and the initial guess as input parameters) to verify this result
def stats(weights):
weights = np.array(weights)
expected_return = np.sum((log_returns.mean()* weights) * 252)
expected_vol = np.sqrt(np.dot(weights.T,np.dot(log_returns.cov()*252,weights)))
sharpe_r = expected_return/expected_vol
return np.array([expected_return,expected_vol,sharpe_r])
from scipy.optimize import minimize
def sr_negate(weights):
neg_sr = stats(weights)[2] * -1
return neg_sr
def weight_check(weights):
weights_sum = np.sum(weights)
return weights_sum – 1
constraints = ({‘type’:’eq’,’fun’:weight_check})
bounds = ((0,1),(0,1),(0,1))
initial_guess = [0.3,0.3,0.4]
results = minimize(sr_negate,initial_guess,method=’SLSQP’,bounds=bounds,constraints=constraints)
results
fun: -0.6819487289981644 jac: array([ 1.87360495e-01, -1.54420733e-04, 1.82241201e-04]) message: 'Optimization terminated successfully' nfev: 20 nit: 5 njev: 5 status: 0 success: True x: array([1.48788148e-16, 5.41313619e-01, 4.58686381e-01])
wt = results.x
wt
stats(wt)
Let’s plot the Return-Volatility map with the volatility frontier envelope
frontier_return = np.linspace(-0.6,0.4,200)
def min_vol(weights):
vol = stats(weights)[1]
return vol
frontier_volatility = []
for exp_return in frontier_return:
constraints = ({‘type’:’eq’,’fun’:weight_check},
{‘type’:’eq’,’fun’:lambda x: stats(x)[0]-exp_return})
result = minimize(min_vol,initial_guess,method=’SLSQP’,bounds=bounds,constraints=constraints)
frontier_volatility.append(result[‘fun’])
plt.figure(figsize=(12,8))
plt.scatter(volatility,returns,c=sharpe)
plt.scatter(max_sharpe_vol,max_sharpe_return,c=’red’,s=200)
plt.scatter(expected_vol,expected_return,c=’black’,s=200)
plt.colorbar(label=’Sharpe Ratio’)
plt.xlabel(‘Volatility’)
plt.ylabel(‘Return’)
plt.plot(frontier_volatility,frontier_return,’r–‘,linewidth=3)
plt.legend([‘SLSQP Optimizer’, ‘Max Sharpe Ratio’,’Expected Sharpe Ratio’,’Frontier Line’])
plt.ylim([0.125, 0.25])

Summary
- Portfolio & Timing
start = datetime.datetime(2020,1,1)
end = datetime.datetime(2022,10,10)
and the 3 stock datasets imported from Yahoo Finance
web.DataReader(‘MSFT’,’yahoo’,start,end)
web.DataReader(‘AAPL’,’yahoo’,start,end)
web.DataReader(‘NDAQ’,’yahoo’,start,end)
- Volatility (Max Sharpe Ratio) ~ Volatility (Expected Sharpe Ratio) ~ 0.31
- Return (Max Sharpe Ratio) ~ 0.21 > Return (Expected Sharpe Ratio) ~ 0.17
- Expected Sharpe Ratio ~ 0.54 < 1.0
- Volatility: var(MSFT) ~4.69e-4 > var(AAPL) ~4.1e-4 > var(NDAQ)~2.9e-4
- Similarity index corr(MSFT,AAPL)~0.81 > corr(MSFT,NAQ)~0.67 ~ corr(AAPL,NAQ) ~0.62
- the mean daily return of the stocks is (AAPL>MSFT>NDAQ)
MSFT 0.000780
AAPL 0.001190
NDAQ 0.000929
Conclusions
- A Sharpe ratio of less than one is considered unacceptable or bad. The risk the portfolio P encounters isn’t being offset well enough by its return.
- The expected return of the portfolio P is lower than the return associated with Max Sharpe Ratio.
- Poor diversification: three stocks follow more or less the similar trend, as confirmed by the relatively high correlation coefficient above 0.5 and a similar value of variance
- Stocks have a similar degree of volatility, as shown by their variance
- The outcome is consistent with the stock-to-sell barchart.com opinion (see above).
Explore More
A TradeSanta’s Quick Guide to Best Swing Trading Indicators
Algorithmic Testing Stock Portfolios to Optimize the Risk/Reward Ratio
Stock Portfolio Risk/Return Optimization
Risk/Return QC via Portfolio Optimization – Current Positions of The Dividend Breeder
Risk/Return POA – Dr. Dividend’s Positions
Invest in AI via Macroaxis Sep ’22 Update
Bear Market Similarity Analysis using Nasdaq 100 Index Data
Are Blue-Chips Perfect for This Bear Market?
Track All Markets with TradingView
Basic Stock Price Analysis in Python
S&P 500 Algorithmic Trading with FBProphet
The Qullamaggie’s TSLA Breakouts for Swing Traders
Predicting Trend Reversal in Algorithmic Trading using Stochastic Oscillator in Python
Stock Forecasting with FBProphet
The Zacks’s Steady Investor – A Quick Look
Zacks Insights into the Commodity Bull Market
Zacks Insights into this High Inflation/Rising Rate Market
SeekingAlpha Risk/Reward July Rundown
Inflation-Resistant Stocks to Buy
Macroaxis AI Investment Opportunity
AAPL Stock Technical Analysis 2 June 2022
OXY Stock Analysis, Thursday, 23 June 2022
OXY Stock Update Wednesday, 25 May 2022
OXY Stock Technical Analysis 17 May 2022
Short-Term Stock Market Price Prediction using Deep Learning Models
ML/AI Regression for Stock Prediction – AAPL Use Case
A Weekday Market Research Update
Upswing Resilient Investor Guide
Supervised ML/AI Stock Prediction using Keras LSTM Models
Investment Risk Management Study
RISK AWARE INVESTMENT: GUIDE FOR EVERYONE
Make a one-time donation
Make a monthly donation
Make a yearly donation
Choose an amount
Or enter a custom amount
Your contribution is appreciated.
Your contribution is appreciated.
Your contribution is appreciated.
DonateDonate monthlyDonate yearly