Overall Statistics |
Total Trades 841 Average Win 0.08% Average Loss -0.03% Compounding Annual Return 1015.850% Drawdown 5.700% Expectancy 0.536 Net Profit 8.971% Sharpe Ratio 22.534 Probabilistic Sharpe Ratio 73.460% Loss Rate 59% Win Rate 41% Profit-Loss Ratio 2.75 Alpha 0 Beta 0 Annual Standard Deviation 0.507 Annual Variance 0.257 Information Ratio 22.534 Tracking Error 0.507 Treynor Ratio 0 Total Fees $904.24 Estimated Strategy Capacity $15000000.00 |
from clr import AddReference AddReference("System") AddReference("QuantConnect") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Indicators") from System import * from System.Drawing import Color 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 * QCAlgorithmFramework = QCAlgorithm QCAlgorithmFrameworkBridge = QCAlgorithm import decimal as d import numpy as np import pandas as pd from io import StringIO import random class SymbolData: """ Class to hold Data for specific Tickers. Currently holding: - SPY - 50 dEMA """ def __init__(self, algorithm, symbol, followerEMAPeriod = 50, resolution = Resolution.Daily, field = Field.Close): self.Symbol = symbol self.followerEMA = None self.followerEmaWindow = None self.ema = ExponentialMovingAverage(followerEMAPeriod) self.consolidator = None def regIndicator(self, algorithm, resolution): self.consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution) algorithm.RegisterIndicator(self.Symbol, self.ema, self.consolidator) def removeConsolidators(self, algorithm): if self.consolidator is not None: algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.consolidator) def warmup(self, history): for tuple in history.itertuples(): self.ema.Update(tuple.Index, tuple.close) class FollowerData: """ Class to hold Data for specific Tickers. Currently holding: - SPY - 50 dEMA """ def __init__(self, algorithm, security, followerEMAPeriod = 50, resolution = Resolution.Daily, field = Field.Close): self.Security = security self.Symbol = security.Symbol self.followerEMA = None self.followerEmaWindow = None def FollowerEmaUpdated(self, sender, updated): self.followerEmaWindow.Add(updated) class CAlphaModel(AlphaModel): ''' Custom Alpha Model. ''' def __init__(self, slowPeriod = 50, lookup = 490, resolution = Resolution.Daily, field = Field.Close): self.lookup = lookup self.slowPeriod = slowPeriod self.resolution = resolution self.field = field self.insightPeriod = timedelta(minutes=10) # ETF watchers self.followers = {'XLK' : True, 'XLC' : True, 'XLV' : True, 'XLY' : True, 'XLI' : True, 'XLF' : True, 'XLRE' : True, 'XLE' : True, 'XLP' : True, 'XLU' : True, 'XLB' : True, 'SPY' : True, 'IYZ' : True, 'ITB' : True, 'CARZ' : True, 'BJK' : True, 'ITA' : True, 'SMH' : True, 'KCE' : True, 'KIE' : True, 'KRE' : True, 'KBE' : True, 'XHS' : True, 'XBI' : True, 'XHE' : True, 'XPH' : True, 'XES' : True, 'XME' : True, 'WOOD' : True, 'ICLN' : True, 'XRT' : True, 'ONLN' : True, 'GLD' : True, 'SLX' : True, 'MJ' : True, 'CEX' : True, 'XWEB' : True, 'IGV' : True, 'JETS' : True, 'IYT' : True } self.followerData = {} self.symbolData = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{})'.format(self.__class__.__name__, slowPeriod, resolutionString) def Update(self, algorithm, data): insights = [] key = 'SPY' spyData = self.followerData[key] if not (data.ContainsKey(spyData.Symbol) and data.Bars.ContainsKey(spyData.Symbol)): return insights spyTime = data[spyData.Symbol].Time spyClose = data[spyData.Symbol].Close if spyClose < spyData.followerEMA.Current.Value: algorithm.Debug(f"- SPY < 50dEMA - {spyTime} close:{spyClose} 50dEMA method#1:{spyData.followerEMA.Current.Value} 50dEMA RW:{spyData.followerEmaWindow[0].Value} 50dEMA method#2:{self.symbolData[key].ema.Current.Value}") self.followers['SPY'] = False elif spyClose > spyData.followerEMA.Current.Value: algorithm.Debug(f"- SPY > 50dEMA - {spyTime} close:{spyClose} 50dEMA method#1:{spyData.followerEMA.Current.Value} 50dEMA_window:{spyData.followerEmaWindow[0].Value} 50dEMA method#2:{self.symbolData[key].ema.Current.Value}") self.followers['SPY'] = True for key, follower in self.followerData.items(): if follower.Symbol.Value not in self.followers: if not (data.ContainsKey(follower.Symbol) and data.Bars.ContainsKey(follower.Symbol)): continue if not self.followers['SPY']: # self.Liquidate(key.Value) insight = Insight.Price(follower.Symbol, self.insightPeriod, InsightDirection.Flat) insights.append(insight) elif self.followers['SPY']: # self.SetHoldings(key.Value, 0.1) insight = Insight.Price(follower.Symbol, self.insightPeriod, InsightDirection.Up) insights.append(insight) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the 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''' # method 1 symbols = [x.Symbol for x in changes.AddedSecurities] his = algorithm.History(symbols, self.lookup) if his.empty: return tickers = his.index.levels[0] for ticker in tickers: symbol = SymbolCache.GetSymbol(ticker) if symbol.Value in self.followers and symbol.Value not in self.symbolData: sd = SymbolData(algorithm, symbol, self.slowPeriod, self.resolution) self.symbolData[symbol.Value] = sd sd.regIndicator(algorithm, self.resolution) sd.warmup(his.loc[ticker]) # method 2 for added in changes.AddedSecurities: if not added.Symbol in self.followerData: follower = FollowerData(algorithm, added, self.slowPeriod, self.resolution) follower.followerEMA = algorithm.EMA(added.Symbol, self.slowPeriod, self.resolution, self.field) follower.followerEMA.Updated += follower.FollowerEmaUpdated follower.followerEmaWindow = RollingWindow[IndicatorDataPoint](self.slowPeriod) # warmup our indicators by pushing history through the indicators history = algorithm.History(added.Symbol, self.lookup, self.resolution) if history.empty: continue if 'close' in history: history = history.close.unstack(0).squeeze() for time, value in history.iteritems(): follower.followerEMA.Update(time, value) self.followerData[added.Symbol.Value] = follower continue for removed in changes.RemovedSecurities: pass
from clr import AddReference AddReference("System") AddReference("QuantConnect") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Indicators") from System import * from System.Drawing import Color 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 import pandas as pd from io import StringIO import numpy as np import random from QuantConnect.Python import * from QuantConnect.Storage import * QCAlgorithmFramework = QCAlgorithm QCAlgorithmFrameworkBridge = QCAlgorithm from CUniverse import EmaUniverseSelectionModel from Alpha import CAlphaModel class GeekyOrangeSheep(QCAlgorithmFramework): def Initialize(self): self.SetStartDate(2021, 1, 20) # Set Start Date self.SetEndDate(2021, 2, 1) # self.SetEndDate(datetime.now() - timedelta(1)) self.SetCash(100000) # Adjust the cash buffer from the default 2.5% to 5% self.Settings.FreePortfolioValuePercentage = 0.05 # Rebalance when the insights state changes/added/expire. self.Settings.RebalancePortfolioOnInsightChanges = False # Rebalance when new assets are added to the universe. self.Settings.RebalancePortfolioOnSecurityChanges = False #Brokerage model and account type: self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) # Adjust the market fill-timeout to 30 seconds. self.Transactions.MarketOrderFillTimeout = timedelta(minutes=30) self.UniverseSettings.Resolution = Resolution.Daily self.UniverseSettings.Leverage = 1 self.SetUniverseSelection(EmaUniverseSelectionModel()) self.SetAlpha(CAlphaModel()) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.SetRiskManagement(NullRiskManagementModel()) # set Security to SplitAdjusted price self.SetSecurityInitializer(self.CustomSecurityInitializer) def CustomSecurityInitializer(self, security): ''' Initialize the security with SplitAdjusted prices mimic using a cash account in backtesting by setting security leverage to 1. ''' security.SetDataNormalizationMode(DataNormalizationMode.SplitAdjusted) security.SetLeverage(1)
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. # Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Indicators") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect.Data.UniverseSelection import * from QuantConnect.Indicators import ExponentialMovingAverage from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel import random import numpy as np class SymbolData: """ Holds every symbol's information and indicators. """ def __init__(self, symbol, algorithm, volPeriod = 30, rocPeriod = 9, volMax = 1000000): self.Symbol = symbol self.Volume = 0 self.Price = 0 self.algo = algorithm self.avgVolPeriod = volPeriod self.avgVolMax = volMax self.sma = SimpleMovingAverage(self.avgVolPeriod) self.rocp = RateOfChangePercent(rocPeriod + 1) self.rocW = RollingWindow[float](rocPeriod + 2) self.rocV = 0 self.isGood = False def update(self, time, volume, price): self.Volume = volume self.Price = price self.sma.Update(time, volume) self.rocp.Update(time, price) self.rocW.Add(price) if self.sma.IsReady and self.rocp.IsReady: sma = self.sma.Current.Value roc = self.rocp.Current.Value self.rocV = 100 * (self.rocW[0] - self.rocW[self.rocW.Count-1]) / self.rocW[self.rocW.Count-1] self.isGood = sma > self.avgVolMax and roc > 0 def warmup(self, history): for index, row in history.loc[str(self.Symbol)].iterrows(): c = row['close'] v = row['volume'] self.sma.Update(index, v) self.rocp.Update(index, c) self.rocW.Add(c) self.rocV = 100 * (self.rocW[0] - self.rocW[self.rocW.Count-1]) / self.rocW[self.rocW.Count-1] class EmaUniverseSelectionModel(FundamentalUniverseSelectionModel): '''Provides an implementation of FundamentalUniverseSelectionModel that subscribes to symbols with the larger delta by percentage between the two exponential moving average''' def __init__(self, slowPeriod = 50, resolution = Resolution.Daily, field = Field.Close, universeSettings = None, securityInitializer = None): '''Initializes a new instance of the EmaCrossUniverseSelectionModel class Args: fastPeriod: Fast EMA period slowPeriod: Slow EMA period universeCount: Maximum number of members of this universe selection universeSettings: The settings used when adding symbols to the algorithm, specify null to use algorthm.UniverseSettings securityInitializer: Optional security initializer invoked when creating new securities, specify null to use algorithm.SecurityInitializer''' super().__init__(True, universeSettings, securityInitializer) self.slowPeriod = slowPeriod self.resolution = resolution self.field = field self.coarseData = {} self.week = 0 self.month = -1 self.__avgVolPeriod = 30 self.__avgVolMax = 1000000 #1M self.__dailyVol = 500000 self.__filterPriceMin = 2 self.__filterPriceMax = 500 self.__numberOfSymbols = 100 self.spy = Symbol.Create('SPY', SecurityType.Equity, 'USA') def SelectCoarse(self, algorithm, coarse): '''Defines the coarse fundamental selection function. Args: algorithm: The algorithm instance coarse: The coarse fundamental data used to perform filtering</param> Returns: An enumerable of symbols passing the filter''' # current_week = algorithm.Time.month # if current_week == self.week: # return self.symbols # self.week = current_week symbols = [x for x in coarse if self.__filterPriceMax > x.Price > self.__filterPriceMin and \ x.Volume > self.__dailyVol] symbols = sorted(symbols, key = lambda x: x.Volume, reverse=True)[:300] for cf in symbols: if not cf.Symbol in self.coarseData: history = algorithm.History([cf.Symbol], 30, self.resolution) if history.empty: continue if history.size < 30: continue self.coarseData[cf.Symbol] = SymbolData(cf.Symbol, algorithm) self.coarseData[cf.Symbol].warmup(history) self.coarseData[cf.Symbol].update(cf.EndTime, cf.Volume, cf.AdjustedPrice) algorithm.Debug(f"-Universe Coarse- {algorithm.Time - timedelta(1)}") values = list(filter(lambda x: x.isGood, self.coarseData.values())) values = sorted(values, key = lambda x: x.rocV, reverse=True)[:self.__numberOfSymbols] algorithm.Debug(f"\t symbols: {[x.Symbol.Value for x in values]}") res = [x.Symbol for x in values] res.append(self.spy) return res def SelectFine(self, algorithm, fine): # current_week = algorithm.Time.month # if current_week == self.week: # return self.symbols symbols = [x.Symbol for x in fine if x.SecurityReference.ExchangeId in ["NAS", "NYS", "ASE"]] symbols.append(self.spy) return symbols def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the 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''' for removed in changes.RemovedSecurities: # clean up data from removed securities symbol = removed.Symbol if symbol in self.coarseData: data = self.coarseData.pop(symbol)