avatarDan Root

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

16048

Abstract

utm_source=medium&utm_medium=referral">Unsplash</a></figcaption></figure><p id="d8f9">During this stage, I like to focus on getting my pseudocode nailed down and my key logic to be worked out for later. During this stage I either open notepad (usually to start with) or the VSCode (usually after I get some key pieces written out). First, I start with keynotes that I deem important off the bat.</p><h2 id="32d9">Key Notes</h2><ol><li>The Alpha of the strategy is going to be where I am spending most of my time, as that is where most of the coding logic resides.</li><li>The Universe function will incorporate sorting and filters to accomplish what I need.</li><li>I have no idea the outcome of these tests and thus want to remain without bias throughout the testing process. The only thing to look for is the results.</li><li>The Strategy may be a reverting strategy in meaning it indicates reversals and signals should be used backward.</li><li>The alpha strategy may do better with different universe models, portfolio models, execution models, and risk models.</li><li>I am always willing to do some tuning and tweaking if results are not ideal before I through a strategy out but will also balance that with not spending too much time if the strategy is not producing strong results.</li></ol><p id="56a0">Next, before I write my pseudocode I like to create a flow chart on Lucid. <a href="https://lucid.app/">https://lucid.app/</a></p><figure id="6de6"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*v-KY2hveNi-MPtOuacfbxw.png"><figcaption>Algorithm Flow Chart by Author</figcaption></figure><p id="e3f6"><b>Pseudocode</b></p><h2 id="5df8">Universe:</h2><p id="c595">Sort universe of stocks by dollar volume.</p><p id="6a9b">Filter out 250 of the highest dollar volume equity stocks from this sorted list.</p><h2 id="a693">Alpha:</h2><p id="d10f">If selected equity has a 14-day return higher than .75% or lower than -.75% trade the stock via long for up and short for down. Insights will be for 1–14 days. This is where the insights are created and the trading logic for the alpha strategy lives. The alpha model is a Class and as such, it has three main methods. The main Python initialization function <code>init()</code>, <code>Update()</code> where the magic happens and trading signals are emitted and <code>OnSecuritiesChanged()</code> handles what happens when securities change in the universe.</p><p id="e53b">Also, it is good to note you can access algorithm variables when inside of other models or classes using the <code>algorithm</code> object, much how you would use <code>self</code> when coding inside of the main algorithm class. In the Alpha model, I will also use a <code>SymbolData()</code> class to help with the Rate Of Change Percent Indicator. The methods that are being used for this Class are similar and come pre-coded for this project in the Magnitude Alpha Model that we started out with. I will list them below.</p><div id="f676"><pre><span class="hljs-built_in">init</span>() # standard init function</pre></div><div id="66b4"><pre>RegisterIndicators() <span class="hljs-meta"># Registers Indicators https:<span class="hljs-comment">//www.quantconnect.com/docs/algorithm-reference/indicators</span></span></pre></div><div id="3273"><pre><span class="hljs-comment">RemoveConsolidators() # Removes any consolidators https://www.quantconnect.com/docs/algorithm-reference/consolidating-data</span></pre></div><div id="e08e"><pre>WarmUpIndicators() # Warms up indicators <span class="hljs-keyword">with</span> historical https:<span class="hljs-comment">//www.quantconnect.com/docs/algorithm-reference/indicators</span></pre></div><div id="aaf5"><pre><span class="hljs-keyword">Return</span>() <span class="hljs-comment"># Returns the indicator value</span></pre></div><div id="e1e5"><pre>CanEmit() <span class="hljs-comment"># lets us know if the indicator can emit insights</span></pre></div><h2 id="4199">Portfolio:</h2><p id="dedd">Will weight insights equally.</p><h2 id="d653">Execution:</h2><p id="06a8">Immediately execute tradable orders that have enough capital allocation.</p><h2 id="3e74">Risk:</h2><p id="376b">None.</p><h2 id="754f">RESEARCH</h2><figure id="bf34"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*fVMVUHsjxKNqyLUe"><figcaption>Photo by <a href="https://unsplash.com/@f7photo?utm_source=medium&amp;utm_medium=referral">Michael Longmire</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p id="f8d7">In my opinion, research is not only important but in most cases necessary to conduct within my algorithm construction workflow. The reason for this is that if I don’t use the research environment and actually explore my data and strategy to a more visual and logical level.</p><p id="d766">When I don’t use the research environment I often find myself thinking I have a full understanding of the algorithm but in reality, I have not done enough EDA, Testing, and Research to have a valid grasp of what is going on under the hood. In these scenarios, I have to go back to the research environment to get a full understanding.</p><p id="85a2">This is not necessarily true for all Algorithms, and I usually leave exceptions to using the research environment if either the algorithm is simple enough or clearly understandable by using the debugging and logging features of the Development IDE provided by QuantConnect.</p><p id="b0bf">In addition, I do not always use the research environment only in the beginning. Because QuantConnect makes it easy to work with objects that are coded in the development environment in your research environment, it can be extremely useful to use the research environment throughout the development workflow as needed.</p><p id="f0b2">I will be using QuantConnect’s Research Notebook to conduct my research for this project. You can find my notebook linked at the top of this article under resources. While researching I am getting a good feel of how the strategy code will look like.</p><p id="ac85">I begin by using a single security in the notebook “MSFT”. This will be enough for me to work out the code necessary to program the actual algorithm. Now, I need to load up the <code>RateOfChangePercent()</code> Indicator, as this will give us the returns we need. I also <code>import plotly.graph_objects as go</code>. This will be used in the second code block to visualize the Microsoft price chart to better understand the security we are dealing with while researching.</p> <figure id="9572"> <div> <div>

            <iframe class="gist-iframe" src="/gist/DanJRoot/95332da806a7ded60011d72b9ef6892e.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><figure id="7200"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*aDtnyQLDaaXp_tw09JcxAQ.png"><figcaption>Research Block One Output by Author</figcaption></figure><p id="1c31">Here is the visual of the Microsoft chart now in the second block.</p>
    <figure id="a6fa">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/DanJRoot/c750afeff67f00f9568361ede84b93e4.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><figure id="7f36"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Zu8WmQGbHocwsBcmUzlh_g.png"><figcaption>Research Block Two Output by Author</figcaption></figure><p id="0101">Now I will work the logic portion of the code out to get the signals I need to trade on. Using the Plotly I will also create an interactive chart like the one on block two, but this time I will add the signal as text and that should give a good idea if the strategy is working or not.</p><div id="ef20" class="link-block">
      <a href="https://plotly.com/">
        <div>
          <div>
            <h2>Plotly: The front end for ML and data science models</h2>
            <div><h3>Dash apps go where Tableau and PowerBI cannot: NLP, object detection, predictive analytics, and more. With 0.5M+…</h3></div>
            <div><p>plotly.com</p></div>
          </div>
          <div>
            <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*arrciflFGdjYG8Fa)"></div>
          </div>
        </div>
      </a>
    </div>
    <figure id="7dd7">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/DanJRoot/902824eaeb23a6ba384615ad2a06445f.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><figure id="360e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*N_W6VT_2EmzTRQtleVPlDQ.png"><figcaption>Research Block Three Output by Author</figcaption></figure><p id="c3e3">Now time to plot the chart out with the signals included.</p>
    <figure id="0d83">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/DanJRoot/27d179e68ba53d9b2180fe054b50bac2.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><figure id="d9e1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*70vC_qDrhnvB1YqvahM4HQ.png"><figcaption>Research Block Four Output by Author</figcaption></figure><p id="1ec7">After looking over the chart produced in Research Block Four, I can conclude that the strategy does look like it is working correctly so far. This is enough for me to work off when I start to code the strategy in the next section.</p><h2 id="0270">DEVELOPMENT</h2><figure id="e000"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*TWxGEUKJC4Z0Rt3Y"><figcaption>Photo by <a href="https://unsplash.com/@quinoal?utm_source=medium&amp;utm_medium=referral">Quino Al</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p id="1100">The development will start with setting up our Algorithm Class with the use of some pre-build models provided by QuantConnect by utilizing The Algorithm Framework. This comes with many benefits, such as separation of concerns, modularity, debugging, and readability to name a few.</p><h2 id="030f">The Setup</h2><p id="b357">The first is the Equal Weighted Portfolio Construction Model <code>self.SetPortfolioConstruction(EquallyWeightingPortfolioConstructionModel())</code>. The second is the Immediate Execution Model <code>self.SetExecution(ImmediateExecutionModel())</code>. The third is the Coarse Universe Selection Model <code>self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseSelectionFunction))</code>.</p><p id="0bdb">And last the Historical Returns Alpha Model. Now I will add my to the beginning of the original Alpha Model (<code>HistoricalReturnsAlphaModel(14, Resolution.Daily</code>) to make it unique. <code>self.AddAlpha(MyHistoricalReturnsAlphaModel(14, Resolution.Daily))</code>. This Alpha-model I will be altering to fit the needs of the strategy.</p><p id="9465">There will be no risk in this strategy as of now, as I prefer to add risk towards the end of the back-testing phase. This is because when I am adding risk it can sometimes add noise to the strategy results and skew the actual strategy. There are some exceptions to this, as some strategies include risk as a base part of the concept, but for this strategy, I will start with the no-risk model.</p><p id="8eb2">Now for programming the universe out. The following code sorts the universe by dollar volume. It then filters stocks that are a price between $0.10 and $10.00 and a volume over 1,000,000. This is arbitrary and can be tweaked and tuned or changed completely for this strategy. This universe gives us the top 250 securities that match these conditions.</p><div id="86b1"><pre>def CoarseSelectionFunction(self<span class="hljs-punctuation">,</span> coarse):

