Whereas momentum and trend-following algorithms share sure similarities, they’ve notable variations. For instance, the Shifting Common Convergence Divergence (MACD) indicator capabilities as each a momentum and a trend-following software.
Momentum algorithms, a subset of trend-following methods, typically give attention to short-term worth actions. They purpose to establish if a inventory has not too long ago demonstrated sturdy momentum, assuming the pattern will persist for a short time.
In distinction, trend-following algorithms are oriented towards figuring out long-term tendencies and capitalize on the directional motion of those tendencies, whatever the time it takes for earnings to materialize.
Momentum buying and selling encompasses a number of methods, together with however not restricted to the next:
Worth Charge of Change (ROC)Absolute MomentumRelative MomentumDual Momentum
Every of those algorithms shall be explored beneath, together with Python code to implement them. For every, I’ll first outline the methodology, describe the method used, and supply an instance implementation in Python from scratch.
Definition
The Worth Charge of Change (ROC) is a momentum-based buying and selling technique that measures the share change in a inventory’s worth over a specified interval. A constructive ROC suggests the inventory is gaining momentum, triggering a purchase sign because the indicator anticipates continued worth development.
Method
Python Code Implementation
As an instance this idea, I’ll use a dataframe containing Apple’s historic inventory costs. Particulars on how the dataset was obtained utilizing Python shall be shared on the conclusion of this information.
Interval (n): Use a 10-day interval.ROC Calculation: Compute the share change in worth over 10 days.Alerts:If the ROC is constructive for a day, set off a purchase sign.If the ROC is unfavourable for a day, set off a promote sign.
4. Efficiency Evaluation:
Calculate each day returns primarily based on the technique.Compute cumulative returns to judge its effectiveness over time.# Outline the time interval for calculating the ROCn = 10
# Calculate the ROC indicatordf[‘ROC’] = df[‘Adj Close’].pct_change(durations=n)
# Generate purchase indicators when the ROC turns into above its sign line (0)df[‘Buy’] = (df[‘ROC’] > 0) & (df[‘ROC’].shift(1) < 0)
# Generate promote indicators when the ROC turns into beneath its sign line (0)df[‘Sell’] = (df[‘ROC’] < 0) & (df[‘ROC’].shift(1) > 0)
# Purchase securities when a purchase sign is generated and promote them when a promote sign is generated# 1 for Purchase, -1 for Promote, 0 for Holddf[‘Signal’] = np.the place(df[‘Buy’]==True, 1, np.the place(df[‘Sell’]==True,-1,0))
# Calculate the each day returns of the strategydf[‘Returns’] = df[‘Signal’].shift(1) * df[‘Adj Close’].pct_change()df[‘Returns+1’] = 1 + df[‘Returns’]
# Calculate the cumulative returns of the strategydf[‘Cumulative_Returns’] = (1+df[‘Returns’]).cumprod()
# Print the ultimate cumulative returnprint(‘Ultimate Cumulative Return Over The Complete Interval: ‘, df[‘Cumulative_Returns’][-1]-1) Ultimate Cumulative Return Over The Complete Interval: 0.04052975893266497
Plotting the cumulative return and the sign:
df[[‘Returns+1′,’Cumulative_Returns’]].plot(figsize=(8,4))plt.title(“Worth Charge of Change (ROC)”)plt.present()
df[[‘Signal’]].plot(figsize=(8,4))plt.present()
The cumulative return through the timeframe from mid-August 2022 to mid-December 2022 didn’t present sturdy efficiency. To handle this, you’ll be able to experiment with altering the look-back interval in days to find out probably the most optimum interval. Check durations of 15 days and 5 days — evaluation reveals that the 5-day interval usually generates higher returns in comparison with the 15-day interval.
Absolute Momentum, additionally known as time-series momentum, includes buying belongings that exhibit constructive returns over a given timeframe and promoting these with unfavourable returns. This technique is predicated on analyzing historic efficiency inside a set interval to make buying and selling choices.
For implementing Absolute Momentum, the method includes the next steps:
Calculate Inventory Returns: Decide the share change within the inventory worth for the specified interval.Generate a Buying and selling Sign: Set up indicators primarily based on the calculated returns — constructive returns suggest a purchase sign, whereas unfavourable returns set off a promote sign.Easy Alerts Utilizing Shifting Averages: To filter out noise, compute a shifting common of the uncooked indicators.Decide Ultimate Alerts: Convert the smoothed sign into actionable buying and selling directions:Use +1+1+1 to point a purchase order, −1–1−1 for a promote order, and 000 to indicate holding the place.def absolute_momentum(df, window):”””Calculate the each day returnCalculate a sign: if return is constructive, then 1, if unfavourable -1, else 0Calculate a shifting common over “window” interval to clean the signalCalulate the ultimate sign:if the smoothed sign is constructive then a purchase (1) order sign is triggered,when unfavourable a promote order is trigerred (-1),else keep in a maintain place (0)”””df[‘returns’] = df[‘Adj Close’].pct_change()df[‘signals’]=np.the place(df[‘returns’]>0,1,np.the place(df[‘returns’]<0,-1,0))df[‘signals_ma’]=df[‘signals’].rolling(window).imply()df[‘signals_final’]=np.the place(df[‘signals_ma’]>0,1,np.the place(df[‘signals_ma’]<0,-1,0))return df
#Calculate the signalsdf = absolute_momentum(df, 30)df[[‘returns’]].plot(figsize=(8,4))plt.title(“Returns”)plt.present()df[[‘signals_ma’,’signals_final’]].plot(figsize=(8,4))plt.legend(loc = ‘higher left’)plt.title(“Absolute Momentum”)plt.present()
Within the second graph, the blue line represents the smoothed sign. When this line is above zero, it triggers a purchase sign represented by +1+1; when it falls beneath zero, a promote sign is generated and represented by −1–1.
Relative momentum is a method inside algorithmic buying and selling that evaluates how a inventory’s efficiency compares to that of the broader market or a selected benchmark. This system identifies shares which can be outperforming or underperforming both the market as an entire or a selected index.
Moreover, relative momentum can assess the power of a inventory’s efficiency over time relative to its personal historic habits. That is helpful for figuring out whether or not a inventory has been overbought or oversold inside a given time window, typically utilizing the Relative Energy Index (RSI) as a metric.
On this instance, the inventory below evaluation is Apple, and it’s benchmarked towards the S&P 500 index. The steps are outlined as follows:
Calculate 14-Day Shifting Common Returns: Compute the rolling imply returns for each the inventory and the index over a 14-day window.Compute the Relative Energy Ratio: Divide the rolling common return of the inventory by that of the index to acquire the relative power ratio.Generate the Relative Energy Line: Apply a rolling imply to the relative power ratio to clean it additional and observe tendencies.Set up Buying and selling Alerts: Create indicators to purchase or promote primarily based on whether or not the relative power ratio is above or beneath the relative power line.window = 14
benchmark_ticker = ‘SPY’benchmark_data = download_stock_data(benchmark_ticker,timestamp_start,timestamp_end).set_index(‘Date’)stock_returns = df[‘Adj Close’].pct_change()benchmark_returns = benchmark_data[‘Adj Close’].pct_change()
# Calculate rolling imply of the return over 14 days for the inventory and the indexstock_rolling_mean = stock_returns.rolling(window=window).imply()benchmark_rolling_mean = benchmark_returns.rolling(window=window).imply()
# Calculate relative strengthrelative_strength = stock_rolling_mean / benchmark_rolling_mean
# Calculate rolling imply of relative strengthrelative_strength_rolling_mean = relative_strength.rolling(window=window).imply()
# Create sign primarily based on relative power rolling meansignal = np.the place(relative_strength > relative_strength_rolling_mean, 1, -1)df_rel=pd.concat((stock_rolling_mean,benchmark_rolling_mean,relative_strength,relative_strength_rolling_mean),axis=1)df_rel.columns=[‘Stock_ma’,’Benchmark_ma’,’RS’,’RS_ma’]df_rel[‘signal’]=signaldf_rel=df_temp.dropna()df_rel.head()
download_stock_data* shall be defined in “Loading Dataset” half.
Right here is when plotting the entire interval:
df_rel[[‘RS’,’RS_ma’]].plot(figsize=(6,4))plt.title(‘Relative Momentum’)
df_rel[[‘signal’]].plot(figsize=(6,4))plt.title(‘Sign’)plt.present()
Let’s plot the ratio and the relative power line for a sure interval (to see extra clearly):
df_rel.question(“Date>’2022-08-30′ and Date<‘2022-11-30′”) [[‘RS’,’RS_ma’,’signal’]].plot(figsize=(8,8))
Definition
Twin Momentum is an algorithm that mixes two indicators: The relative power and absolutely the momentum. It’s primarily based on the concept that when a inventory is performing properly relative to its friends and on the identical time, its absolute momentum is constructive, it’s prone to proceed to carry out properly within the close to future.
Python Code
On this instance, I construct 2 datasets:
df_global: wherein we now have 4 shares (‘NFLX’, ‘AMZN’, ‘GOOG’, ‘AAPL’) that make up our portfolio. The aim is to know which one has a powerful twin momentum.
df_global_market: which represents the market or a selected benchmark. For illustration, I put solely 6 shares : ‘MSFT’, ‘META’, ‘GM’, ‘GS’, ‘TTE’, ‘F’.
Then:
The momentum for every inventory within the portfolio is computedThe momentum for the entire market is computedThen, the twin momentum is computed for every inventory within the portfolioAlso a rank among the many 4 shares is given for the entire intervaldef dual_momentum(df_global,df_global_market,window):”””dual_momentum:Calculate the momentum for every stockCalculate the momentum of the marketCalculate the twin momentum because the product of the inventory’s momentum and the market one”””# Calculate 10-days momentum of the pricesmom = df_global.pct_change(window).dropna()# Calculate 10-days momentum of the worldwide inventory marketglobal_mom = df_global_market.pct_change(window).dropna()global_mom_mean = global_mom.imply(axis=1)
# Create a knowledge body to carry the ultimate resultsresults = pd.DataFrame()for ticker in df_global.columns:mom_ticker = mother[ticker]# Calculate the twin momentum rating for this stockdual_mom = pd.DataFrame(mom_ticker * global_mom_mean)dual_mom.columns=[ticker+’_dual_mom’]outcomes=pd.concat((dual_mom,outcomes),axis=1)return outcomes
window=10results=dual_momentum(df_global,df_global_market,window)outcomes.iloc[-30:,:].plot(figsize=(12,6))plt.title(“Twin Momentum”)plt.present()outcomes.apply(lambda x: x.rank(ascending=False),axis=1).iloc[-30:,:].plot(figsize=(12,6))plt.title(“Rank of Twin Momentum (1:Greatest, 4:Worst)”)plt.present()
I solely plotted the final 30 days for readability within the chart:
Within the final interval, Google is ranked N°1 towards the opposite shares, as a result of it’s exhibiting a powerful twin momentum. The next one within the rating is Apple. The final one is Netflix.
This rating, as you’ll be able to see within the graph, was not fixed over the previous 30 days. Apple was typically ranked 4. However, we will see Netflix taking the primary place on the rostrum extra typically than the opposite shares.
There are completely different options to obtain datasets. Listed below are two strategies you should use:
First methodology
import pandas_datareader.knowledge as webimport yfinance as yfin
begin = dt.datetime(2022, 1, 1)finish = dt.datetime.right now()yfin.pdr_override()
# Outline the ticker image for the stockticker = ‘AAPL’
# Load the inventory costs from Yahoo Financedf = internet.DataReader(ticker, begin, finish)df.tail()
I discover it slower than the second methodology, which I used for the entire datasets.
Second methodology
AAPL
def download_stock_data(ticker,timestamp_start,timestamp_end):url=f”https://query1.finance.yahoo.com/v7/finance/obtain/{ticker}?period1={timestamp_start}&period2={timestamp_end}&interval=1d&occasions=historical past&includeAdjustedClose=true”df = pd.read_csv(url)return df
datetime_start=dt.datetime(2022, 1, 1, 7, 35, 51)datetime_end=dt.datetime.right now()
# Convert to timestamp:timestamp_start=int(datetime_start.timestamp())timestamp_end=int(datetime_end.timestamp())df = download_stock_data(“AAPL”,timestamp_start,timestamp_end)df = df.set_index(‘Date’)
SPY
benchmark_ticker = ‘SPY’benchmark_data = download_stock_data(benchmark_ticker,timestamp_start,timestamp_end).set_index(‘Date’)
df_global with 4 shares:
tickers=[‘AAPL’,’GOOG’,’AMZN’,’NFLX’]
df_global=pd.DataFrame()
for ticker in tickers:df = download_stock_data(ticker,timestamp_start,timestamp_end)[[‘Date’,’Adj Close’]]df = df.set_index(‘Date’)df.columns=[ticker]df_global=pd.concat((df_global, df),axis=1)
df_global.head()
df_global_market with 6 shares
tickers=[‘MSFT’,’META’,’GM’,’GS’,’TTE’,’F’]
df_global_market=pd.DataFrame()
for ticker in tickers:df = download_stock_data(ticker,timestamp_start,timestamp_end)[[‘Date’,’Adj Close’]]df = df.set_index(‘Date’)df.columns=[ticker]df_global_market=pd.concat((df_global_market, df),axis=1)
df_global_market.head()