Momentum Investing with R (2024)

[This article was first published on R Views, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

After an extended hiatus, Reproducible Finance is back! We’ll celebrate by changing focus a bit and coding up an investment strategy called Momentum. Before we even tiptoe in that direction, please note that this is not intended as investment advice and it’s not intended to be a script that can be implemented for trading. The goal is to explore some R code flows applied to a real-world project. Don’t live-trade this at home!

Back to the substance of the day, the theory behind momentum investing is that an asset that has done well in the recent past will continue to do so. It’s not “buy low and sell high”. It’s “buy high, and sell higher”! What might explain this anomaly? Behavioral economics has some possible answers, like anchoring, disposition, and herding.

In practice, momentum entails a look back into the past to determine whether an asset has exceeded some benchmark, and if it has, buy and hold that asset for some time into the future. That’s completely flying in the face of the efficient market hypothesis because it’s positing that the past is somehow giving us information that has not been reflected in the current price of the asset.

There’s a plethora of fascinating research on momentum investing; here’s a sampling.

The seminal academic paper is Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency by Jegadeesh and Titman from way back in 1993.

An excellent primer on the philosophy of momentum (and where I would recommend to start) is this piece from Alpha Architect. From there, AA also has a treasure trove of momentum posts here. More recently, there are two excellent and more advanced research papers from ReSolve Asset Management, with some excellent data visualizations, andNewfound Research, with a concise explanation of the strategy logic.

That’s a lot of material – here’s a short quotation from Fama and French by way of Alpha Architect that should provide us plenty of motivation:
“The premier anomaly is momentum.” 1

Let’s get to it and load up some packages.

library(tidyverse)library(highcharter)library(tibbletime)library(tidyquant)library(timetk)library(riingo)

We are going to implement a simplified version of a momentum strategy that deals with 4 assets:

+ SPY, an SP500 ETF+ EFA, a global equities ETF+ AGG, a bond ETF+ TLT, a treasuries ETF

The strategy logic goes as follows: compare the previous twelve months’ returns of the SP500 (SPY) to treasury bonds (TLT). If the returns of SPY do not exceed those of TLT, hold bonds (AGG) for the next month. If SPY returns do exceed TLT, compare the previous 12 months’ returns of the SP500 to the non-US equities (EFA). Whichever of SP500 or non-US equities had the higher previous twelve months’ returns, hold that asset for the next month. Thus, each month, our strategy will hold either AGG, SPY or EFA and we reexamine at the end of each month. That’s twelve look-backs per year, and twelve possible buy/sell transactions per year.

Here is the trading logic broken down into more code-oriented steps:1) Import prices for SPY, TLT, AGG and EFA2) Convert to monthly prices3) Convert AGG to monthly returns4) Convert TLT to twelve months’ returns5) Convert SPY and EFA to both monthly and twelve month’s returns6) Each month, compare previous twelve months’ SPY returns to those of TLT; if TLT exceeds SPY, hold AGG next month7) Else, compare previous twelve months’ SPY returns to EFA8) If previous twelve months’ SPY returns exceeded those of EFA, hold SPY next month9) If previous twelve months’ EFA returns exceeded those of SPY, hold EFA next month

Let’s start by importing the price data from tiingo. We used tiingo via the riingo package in a previous post, if you’d like to see it in a different context and get a bit more explanation.

We’ll first create a vector that holds tickers for SPY, AGG, EFA and TLT, and then pass that vector to riingo_prices().

# riingo requires an API key. You can get one free from tiingo.com# riingo_set_token("your API key here")symbols <- c("SPY", "AGG", "EFA", "TLT")symbols %>% riingo_prices(., start_date = "2000-01-01", end_date = "2018-12-31") %>% mutate(date = ymd(date)) %>% # see what happens if don't group_by here group_by(ticker) %>% slice(1)# A tibble: 4 x 14# Groups: ticker [4] ticker date close high low open volume adjClose adjHigh adjLow <chr> <date> <dbl> <dbl> <dbl> <dbl> <int> <dbl> <dbl> <dbl>1 AGG 2003-09-26 102. 102. 102 102 1.18e4 60.9 60.9 60.72 EFA 2001-08-17 126. 126. 125. 126 1.61e5 27.0 27.0 26.93 SPY 2000-01-03 145. 148. 144. 148. 8.16e6 101. 103. 100. 4 TLT 2002-07-26 82.5 82.8 82.4 82.7 3.16e5 44.6 44.7 44.5# … with 4 more variables: adjOpen <dbl>, adjVolume <int>, divCash <dbl>,# splitFactor <dbl>

