<jupyter_start><jupyter_text><jupyter_code>!pip install yfinance
import yfinance as yf
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.transforms as transform
import matplotlib.gridspec as gridspec
import pandas as pd
from pandas.tseries.offsets import MonthEnd
pd.options.mode.chained_assignment = None
pd.set_option('use_inf_as_na', True)
from datetime import datetime
tickers=["SGRY", "NTRA", "Z", "FATE", "DIS", "GM", 'BPMC', "PTC"]
ls_key = 'Adj Close'
start = datetime(2018,1,1)
 
df = yf.download(tickers,start, freq='w')
prices = df[[("Adj Close", s) for s in tickers]]
prices.columns = prices.columns.droplevel(level=0)
prices
plt.figure(figsize= (15,8))
plt.plot(prices, label = 'Daily Closing price' )
# plt.xticks([])
plt.ylabel('Adj Close prices (US$)'); plt.xlabel('timestamp')
plt.grid(True); plt.show()
plt.figure(figsize= (15,6))
plt.plot(prices['SGRY'].resample('y').mean())
# plt.xticks([])
plt.ylabel('SGRY Adj Close yearly prices (US$)'); plt.xlabel('timestamp')
plt.grid(True); plt.show()
plt.figure(figsize= (15,6))
plt.plot(prices['SGRY'].resample('w').mean()[-52:], label = 'weekly Closing price' )
# plt.xticks([])
plt.ylabel('SGRY Adj Close weekly price trend (US$)'); plt.xlabel('timestamp')
plt.grid(True); plt.show()
import numpy as np
p_m =prices['SGRY'].resample('m').mean()[-12:]
plt.figure(figsize= (15,6))
plt.plot(p_m)
# plt.xticks([])
plt.ylabel('SGRY Adj Close monthly price trend (US$)'); plt.xlabel('timestamp')
plt.grid(True); plt.show()

import matplotlib.dates as mpl_dates
df = prices.copy()
df.reset_index(inplace=True)
df['Date']=df['Date'].apply(mpl_dates.date2num)
df = df.astype(float)
# y = prices['value'].tolist()
# X = dates.date2num(list(pd.to_datetime(x)))
X = df.Date.values
fig, ax = plt.subplots(2, 4, figsize=(15,6), sharex=True, sharey=True)

# SGRY
z = np.polyfit(X, df['SGRY'].values, 2)
p = np.poly1d(z)
ax[1, 0].plot(X,p(X),"r--")
ax[1, 0].plot(X, df['SGRY'])
ax[1, 0].set_title('SGRY', fontsize=12)

# NTRA
z = np.polyfit(X, df['NTRA'].values, 2)
p = np.poly1d(z)
ax[0, 0].plot(X,p(X),"r--")
ax[0, 0].plot(X, df['NTRA'] )
ax[0, 0].set_title('NTRA', fontsize=12)

# Z
z = np.polyfit(X, df['Z'], 2)
p = np.poly1d(z)
ax[1, 1].plot(X,p(X),"r--")
ax[1, 1].plot(X, df['Z'])
ax[1, 1].set_title('Z', fontsize=12)

# BPMC
z = np.polyfit(X, df['BPMC'], 2)
p = np.poly1d(z)
ax[1, 2].plot(X,p(X),"r--")
ax[1, 2].plot(X,  df['BPMC'])
ax[1, 2].set_title('BPMC', fontsize=12)

# FATE
z = np.polyfit(X, df['FATE'], 2)
p = np.poly1d(z)
ax[1, 3].plot(X,p(X),"r--")
ax[1, 3].plot(X,  df['FATE'])
ax[1, 3].set_title('FATE', fontsize=12)

# GM
z = np.polyfit(X, df['GM'], 2)
p = np.poly1d(z)
ax[0, 1].plot(X,p(X),"r--")
ax[0, 1].plot(X,  df['GM'])
ax[0, 1].set_title('GM', fontsize=12)

# GM
z = np.polyfit(X, df['DIS'], 2)
p = np.poly1d(z)
ax[0, 2].plot(X,p(X),"r--")
ax[0, 2].plot(X,  df['DIS'])
ax[0, 2].set_title('DIS', fontsize=12)

# PTC
z = np.polyfit(X, df['PTC'], 2)
p = np.poly1d(z)
ax[0, 3].plot(X,p(X),"r--", label = 'Trend line')
ax[0, 3].plot(X,  df['PTC'])
ax[0, 3].set_title('PTC', fontsize=12)

# Draw the plot
fig.text(0.5, 0.00, 'Years', ha='center')
fig.text(0.00, 0.5, 'Average close prices', va='center', rotation='vertical')
plt.tight_layout()
# monthly_ret = prices.pct_change().resample('m').agg(lambda x: (x+1).prod() - 1)
# monthly_ret
# returns = prices.copy()
weekly_returns = prices.resample('w').mean().pct_change()
# prices.pct_change().resample('w').agg(lambda x: (x+1).prod() - 1)


# returns.apply(lambda x: x.shift(-1)/x - 1, axis = 0)
weekly_returns # sanity check
# ranking of the returns
returns_rank = weekly_returns.rank(axis=1,method='average', numeric_only=True, 
                            na_option='keep', ascending=False, pct=False)