sortedByDollarVolume <span class="hljs-operator">=</span> sorted(coarse<span class="hljs-punctuation">,</span> key<span class="hljs-operator">=</span>lambda <span class="hljs-keyword">x</span>: <span class="hljs-keyword">x</span>.DollarVolume<span class="hljs-punctuation">,</span> reverse<span class="hljs-operator">=</span>True) filtered <span class="hljs-operator">=</span> [ <span class="hljs-keyword">x</span>.Symbol for <span class="hljs-keyword">x</span> in sortedByDollarVolume if <span class="hljs-keyword">x</span>.HasFundamentalData <span class="hljs-keyword">and</span> <span class="hljs-keyword">x</span>.Price ><span class="hljs-operator">=</span> .<span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">x</span>.Price <<span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">x</span>.DollarVolume > <span class="hljs-number">1000000</span> ] return [ <span class="hljs-keyword">x</span> for <span class="hljs-keyword">x</span> in filtered[:<span class="hljs-number">250</span>] ]</pre></div><h2 id="b493">The Algorithm</h2><p id="f06e">Next, we change the existing Historical Returns Alpha Model provided by QuantConnect.</p><div id="9766" class="link-block"> <a href="https://github.com/QuantConnect/Lean/blob/master/Algorithm.Framework/Alphas/HistoricalReturnsAlphaModel.py"> <div> <div> <h2>Lean/HistoricalReturnsAlphaModel.py at master · QuantConnect/Lean</h2> <div><h3>This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below…</h3></div> <div><p>github.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*oqm29fxt8t0vtFpz)"></div> </div> </div> </a> </div><p id="e9db">I started this series off with an alteration of an existing alpha model to demonstrate the ease of using existing code in your projects and the plug-and-play modular feel that using the Algorithm Framework can give a user. Here is the modified code I restructured for my strategy.</p><div id="f5f5"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyHistoricalReturnsAlphaModel</span>(<span class="hljs-title class_ inherited__">AlphaModel</span>): <span class="hljs-string">'''Uses Historical returns to create insights.'''</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, *args, **kwargs</span>):
    <span class="hljs-string">'''Initializes a new default instance of the HistoricalReturnsAlphaModel class.
    Args:
        lookback(int): Historical return lookback period
        resolution: The resolution of historical data'''</span>
    self.lookback = kwargs[<span class="hljs-string">'lookback'</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">'lookback'</span> <span class="hljs-keyword">in</span> kwargs <span class="hljs-keyword">else</span> <span class="hljs-number">1</span>
    self.resolution = kwargs[<span class="hljs-string">'resolution'</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">'resolution'</span> <span class="hljs-keyword">in</span> kwargs <span class="hljs-keyword">else</span> Resolution.Daily
    self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
    self.symbolDataBySymbol = {}</pre></di

Options

v><div id="ac4b"><pre><span class="hljs-title">def</span> <span class="hljs-type">Update</span>(self, algorithm, <span class="hljs-class"><span class="hljs-keyword">data</span>):</span> <span class="hljs-string">''</span>'<span class="hljs-type">Updates</span> this alpha model with the latest <span class="hljs-class"><span class="hljs-keyword">data</span> from the algorithm.</span> <span class="hljs-type">This</span> is called each time the algorithm receives <span class="hljs-class"><span class="hljs-keyword">data</span> for subscribed securities</span> <span class="hljs-type">Args</span>: algorithm: <span class="hljs-type">The</span> algorithm <span class="hljs-keyword">instance</span> <span class="hljs-class"><span class="hljs-keyword">data</span>: <span class="hljs-type">The</span> new <span class="hljs-keyword">data</span> available</span> <span class="hljs-type">Returns</span>: <span class="hljs-type">The</span> new insights generated<span class="hljs-string">''</span>' insights = []</pre></div><div id="3ac0"><pre><span class="hljs-keyword">for</span> symbol, symbolData <span class="hljs-keyword">in</span> self.symbolDataBySymbol.items(): <span class="hljs-keyword">if</span> symbolData.CanEmit:

            direction = InsightDirection.Flat
            magnitude = symbolData.Return
            <span class="hljs-keyword">if</span> magnitude &gt; <span class="hljs-number">.75</span>: direction = InsightDirection.Up
            <span class="hljs-keyword">if</span> magnitude &lt; -<span class="hljs-number">.75</span>: direction = InsightDirection.Down
            
            insights.append(Insight.Price(symbol, self.predictionInterval, direction, magnitude, <span class="hljs-literal">None</span>))
            
    <span class="hljs-keyword">return</span> insights
        
<span class="hljs-keyword">def</span> <span class="hljs-title function_">OnSecuritiesChanged</span>(<span class="hljs-params">self, algorithm, changes</span>):
    <span class="hljs-string">'''Event fired each time the we add/remove securities from the data feed
    Args:
        algorithm: The algorithm instance that experienced the change in securities
        changes: The security additions and removals from the algorithm'''</span>
        
    <span class="hljs-comment"># clean up data for removed securities</span>
    <span class="hljs-keyword">for</span> removed <span class="hljs-keyword">in</span> changes.RemovedSecurities:
        symbolData = self.symbolDataBySymbol.pop(removed.Symbol, <span class="hljs-literal">None</span>)
        <span class="hljs-keyword">if</span> symbolData <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
            symbolData.RemoveConsolidators(algorithm)
            
    <span class="hljs-comment"># initialize data for added securities</span>
    symbols = [ x.Symbol <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> changes.AddedSecurities ]
    history = algorithm.History(symbols, self.lookback, self.resolution)
    <span class="hljs-keyword">if</span> history.empty: <span class="hljs-keyword">return</span>
        
    tickers = history.index.levels[<span class="hljs-number">0</span>]
    <span class="hljs-keyword">for</span> ticker <span class="hljs-keyword">in</span> tickers:
        symbol = SymbolCache.GetSymbol(ticker)
            
        <span class="hljs-keyword">if</span> symbol <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self.symbolDataBySymbol:
            symbolData = SymbolData(symbol, self.lookback)
            self.symbolDataBySymbol[symbol] = symbolData
            symbolData.RegisterIndicators(algorithm, self.resolution)
            symbolData.WarmUpIndicators(history.loc[ticker])
            
            

<span class="hljs-keyword">class</span> <span class="hljs-title class_">SymbolData</span>: <span class="hljs-string">'''Contains data specific to a symbol required by this model'''</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self, symbol, lookback</span>): self.Symbol = symbol self.ROCP = RateOfChange(<span class="hljs-string">'{}.ROCP({})'</span>.<span class="hljs-built_in">format</span>(symbol, lookback), lookback)

    self.Consolidator = <span class="hljs-literal">None</span>
    self.previous = <span class="hljs-number">0</span>
        
<span class="hljs-keyword">def</span> <span class="hljs-title function_">RegisterIndicators</span>(<span class="hljs-params">self, algorithm, resolution</span>):
    self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
    algorithm.RegisterIndicator(self.Symbol, self.ROCP, self.Consolidator)
        
<span class="hljs-keyword">def</span> <span class="hljs-title function_">RemoveConsolidators</span>(<span class="hljs-params">self, algorithm</span>):
    <span class="hljs-keyword">if</span> self.Consolidator <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
        algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
        
<span class="hljs-keyword">def</span> <span class="hljs-title function_">WarmUpIndicators</span>(<span class="hljs-params">self, history</span>):
    <span class="hljs-keyword">for</span> <span class="hljs-built_in">tuple</span> <span class="hljs-keyword">in</span> history.itertuples():
        self.ROCP.Update(<span class="hljs-built_in">tuple</span>.Index, <span class="hljs-built_in">tuple</span>.close)
        

<span class="hljs-meta"> @property</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">Return</span>(<span class="hljs-params">self</span>): <span class="hljs-keyword">return</span> <span class="hljs-built_in">float</span>(self.ROCP.Current.Value)

<span class="hljs-meta"> @property</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">CanEmit</span>(<span class="hljs-params">self</span>): <span class="hljs-keyword">if</span> self.previous == self.ROCP.Samples: <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

    self.previous = self.ROCP.Samples
    <span class="hljs-keyword">return</span> self.ROCP.IsReady</pre></div><p id="8d64">One of the major changes is going from RateOfChange to RateOfPercentChange.</p><h2 id="5efd">Full Code</h2><p id="4349">Here is the code for the whole strategy.</p>
    <figure id="fd3e">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/DanJRoot/9298a53a75a41b0cd49d76721afc432b.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="1f05">Now let’s see how it does on back-testing.</p><h2 id="0bf5">BACK-TESTING</h2><figure id="de8e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*vVJI6nDjsYl9mIq5"><figcaption>Photo by <a href="https://unsplash.com/@kaedu?utm_source=medium&amp;utm_medium=referral">Kajetan Sumila</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h2 id="5962">Backtest №1</h2><figure id="f2f8"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*JGLNfRvlbBE85OnUTc-3vA.png"><figcaption>Back-test 1 Results pt. 1 by Author</figcaption></figure><figure id="37c1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Ue1rbDR8SJRn1oq477DbKg.png"><figcaption>Back-test 1 Results pt. 2 by Author</figcaption></figure><figure id="3889"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*wRM8oUDulAycp7bn_qpAdQ.png"><figcaption>Back-test 1 Results pt. 3 by Author</figcaption></figure><p id="f5f9">From the results of the first back-test, we can see that it was far from satisfactory. The strategy equity seems to diminish quickly with no signs of recovery. Looking at the Average Loss and the Average Win, as well as the Loss Rate and the Win Rate, we can see why it isn’t doing too good.</p><p id="a3ee">The Loss Rate is Larger than Win Rate and the Average Loss is larger than the Average Win. Giving the strategy a profit-loss ratio of 0.84. It is making a suitable number of trades at 263. The fees were low. Let’s reverse the signals to see if that can improve the overall performance.</p><p id="d311">From:</p><div id="4aea"><pre>if magnitude &gt; .<span class="hljs-number">75</span>: <span class="hljs-keyword">direction </span>= <span class="hljs-keyword">InsightDirection.Up

</span>if magnitude < -.<span class="hljs-number">75</span>: <span class="hljs-keyword">direction </span>= <span class="hljs-keyword">InsightDirection.Down</span></pre></div><p id="eb30">To:</p><div id="a8f9"><pre>if magnitude > .<span class="hljs-number">75</span>: <span class="hljs-keyword">direction </span>= <span class="hljs-keyword">InsightDirection.Down </span>if magnitude < -.<span class="hljs-number">75</span>: <span class="hljs-keyword">direction </span>= <span class="hljs-keyword">InsightDirection.Up</span></pre></div><p id="4240">Now let’s see what the second back-test brings.</p><h2 id="f4d6">Backtest №2</h2><figure id="3207"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*5BOyx-S_EIgpXFcrB3dkzg.png"><figcaption>Back-test 2 Results pt. 1 by Author</figcaption></figure><figure id="0a0e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*KqBBuSNJjaxW6m1T2wO9QQ.png"><figcaption>Back-test 2 Results pt. 2 by Author</figcaption></figure><figure id="6192"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*mTuzovh6W-sXZiiSBYFedA.png"><figcaption>Back-test 1 Results pt. 3 by Author</figcaption></figure><figure id="7cb0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*iQr-C8m9w8hpGP3ig3Zhww.png"><figcaption>Back-test 1 Results pt. 4 by Author</figcaption></figure><figure id="9899"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*8jxefgr9yWOkA9b0P7NyPg.png"><figcaption>Alpha Ranking by Author</figcaption></figure><p id="ac61">As you can see the performance was drastically better and now this strategy is showing some signs of potential. It is interesting how a quick reversal of signal logic can make such a powerful difference.</p><p id="2d24">The hypothesis seems to be strong still because there was an effect that 14-day returns have on future prices, although it was the reverse of our original implementation that ended up being correlated at all.</p><p id="60ce">Also, this could have much bias still with the selection of the universe, as this strategy might not perform as well on a different universe. With a PSR above 80%, this strategy now should be scrutinized for its logic and decisions as well as sanity checked.</p><p id="df33">This is how I will leave this strategy for now and again I encourage anyone looking to better this strategy to post their results and work on the QuantConnect forum this algorithm is posted on.</p><h2 id="316f">FORWARD-TESTING</h2><figure id="423c"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*6rmTJSiepStE9KBE"><figcaption>Photo by <a href="https://unsplash.com/@drew_beamer?utm_source=medium&amp;utm_medium=referral">Drew Beamer</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p id="85cd">The next step would be to paper trade this strategy, sometimes called forward-testing. QuantConnect makes this process extremely easy and fun. Make sure to check out their docs for more information on this here:</p><div id="5dba" class="link-block"> <a href="https://www.quantconnect.com/docs/live-trading/paper-trading"> <div> <div> <h2>Documentation - Live Trading - Paper Trading - QuantConnect.com</h2> <div><h3>Whether our paper model or a real brokerage, you can source data for your algorithm from QuantConnect or your brokerage…</h3></div> <div><p>www.quantconnect.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*Y7ukRZX9BtsnGRhS)"></div> </div> </div> </a> </div><h2 id="fcf8">DEPLOYMENT</h2><figure id="e6b4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*MB-rCEaDaiZR4UCt"><figcaption>Photo by <a href="https://unsplash.com/@grstocks?utm_source=medium&amp;utm_medium=referral">GR Stocks</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p id="1853">If you have paper traded your strategy out and are convinced it is worth investing money, QuantConnect also makes it easy to do this by deploying the strategy live with a connected broker that integrates with them. You can learn more about this process here:</p><div id="ecdc" class="link-block"> <a href="https://www.quantconnect.com/docs/live-trading/overview"> <div> <div> <h2>Documentation - Live Trading - Overview - QuantConnect.com</h2> <div><h3>QuantConnect has supported live trading since 2015. We have battle-tested, colocated servers that serve thousands of…</h3></div> <div><p>www.quantconnect.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*cdq9wzGlsUf5D0TS)"></div> </div> </div> </a> </div><p id="3fb7">Again, I do NOT recommend trading any of my strategies live and none of this information is to be considered financial advice. This is merely for entertainment purposes.</p><h1 id="d590">Conclusion</h1><p id="05f9">While this strategy shows some promise, it is still too early to tell. The strategy really needs to be thoroughly tested, the risk may need to be added, an implementation may not be the best, and to be reviewed of errors, mistakes, and issues/bugs.</p><p id="6991">This is an incredibly simple strategy and a good one to start the series with because sometimes simple can really surprise you and it gives you a place to start. I really recommend QuantConnect's Bootcamp if you are interested in learning more on their platform. It is very interactive and a valuable resource, especially if you are new to Algorithmic Trading. They also have Video Series, a thriving community forum, and much more. There are many approaches to developing algorithms and I will go over other approaches in future Articles.</p><p id="3744">This does demonstrate how easy it is to immerse yourself in the Algorithmic Trading world. QuantConnect really has done an amazing job of bridging the gap for the average person to be involved in such an advanced and fast-moving industry. I plan to roll out more strategies on the QuantConnect platform as a part of this series.</p><p id="5539">On another note, if you notice anything wrong with my article or code, please respond and I will try to address the issue as fast as I can. Until next time, happy coding everyone!</p><p id="e020"><i>More content at <a href="http://plainenglish.io/"><b>plainenglish.io</b></a>. Sign up for our <a href="http://newsletter.plainenglish.io/"><b>free weekly newsletter</b></a>. Get exclusive access to writing opportunities and advice in our <a href="https://discord.gg/GtDtUAvyhW"><b>community Discord</b></a>.</i></p></article></body>

