Overall Statistics |
Total Trades 18 Average Win 3.31% Average Loss -0.91% Compounding Annual Return 0.008% Drawdown 6.200% Expectancy 0.031 Net Profit 0.014% Sharpe Ratio 0.02 Probabilistic Sharpe Ratio 5.822% Loss Rate 78% Win Rate 22% Profit-Loss Ratio 3.64 Alpha 0 Beta 0 Annual Standard Deviation 0.038 Annual Variance 0.001 Information Ratio 0.02 Tracking Error 0.038 Treynor Ratio 0 Total Fees $158.78 Estimated Strategy Capacity $2000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP Portfolio Turnover 2.46% |
# region imports from AlgorithmImports import * # endregion class FocusedFluorescentOrangeHyena(QCAlgorithm): def Initialize(self): self.SetStartDate(2004, 8, 26) self.SetEndDate(2006, 6, 5) self.SetCash(100000) self.UniverseSettings.Resolution = Resolution.Daily self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash) self.SetUniverseSelection(SingleTickerSelectionModel()) self.AddAlpha(MacroTrendSMAAlphaModel(window=100)) self.SetPortfolioConstruction(MyPortfolioConstructionModel()) self.SetExecution(MyAwesomeImmediateExecutionModel()) self.AddRiskManagement(NullRiskManagementModel()) class SingleTickerSelectionModel(ManualUniverseSelectionModel): def __init__(self): tickers = ['TLT'] symbols = [Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers] super().__init__(symbols) class MacroTrendSMAAlphaModel(AlphaModel): def __init__(self, window, resolution = Resolution.Daily): """Initialises a new instance of the MacroTrendSMAAlphaModel """ self.window = window self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), window) self.symbolDataBySymbol = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = f'{self.__class__.__name__}({window},{resolutionString})' def Update(self, algorithm, data): """ Updates the alpha model with the latest data from the algorithm. This is called each time the algorithm receives new data for the subscribed securities """ insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): if symbolData.IsReady: if symbolData.lookback.IsReady: if symbolData.TurningDown: if symbolData.lookback[0].Price > symbolData.lookback[1].Price: insights.append(Insight.Price(symbolData.Symbol, self.predictionInterval, InsightDirection.Up)) algorithm.Log(f'Insight Up: {algorithm.Time.date()} Prior Ind: {symbolData.lookback[1].Price:.3f}, Curr Ind: {symbolData.lookback[0].Price:.3f}') elif symbolData.TurningUp: if symbolData.lookback[0].Price < symbolData.lookback[1].Price: insights.append(Insight.Price(symbolData.Symbol, self.predictionInterval, InsightDirection.Flat)) algorithm.Log(f'Insight Flat: {algorithm.Time.date()} Prior Ind: {symbolData.lookback[1].Price:.3f}, Curr Ind: {symbolData.lookback[0].Price:.3f}') symbolData.TurningUp = symbolData.lookback[0].Price > symbolData.lookback[1].Price return insights def OnSecuritiesChanged(self, algorithm, changes): """ Event is fired each time we add or remove securities from the data feed """ for security in changes.AddedSecurities: symbolData = self.symbolDataBySymbol.get(security.Symbol) if symbolData is None: symbolData = SymbolData(security, self.window, algorithm, self.resolution) self.symbolDataBySymbol[security.Symbol] = symbolData else: # A security that was already intialised was re-added, reset the indicators symbolData.SMA.Reset() for security in changes.RemovedSecurities: data = self.symbolDataBySymbol.pop(security.Symbol, None) if data is not None: # clean up our consolidators data.RemoveConsolidators() class SymbolData: """ Contains data specific to a symbol required by this model """ def __init__(self, security, window, algorithm, resolution): self.Security = security self.Symbol = security.Symbol self.algorithm = algorithm # rolling window to store the SMA values below self.lookback = RollingWindow[IndicatorDataPoint](2) self.SMAConsolidator = algorithm.ResolveConsolidator(security.Symbol, resolution) algorithm.SubscriptionManager.AddConsolidator(security.Symbol, self.SMAConsolidator) self.SMA = SimpleMovingAverage(security.Symbol, window) # This line is causing the problem I think. I want to instuct the auto updating of the lookback to hold the SMA values self.SMA.Updated += (lambda sender, updated: self.lookback.Add(updated)) algorithm.RegisterIndicator(security.Symbol, self.SMA, self.SMAConsolidator); algorithm.WarmUpIndicator(security.Symbol, self.SMA, resolution); # True if SMA indicator is turning up and false if not self.TurningUp = False def RemoveConsolidator(self): self.algorithm.SubscriptionManager.RemoveConsolidator(self.Security.Symbol, self.SMAConsolidator) def IsReady(self): return self.SMA.IsReady @property def TurningDown(self): return not self.TurningUp class MyPortfolioConstructionModel(PortfolioConstructionModel): '''Provides an implementation of IPortfolioConstructionModel that gives equal weighting to all securities. The target percent holdings of each security is 1/N where N is the number of securities. For insights of direction InsightDirection.Up, long targets are returned and for insights of direction InsightDirection.Down, short targets are returned.''' def __init__(self, rebalance = None, portfolioBias = PortfolioBias.Long): '''Initialize a new instance of EqualWeightingPortfolioConstructionModel Args: rebalance: Rebalancing parameter. If it is a timedelta, date rules or Resolution, it will be converted into a function. If None will be ignored. The function returns the next expected rebalance time for a given algorithm UTC DateTime. The function returns null if unknown, in which case the function will be called again in the next loop. Returning current time will trigger rebalance. portfolioBias: Specifies the bias of the portfolio (Short, Long/Short, Long)''' super().__init__() self.portfolioBias = portfolioBias # If the argument is an instance of Resolution or Timedelta # Redefine rebalancingFunc rebalancingFunc = rebalance if isinstance(rebalance, int): rebalance = Extensions.ToTimeSpan(rebalance) if isinstance(rebalance, timedelta): rebalancingFunc = lambda dt: dt + rebalance if rebalancingFunc: self.SetRebalancingFunc(rebalancingFunc) def DetermineTargetPercent(self, activeInsights): '''Will determine the target percent for each insight Args: activeInsights: The active insights to generate a target for''' result = {} # give equal weighting to each security count = sum(x.Direction != InsightDirection.Flat and self.RespectPortfolioBias(x) for x in activeInsights) percent = 0 if count == 0 else 1.0 / count for insight in activeInsights: result[insight] = (insight.Direction if self.RespectPortfolioBias(insight) else InsightDirection.Flat) * percent return result def RespectPortfolioBias(self, insight): '''Method that will determine if a given insight respects the portfolio bias Args: insight: The insight to create a target for ''' return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == self.portfolioBias class MyAwesomeImmediateExecutionModel(ExecutionModel): '''Provides an implementation of IExecutionModel that immediately submits market orders to achieve the desired portfolio targets''' def __init__(self): '''Initializes a new instance of the ImmediateExecutionModel class''' self.targetsCollection = PortfolioTargetCollection() def Execute(self, algorithm, targets): '''Immediately submits orders for the specified portfolio targets. Args: algorithm: The algorithm instance targets: The portfolio targets to be ordered''' # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call self.targetsCollection.AddRange(targets) if not self.targetsCollection.IsEmpty: for target in self.targetsCollection.OrderByMarginImpact(algorithm): security = algorithm.Securities[target.Symbol] # calculate remaining quantity to be ordered quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security) if quantity != 0: aboveMinimumPortfolio = BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(security.BuyingPowerModel, security, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage) if aboveMinimumPortfolio: algorithm.MarketOrder(security, quantity) elif not PortfolioTarget.MinimumOrderMarginPercentageWarningSent: # will trigger the warning if it has not already been sent PortfolioTarget.MinimumOrderMarginPercentageWarningSent = False self.targetsCollection.ClearFulfilled(algorithm)