returns_rank<jupyter_output><empty_output><jupyter_text>For each period(i), we want to calculate the average return for period(i) of the 2 stocks from the list that had the best performance over the previous period (period(i-1)).<jupyter_code># Creating a mask to select only 2 best returns per period, shifting down one line, replacing NaN in first line by false
import numpy as np
mask = (returns_rank < 6).shift(1) 
mask = mask.replace(np.nan,False)
mask
# Applying the mask to the returns
best_returns = weekly_returns[mask]
best_returns
# averaging the returns :
average_return = best_returns.mean(axis=1, skipna='true')
average_return 
cum_returns = np.exp(np.log1p(average_return).cumsum())

plt.figure(figsize= (10,5))
plt.plot(cum_returns)
plt.title('Portfolio cumulative returns')
plt.grid(True); plt.show()<jupyter_output><empty_output><jupyter_text>Momentun signal computation:<jupyter_code>momentum_signal = prices.resample('w').mean()

"""
return of the securities of last 6 weeks prior to the week we will be trading
we are not using current weeks because:
1. traditional momentum has atendency of short term reversal and longer term trend
2. it algns with execution strategy interms of  consistent with actual execution because
if we receive a signal on close price, we won't be able to execute immedeate
"""
momentum_signal = (momentum_signal.apply(func = lambda x: x.shift(1)/x.shift(7) - 1, axis = 0))
momentum_signal # sanity check<jupyter_output><empty_output><jupyter_text>creating signal >= 7 means 1, <=2 means -1, else 0<jupyter_code># ranking of the returns
rank_df = momentum_signal.rank(axis=1,method='average', numeric_only=True, 
                            na_option='keep', ascending=False, pct=False)
rank_df
for col in rank_df.columns:
    rank_df[col] = np.where(rank_df[col] >= 7.0, 1, np.where(rank_df[col] <= 2.0, -1, 0))

rank_df.tail() # sanity check
rank_df = momentum_signal.rank(axis =1)
rank_df # sanity check
# returns = prices.pct_change()
portfolio = np.multiply(rank_df, weekly_returns)
portfolio.tail(50) # sanity check
portfolio_returns = portfolio.sum(axis=1) / 3
portfolio_returns
cum_returns
cum_returns = np.exp(np.log1p(portfolio_returns).cumsum())
plt.figure(figsize= (10,6))
plt.plot(cum_returns)
plt.title('Portfolio cumulative returns')
plt.grid(True); plt.show()
# for col in rank_df.columns:
#     rank_df[col] = np.where(rank_df[col] >= 7.0, 1, np.where(rank_df[col] <= 2.0, -1, 0))

# rank_df.tail() # sanity check
# portfolio = np.multiply(rank_df, returns)
# portfolio.tail(50) # sanity check
# portfolio_returns = portfolio.sum(axis=1) / 3
# portfolio_returns
# cum_returns = np.exp(np.log1p(portfolio_returns).cumsum())

# plt.figure(figsize= (15,8))
# plt.plot(cum_returns)
# plt.title('Portfolio cumulative returns')
# plt.grid(True); plt.show()<jupyter_output><empty_output><jupyter_text>linear least-squares regression for trendlines<jupyter_code>tickers=["SGRY"]
start = datetime(2018,1,1)
 
df = yf.download(tickers,start)
df
df_len = len(df)
df['Number'] = np.arange(df_len)+1
df_high = df.copy()
df_low = df.copy()
df.tail()<jupyter_output><empty_output><jupyter_text>Here we are selecting 2 higher and lower data points from DataFrame. The computation returned only 2 sets of DataFrame rows where the data points broke above or below the calculated linear regression line in either case.<jupyter_code>while len(df_high)>2:
    slope, intercept, r_value, p_value, std_err = linregress(x=df_high['Number'], y=df_high['High'])
    df_high = df_high.loc[df_high['High'] > slope * df_high['Number'] + intercept]
    
df_high.tail()
while len(df_low)>2:
    slope, intercept, r_value, p_value, std_err = linregress(x=df_low['Number'], y=df_low['Low'])
    df_low = df_low.loc[df_low['Low'] < slope * df_low['Number'] + intercept]
    
df_low.tail()<jupyter_output><empty_output><jupyter_text>So, now that We have 2 higher and lower data points calculated, let’s take those 2 points in both uptrend and downtrend calculation for scipy.stats.linregress method. The method returns a slope, interception, p&r values also standard errors of a function.<jupyter_code>slope, intercept, r_value, p_value, std_err = linregress(x=df_high['Number'], y=df_high['Close'])
df['Uptrend'] = slope * df['Number'] + intercept
df.tail()
slope, intercept, r_value, p_value, std_err = linregress(x=df_low['Number'], y=df_low['Close'])
df['Downtrend'] = slope * df['Number'] + intercept
df.tail()
# draw the closing price and related trendlines (uptrend and downtrend)
fig, ax1 = plt.subplots(figsize=(15,6))

color = 'tab:green'
xdate = [x.date() for x in df.index]
ax1.set_xlabel('Date', color=color)
ax1.plot(xdate, df.Close, label="close", color=color)
ax1.tick_params(axis='x', labelcolor=color)
ax1.legend()

ax2 = ax1.twiny()
ax2.plot(df.Number, df.Uptrend, label="uptrend")
ax2.plot(df.Number, df.Downtrend, label="downtrend")

plt.legend()
plt.grid()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1758077497987812, 'fraction_numerical': 0.023801310796826493, 'mean_word_length': 5.726991492652745, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '247863', 'license': 'MIT', 'n_tokens_mistral': 3533, 'n_tokens_neox': 3365, 'n_words': 776, 'path': 'Weekly_Series_Momentum_Signal.ipynb', 'repo_name': 'saritmaitra/Momentum', 'size': '8697'}