Algorithmic Trading with Python: Does Two Week Magnitude Effect Current Returns

Algo Trading with Python — Strategy 1: Test If Historical Returns Can Help Indicate Future Daily Momentum

Photo by Valerie Blanchett on Unsplash

This will be the starting article on a series of articles titled Algorithmic Trading with Python.

I want to demonstrate the ease and general practice of trading in various market scenarios, conditions, and security types. To develop and research this algorithm, I will be using the QuantConnect Platform:

This article will cover the following: ∘ CONCEPTDESIGNRESEARCHDEVELOPMENTBACK-TESTINGFORWARD-TESTINGDEPLOYMENT

Conclusion

To design the algorithm, I will use Lucid.

I find it a good habit to visualize my algorithms in the design portion of the steps. I also like to write pseudocode to help stamp out static parameter values and figure out the logic of the code as well. To do the pseudocode I use any good text editor I choose VSCode as I find it suitable, and the syntax highlighting is extremely effective for the readability of your work.

I chose to do this project in the Python Programming Language. The two main reasons for this are that QuantConnect has integrated Python heavily into their platform as the most accepted language for their IDE in the community, but also because Python is a great language for understanding how your code is working and for beginners to quickly get their hands dirty with a simpler language.

To start we need a clever idea or concept of a strategy. I will start this series with a simple algorithm. The algorithm will also be utilizing QuantConnect’s algorithm framework. This allows you to be creative in the way you build while retaining the robustness of relying on a proven and efficient architecture. Because of these factors, you can build professional, well-engineered, and unique algorithmic trading systems fairly easily.

