Hi Everyone,
Here is the code from my latest algortihmic trading video tutorial: https://youtu.be/rYHFGOZM7s8
Just click the "Clone Algorithm" button below to clone the algorithm to your own projects.
Let me know if you have any questions or comments.
Special thanks to Jack Simonson for his Fundamental factor long short strategy as alpha model community post.
Cheers,
Louis
Alex Monk
I spent my holidays on bootcamps and learning QC - and ofcourse lots a lot of hair and the remainig is grey; this video by far has been the best big thanks to you Louis.
My main issues with QC:
- I still don't know how to plot candle sticks on an examplary alpha model - say EMA crossover
- Code completion and suggestion basically doesn't work for me or it's ultra slow if it wants to suggest a thing; thus forcing me to use local dev env.
- In local Docker, plumming plotting and using my broker to get historical data has been chasing the rabbit hole.
Would be great if you can make video on any of these topics.
Shile Wen
Hi Alex,
If you would like OHLC candlestick plotting, it is not supported at the moment. Otherwise, please refer to this thread on plotting candlestick charts.
On the code completion, are you using Skylight? If so, please tell us your IDE and other details to see if there are ways to help us speed up the code completion. If you are using C#, please refer to this post on how to make autocomplete work using local Lean.
Best,
Shile Wen
Eben Olivier
Louis
Louis Very useful indeed, thankyou so much
One thing I did notice though is that you check to exit positions that should not be long, but you never check to not enter them again if they are already invested in. I guess this must be a functionality of the framework to handle that and balance that out automatically for you according to the weight. I assume that InsightWeightingPortfolioConstructionModel will always invest 100% of the portfolio balanced on the weight of the Insights? This will mean when only one insight is given the weight will have no effect and 100% of the portfolio will be allocated? I assume this because the weight you calculated is relative to each other, but what about what is already in your portfolio?
So Many questions about so many things because I do not understand how the portfolio management will work in all these different scenarios and I struggle to find any relevant information on this. I do not say there is no documentation on this, but perhaps I do not know how/where to find it. These are things that become worrisome when one thinks about live trading. How is the portfolio synchronised with the broker account, what if a position gets opened outside the algo on your account or closed for that matter? Or errors occur?
Louis
Hi Eben Olivier
Thanks for the comment. You are completely right in that the insight weights are automatically normalized. Furthermore, the insights of this algorithm expire within 31 days. So if we don't resend them, the positions would automatically be closed after these 31 days. That's why it is important for us to send out those insights again.
I certainly agree that it can sometimes be hard to find certain details. In my opinion, a good way to learn more (besides the documentation and forum) is the actual Lean code. For example, you can find the code for the algorithm framework here:
https://github.com/QuantConnect/Lean/tree/f059ef6e5fff6d57bed867e5bdfea90a428f0bf4/Algorithm.FrameworkI certainly understand that it can be scary to live trade if you aren't completely sure how everything works. But if that's the case, I just wouldn't recommend live trading. It takes time to learn everything and get used to QC's API. Just take your time and don't rush to live trade. Besides that, make sure to very thoroughly test all your algorithms by backtesting, stress testing, and live paper trading them before you actually deploy them with real money.
I hope this helps.
Eben Olivier
Thanks for the feedback, surely do help
Emiliano Fraticelli
Hi! I'm adding new "fundamentals factors" to the strategy.
I've added many in the quality and scores area, I'm wondering if there are more that I haven't added yet.
For instance in the Earnings Per Share area...
quality_scores = self.Scores(added, [(lambda x: x.Fundamentals.OperationRatios.GrossMargin.Value, True, 1), #True or false stands for reverse = True or not (lambda x: x.Fundamentals.OperationRatios.QuickRatio.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.DebttoAssets.Value, False, 1), (lambda x: x.Fundamentals.OperationRatios.FCFGrowth.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.FCFNetIncomeRatio.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.FCFSalesRatio.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.FixAssetsTuronver.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.GrossMargin.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.CapExSalesRatio.Value, True, 100), (lambda x: x.Fundamentals.OperationRatios.CapitalExpenditureAnnual5YrGrowth.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.GrossMargin5YrAvg.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.GrossProfitAnnual5YrGrowth.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.InterestCoverage.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.NetIncomeGrowth.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.NetMargin.Value,True, 1), #Ann. alpha 0.090 0.056 0.060 (lambda x: x.Fundamentals.OperationRatios.OperationIncomeGrowth.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.OperationMargin.Value,True, 1), (lambda x: x.Fundamentals.OperationRatios.OperationRevenueGrowth3MonthAvg.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.QuickRatio.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.ROA.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.ROE.Value, True, 5), # improves alpha (lambda x: x.Fundamentals.OperationRatios.ROE5YrAvg.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.ROIC.Value, True, 5), # improves alpha (lambda x: x.Fundamentals.OperationRatios.SalesPerEmployee.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.TotalDebtEquityRatio.Value, True, 1), (lambda x: x.Fundamentals.OperationRatios.CFOGrowth.Value, True, 1), ]) value_scores = self.Scores(added, [ (lambda x: x.Fundamentals.ValuationRatios.BookValuePerShare, True, 1), (lambda x: x.Fundamentals.ValuationRatios.CashReturn, True, 1), (lambda x: x.Fundamentals.ValuationRatios.EarningYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.CashReturn, True, 1), (lambda x: x.Fundamentals.ValuationRatios.BuyBackYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.TotalYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.FCFPerShare, True, 1), (lambda x: x.Fundamentals.ValuationRatios.EarningYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.FCFRatio, True, 10), (lambda x: x.Fundamentals.ValuationRatios.FCFYield, True, 100), #Ann. alpha 0.079 0.076 0.073 (lambda x: x.Fundamentals.ValuationRatios.ForwardDividendYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.ForwardEarningYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.NormalizedPERatio, True, 1), (lambda x: x.Fundamentals.ValuationRatios.PCFRatio, True, 1), (lambda x: x.Fundamentals.ValuationRatios.SustainableGrowthRate, True, 1), # improves alpha (lambda x: x.Fundamentals.ValuationRatios.TangibleBookValuePerShare, True, 1), (lambda x: x.Fundamentals.ValuationRatios.TotalYield, True, 1), (lambda x: x.Fundamentals.ValuationRatios.WorkingCapitalPerShare, True, 1), ]) #added by Emiliano size_scores = self.Scores(added, [(lambda x: x.Fundamentals.MarketCap, True, 1), ])
So far these are the ones that I've added, do you know more of them?
For instance also in the sizes area, where there's just the Market Cap.
Many thanks
Louis
Hi Emiliano,
Thanks for the comment. You can check out the documentation page on the available fundamental data here:
https://www.quantconnect.com/docs/data-library/fundamentalsThere you should find a list of the currently supported fundamental data. Just note that more data doesn't always lead to better results. You could try analyzing the correlation between some of these factors with returns to filter out the useful ones.
Emiliano Fraticelli
Thanks a lot Louis,
yes I know that more data doesn't always lead to better results. I have been a Quantopian user for a long time and I used to do this kind of research in their research envionment using AlphaLens.
For the moment, to do something similar, I've upped the single "Factor" value in my algo by giving to it a very high score.
For instance something like:
(lambda x: x.Fundamentals.OperationRatios.CFOGrowth.Value, True, 100)
to test the impact of this "Factor" to the Sharpe ratio. But improvements have been limited, the "best" seems to be FCFYield even giving to this factor the 90% and more of the importance (notice 100 ) Sharpe ratio from 2008 to current date is still somewhere around 0.7%, no more than that.
(lambda x: x.Fundamentals.ValuationRatios.FCFYield, True, 100), #Ann. alpha 0.079 0.076 0.073
Emiliano Fraticelli
Ah I see there's something similar even here on QC:
https://github.com/QuantConnect/Research/blob/master/Analysis/01%20Fudamental%20Factor%20Analysis.ipynbLouis
Yes, inside of your algorithms, you can set up and work on your own research notebooks. Thanks for linking to such a sample notebook on fundamental factor analysis. It looks like a great guide on how to perform such research/analysis. I might create a video on this in the future.
Henry Kwek
Hi Louis,
Thanks for the video and the strategy. Great stuff. If I want to do weekly rebalancing instead of monthly, what do I need to change
I believe I need to change the timedelta to 7 days from 31 days: (i.e. self.period = timedelta(7) ) within the main.py function. How should I amended correctly the AlphaModel.py function below?
# Return no insights if it's not time to rebalance
if algorithm.Time.month == self.lastMonth:
return []
self.lastMonth = algorithm.Time.month
Appreciate your kind advice !
Louis
Hi Henry,
Thanks for the comment. The timedelta that is saved into the period variable is used as a time-frame for the insights. If you want weekly rebalancing, it does make sense to change that from 31 to 7 days.
For weekly rebalancing, you could adjust the if statement as follows:
if self.Time.strftime("%V") == self.lastWeek: # not time for rebalancing # Else reassign the week variable self.lastWeek = self.Time.strftime("%V")
You can check out the documentation of strftime here: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
Make sure to also change this in the main file as well as the alpha model (I also recommend renaming the lastMonth variable to lastWeek).
Just note that weekly rebalancing can dramatically increase transaction costs.
I hope this helps.
Henry Kwek
Hi Louis,
Appreciate your quick advice. Code works after factoring in your suggestions.
Thanks !
Bernino Lind
Extremely useful post Louis - thanks for that.
I'm wondering in your forcing the rebalancing to monthly, one day only with the little time trick you do:
This way the “scanning” of the universe could be done daily (finding rough diamonds during 30 days rather than 1 days) meanwhile the rebalancing would be done per security only if the security has been held. a minimum e.g. 30 days, so as to give it a time chance to proof itself.
Louis Szeto
Hi Bernino
Since the insights are active for 31 bars (31 days in here), the algorithm will try to attain the set % of the portfolio from the insight weight throughout this 31 bars' period. This will be check and adjusted every rebalancing period of the Portfolio Construction Model (default as daily). So no matter did the order got filled on today or not, the algorithm would place/re-place order to attain the target on tomorrow.
Our fellow staff Varad has answered in this thread.
Best
Louis Szeto
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
George Riley
I find this extremely useful, thank you Louis .
I went through the code line by line to understand its mechanics in detail. I am just wondering one minor thing: In the AlphaModel in these lines
are the quality_rank / value_rank / size_rank variables really RANKS or SCORES? I understand the Scores() function to return score values (floats) per symbol. Sorry if I am overly accurate I am just trying to really understand…
Thx for any clearification, cheers,
George
Derek Melchin
Hi George,
The quality_rank variable represents the weighted rank of the security's quality factors, relative to the other securities in the universe. The value_rank and size_rank variables also represent the weighted rank, but on the value and size factors, respectively. In the alpha model, we see
For example, say there are 200 securities in the universe. If one security has the highest gross margin, highest quick ratio, and lowest debt to assets ratio in the universe, it will have the lowest quality_rank.
Best,
Derek Melchin
Want to invest in QuantConnect as we build the Linux of quant finance? Checkout our Wefunder campaign to join the revolution.
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
George Riley
Thx Derek Melchin for your answer.
What confuses me is the term RANK. A rank, at least for me, is 1st, 2nd, 3rd… i.e. it's integers. That's also how it's used in the code you quoted. However in this code here
we iterate through the scores. A score can be a float with weights etc., whereas a weighted rank doesn't make sense to me. That's why I was wondering if it should rather be quality_score instead of quality_rank. But I maybe mistaken…
Thx
Derek Melchin
Hi George,
I call it a “weighted rank" because the value of quality_rank is a function of the security rank for a factor and the corresponding weight of that factor.
The quality_rank, value_rank, and size_rank values are not all integers like 1, 2, 3, etc, but the variable names that we use to reference these are arbitrary.
Best,
Derek Melchin
Want to invest in QuantConnect as we build the Linux of quant finance? Checkout our Wefunder campaign to join the revolution.
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Jeroen van Hoof
Hey Louis, it seems that your algorithm only longs the newly added securities, but not all the existing securities in the universe. Instead, you are closing the existing securities, only to long the newly added ones. So, e.g. if one new security enters your universe, the algorithm will only buy that security, and remove all the other ones.
Basically, here you are assigning the newly added (now sorted) symbols to the self.longs variable. So you're overwriting the existing longs.
Then here, you are closing the positions that are not in the longs:
Let me know if I have some misunderstanding. But wouldn't you want to keep the longs on all securities in your current universe and perhaps re-score and re-order all of these securities regularly?
Louis
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!