Overall Statistics |
Total Trades 1625 Average Win 0.30% Average Loss -0.34% Compounding Annual Return 48.294% Drawdown 33.500% Expectancy -0.053 Net Profit 120.387% Sharpe Ratio 1.519 Probabilistic Sharpe Ratio 64.950% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.89 Alpha 0.481 Beta -0.169 Annual Standard Deviation 0.292 Annual Variance 0.085 Information Ratio 0.55 Tracking Error 0.393 Treynor Ratio -2.63 Total Fees $1833.50 Estimated Strategy Capacity $250000000.00 Lowest Capacity Asset DIS R735QTJ8XC9X |
QCAlgorithmFramework = QCAlgorithm QCAlgorithmFrameworkBridge = QCAlgorithm from QuantConnect import * from QuantConnect.Parameters import * from QuantConnect.Benchmarks import * from QuantConnect.Brokerages import * from QuantConnect.Util import * from QuantConnect.Interfaces import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Selection import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Risk import * from QuantConnect.Indicators import * from QuantConnect.Data import * from QuantConnect.Data.Consolidators import * from QuantConnect.Data.Custom import * from QuantConnect.Data.Fundamental import * from QuantConnect.Data.Market import * from QuantConnect.Data.UniverseSelection import * from QuantConnect.Notifications import * from QuantConnect.Orders import * from QuantConnect.Orders.Fees import * from QuantConnect.Orders.Fills import * from QuantConnect.Orders.Slippage import * from QuantConnect.Scheduling import * from QuantConnect.Securities import * from QuantConnect.Securities.Equity import * from QuantConnect.Securities.Forex import * from QuantConnect.Securities.Interfaces import * from datetime import date, datetime, timedelta from QuantConnect.Python import * from QuantConnect.Storage import * from QuantConnect import Resolution from QuantConnect.Algorithm import QCAlgorithm # topics # 1. use of CoarseSelectionFunction with indicator # 2. creation of self-defined SelectionData class used in CoarseSelectionFunction # 3. use of historical data to warm up indicator # takeaways # 1. avoid updating the indicator using the same price by specificying a time stamp # 2. avoid placing invalid orders by checking if the current slice has data for a symbol class EMAMomentumUniverse(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 7) self.SetEndDate(2021, 1, 7) self.SetCash(100000) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction) self.averages = {} def CoarseSelectionFunction(self, universe): selected = [] universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True) universe = [c for c in universe if c.Price > 10][:100] for coarse in universe: symbol = coarse.Symbol if symbol not in self.averages: # 1. Call history to get an array of 200 days of history data history = self.History(symbol, 200, Resolution.Daily) # 2. Adjust SelectionData to pass in the history result self.averages[symbol] = SelectionData(history) # self.Debug(str(symbol)) # self.Debug(history.index.get_level_values(1)[-1]) # last history date # self.Debug(f"history price: {history.close[-1]}") # last history price # self.Debug(self.Time) # algo date # self.Debug(f"algo price: {coarse.AdjustedPrice}") # algo price self.averages[symbol].update(self.Time, coarse.AdjustedPrice) if ( self.averages[symbol].is_ready() and self.averages[symbol].fast > self.averages[symbol].slow ): selected.append(symbol) return selected[:10] def OnSecuritiesChanged(self, changes): # self.Debug(self.Time) for security in changes.RemovedSecurities: self.Liquidate(security.Symbol) for security in changes.AddedSecurities: # self.Debug(str(security)) if self.CurrentSlice.ContainsKey( security.Symbol ): # check if the current slice has data for this symbol self.SetHoldings(security.Symbol, 0.10) class SelectionData: # 3. Update the constructor to accept a history array def __init__(self, price_hist): self.slow = ExponentialMovingAverage(200) self.fast = ExponentialMovingAverage(50) # 4. Loop over the history data and update the indicators for bar in price_hist.itertuples(): self.fast.Update(bar.Index[1], bar.close) self.slow.Update(bar.Index[1], bar.close) def is_ready(self): return self.slow.IsReady and self.fast.IsReady def update(self, time, price): self.fast.Update(time, price) self.slow.Update(time, price)