We imported price data for each of our ETFs, but they don’t have the same inception dates. AGG launched in September of 2003, so that’s when we’ll be constrained to as a start date. We will have about 15 years of data.

As noted above, our strategy is tied to a monthly periodicity, looking back twelve months to determine if we wish to hold a certain asset for the next month. Let’s convert our daily prices to monthly prices with tq_transmute(select = adjClose, mutate_fun = to.monthly, indexAt = "lastof") from the tidyquant package. We are telling that function to convert the column called ‘adjClose’ to monthly prices, and anchored to the end of the month. We will store the results in an object called prices_monthly.

prices_monthly <- symbols %>% riingo_prices(., start_date = "2000-01-01", end_date = "2018-12-31") %>% mutate(date = ymd(date)) %>% group_by(ticker) %>% tq_transmute(select = adjClose, mutate_fun = to.monthly, indexAt = "lastof")

Let’s use slice(1, n()) to grab the first and last observation for each of our funds. The last observation is considered the nth observation here.

prices_monthly %>% slice(1, n())# A tibble: 8 x 3# Groups: ticker [4] ticker date adjClose <chr> <date> <dbl>1 AGG 2003-09-30 61.12 AGG 2018-12-31 105. 3 EFA 2001-08-31 26.84 EFA 2018-12-31 58.85 SPY 2000-01-31 97.36 SPY 2018-12-31 249. 7 TLT 2002-07-31 44.68 TLT 2018-12-31 120. 

We have monthly prices for our funds, with differing start dates and a common end date. Now let’s start to wrangle this data into a format that is suited for our strategy’s logic. Recall that we wish to implement this flow:

  1. If prev twelve months’ SPY returns is lower than TLT’s, buy/hold AGG this month, else move to step 2.
  2. If prev twelve months’ SPY is higher then prev twelve months’ EFA, buy/hold SPY this month, else move to step 3.
  3. If prev twelve months’ EFA is higher then prev twelve months’ SPY, buy/hold EFA this month.

Since we need to compare the past twelve months’ return of SPY to that of TLT and then to that of EFA, it will be nice if those twelve months’ returns for each asset are in three separate columns. That means we’ll want a tibble with one column for twelve month’s returns of SPY, one column for twelve months’ returns of TLT, and one column for 12 months’ returns of EFA.

Honestly, that last sentence makes me pause and wonder if I’m doing something totally wrong. Any time I start taking data that is tidy and making it wider, I stop and think about why I need to do that. There is currently one column for prices, one column for the date, and one column for the ticker name.

# A tibble: 8 x 3# Groups: ticker [4] ticker date adjClose <chr> <date> <dbl>1 AGG 2003-09-30 61.12 AGG 2003-10-31 60.53 EFA 2001-08-31 26.84 EFA 2001-09-30 24.25 SPY 2000-01-31 97.36 SPY 2000-02-29 95.87 TLT 2002-07-31 44.68 TLT 2002-08-31 47.0

To me, by putting those symbols in one column, we are treating them as being the same variable but different categories or groups of that variable. However, our trading logic treats them as different classes of assets entirely, not just different groups within the same thing called ‘ticker’. Plus, it’s easier to compare these assets with if_else() logic when they are in different columns. So, we’ll take this nice, tidy tibble of ETF prices and make it wider with different returns data.

Let’s get to it and hopefully that will make sense.

Since we are going to be calculating monthly and rolling twelve month returns for several assets and mashing them together, let’s run the calculations in pieces then join them. We’ll start with TLT, which means using filter(ticker == "TLT"). Then we’ll use mutate() to calculate twelve-month returns. Notice that we use quite verbose names for the new column, e.g., tbill_twelve_mon_ret. That will get cumbersome, but it will also help our human eyes to quickly glance at our end data and find the new columns.

n_lag <- 12risk_free_tlt <- prices_monthly %>% filter(ticker == "TLT") %>% mutate(tbill_twelve_mon_ret = ((adjClose / lag(adjClose, n_lag)) - 1)) %>% # Why ungroup here? If we don't tibble won't let us delete the ticker column ungroup() %>% select(-adjClose, -ticker) %>% na.omit()risk_free_tlt %>% head()# A tibble: 6 x 2 date tbill_twelve_mon_ret <date> <dbl>1 2003-07-31 0.05352 2003-08-31 0.01153 2003-09-30 0.02794 2003-10-31 0.03505 2003-11-30 0.04816 2003-12-31 0.0162

We calculated just the twelve months’ returns and did not include the one month return, because our logic does not contemplate holding this asset for even a month. We use AGG for our bond exposure. But, the twelve months’ returns of AGG are not part of our logic, so we won’t calculate that. This is another reason to break up these returns calculations and then do a big join at the end.

We will calculate the one month returns of AGG with the exact same code, except we lag by one instead of twelve.

bond_returns <- prices_monthly %>% filter(ticker == "AGG") %>% mutate(bond_return = ((adjClose / lag(adjClose, 1)) - 1)) %>% ungroup() %>% select(-adjClose, -ticker) %>% na.omit()bond_returns %>% head()# A tibble: 6 x 2 date bond_return <date> <dbl>1 2003-10-31 -0.009352 2003-11-30 0.003353 2003-12-31 0.009794 2004-01-31 0.004415 2004-02-29 0.0114 6 2004-03-31 0.00684

For EFA and SPY, we need to calculate both twelve months’ returns and one month returns. The code flow for calculating their returns are identical. I’m not going to delete the ticker column from SPY, but I will rename it to mom_asset (just in case we want to try different assets later, or even use Shiny to dynamically choose different assets).

equities_ex_us_returns <- prices_monthly %>% filter(ticker == "EFA") %>% mutate(ex_us_return = ((adjClose / lag(adjClose)) - 1), ex_us_twelve_mon_ret = log(adjClose) - log(lag(adjClose, n_lag))) %>% ungroup() %>% select(-adjClose, -ticker) %>% na.omit()sp_500_returns <- prices_monthly %>% filter(ticker == "SPY") %>% mutate(spy_return = ((adjClose / lag(adjClose)) - 1), spy_twelve_mon_ret = ((adjClose / lag(adjClose, n_lag)) - 1)) %>% select(-adjClose) %>% rename(mom_asset = ticker)

We now have four tibbles of returns, and want to combine them to one tibble. They all have a column called date, so we can run a bunch of calls to left_join(..., by = "date").

joined_returns_tbl <-sp_500_returns %>% left_join(risk_free_tlt, by = "date") %>% left_join(equities_ex_us_returns, by = "date") %>% left_join(bond_returns, by = "date") %>% na.omit()joined_returns_tbl %>% head()# A tibble: 6 x 8# Groups: mom_asset [1] mom_asset date spy_return spy_twelve_mon_… tbill_twelve_mo… <chr> <date> <dbl> <dbl> <dbl>1 SPY 2003-10-31 0.0535 0.209 0.03502 SPY 2003-11-30 0.0109 0.151 0.04813 SPY 2003-12-31 0.0503 0.282 0.01624 SPY 2004-01-31 0.0198 0.340 0.04115 SPY 2004-02-29 0.0136 0.377 0.03296 SPY 2004-03-31 -0.0132 0.356 0.0619# … with 3 more variables: ex_us_return <dbl>, ex_us_twelve_mon_ret <dbl>,# bond_return <dbl>

Alright, we now have one massive tibble called joined_returns_tbl with eight columns. Those verbose names will come in handy here. For example, if we want to see all our twelve month calculations, we can use select(date, contains("twelve")) to grab each column whose name contains the string “twelve”.