I will grade my algorithm using QuantConnect’s PSR ratio, which is a good single-point measurement for quick overall performance review, but I will go into other performance and statistical measurements as well.

I find QuantConnect to be a great research and algorithmic trading platform. Not only do they offer a great education bootcamp, but they also offer a full ecosystem of top-notch quants. The community forums, a Discord Server, mixed with the beautiful IDE, API, Research Notebook, Documentation, Licensing Marketplace (Alpha Streams), and too many other features and helpers to list them all for time's sake.

If you want to know more about them, take a look at the website https://quantconnect.com. QuantConnect really works for me because it covers many of the hurdles that come with algorithmic trading, such as working with large broker APIs, dealing with getting clean reliable data, slippage, trading fees, price adjustments, following well-accepted guidelines, local and cloud development, and many other factors. It really is just a suitable place to start as a Quant in my opinion.

This article assumes you know the basics of Python, the QuantConnect platform, API, and Documentation, and some basic knowledge of statistics. If you want to learn more about Python, check out some of my other articles on the subject on my Medium page. To learn more about QuantConnect They offer tutorials, a Bootcamp, a strategy library, great documentation, the community forum, and a Discord Server.

There is also a great site called Quantpedia that offers a great service for Quants by delivering a gigantic 600+ Algorithmic Trading Strategies research pre-done by professionals and that isn’t it, 500+ Trading Strategies that include QuantConnect code, at the time of authoring this article. One use for this is that it is meant to give Quants a great place to start for their next strategy.

