Towards Max(ROI/Risk) Trading in Q1 2023

In this post, we will compare 1Y ROI/Risk of selected stocks vs ETF using a set of basic stock analyzer functions. The posts consists of the following three parts:

  1. Comparing normalized prices of selected stocks

Looking at the closing price of a stock over time is a good way to track its performance

  1. Visualizing and comparing annual risk and return

We combine the risk and return metrics into a single plot; we define return as the percent change in 1Y closing price and risk will be the corresponding standard deviation (STDV) of daily returns over the period of time.

  1. Examining correlation matrix of stock returns

We look at the correlation matrix that would give us useful insights into how certain stocks will react under similar market conditions.

Requirements

import os
os.chdir(‘YOURPATH’)
os. getcwd()

import pandas as pd
import plotly.offline as offline
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly.express as px
import plotly.graph_objs as go
offline.init_notebook_mode(connected=True)
pd.set_option(‘display.max_rows’, 10)

Input Data

import yfinance as yf
import plotly.express as px
import plotly.io as pio
import numpy as np
import plotly.graph_objects as go
pio.renderers.default = “browser”
tickers=[‘AMZN’,’AAPL’,’MSFT’,’CPB’,’DG’,’^GSPC’,’NVO’,’REGN’,’VRTX’]
start_date=”2022-01-01″
mydf=yf.download(tickers,start=start_date)

[*********************100%***********************]  9 of 9 completed

Price

def close_plot(df, adj = True, normalize = False):

if adj:
    close = df.loc[:,"Adj Close"].copy()
    title = "Adjusted Closing Prices"
else:
    close = df.loc[:,"Close"].copy()
    title = "Closing Prices"

if normalize:
    normclose = close.div(close.iloc[0]) #Normalizes data
    fig = px.line(normclose, 
                  x = normclose.index,
                  y = normclose.columns,
                  title = "Normalized " + title,      
                  template = 'plotly_dark') # Plotting Normalized closing data
    fig.update_layout(
        legend = dict(title = None, font = dict(size = 16)),
        title={
        'y':0.9,
        'x':0.5,
        'font': {'size': 24},
        'xanchor': 'center',
        'yanchor': 'top'},
        hovermode = "x unified",
        xaxis_title = "Date",
        yaxis_title = "Normalized " + title + " (USD)"
        )
    fig.show()
else:
    fig = px.line(close, 
                  x = close.index,
                  y = close.columns,
                  title = title,
                  template = 'plotly_dark') # Plotting Normalized closing data
    fig.update_layout(
        legend = dict(title = None, font = dict(size = 16)),
        title={
        'y':0.9,
        'x':0.5,
        'font': {'size': 24},
        'xanchor': 'center',
        'yanchor': 'top'},
        hovermode = "x unified",
        xaxis_title = "Date",
        yaxis_title = title +  " (USD)"
        )
    fig.show()

close_plot(mydf, adj = True, normalize = False)

close_plot(mydf, adj = True, normalize = True)

Return

def returns_plot(df, adj = True):

if adj:
    close = df.loc[:,"Adj Close"].copy()
else:
    close = df.loc[:,"Close"].copy()

ret = close.pct_change().dropna()
cum_ret  = ((1 + ret).cumprod() -1) * 100
fig = px.line(cum_ret, template = 'plotly_dark')
fig.update_layout(
    legend = dict(title = None, font = dict(size = 16)),
    title={
        'y':0.95,
        'x':0.5,
        'text': "Daily Cumulative Returns",
        'font': {'size': 24},
        'xanchor': 'center',
        'yanchor': 'top'},
    hovermode = "x unified",
    xaxis_title = "Date",
    yaxis_title = "% Returns")

fig.show()  

returns_plot(mydf, adj = True)

ROI/Risk

def risk_return(df, adj = True, crypto = False):

if adj:
    close = df.loc[:,"Adj Close"].copy()
else:
    close = df.loc[:,"Close"].copy()

if crypto:
    trading_days = 365
else:
    trading_days  = 252


ret = close.pct_change().dropna().mul(100) #Returns of each stock in terms of percent change
summary = ret.describe().T.loc[:,["mean","std"]]
summary["mean"] = summary["mean"]*trading_days # Multiply by number of trading days
summary["std"]  = summary["std"]*np.sqrt(trading_days) # Multiply by number of trading dayss
summary.rename(columns = {'mean':'Return', 'std':'Risk'}, inplace = True)  
fig = px.scatter(summary, 
                 x = 'Risk', 
                 y = 'Return', 
                 title = "Annual Risk / Return",
                 text = summary.index,
                 template = 'plotly_dark')
fig.update_traces(marker={'size': 15},
                  textposition='top center',
                  hoverlabel=dict(font=dict(size=20) ))
fig.update_layout(
    legend = dict(title = None),
    title={
    'y':0.9,
    'x':0.5,
    'font': {'size': 24},
    'xanchor': 'center',
    'yanchor': 'top',},
    xaxis = dict(title = dict(font = dict(size = 20))),
    yaxis = dict(title = dict(font = dict(size = 20)))
    )
fig.show()

risk_return(mydf, adj = True, crypto = False)

Correlations

def ret_corr(df, adj = True, crypto = False):

if adj:
    close = df.loc[:,"Adj Close"].copy()
else:
    close = df.loc[:,"Close"].copy()

if crypto:
    trading_days = 365
else:
    trading_days  = 252

ret = close.pct_change().dropna().mul(100) #Returns of each stock in terms of percent change
summary = ret.describe().T.loc[:,["mean","std"]]
summary["mean"] = summary["mean"]*trading_days # Multiply by number of trading days
summary["std"]  = summary["std"]*np.sqrt(trading_days) # Multiply by number of trading days
summary.rename(columns = {'mean':'Return', 'std':'Risk'}, inplace = True) 

fig = px.imshow(ret.corr(), text_auto=True, color_continuous_scale='tempo', template = 'plotly_dark', title = "Returns Correlation")
fig.update_layout(
    legend = dict(title = None),
    title={
    'y':0.9,
    'x':0.5,
    'xanchor': 'center',
    'yanchor': 'top'}
    )
fig.show()

ret_corr(mydf, adj = True, crypto = False)

Summary

Based on the above plots, we select the CPB stock for trading because of:

  • Low correlation between CPB and ^GSPC
  • High return(CPB) ~20% compared to loss(^GSPC) ~ 13%
  • Low risk(CPB) ~ 23% comparable to low risk(^GSPC).

Explore More

Bear vs. Bull Portfolio Risk/Return Optimization QC Analysis

A TradeSanta’s Quick Guide to Best Swing Trading Indicators

Algorithmic Testing Stock Portfolios to Optimize the Risk/Reward Ratio

Algorithmic Trading using Monte Carlo Predictions and 62 AI-Assisted Trading Technical Indicators (TTI)

Stock Portfolio Risk/Return Optimization

Risk/Return QC via Portfolio Optimization – Current Positions of The Dividend Breeder

Risk/Return POA – Dr. Dividend’s Positions


One-Time
Monthly
Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

$5.00
$15.00
$100.00
$5.00
$15.00
$100.00
$5.00
$15.00
$100.00

Or enter a custom amount

$

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: