diff --git "a/04 Strategy Library/01 CAPM Alpha Ranking Strategy on Dow 30 Companies/05 \347\256\227\346\263\225.cn.html" "b/04 Strategy Library/01 CAPM Alpha Ranking Strategy on Dow 30 Companies/05 \347\256\227\346\263\225.cn.html" index 1f296ed..4a79e84 100644 --- "a/04 Strategy Library/01 CAPM Alpha Ranking Strategy on Dow 30 Companies/05 \347\256\227\346\263\225.cn.html" +++ "b/04 Strategy Library/01 CAPM Alpha Ranking Strategy on Dow 30 Companies/05 \347\256\227\346\263\225.cn.html" @@ -4,6 +4,6 @@
diff --git a/04 Strategy Library/02 Combining Mean Reversion and Momentum in Forex Market/06 Algorithm.html b/04 Strategy Library/02 Combining Mean Reversion and Momentum in Forex Market/06 Algorithm.html index 5c357f4..9717146 100755 --- a/04 Strategy Library/02 Combining Mean Reversion and Momentum in Forex Market/06 Algorithm.html +++ b/04 Strategy Library/02 Combining Mean Reversion and Momentum in Forex Market/06 Algorithm.html @@ -1,6 +1,6 @@ diff --git "a/04 Strategy Library/03 Pairs Trading-Copula vs Cointegration/06 \347\256\227\346\263\225.cn.html" "b/04 Strategy Library/03 Pairs Trading-Copula vs Cointegration/06 \347\256\227\346\263\225.cn.html" index 932854a..c5d9f52 100644 --- "a/04 Strategy Library/03 Pairs Trading-Copula vs Cointegration/06 \347\256\227\346\263\225.cn.html" +++ "b/04 Strategy Library/03 Pairs Trading-Copula vs Cointegration/06 \347\256\227\346\263\225.cn.html" @@ -4,7 +4,7 @@ @@ -14,6 +14,6 @@ diff --git a/04 Strategy Library/04 The Dynamic Breakout II Strategy/04 Algorithm.html b/04 Strategy Library/04 The Dynamic Breakout II Strategy/04 Algorithm.html index 58173b8..3358861 100755 --- a/04 Strategy Library/04 The Dynamic Breakout II Strategy/04 Algorithm.html +++ b/04 Strategy Library/04 The Dynamic Breakout II Strategy/04 Algorithm.html @@ -4,7 +4,7 @@@@ -13,6 +13,6 @@
diff --git a/04 Strategy Library/06 Can Crude Oil Predict Equity Returns/05 Algorithm.html b/04 Strategy Library/06 Can Crude Oil Predict Equity Returns/05 Algorithm.html index 01b99d6..0115518 100755 --- a/04 Strategy Library/06 Can Crude Oil Predict Equity Returns/05 Algorithm.html +++ b/04 Strategy Library/06 Can Crude Oil Predict Equity Returns/05 Algorithm.html @@ -4,6 +4,6 @@ diff --git a/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 Algorithm.html b/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 Algorithm.html index 69b6365..3d55776 100755 --- a/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 Algorithm.html +++ b/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 Algorithm.html @@ -1,6 +1,6 @@ diff --git "a/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 \347\256\227\346\263\225.cn.html" "b/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 \347\256\227\346\263\225.cn.html" index 69b6365..3d55776 100644 --- "a/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 \347\256\227\346\263\225.cn.html" +++ "b/04 Strategy Library/07 Intraday Dynamic Pairs Trading using Correlation and Cointegration Approach/06 \347\256\227\346\263\225.cn.html" @@ -1,6 +1,6 @@ diff --git a/04 Strategy Library/08 The Momentum Strategy Based on the Low Frequency Component of Forex Market/05 Algorithm.html b/04 Strategy Library/08 The Momentum Strategy Based on the Low Frequency Component of Forex Market/05 Algorithm.html index 03b3ba2..f9505bd 100755 --- a/04 Strategy Library/08 The Momentum Strategy Based on the Low Frequency Component of Forex Market/05 Algorithm.html +++ b/04 Strategy Library/08 The Momentum Strategy Based on the Low Frequency Component of Forex Market/05 Algorithm.html @@ -1,6 +1,6 @@ diff --git "a/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/04 \347\256\227\346\263\225.cn.html" "b/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/04 \347\256\227\346\263\225.cn.html" index bcf0bc2..d1a72fa 100644 --- "a/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/04 \347\256\227\346\263\225.cn.html" +++ "b/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/04 \347\256\227\346\263\225.cn.html" @@ -1,6 +1,6 @@ diff --git a/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/05 References.html b/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/05 References.html index 145c7bf..4d6f9c3 100644 --- a/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/05 References.html +++ b/04 Strategy Library/09 Stock Selection Strategy Based on Fundamental Factors/05 References.html @@ -1,5 +1,5 @@- This strategy is called Short-Term Reversal Strategy which is discussed in detail in the paper written by Wilma de Groot, Joop Huij and Weili Zhou (2011) titled "Another look at trading costs and short-term reversal profits". The standard reversal strategy takes the whole universe of stocks into consideration, while this paper limits the stock universe only to large cap stocks so that trading costs could be significantly reduced. -
-- One simple version of this strategy could be described like this: The investment universe consists of 100 biggest companies by market capitalization. We go long on the 10% stocks which have the lowest performances in the last month while going short on the 10% stocks with the highest ones. The portfolio is rebalanced weekly. - In the paper, however, strategies with different investment universes and different rebalancing frequencies are all backtested. The results show that, the larger the size of the investment universe, the larger the trading costs caused by extensively trading in small cap stocks which are less liquid; and trading costs become substantially lower when the rebalancing frequency is decreased from daily to weekly, but so do gross returns. - In this tutorial, we only use 100 stocks with weekly rebalancing for illustration. + In this tutorial, we implement a version of the short-term reversal strategy published by De Groot, Huij, & Zhou + (2012). The strategy works by observing the returns of each security in the universe over the previous month. Every + week, the algorithm longs the worst performers and shorts the top performers. The original strategy outlined in the + literature considers the entire universe of stocks when trading. To reduce trading costs, we limit our universe to + the most liquid large cap stocks. Our analysis shows the strategy underperforms the S&P 500 index during all our + backtest periods except the 2020 market crash.
diff --git a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/02 Method.html b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/02 Method.html index a666b03..8b9f021 100755 --- a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/02 Method.html +++ b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/02 Method.html @@ -1,103 +1,141 @@- The strategy code mainly consists of three parts: Initialization, Warm Up, and Weekly Rebalancing. + The strategy code mainly consists of four parts: Initialization, Universe Selection, OnData, and OnSecuritiesChanged.
-- In the Initialize function, we set up look-back period, beginning cash balance, the size of the investment universe, the number of traded stocks, etc. We use self._numOfWeeks to count?the number of weeks that have passed since the start date, and self._LastDay to indicate whether it is a new week. self._ifWarmUp is true when the self._numOfWeeks is 3, which means as long as next week's data come, we can make our investment decisions.??self._stocks is a list containing all the symbols of the 100 stocks that are taken into consideration. self._values is a dictionary with keys the stock symbols and values the lists containing the prices of stock each week since 4 weeks ago. + When initializing the algorithm, we add a coarse universe selection method and specify several parameters to use + when selecting securities.
- def Initialize(self):
- self.SetStartDate(2005, 1, 1)
- self.SetEndDate(2017, 5, 10)
- self.SetCash(1000000)
-
+
+class ShortTimeReversal(QCAlgorithm):
+ def Initialize(self):
+ # ...
+
self.UniverseSettings.Resolution = Resolution.Daily
- self.AddUniverse(self.CoarseSelectionFunction)
- self._numberOfSymbols = 100
- self._numberOfTradings = int(0.1 * self._numberOfSymbols)
-
- self._numOfWeeks = 0
- self._LastDay = -1
- self._ifWarmUp = False
-
- self._stocks = []
- self._values = {}
+ self.AddUniverse(self.SelectCoarse)
+
+ self.dollar_volume_selection_size = 100
+ self.roc_selection_size = int(0.1 * self.dollar_volume_selection_size)
+
+ self.lookback = 22
+ self.roc_by_symbol = {}
+ self.week = 0
+
- Also, we need to use?CoarseSelectionFunction to select 100 qualified stocks from the total stock universe. Here, we sort the total stock universe by each stock's DollarVolume in decreasing order. Then, we select the first 100 stocks that have the largest DollarVolume among all the stocks in the universe. -
--def CoarseSelectionFunction(self, coarse): - sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) - top100 = sortedByDollarVolume[:self._numberOfSymbols] - return [i.Symbol for i in top100] --
- Before we are able to make our investment decisions, we must have at least 4 weeks' data to calculate the performance, i.e. the monthly return, of each stock. Hence, we need a warm up period as long as 3 weeks to accumulate price series, so that once the fourth week's data come we can calculate?the return of the whole month. + The coarse universe selection method creates a RateOfChange + indicator for each of the top 100 + most liquid securities in the market. Upon creation, the indicator is manually warmed-up with historical closing + prices. After the indicators are ready, the universe selects the securities with the 10 best and 10 worst + RateOfChange values.
+class ShortTimeReversal(QCAlgorithm):
+ # ...
+
+ def SelectCoarse(self, coarse):
+
+ # We should keep a dictionary for all securities that have been selected
+ for cf in coarse:
+ symbol = cf.Symbol
+ if symbol in self.roc_by_symbol:
+ self.roc_by_symbol[symbol].Update(cf.EndTime, cf.AdjustedPrice)
+
+ # Refresh universe each week
+ week_number = self.Time.date().isocalendar()[1]
+ if week_number == self.week:
+ return Universe.Unchanged
+ self.week = week_number
+
+ # sort and select by dollar volume
+ sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
+ selected = {cf.Symbol: cf for cf in sortedByDollarVolume[:self.dollar_volume_selection_size]}
+
+ # New selections need a history request to warm up the indicator
+ symbols = [k for k in selected.keys()
+ if k not in self.roc_by_symbol or not self.roc_by_symbol[k].IsReady]
+
+ if symbols:
+ history = self.History(symbols, self.lookback, Resolution.Daily)
+ if history.empty:
+ self.Log(f'No history for {", ".join([x.Value for x in symbols])}')
+ history = history.close.unstack(0)
+
+ for symbol in symbols:
-self._stocks = []
-self.uni_symbol = None
-symbols = self.UniverseManager.Keys
-for i in symbols:
- if str(i.Value) == "QC-UNIVERSE-COARSE-USA":
- self.uni_symbol = i
- for i in self.UniverseManager[self.uni_symbol].Members:
- self._stocks.append(i.Value.Symbol)
- self._values[i.Value.Symbol] = [self.Securities[i.Value.Symbol].Price]
+ if symbol not in history:
+ continue
+ # Create and warm-up the RateOfChange indicator
+ roc = RateOfChange(self.lookback)
+ for time, price in history[symbol].dropna().iteritems():
+ roc.Update(time, price)
+
+ if roc.IsReady:
+ self.roc_by_symbol[symbol] = roc
+
+ # Sort the symbols by their ROC values
+ selectedRateOfChange = {}
+ for symbol in selected.keys():
+ if symbol in self.roc_by_symbol:
+ selectedRateOfChange[symbol] = self.roc_by_symbol[symbol]
+ sortedByRateOfChange = sorted(selectedRateOfChange.items(), key=lambda kv: kv[1], reverse=True)
+
+ # Define the top and the bottom to buy and sell
+ self.rocTop = [x[0] for x in sortedByRateOfChange[:self.roc_selection_size]]
+ self.rocBottom = [x[0] for x in sortedByRateOfChange[-self.roc_selection_size:]]
+
+ return self.rocTop + self.rocBottom
- We get all the symbols of qualified stocks from UniverseManager and keep them in self._stocks which is a list. Then we create for each key in the dictionary self._values a list where its first week's price is stored. And every time new data come, we append the new price to the end of the list of each stock. -
-for stock in self._stocks: - self._values[stock].append(self.Securities[stock].Price)-
- After the warm-up period, we calculate monthly returns every week and based on the returns, we make our investment decisions. + As new data is passed to the OnData method, we issue orders to form a long-short portfolio. We long the securities + with the lowest RateOfChange values and short those with the largest values. After rebalancing, we clear the + `rocTop` and `rocBottom` lists to ensure we don’t trade again until the universe is refreshed.
-
+class ShortTimeReversal(QCAlgorithm):
+ # ...
-returns = {}
-for stock in self._stocks:
- newPrice = self.Securities[stock].Price
- oldPrice = self._values[stock].pop(0)
- self._values[stock].append(newPrice)
- returns[stock] = newPrice/oldPrice
+ def OnData(self, data):
+ # Rebalance
+ for symbol in self.rocTop:
+ self.SetHoldings(symbol, -0.5/len(self.rocTop))
+ for symbol in self.rocBottom:
+ self.SetHoldings(symbol, 0.5/len(self.rocBottom))
+
+ # Clear the list of securities we have placed orders for
+ # to avoid new trades before the next universe selection
+ self.rocTop.clear()
+ self.rocBottom.clear()
- Every week when new data come, we use them along with the data four weeks ago to calculate the monthly returns. At the same time, we remove the oldest data from our lists. This step is essential to prevent memory size exceeding the limit. + We are rebalancing the portfolio on a weekly basis, but securities can leave our defined universe between rebalance + days. To accommodate this, we liquidate any securities that are removed from the universe in the + OnSecuritiesChanged method.
-+class ShortTimeReversal(QCAlgorithm): + # ... -newArr = [(v,k) for k,v in returns.items()] -newArr.sort() -for ret, stock in newArr[self._numberOfTradings:-self._numberOfTradings]: - self.SetHoldings(stock, 0) -for ret, stock in newArr[0:self._numberOfTradings]: - self.SetHoldings(stock, 0.5/self._numberOfTradings) -for ret, stock in newArr[-self._numberOfTradings:]: - self.SetHoldings(stock, -0.5/self._numberOfTradings) + def OnSecuritiesChanged(self, changes): + for security in changes.RemovedSecurities: + self.Liquidate(security.Symbol, 'Removed from Universe')-
- Finally, we sort the returns in increasing order. For the stocks whose monthly returns fall into the first 10% (performed badly in last month), we long them; For those fall into the last 10% (performed well in last month), we short them. Others (between 10% and 90%) will be set to 0. -
+ \ No newline at end of file diff --git a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/03 Summary.html b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/03 Summary.html deleted file mode 100755 index 0c2b46e..0000000 --- a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/03 Summary.html +++ /dev/null @@ -1,5 +0,0 @@ -- In the paper, the look-back period is from 1990 to 2009. However, we want to test whether the strategy is still profitable in the new time period. Hence we use different look-back periods instead. - If we begin from 2005 and end in 2017, there will be a total return of 131.50%. Although to some extent the performance of this strategy is dependent on different market situations,?nevertheless, in either situation mentioned above, this strategy could significantly beat the S&P 500 benchmark. - Further research and backtesting could be done on different look-back periods, rebalancing frequencies, investment universes, numbers of traded stocks, etc. -
diff --git a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/04 Algorithm.html b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/04 Algorithm.html index 009e778..c2e37d5 100755 --- a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/04 Algorithm.html +++ b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/04 Algorithm.html @@ -1,6 +1,6 @@ diff --git a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/05 References.html b/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/05 References.html deleted file mode 100644 index 6c1e761..0000000 --- a/04 Strategy Library/10 Short-Term Reversal Strategy in Stocks/05 References.html +++ /dev/null @@ -1,5 +0,0 @@ -| Period Name | +Start Date | +End Date | +Strategy | +Sharpe | +Variance | +
|---|---|---|---|---|---|
| 5 Year Backtest | +1/1/2016 | +1/1/2021 | +Strategy | +0.24 | +0.058 | +
| Benchmark | +0.825 | +0.028 | +|||
| 2020 Crash | +2/19/2020 | +3/23/2020 | +Strategy | +-1.025 | +0.917 | +
| Benchmark | +-1.4 | +0.474 | +|||
| 2020 Recovery | +3/23/2020 | +6/8/2020 | +Strategy | +1.688 | +0.16 | +
| Benchmark | +8.765 | +0.103 | +
+ Although this strategy passes several of the + metrics required for Alpha Streams + and the Quant League competition, it requires further work to pass the following requirements: +
+ ++ The short-term reversal strategy implemented in this tutorial produced a lower Sharpe ratio than the S&P + 500 index ETF benchmark over all our testing periods except during the 2020 market crash. To continue the + development of this strategy, future areas of research include: +
+ ++ To continue the development of this strategy, future areas of research include: +
+ +- Here we use the Quandl API to retrieve data. -
-import quandl -quandl.ApiConfig.api_key = 'dRQxJ15_2nrLznxr1Nn4' --
- We will create a Series named "aapl" whose values are Apple's daily closing prices, which are of course indexed by dates: -
-aapl_table = quandl.get('WIKI/AAPL')
-aapl = aapl_table['Adj. Close']['2017']
-print aapl
-
-- Recall that we can fetch a specific data point using series['yyyy-mm-dd']. We can also fetch the data in a specific month using series['yyyy-mm']. -
-print aapl['2017-3'] -Date -2017-03-01 138.657681 -2017-03-02 137.834404 -2017-03-03 138.647762 -2017-03-06 138.211326 -2017-03-07 138.389868 -2017-03-08 137.874080 -2017-03-09 137.556672 -2017-03-10 138.012946 -2017-03-13 138.072460 -2017-03-14 137.864161 -2017-03-15 139.322254 -2017-03-16 139.550391 -2017-03-17 138.856061 -2017-03-20 140.314154 -2017-03-21 138.707276 -2017-03-22 140.274478 -2017-03-23 139.778528 -2017-03-24 139.500796 -2017-03-27 139.738852 -2017-03-28 142.635200 -2017-03-29 142.952608 -2017-03-30 142.764147 -2017-03-31 142.496334 --
- Or in several consecutive months: -
-aapl['2017-2':'2017-4'] --
- .head(N) and .tail(N) are methods for quickly accessing the first or last N elements. -
-print aapl.head() -print aapl.tail(10) --
- The output: -
--Date -2017-01-03 114.715378 -2017-01-04 114.586983 -2017-01-05 115.169696 -2017-01-06 116.453639 -2017-01-09 117.520300 -Name: Adj. Close, dtype: float64 -Date -2017-08-08 159.433108 -2017-08-09 160.409148 -2017-08-10 155.270000 -2017-08-11 157.480000 -2017-08-14 159.850000 -2017-08-15 161.600000 -2017-08-16 160.950000 -2017-08-17 157.870000 -2017-08-18 157.500000 -2017-08-21 157.210000 -Name: Adj. Close, dtype: float64 --
+ Here we use the Quandl API to retrieve data... +
+import quandl +quandl.ApiConfig.api_key = 'dRQxJ15_2nrLznxr1Nn4' ++
+ We will create a Series named "aapl" whose values are Apple's daily closing prices, which are of course indexed by dates: +
+aapl_table = quandl.get('WIKI/AAPL')
+aapl = aapl_table['Adj. Close']['2017']
+print aapl
+
++ Recall that we can fetch a specific data point using series['yyyy-mm-dd']. We can also fetch the data in a specific month using series['yyyy-mm']. +
+print aapl['2017-3'] +Date +2017-03-01 138.657681 +2017-03-02 137.834404 +2017-03-03 138.647762 +2017-03-06 138.211326 +2017-03-07 138.389868 +2017-03-08 137.874080 +2017-03-09 137.556672 +2017-03-10 138.012946 +2017-03-13 138.072460 +2017-03-14 137.864161 +2017-03-15 139.322254 +2017-03-16 139.550391 +2017-03-17 138.856061 +2017-03-20 140.314154 +2017-03-21 138.707276 +2017-03-22 140.274478 +2017-03-23 139.778528 +2017-03-24 139.500796 +2017-03-27 139.738852 +2017-03-28 142.635200 +2017-03-29 142.952608 +2017-03-30 142.764147 +2017-03-31 142.496334 ++
+ Or in several consecutive months: +
+aapl['2017-2':'2017-4'] ++
+ .head(N) and .tail(N) are methods for quickly accessing the first or last N elements. +
+print aapl.head() +print aapl.tail(10) ++
+ The output: +
++Date +2017-01-03 114.715378 +2017-01-04 114.586983 +2017-01-05 115.169696 +2017-01-06 116.453639 +2017-01-09 117.520300 +Name: Adj. Close, dtype: float64 +Date +2017-08-08 159.433108 +2017-08-09 160.409148 +2017-08-10 155.270000 +2017-08-11 157.480000 +2017-08-14 159.850000 +2017-08-15 161.600000 +2017-08-16 160.950000 +2017-08-17 157.870000 +2017-08-18 157.500000 +2017-08-21 157.210000 +Name: Adj. Close, dtype: float64 ++
- Mean-variance analysis is used to optimize portfolios with several strategies. Here we treat Dow 30 stocks as strategy and designed an algorithm to test mean-variance analysis: -
- ++ Mean-variance analysis is used to optimize portfolios with several strategies. Here we treat Dow 30 stocks as strategy and designed an algorithm to test mean-variance analysis: +
+ diff --git a/05 Introduction to Financial Python[]/13 Market Risk/06 Algorithm.html b/05 Introduction to Financial Python[]/13 Market Risk/06 Algorithm.html index 3069322..64474c1 100755 --- a/05 Introduction to Financial Python[]/13 Market Risk/06 Algorithm.html +++ b/05 Introduction to Financial Python[]/13 Market Risk/06 Algorithm.html @@ -1,13 +1,13 @@ - - - + + + diff --git a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/02 Fama-French Three-Factor Model.html b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/02 Fama-French Three-Factor Model.html index 21d0568..1f83f6d 100755 --- a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/02 Fama-French Three-Factor Model.html +++ b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/02 Fama-French Three-Factor Model.html @@ -1,8 +1,5 @@ - This model was proposed in 1993 by Eugene Fama and Kenneth French to describe stock returns.[ref] Fama, E F; French, K R (1993). Common risk factors in the returns on stocks and bonds. Journal of Financial Economics. 33: 3. CiteSeerX 10.1.1.139.5892 Freely accessible. doi:10.1016/0304-405X(93)90023-5[/ref] -
-- The 3-factor model is + This model was proposed in 1993 by Eugene Fama and Kenneth French to describe stock returns. The 3-factor model is
\[ R = \alpha + \beta_m MKT + \beta_s SMB + \beta_h HML \] @@ -12,7 +9,7 @@diff --git a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Other Factors.html b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Other Factors.html deleted file mode 100755 index 510c436..0000000 --- a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Other Factors.html +++ /dev/null @@ -1,12 +0,0 @@ -
- The Fama-French 5-Factor model comprises two more factors: -
-- RMW was proposed by Novy-Marx (2013) who wrote that: - "Controlling for gross profitability explains most earnings related anomalies, and a wide range of seemingly unrelated profitable trading strategies." CMA was proposed by Fama and French (2014) who pointed out that: A five-factor model directed at capturing the size, value, profitability, and investment patterns in average stock returns is rejected on the GRS test, but for applied purposes it provides an acceptable description of average returns. Finally, momentum is another commonly used factor. It captures excess returns of stocks with highest returns over those with lowest returns -
diff --git a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Summary.html b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Summary.html old mode 100755 new mode 100644 similarity index 98% rename from 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Summary.html rename to 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Summary.html index 549200f..d2b7e7a --- a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Summary.html +++ b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/05 Summary.html @@ -1,3 +1,3 @@ -- In this chapter we expand Capital Asset Pricing Model (CAPM) into multi-factor models: the Fama-French factor models in particular. They are the most empirically successful multi-factor models by far, and are commonly used in practice. -
++ In this chapter we expand Capital Asset Pricing Model (CAPM) into multi-factor models: the Fama-French factor models in particular. They are the most empirically successful multi-factor models by far, and are commonly used in practice. +
diff --git a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 Algorithm.html b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Algorithm.html old mode 100755 new mode 100644 similarity index 74% rename from 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 Algorithm.html rename to 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Algorithm.html index e3c69c8..3eb4334 --- a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 Algorithm.html +++ b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/06 Algorithm.html @@ -1,15 +1,15 @@ -- Multi-factor strategies are stock picking strategies. Here we try to implement a 2013 paper published by AQR Capital Management. - The paper recommends picking stocks by their value, quality (profitability) and momentum. - The empirically successful measure of value is book-to-price ratio (B/P), but other measures can be used simultaneously to form a more robust and reliable view of a stock's value. The paper uses 5 measures: book-to-price, earnings-to-price ratio (EPS), forecasted EPS, cash flow-to-enterprise value and sales-to-enterprise value. - The paper suggested a few quality measures: total profit over assets, gross margin and free cash flow over assets. There are also various measures of momentum. 1-year momentum, fundamental momentum and returns around earnings announcement are good choices. -
-- In our backtested strategy, we used operating profit margin to measure quality, P/B value to measure value, and 1-month momentum. The portfolio was rebalanced every 2 months and our backtest period runs from Jan 2012 to Jan 2015. You can build your own version by changing the factor, the weight of each factor, and the rebalance period based on the backtested strategy. -
- ++ Multi-factor strategies are stock picking strategies. Here we try to implement a 2013 paper published by AQR Capital Management. + The paper recommends picking stocks by their value, quality (profitability) and momentum. + The empirically successful measure of value is book-to-price ratio (B/P), but other measures can be used simultaneously to form a more robust and reliable view of a stock's value. The paper uses 5 measures: book-to-price, earnings-to-price ratio (EPS), forecasted EPS, cash flow-to-enterprise value and sales-to-enterprise value. + The paper suggested a few quality measures: total profit over assets, gross margin and free cash flow over assets. There are also various measures of momentum. 1-year momentum, fundamental momentum and returns around earnings announcement are good choices. +
++ In our backtested strategy, we used operating profit margin to measure quality, book value per share to measure value, and 1-month momentum. The portfolio was rebalanced every month. You can build your own version by changing the factor, the weight of each factor, and the rebalance period based on the backtested strategy. +
+ diff --git a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/08 References.html b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 References.html similarity index 81% rename from 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/08 References.html rename to 05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 References.html index 79b3bcb..eb7216e 100644 --- a/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/08 References.html +++ b/05 Introduction to Financial Python[]/14 Fama-French Multi-Factor Models/07 References.html @@ -14,4 +14,7 @@-For example, an AAPL call option contract which expires after 10 days has strike $143 and premium $10. now the market price of AAPL is $160. The intrinsic value of this contract is 160-143=$17, the time value is 17-10=$7. Although the intrinsic value of OTM and ATM options is zero, they have time values if they still have a certain amount of time until the option expires so for OTM and ATM options, their premiums equal their time values. +For example, an AAPL call option contract which expires after 10 days has strike $143 and premium $10. now the market price of AAPL is $150. The intrinsic value of this contract is 150-143=$7, the time value is 10-7=$3. Although the intrinsic value of OTM and ATM options is zero, they have time values if they still have a certain amount of time until the option expires so for OTM and ATM options, their premiums equal their time values.
diff --git a/06 Introduction to Options[]/02 QuantConnect Options API/02 Add Options.html b/06 Introduction to Options[]/02 QuantConnect Options API/02 Add Options.html index a1d5a37..44c5959 100755 --- a/06 Introduction to Options[]/02 QuantConnect Options API/02 Add Options.html +++ b/06 Introduction to Options[]/02 QuantConnect Options API/02 Add Options.html @@ -22,8 +22,8 @@def Initialize(self):
- self.SetStartDate(2017, 01, 01) #Set Start Date
- self.SetEndDate(2017, 06, 30) #Set End Date
+ self.SetStartDate(2017, 1, 1) #Set Start Date
+ self.SetEndDate(2017, 6, 30) #Set End Date
self.SetCash(50000) #Set Strategy Cash
equity = self.AddEquity("GOOG", Resolution.Minute) # Add the underlying stock: Google
option = self.AddOption("GOOG", Resolution.Minute) # Add the option corresponding to underlying stock
diff --git a/06 Introduction to Options[]/02 QuantConnect Options API/04 Select Contracts.html b/06 Introduction to Options[]/02 QuantConnect Options API/04 Select Contracts.html
index 54084fb..07ea589 100755
--- a/06 Introduction to Options[]/02 QuantConnect Options API/04 Select Contracts.html
+++ b/06 Introduction to Options[]/02 QuantConnect Options API/04 Select Contracts.html
@@ -65,11 +65,11 @@
def OnData(self,slice):
for i in slice.OptionChains:
if i.Key != self.symbol: continue
- optionchain = i.Value
- self.Log("underlying price:" + str(optionchain.Underlying.Price))
- df = pd.DataFrame([[x.Right,float(x.Strike),x.Expiry,float(x.BidPrice),float(x.AskPrice)] for x in optionchain],
- index=[x.Symbol.Value for x in optionchain],
- columns=['type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price'])
+ optionchain = i.Value
+ self.Log("underlying price:" + str(optionchain.Underlying.Price))
+ df = pd.DataFrame([[x.Right,float(x.Strike),x.Expiry,float(x.BidPrice),float(x.AskPrice)] for x in optionchain],
+ index=[x.Symbol.Value for x in optionchain],
+ columns=['type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price'])
self.Log(str(df))
for i in slice.OptionChains:
if i.Key != self.symbol: continue
- chain = i.Value
-# differentiate the call and put options
-call = [x for x in optionchain if chain.Right == 0]
-put = [x for x in optionchain if chain.Right == 1]
-# choose ITM contracts
-contracts = [x for x in call if call.UnderlyingLastPrice - x.Strike > 0]
-# or choose ATM contracts
-contracts = sorted(optionchain, key = lambda x: abs(optionchain.Underlying.Price - x.Strike))[0]
-# or choose OTM contracts
-contracts = [x for x in call if call.UnderlyingLastPrice - x.Strike < 0]
-# sort the contracts by their expiration dates
-contracts = sorted(contracts, key = lambda x:x.Expiry, reverse = True)
+ optionchain = i.Value
+ # differentiate the call and put options
+ call = [x for x in optionchain if x.Right == 0]
+ put = [x for x in optionchain if x.Right == 1]
+ # choose ITM call contracts
+ contracts = [x for x in call if x.UnderlyingLastPrice - x.Strike > 0]
+ # or choose ATM contracts
+ contracts = sorted(optionchain, key = lambda x: abs(x.UnderlyingLastPrice - x.Strike))[0]
+ # or choose OTM call contracts
+ contracts = [x for x in call if x.UnderlyingLastPrice - x.Strike < 0]
+ # sort the contracts by their expiration dates
+ contracts = sorted(contracts, key = lambda x: x.Expiry, reverse = True)
diff --git a/06 Introduction to Options[]/02 QuantConnect Options API/05 Algorithm.html b/06 Introduction to Options[]/02 QuantConnect Options API/05 Algorithm.html index 64b1d35..e485feb 100755 --- a/06 Introduction to Options[]/02 QuantConnect Options API/05 Algorithm.html +++ b/06 Introduction to Options[]/02 QuantConnect Options API/05 Algorithm.html @@ -4,6 +4,6 @@
diff --git a/06 Introduction to Options[]/03 Put-Call Parity and Arbitrage Strategies/05 Algorithm.html b/06 Introduction to Options[]/03 Put-Call Parity and Arbitrage Strategies/05 Algorithm.html index 12d6ce9..b196a80 100755 --- a/06 Introduction to Options[]/03 Put-Call Parity and Arbitrage Strategies/05 Algorithm.html +++ b/06 Introduction to Options[]/03 Put-Call Parity and Arbitrage Strategies/05 Algorithm.html @@ -1,6 +1,6 @@ diff --git a/07 Applied Options[]/01 Covered Call/04 Algorithm.html b/07 Applied Options[]/01 Covered Call/04 Algorithm.html index 9fa4e5e..6858e6e 100755 --- a/07 Applied Options[]/01 Covered Call/04 Algorithm.html +++ b/07 Applied Options[]/01 Covered Call/04 Algorithm.html @@ -4,7 +4,7 @@@@ -13,6 +13,6 @@
diff --git a/07 Applied Options[]/02 Bull Call Spread/01 Definition.html b/07 Applied Options[]/02 Bull Call Spread/01 Definition.html index 0418abb..c361521 100755 --- a/07 Applied Options[]/02 Bull Call Spread/01 Definition.html +++ b/07 Applied Options[]/02 Bull Call Spread/01 Definition.html @@ -5,7 +5,7 @@ This strategy creates a ceiling and floor for the profit. By purchasing a call and selling a call with higher strike simultaneously, traders can reduce the cost of just one long call option with the premium of a short call option. But the premium of ITM call is more expensive than the OTM call. The strategy limits the loss resulting from a drop in the price of the underlying stock but still creates a ceiling to the profit while the underlying price is increasing.- Take GOOG as an example. If the share price of GOOG is $950 at time 0, the premium of ITM call option is 20 with strike 900 and the premium of OTM call option is 2 with strike 1000. If we ignore the commission, dividends and other transaction fees, the payoff of Bull Call Spread strategy is as follows: + Take GOOG as an example. If the share price of GOOG is $950 at time 0, the premium of ITM call option is 50 with strike 900 and the premium of OTM call option is 2 with strike 1000. If we ignore the commission, dividends and other transaction fees, the payoff of Bull Call Spread strategy is as follows:
@@ -13,6 +13,6 @@
diff --git a/07 Applied Options[]/03 Long Straddle/04 Algorithm.html b/07 Applied Options[]/03 Long Straddle/04 Algorithm.html index 3e98c40..89e3d28 100755 --- a/07 Applied Options[]/03 Long Straddle/04 Algorithm.html +++ b/07 Applied Options[]/03 Long Straddle/04 Algorithm.html @@ -4,7 +4,7 @@@@ -13,6 +13,6 @@
diff --git a/07 Applied Options[]/04 Long Strangle/04 Algorithm.html b/07 Applied Options[]/04 Long Strangle/04 Algorithm.html index 78ab066..09a8a85 100755 --- a/07 Applied Options[]/04 Long Strangle/04 Algorithm.html +++ b/07 Applied Options[]/04 Long Strangle/04 Algorithm.html @@ -4,7 +4,7 @@ @@ -14,6 +14,6 @@ diff --git a/07 Applied Options[]/05 Butterfly Spread/04 Algorithm.html b/07 Applied Options[]/05 Butterfly Spread/04 Algorithm.html index 134f5b1..beb7ac0 100755 --- a/07 Applied Options[]/05 Butterfly Spread/04 Algorithm.html +++ b/07 Applied Options[]/05 Butterfly Spread/04 Algorithm.html @@ -4,7 +4,7 @@ @@ -14,6 +14,6 @@ diff --git a/07 Applied Options[]/06 Iron Condor/04 Algorithm.html b/07 Applied Options[]/06 Iron Condor/04 Algorithm.html index cf2d154..7a08824 100755 --- a/07 Applied Options[]/06 Iron Condor/04 Algorithm.html +++ b/07 Applied Options[]/06 Iron Condor/04 Algorithm.html @@ -4,7 +4,7 @@@@ -14,6 +14,6 @@
diff --git a/07 Applied Options[]/07 Iron Butterfly/04 Algorithm.html b/07 Applied Options[]/07 Iron Butterfly/04 Algorithm.html index cd42f7d..05d0e03 100755 --- a/07 Applied Options[]/07 Iron Butterfly/04 Algorithm.html +++ b/07 Applied Options[]/07 Iron Butterfly/04 Algorithm.html @@ -4,7 +4,7 @@ @@ -14,6 +14,6 @@ diff --git a/07 Applied Options[]/08 Protective Collar/04 Algorithm.html b/07 Applied Options[]/08 Protective Collar/04 Algorithm.html index 245885d..77dc3ce 100755 --- a/07 Applied Options[]/08 Protective Collar/04 Algorithm.html +++ b/07 Applied Options[]/08 Protective Collar/04 Algorithm.html @@ -4,7 +4,7 @@ @@ -14,6 +14,6 @@ diff --git a/README.md b/README.md index 5e2fd23..c9846d7 100644 --- a/README.md +++ b/README.md @@ -8,40 +8,22 @@ This repository is a collection of WordPress and Jupyter notebook tutorials for Lean Engine is an open-source fully managed C# algorithmic trading engine built for desktop and cloud usage. It was designed in Mono and operates in Windows, Linux and Mac platforms. For more information about the LEAN Algorithmic Trading engine see the [Lean][4] Engine repository. - -## New Tutorial Requests and Edits ## - -Please submit new tutorial requests as an issue to the [Tutorials][5] repository. Before submitting an issue please read others to ensure it is not a duplicate. Edits and fixes for clarity are warmly welcomed! - -## Mailing List ## - -The mailing list for the project can be found on [Google Groups][6] - ## Contributors and Pull Requests ## Contributions are warmly very welcomed but we ask you read the existing code to see how it is formatted, commented and ensure contributions match the existing style. All code submissions must include accompanying tests. Please see the [contributor guide lines][7]. ## Strategy Library Development Workflow ## -To publish a strategy to our [Strategy Library](https://www.quantconnect.com/tutorials/strategy-library/strategy-library), follow these steps: -1. Review filtered sources like SSRN, arxiv, and other academic journals/papers for a strategy to implement. Try to adhere to the [Quant League competition](https://www.quantconnect.com/competitions/quant-league-1) criteria and the Alpha Streams [minimum criteria](https://www.quantconnect.com/docs/alpha-streams/submitting-an-alpha#Submitting-an-Alpha-Minimum-Criteria) and [review process](https://www.quantconnect.com/docs/alpha-streams/submitting-an-alpha#Submitting-an-Alpha-Subsequent-Review-Process). -2. Post a 3-point development plan to [our Slack channel](https://www.quantconnect.com/slack) and wait for approval by @jaredbroad or @alexcatarino. See an example [here](https://cdn.quantconnect.com/i/tu/development-plan-example.png). -3. Develop the strategy (add [license and imports](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/BasicTemplateAlgorithm.py#L1) to main.py). -4. Add an Issue to the [Tutorials repo](https://github.com/QuantConnect/Tutorials/issues) ([example](https://github.com/QuantConnect/Tutorials/issues/277)). -5. Add @alexcatarino as a [collaborator](https://www.quantconnect.com/blog/collaborating-in-quantconnect/) to the project. -6. Publish a strategy write-up in the Slack channel and wait for approval (see [Strategy Library](https://www.quantconnect.com/tutorials/strategy-library/strategy-library) for examples). -7. Convert the strategy write-up to HTML form ([examples](https://github.com/QuantConnect/Tutorials/tree/master/04%20Strategy%20Library)). -8. Make PR (following the [Contributor's Guidelines](https://github.com/QuantConnect/Lean/blob/master/CONTRIBUTING.md)): - - If the write-up includes images, upload them [here](https://www.quantconnect.com/admin/cdnUpload). - - Add summary HTML files to [Strategy Library directory](https://github.com/QuantConnect/Tutorials/tree/master/04%20Strategy%20Library). If it's a non-Quantpedia strategy, set the ID number (in the directory name) to the next available after 1023. - - If the strategy is from Quantpedia, add strategy ID and backtest ID to [quantpedia.json](https://github.com/QuantConnect/Tutorials/blob/master/quantpedia.json). - - Add strategy metadata to [this file](https://github.com/QuantConnect/Tutorials/blob/master/04%20Strategy%20Library/00%20Strategy%20Library/01%20Strategy%20Library.php) (Currently semi-sorted by Quantpedia strategy ID). -9. After the PR is merged, send @jaredbroad the URL and a 1-sentence summary of what the paper/strategy is about and post the strategy to the forum with the backtest of the algorithm and a short summary of the project ([example](https://www.quantconnect.com/forum/discussion/8608/strategy-library-addition-residual-momentum/p1)). + +To publish a strategy to our [Strategy Library](https://www.quantconnect.com/tutorials/strategy-library/strategy-library), follow the steps on the [documentation page](https://www.quantconnect.com/docs/v2/writing-algorithms/strategy-library#03-Contribute-Tutorials) + +## New Tutorial Requests and Edits ## + +Please submit new tutorial requests as an issue to the [Tutorials][5] repository. Before submitting an issue please read others to ensure it is not a duplicate. Edits and fixes for clarity are warmly welcomed! [1]: https://www.quantconnect.com/tutorials "Tutorials Viewer" [2]: https://www.quantconnect.com/lean/docs "Lean Documentation" [3]: https://github.com/QuantConnect/Lean/archive/master.zip [4]: https://github.com/QuantConnect/Lean [5]: https://github.com/QuantConnect/Tutorials/issues -[6]: https://groups.google.com/forum/#!forum/lean-engine [7]: https://github.com/QuantConnect/Lean/blob/master/CONTRIBUTING.md [8]: https://www.quantconnect.com/slack