They also offer much more with a great screener for these strategies and a Pro service that gives you a ton of extra features and tools. I really recommend checking it out more in-depth. I will list them below:

This first strategy is going to be mostly modifying an existing Alpha Model. This model is in the Alpha Creation section of QuantConnect’s Docs.

I do not recommend trading real money with this algorithm, nor is any of this to be considered financial advice. This is merely entertainment for learning purposes only. I am also not affiliated with QuantConnect and this article is not a promotion for them. I am just a satisfied fan of the platform.

Photo by Lance Anderson on Unsplash

Resources

My QuantConnect Algorithm Backtest & Research Notebook. Also, below is the forum discussion I started about this strategy.

Here is my GitHub repo for this algorithm.

QuantStrategies/Strategies/TwoWeekMagnitudeEffectOnCurrentReturns at main · third-eye-cyborg/QuantStrategies (github.com)

Here is the 2nd strategy in this series so far.

CONCEPT

Photo by Alessandro Bianchi on Unsplash

Question:

Does Two Week Magnitude Affect Current Returns for a liquid equity stock selected from a dynamic universe along with 249 others, rebalanced daily? In addition, can that edge be taken advantage of to create a profitable alpha for a trading algorithm?

Hypothesis:

If 14-day returns do have a correlation with single-day/multi-day momentum, can I use this indicator to create signals for insights on both longing and shorting equities associated with the signal?

Universe:

I will pick 250 stocks from a liquid universe of stocks that have a volume of over 1,000,000 and a price between $0.10 and $10.00. I will rebalance these stocks once a day. This will give me a good dynamic range of stocks that I can use to trade my algorithm, which can help with overfitting and selection bias.

Alpha:

Ideally, I want to Long a stock if the 14-day return is above .75% and Short a stock if it is under -.75%. Something to note is this is the basic and flexible starting alpha. You should never work on a simple alpha too much if the results are not significant and you are just tuning the performance to cherry-pick trades that will look great on a back-test, but do not actually hold their ground with new data.

The reason that this is a flexible alpha strategy is that during the design, research, development, and back-testing stage you may want to change key concepts, design principles, and development models to achieve a better overall strategy.

Portfolio:

The portfolio model I will be using in this model is going to be an Equally Weighted Portfolio Construction Model that is pre-built by QuantConnect and implements an equal cut of weight to all assets in the portfolio.

Execution:

I will be utilizing the pre-built Execution Model from QuantConnect, Immediate Execution Model. This model just immediately invokes your orders when the insights associated are emitted if there is enough portfolio allocation to cover the trade.

Risk:

We will not be choosing a risk model for this strategy, but I encourage anyone reading to implement your own or any pre-built risk models and share your story with what happens on the QC forums or by replying to this article!

DESIGN

Photo by Neven Krcmarek on Unsplash

During this stage, I like to focus on getting my pseudocode nailed down and my key logic to be worked out for later. During this stage I either open notepad (usually to start with) or the VSCode (usually after I get some key pieces written out). First, I start with keynotes that I deem important off the bat.

Key Notes

  1. The Alpha of the strategy is going to be where I am spending most of my time, as that is where most of the coding logic resides.
  2. The Universe function will incorporate sorting and filters to accomplish what I need.
  3. I have no idea the outcome of these tests and thus want to remain without bias throughout the testing process. The only thing to look for is the results.
  4. The Strategy may be a reverting strategy in meaning it indicates reversals and signals should be used backward.
  5. The alpha strategy may do better with different universe models, portfolio models, execution models, and risk models.
  6. I am always willing to do some tuning and tweaking if results are not ideal before I through a strategy out but will also balance that with not spending too much time if the strategy is not producing strong results.

Next, before I write my pseudocode I like to create a flow chart on Lucid. https://lucid.app/

Algorithm Flow Chart by Author

Pseudocode

Universe:

Sort universe of stocks by dollar volume.

Filter out 250 of the highest dollar volume equity stocks from this sorted list.

Alpha:

If selected equity has a 14-day return higher than .75% or lower than -.75% trade the stock via long for up and short for down. Insights will be for 1–14 days. This is where the insights are created and the trading logic for the alpha strategy lives. The alpha model is a Class and as such, it has three main methods. The main Python initialization function __init__(), Update() where the magic happens and trading signals are emitted and OnSecuritiesChanged() handles what happens when securities change in the universe.

Also, it is good to note you can access algorithm variables when inside of other models or classes using the algorithm object, much how you would use self when coding inside of the main algorithm class. In the Alpha model, I will also use a SymbolData() class to help with the Rate Of Change Percent Indicator. The methods that are being used for this Class are similar and come pre-coded for this project in the Magnitude Alpha Model that we started out with. I will list them below.

__init__() # standard init function
RegisterIndicators() # Registers Indicators https://www.quantconnect.com/docs/algorithm-reference/indicators
RemoveConsolidators() # Removes any consolidators https://www.quantconnect.com/docs/algorithm-reference/consolidating-data
WarmUpIndicators() # Warms up indicators with historical https://www.quantconnect.com/docs/algorithm-reference/indicators
Return() # Returns the indicator value
CanEmit() # lets us know if the indicator can emit insights

Portfolio:

Will weight insights equally.

Execution:

Immediately execute tradable orders that have enough capital allocation.

Risk:

None.

RESEARCH

Photo by Michael Longmire on Unsplash

In my opinion, research is not only important but in most cases necessary to conduct within my algorithm construction workflow. The reason for this is that if I don’t use the research environment and actually explore my data and strategy to a more visual and logical level.

When I don’t use the research environment I often find myself thinking I have a full understanding of the algorithm but in reality, I have not done enough EDA, Testing, and Research to have a valid grasp of what is going on under the hood. In these scenarios, I have to go back to the research environment to get a full understanding.

This is not necessarily true for all Algorithms, and I usually leave exceptions to using the research environment if either the algorithm is simple enough or clearly understandable by using the debugging and logging features of the Development IDE provided by QuantConnect.

In addition, I do not always use the research environment only in the beginning. Because QuantConnect makes it easy to work with objects that are coded in the development environment in your research environment, it can be extremely useful to use the research environment throughout the development workflow as needed.

I will be using QuantConnect’s Research Notebook to conduct my research for this project. You can find my notebook linked at the top of this article under resources. While researching I am getting a good feel of how the strategy code will look like.

I begin by using a single security in the notebook “MSFT”. This will be enough for me to work out the code necessary to program the actual algorithm. Now, I need to load up the RateOfChangePercent() Indicator, as this will give us the returns we need. I also import plotly.graph_objects as go. This will be used in the second code block to visualize the Microsoft price chart to better understand the security we are dealing with while researching.

Research Block One Output by Author

Here is the visual of the Microsoft chart now in the second block.

Research Block Two Output by Author

Now I will work the logic portion of the code out to get the signals I need to trade on. Using the Plotly I will also create an interactive chart like the one on block two, but this time I will add the signal as text and that should give a good idea if the strategy is working or not.

Research Block Three Output by Author

Now time to plot the chart out with the signals included.

Research Block Four Output by Author

After looking over the chart produced in Research Block Four, I can conclude that the strategy does look like it is working correctly so far. This is enough for me to work off when I start to code the strategy in the next section.

DEVELOPMENT

Photo by Quino Al on Unsplash

The development will start with setting up our Algorithm Class with the use of some pre-build models provided by QuantConnect by utilizing The Algorithm Framework. This comes with many benefits, such as separation of concerns, modularity, debugging, and readability to name a few.

The Setup

The first is the Equal Weighted Portfolio Construction Model self.SetPortfolioConstruction(EquallyWeightingPortfolioConstructionModel()). The second is the Immediate Execution Model self.SetExecution(ImmediateExecutionModel()). The third is the Coarse Universe Selection Model self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseSelectionFunction)).

And last the Historical Returns Alpha Model. Now I will add my to the beginning of the original Alpha Model (HistoricalReturnsAlphaModel(14, Resolution.Daily) to make it unique. self.AddAlpha(MyHistoricalReturnsAlphaModel(14, Resolution.Daily)). This Alpha-model I will be altering to fit the needs of the strategy.

There will be no risk in this strategy as of now, as I prefer to add risk towards the end of the back-testing phase. This is because when I am adding risk it can sometimes add noise to the strategy results and skew the actual strategy. There are some exceptions to this, as some strategies include risk as a base part of the concept, but for this strategy, I will start with the no-risk model.

Now for programming the universe out. The following code sorts the universe by dollar volume. It then filters stocks that are a price between $0.10 and $10.00 and a volume over 1,000,000. This is arbitrary and can be tweaked and tuned or changed completely for this strategy. This universe gives us the top 250 securities that match these conditions.

def CoarseSelectionFunction(self, coarse):
 sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
 filtered = [ x.Symbol for x in sortedByDollarVolume if x.HasFundamentalData and x.Price >= .1 and x.Price <= 10 and x.DollarVolume > 1000000 ]
 return [ x for x in filtered[:250] ]

The Algorithm

Next, we change the existing Historical Returns Alpha Model provided by QuantConnect.

I started this series off with an alteration of an existing alpha model to demonstrate the ease of using existing code in your projects and the plug-and-play modular feel that using the Algorithm Framework can give a user. Here is the modified code I restructured for my strategy.

class MyHistoricalReturnsAlphaModel(AlphaModel):
    '''Uses Historical returns to create insights.'''
        
    def __init__(self, *args, **kwargs):
        '''Initializes a new default instance of the HistoricalReturnsAlphaModel class.
        Args:
            lookback(int): Historical return lookback period
            resolution: The resolution of historical data'''
        self.lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
        self.resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
        self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
        self.symbolDataBySymbol = {}
def Update(self, algorithm, data):
        '''Updates this alpha model with the latest data from the algorithm.
        This is called each time the algorithm receives data for subscribed securities
        Args:
            algorithm: The algorithm instance
            data: The new data available
        Returns:
            The new insights generated'''
        insights = []
for symbol, symbolData in self.symbolDataBySymbol.items():
            if symbolData.CanEmit:
                
                direction = InsightDirection.Flat
                magnitude = symbolData.Return
                if magnitude > .75: direction = InsightDirection.Up
                if magnitude < -.75: direction = InsightDirection.Down
                
                insights.append(Insight.Price(symbol, self.predictionInterval, direction, magnitude, None))
                
        return insights
            
    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
            
        # clean up data for removed securities
        for removed in changes.RemovedSecurities:
            symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)
            if symbolData is not None:
                symbolData.RemoveConsolidators(algorithm)
                
        # initialize data for added securities
        symbols = [ x.Symbol for x in changes.AddedSecurities ]
        history = algorithm.History(symbols, self.lookback, self.resolution)
        if history.empty: return
            
        tickers = history.index.levels[0]
        for ticker in tickers:
            symbol = SymbolCache.GetSymbol(ticker)
                
            if symbol not in self.symbolDataBySymbol:
                symbolData = SymbolData(symbol, self.lookback)
                self.symbolDataBySymbol[symbol] = symbolData
                symbolData.RegisterIndicators(algorithm, self.resolution)
                symbolData.WarmUpIndicators(history.loc[ticker])
                
                
class SymbolData:
    '''Contains data specific to a symbol required by this model'''
    def __init__(self, symbol, lookback):
        self.Symbol = symbol
        self.ROCP = RateOfChange('{}.ROCP({})'.format(symbol, lookback), lookback)
        
        self.Consolidator = None
        self.previous = 0
            
    def RegisterIndicators(self, algorithm, resolution):
        self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
        algorithm.RegisterIndicator(self.Symbol, self.ROCP, self.Consolidator)
            
    def RemoveConsolidators(self, algorithm):
        if self.Consolidator is not None:
            algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
            
    def WarmUpIndicators(self, history):
        for tuple in history.itertuples():
            self.ROCP.Update(tuple.Index, tuple.close)
            
    @property
    def Return(self):
        return float(self.ROCP.Current.Value)
            
    @property
    def CanEmit(self):
        if self.previous == self.ROCP.Samples:
            return False
            
        self.previous = self.ROCP.Samples
        return self.ROCP.IsReady

One of the major changes is going from RateOfChange to RateOfPercentChange.

Full Code

Here is the code for the whole strategy.

Now let’s see how it does on back-testing.

BACK-TESTING

Photo by Kajetan Sumila on Unsplash

Backtest №1

Back-test 1 Results pt. 1 by Author
Back-test 1 Results pt. 2 by Author
Back-test 1 Results pt. 3 by Author

From the results of the first back-test, we can see that it was far from satisfactory. The strategy equity seems to diminish quickly with no signs of recovery. Looking at the Average Loss and the Average Win, as well as the Loss Rate and the Win Rate, we can see why it isn’t doing too good.

The Loss Rate is Larger than Win Rate and the Average Loss is larger than the Average Win. Giving the strategy a profit-loss ratio of 0.84. It is making a suitable number of trades at 263. The fees were low. Let’s reverse the signals to see if that can improve the overall performance.

From:

if magnitude > .75: direction = InsightDirection.Up
if magnitude < -.75: direction = InsightDirection.Down

To:

if magnitude > .75: direction = InsightDirection.Down
if magnitude < -.75: direction = InsightDirection.Up

Now let’s see what the second back-test brings.

Backtest №2

Back-test 2 Results pt. 1 by Author
Back-test 2 Results pt. 2 by Author
Back-test 1 Results pt. 3 by Author
Back-test 1 Results pt. 4 by Author
Alpha Ranking by Author

As you can see the performance was drastically better and now this strategy is showing some signs of potential. It is interesting how a quick reversal of signal logic can make such a powerful difference.

The hypothesis seems to be strong still because there was an effect that 14-day returns have on future prices, although it was the reverse of our original implementation that ended up being correlated at all.

Also, this could have much bias still with the selection of the universe, as this strategy might not perform as well on a different universe. With a PSR above 80%, this strategy now should be scrutinized for its logic and decisions as well as sanity checked.

This is how I will leave this strategy for now and again I encourage anyone looking to better this strategy to post their results and work on the QuantConnect forum this algorithm is posted on.

FORWARD-TESTING

Photo by Drew Beamer on Unsplash

The next step would be to paper trade this strategy, sometimes called forward-testing. QuantConnect makes this process extremely easy and fun. Make sure to check out their docs for more information on this here:

DEPLOYMENT

Photo by GR Stocks on Unsplash

If you have paper traded your strategy out and are convinced it is worth investing money, QuantConnect also makes it easy to do this by deploying the strategy live with a connected broker that integrates with them. You can learn more about this process here:

Again, I do NOT recommend trading any of my strategies live and none of this information is to be considered financial advice. This is merely for entertainment purposes.

Conclusion

While this strategy shows some promise, it is still too early to tell. The strategy really needs to be thoroughly tested, the risk may need to be added, an implementation may not be the best, and to be reviewed of errors, mistakes, and issues/bugs.

This is an incredibly simple strategy and a good one to start the series with because sometimes simple can really surprise you and it gives you a place to start. I really recommend QuantConnect's Bootcamp if you are interested in learning more on their platform. It is very interactive and a valuable resource, especially if you are new to Algorithmic Trading. They also have Video Series, a thriving community forum, and much more. There are many approaches to developing algorithms and I will go over other approaches in future Articles.

This does demonstrate how easy it is to immerse yourself in the Algorithmic Trading world. QuantConnect really has done an amazing job of bridging the gap for the average person to be involved in such an advanced and fast-moving industry. I plan to roll out more strategies on the QuantConnect platform as a part of this series.

On another note, if you notice anything wrong with my article or code, please respond and I will try to address the issue as fast as I can. Until next time, happy coding everyone!

More content at plainenglish.io. Sign up for our free weekly newsletter. Get exclusive access to writing opportunities and advice in our community Discord.

Python
Algorithms
Quant
Finance
Algorithmic Trading
Recommended from ReadMedium