joined_returns_tbl %>% select(date, contains("twelve")) %>% head()# A tibble: 6 x 5# Groups: mom_asset [1] mom_asset date spy_twelve_mon_r… tbill_twelve_mon… ex_us_twelve_mo… <chr> <date> <dbl> <dbl> <dbl>1 SPY 2003-10-31 0.209 0.0350 0.2502 SPY 2003-11-30 0.151 0.0481 0.2213 SPY 2003-12-31 0.282 0.0162 0.3354 SPY 2004-01-31 0.340 0.0411 0.3905 SPY 2004-02-29 0.377 0.0329 0.4346 SPY 2004-03-31 0.356 0.0619 0.458

We selected twelve months’ returns for SPY, EFA, and TLT so we can quickly glance at the new data and make sure it looks how we were expecting.

Next, we’ll implement the trading logic, which is, to repeat:

  1. If previous twelve months SP500 returns are lower than treasuries, buy/hold bonds via AGG this month, else to next step.
  2. If previous twelve months SP500 returns higher than EFA (equities ex us proxy), buy/hold SP500 this month.
  3. If previous twelve months EFA returns higher than SP500, buy/hold EFA this month.

We can implement this using the if_else() function from dplyr, and we’ll place those if_else() calls inside mutate(). To implement step one, we writeif_else(lag(spy_twelve_mon_ret) < lag(tbill_twelve_mon_ret), bond_return, which in English says if the lagged 12-month SPY return is less than the lagged 12-month TLT return, then this month we invest in AGG, or we book the one month return of AGG. We follow that with the else logic,if_else(lag(spy_twelve_mon_ret) > lag(ex_us_twelve_mon_ret), spy_return, and that with our final else logic, ex_us_return. We labeled the new column that holds the results of those if_else() statements as strat_returns.

It might be interesting or important to know when the strategy is holding AGG, SPY, or EFA, so let’s create a column called strat_label that has the values bond, spy, and ex-us depending on where the strategy invests. That would allow us to calculate and visualize, for example, the proportion of time spent invested in EFA.

joined_returns_tbl %>% # encode logic, if ticker higher than tbill, we could complicate this by adding in other # assets for comparison. mutate(strat_returns = if_else(lag(spy_twelve_mon_ret) < lag(tbill_twelve_mon_ret), bond_return, if_else(lag(spy_twelve_mon_ret) > lag(ex_us_twelve_mon_ret), spy_return, ex_us_return)), strat_label = if_else(lag(spy_twelve_mon_ret) < lag(tbill_twelve_mon_ret), "bond", if_else(lag(spy_twelve_mon_ret) > lag(ex_us_twelve_mon_ret), "spy", "ex_us"))) %>% na.omit() %>% select(date, contains("strat")) %>% head()# A tibble: 6 x 4# Groups: mom_asset [1] mom_asset date strat_returns strat_label <chr> <date> <dbl> <chr> 1 SPY 2003-11-30 0.0253 ex_us 2 SPY 2003-12-31 0.0834 ex_us 3 SPY 2004-01-31 0.0113 ex_us 4 SPY 2004-02-29 0.0230 ex_us 5 SPY 2004-03-31 0.000707 ex_us 6 SPY 2004-04-30 -0.0339 ex_us 

All right, the logic or the signal is encoded. Let’s add a column for a 80/20 SPY/AGG portfolio as a sort of buy and hold benchmark and then save the whole massive tibble as strat_returns.

strat_returns <-joined_returns_tbl %>% # encode logic, if ticker higher than tbill, we could complicate this by adding in other # assets for comparison. mutate(strat_returns = if_else(lag(spy_twelve_mon_ret) < lag(tbill_twelve_mon_ret), bond_return, if_else(lag(spy_twelve_mon_ret) > lag(ex_us_twelve_mon_ret), spy_return, ex_us_return)), strat_label = if_else(lag(spy_twelve_mon_ret) < lag(tbill_twelve_mon_ret), "bond", if_else(lag(spy_twelve_mon_ret) > lag(ex_us_twelve_mon_ret), "spy", "ex_us")), bench_returns = (.8 * spy_return) + (.2 * bond_return)) %>% na.omit() %>% select(date, bench_returns, contains("strat"))

Let’s see how frequently we are invested in bonds versus SPY versus equities ex-USA.

strat_returns %>% count(strat_label) %>% mutate(prop = prop.table(n))# A tibble: 3 x 4# Groups: mom_asset [1] mom_asset strat_label n prop <chr> <chr> <int> <dbl>1 SPY bond 63 0.3462 SPY ex_us 55 0.3023 SPY spy 64 0.352

Let’s visualize the same data with a bar chart using geom_col() and the height set to the proportion of months in each asset. Instead of using a legend, or placing the labels on the x-axis, we will place them on the chart above the bars.

First we add the labels with geom_label(aes(label = strat_label) and let’s make them white with fill = "white". We can remove the legend with theme(legend.position = "none") and the x-axis text can be removed with theme(...axis.text.x = element_blank(), axis.ticks = element_blank()).

strat_returns %>% count(strat_label) %>% mutate(prop = prop.table(n)) %>% ggplot(aes(x = strat_label, y = prop, fill = strat_label)) + geom_col(width = .15) + scale_y_continuous(labels = scales::percent) + geom_label(aes(label = strat_label), vjust = -.5, fill = "white") + ylab("relative frequencies") + xlab("") + expand_limits(y = .4) + theme(legend.position = "none", axis.text.x = element_blank(), axis.ticks = element_blank()) 

Momentum Investing with R (1)

Since the data is in a nice, tidy format, we can also head straight to highcharter to build an interactive bar chart.

strat_returns %>% count(strat_label) %>% mutate(prop = prop.table(n)) %>% hchart(., hcaes(x = strat_label, y = prop, color = strat_label), type = "column", pointWidth = 30) %>% hc_tooltip(pointFormat = "{point.strat_label}: {point.prop: .2f}")

Maybe we want to see the distribution of returns for each strategy. Here is a histogram of each using geom_histogram().

strat_returns %>% ungroup() %>% select(bench_returns, strat_returns) %>% gather(type, returns) %>% ggplot(aes(returns, color = type, fill = type)) + geom_histogram(bins = 60) + facet_wrap(~type)

Momentum Investing with R (2)

Here’s a horizontal box plot and violin chart built using a combination of gom_boxplot and geom_violin().

strat_returns %>% ungroup() %>% select(bench_returns, strat_returns) %>% gather(type, returns) %>% ggplot(aes(x = type, y = returns, color = type, fill = type)) + geom_boxplot(width = 0.1, fill = "white")+ geom_violin(alpha = .05) +coord_flip()

Momentum Investing with R (3)

The distribution of returns is helpful, but let’s also have a look at which returns path delivered the highest growth. We won’t take account of risk here; we’ll just visualize how one dollar would have grown in each strategy. We will start with the seemingly underused accumulate() function from purrr to create two new columns called strat_growth and bench_growth. Then we use select(date, contains("growth")) to isolate just the date and growth columns.

strat_growth <- strat_returns %>% mutate(strat_growth = accumulate(1 + strat_returns, `*`), bench_growth = accumulate(1 + bench_returns, `*`)) %>% ungroup() %>% select(date, contains("growth")) %>% gather(strat, growth, -date)

Now we can pipe strat_growth to hchart().

strat_growth %>% hchart(., hcaes(x = date, y = growth, group = strat), type = "line") %>% hc_tooltip(pointFormat = "{point.strat}: ${point.growth: .2f}")

Our momentum strategy did not grow as much as a pure buy-hold strategy. Let’s check some summary statistics by using tq_performance() and table.Stats.

strat_returns %>% ungroup() %>% select(date, strat_returns, bench_returns) %>% gather(strats, returns, -date) %>% group_by(strats) %>% tq_performance(Ra = returns, performance_fun = table.Stats) %>% gather(stat, value, -strats)# A tibble: 32 x 3# Groups: strats [2] strats stat value <chr> <chr> <dbl> 1 strat_returns ArithmeticMean 0.0056 2 bench_returns ArithmeticMean 0.0064 3 strat_returns GeometricMean 0.0052 4 bench_returns GeometricMean 0.0059 5 strat_returns Kurtosis 1.18 6 bench_returns Kurtosis 2.57 7 strat_returns LCLMean(0.95) 0.0016 8 bench_returns LCLMean(0.95) 0.0018 9 strat_returns Maximum 0.083410 bench_returns Maximum 0.0876# … with 22 more rows

Thus far, our strategy seems inferior to buy-hold. Let’s check the max drawdowns with the table.DownsideRisk function.

strat_returns %>% ungroup() %>% select(date, strat_returns, bench_returns) %>% gather(strats, returns, -date) %>% group_by(strats) %>% tq_performance(Ra = returns, performance_fun = table.DownsideRisk) %>% gather(stat, value, -strats)# A tibble: 22 x 3# Groups: strats [2] strats stat value <chr> <chr> <dbl> 1 strat_returns DownsideDeviation(0%) 0.0178 2 bench_returns DownsideDeviation(0%) 0.0213 3 strat_returns DownsideDeviation(MAR=10%) 0.0217 4 bench_returns DownsideDeviation(MAR=10%) 0.025 5 strat_returns DownsideDeviation(Rf=0%) 0.0178 6 bench_returns DownsideDeviation(Rf=0%) 0.0213 7 strat_returns GainDeviation 0.0173 8 bench_returns GainDeviation 0.0176 9 strat_returns HistoricalES(95%) -0.061110 bench_returns HistoricalES(95%) -0.0727# … with 12 more rows

If we isolate the MaximumDrawdown and VaR measures, we see this:

strat_returns %>% ungroup() %>% select(date, strat_returns, bench_returns) %>% gather(strats, returns, -date) %>% group_by(strats) %>% tq_performance(Ra = returns, performance_fun = table.DownsideRisk) %>% select(MaximumDrawdown, contains("VaR"))# A tibble: 2 x 4# Groups: strats [2] strats MaximumDrawdown `HistoricalVaR(95%)` `ModifiedVaR(95%)` <chr> <dbl> <dbl> <dbl>1 strat_returns 0.169 -0.0424 -0.04212 bench_returns 0.422 -0.0496 -0.0503

The momentum strat didn’t grow as much as buy-hold, but it had a far smaller max drawdown.

That’s all for today - thanks for reading!

A couple of plugs before we close:

If you like this sort of thing, check out my book, Reproducible Finance with R.

This is not specific to finance, but several of the stringr and ggplot tricks in this post came from this awesome Business Science University course.

Want to get into Momentum Investing? Have a look at this book Quantitative Momentum first.

Happy coding!

  1. Fama, E. and K. French, 2008, Dissecting Anomalies, The Journal of Finance, 63, pg. 1653-1678.]

Related

To leave a comment for the author, please follow the link and comment on their blog: R Views.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Momentum Investing with R (2024)

FAQs

Is momentum trading legit? ›

Momentum Investment Limited is not a trusted broker because it is not regulated by a financial authority with strict standards. We would not open an account for ourselves with them. If you want to stay safe, only sign up with brokers that are overseen by a top-tier and stringent regulator.

Is momentum a good investment? ›

Momentum investing helps only when you are aware of the various market nuances. Momentum investing, a widely adopted investment approach, seeks to generate profits by capitalising on upward trends while steering clear of assets on a downward trajectory.

Who is a famous momentum investor? ›

The investing principle was made popular by Richard Driehaus, who is also known as the father of momentum investing. According to him, one can make far more money by buying high and selling at even higher prices instead of looking for undervalued securities.

What is the formula for momentum in investing? ›

Momentum is measured by continually taking price differences for a fixed time period. To create a 10 day period momentum line you would subtract the closing price from 10 days ago from the last closing price.

How profitable is momentum trading? ›

Potential for High Profits Over a Short Period

You then sell at a profit of 50% before the stock price corrects itself. You've made a 50% return over the course of a few weeks or months (not an annualized return). Over time, the profit potential increase using momentum investing can be staggeringly large.

What is a momentum trap? ›

Momentum Trap stocks are those with low durability scores, expensive valuation, but high momentum. These stocks are risky bets that investors may be drawn to due to changes in share price. They however do not necessarily justify existing valuations and share price gains. Click to see classifications.

What are the disadvantages of momentum funds? ›

Reversal risk: Momentum funds are highly volatile compared to other mutual funds, as they invest in stocks that have shown rapid price appreciation. However, there is a high risk of a trend reversal. Markets are inherently unpredictable and asset prices that have exhibited strong recent momentum may suddenly plummet.

Which trading is best for beginners? ›

Overview: Swing trading is an excellent starting point for beginners. It strikes a balance between the fast-paced day trading and long-term investing.

What are the best momentum stocks today? ›

Momentum Stocks
SymbolCompany NameTwelve Minus One Return
JANXJANUX THERAPEUTICS INC280.6%
STTKSHATTUCK LABS INC273.9%
CRBPCORBUS PHARMACEUTICALS HOLDINGS INC273.1%
COINCOINBASE GLOBAL INC254.8%
26 more rows

How successful is momentum investing? ›

While average time-series momentum returns have been high, momentum investors have also experienced huge drawdowns at turning points (which mark reversals in trend from uptrend to downtrend or vice versa) because momentum strategies are prone to place bad bets.

Who is World No 1 investor? ›

Warren Buffet

Warren Buffett is widely considered the greatest investor in the world. Born in 1930 in Omaha, Nebraska, Buffett began investing at a young age and became the chairman and CEO of Berkshire Hathaway, one of the world's largest and most successful investment firms.

How to use momentum investing? ›

Momentum traders will seek to identify how strong the trend is in a given direction, then open a position to take advantage of the expected price change and close the position when the trend starts to lose its strength.

What is the best momentum indicator? ›

Moving Average Convergence Divergence (MACD)

Often regarded as the best momentum indicator, MACD is a trend-following indicator. It represents the relationship between 2 moving averages of a financial instrument's price.

How to build a momentum portfolio? ›

Given the above, here is a systematic guide to building a 'Momentum Portfolio'.
  1. Step 1 – Define your stock universe. ...
  2. Step 2 – Set up the data. ...
  3. Step 3 – Calculate returns. ...
  4. Step 4 – Rank the returns. ...
  5. Step 5 – Create the portfolio. ...
  6. Step 6 – Rebalance the portfolio.

How do I choose a stock for momentum investing? ›

Following the stock market trend is a safe and risk free way to find momentum trading stocks. Strong stocks: The pace of momentum determines if a stock is strong or weak. If the movement is higher than the market rate, it is a stronger stock, and a slower pace determines weaker stocks.

Is momentum trading the same as scalping? ›

Momentum trading is mostly aligned with scalp trading where traders capitalize on smaller price fluctuations of the larger move. Scalping modifies the approach to risk management by focusing more heavily on the probability component of the equation.

Is momentum a good indicator? ›

1 For trending analysis, momentum is a useful indicator of strength or weakness in the issue's price. History has shown that momentum is far more useful during rising markets than falling markets because markets rise more often than they fall. In other words, bull markets tend to last longer than bear markets.

Is momentum trading the same as trend trading? ›

Difference No.

For instance, a momentum strategy might involve going long Nvidia and short Intel. On the other hand, trend following, being a macro style factor, is implemented by using derivatives across various macro asset classes including equities, fixed income, currencies, and commodities.

Does momentum beat the market? ›

Quoting the authors: “Compared to the market, value or size risk factors, momentum has offered investors the highest Sharpe ratio.

Top Articles
Latest Posts
Article information

Author: Fr. Dewey Fisher

Last Updated:

Views: 5868

Rating: 4.1 / 5 (62 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Fr. Dewey Fisher

Birthday: 1993-03-26

Address: 917 Hyun Views, Rogahnmouth, KY 91013-8827

Phone: +5938540192553

Job: Administration Developer

Hobby: Embroidery, Horseback riding, Juggling, Urban exploration, Skiing, Cycling, Handball

Introduction: My name is Fr. Dewey Fisher, I am a powerful, open, faithful, combative, spotless, faithful, fair person who loves writing and wants to share my knowledge and understanding with you.