Overall Statistics |
Total Trades 102 Average Win 0.49% Average Loss -1.45% Compounding Annual Return 8.740% Drawdown 12.900% Expectancy 0.169 Net Profit 37.304% Sharpe Ratio 0.88 Loss Rate 13% Win Rate 87% Profit-Loss Ratio 0.34 Alpha 0.175 Beta -6.223 Annual Standard Deviation 0.082 Annual Variance 0.007 Information Ratio 0.68 Tracking Error 0.082 Treynor Ratio -0.012 Total Fees $135.91 |
# 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("QuantConnect.Algorithm.Framework") AddReference("QuantConnect.Indicators") AddReference("QuantConnect.Common") from QuantConnect import * from QuantConnect.Indicators import * from QuantConnect.Algorithm.Framework.Alphas import * from datetime import timedelta from enum import Enum class PPOAlphaModel(AlphaModel): '''Uses PPO to create insights. Using default settings, slow/fast is 12/26. Above/below -.5 will trigger a new insight.''' rebalance_date = None rebalance_complete = False def __init__(self, fastPeriod = 12*5, slowPeriod = 26*5, trigger = 0.0, consolidationPeriod = 7, resolution = Resolution.Daily): self.lookback = (slowPeriod * 3) self.fastPeriod = fastPeriod self.slowPeriod = slowPeriod self.resolution = resolution self.consolidationPeriod = consolidationPeriod self.trigger = trigger self.predictionInterval = Extensions.ToTimeSpan(self.resolution) self.symbolDataBySymbol = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, resolutionString) 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''' #algorithm.Debug("Update Called on PPOAlphaModel") # generate insights when scheduled insights = [] #and algorithm.Time.hour == 8 and algorithm.Time.minute == 59 if self.rebalance_complete or not (algorithm.Time.date() == self.rebalance_date): return insights # only get here to build new insights once on the scheduled trading date self.rebalance_complete = True #algorithm.Debug("Now Generating Insights in PPOAlpha") for symbol, symbolData in self.symbolDataBySymbol.items(): if symbolData.CanEmit: direction = InsightDirection.Flat magnitude = symbolData.Return #algorithm.Debug("got a positive CanEmit with symbol and magnitude: " + str(symbol) + str(magnitude)) if magnitude > self.trigger: direction = InsightDirection.Up if magnitude < self.trigger: direction = InsightDirection.Flat insights.append(Insight.Price(symbol, self.predictionInterval, direction)) algorithm.Log(str(symbol) + ": " + str(magnitude) + ": " + str(direction)) 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''' #algorithm.Debug("starting OnSecuritiesChanged") # 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) #algorithm.Debug("in OnSecuritiesChanged past removed list") # initialize data for added securities symbols = [ x.Symbol for x in changes.AddedSecurities ] #algorithm.Debug("before history retrieval") history = algorithm.History(symbols, self.lookback, self.resolution) #algorithm.Debug("after history retrieval") 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.fastPeriod, self.slowPeriod, self.consolidationPeriod) 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, fastPeriod, slowPeriod, consolidationPeriod): self.Symbol = symbol self.Fast = fastPeriod self.Slow = slowPeriod self.PPO = PercentagePriceOscillator(fastPeriod, slowPeriod, MovingAverageType.Exponential) #self.Consolidator = TradeBarConsolidator(TimeSpan.FromDays(consolidationPeriod)) self.Consolidator = None self.Previous = None # True if the fast is above the slow, otherwise false. # This is used to prevent emitting the same signal repeatedly #self.FastIsOverSlow = False #self.abovePPOTrigger = False #def setPPOTrigger (self, value): #self.abovePPOTrigger = value @property def belowPPOTrigger(self): return (not self.abovePPOTrigger) @property def CanEmit(self): if self.Previous == self.PPO.Samples: return False self.Previous = self.PPO.Samples return self.PPO.IsReady @property def Return(self): return float(self.PPO.Current.Value) #def OnWeeklyData(self, sender, bar): #self.PPO.Update(bar.EndTime, bar.Close) def RegisterIndicators(self, algorithm, resolution): #self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution) algorithm.RegisterIndicator(self.Symbol, self.PPO, 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.PPO.Update(tuple.Index, tuple.close) #self.Consolidator.Update(tuple)
from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") AddReference("QuantConnect.Common") from System import * from QuantConnect import * from QuantConnect.Orders import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Selection import * from PPOAlphaModel import PPOAlphaModel #from QuantConnect.Algorithm.Framework.Alphas.ConstantAlphaModel import ConstantAlphaModel from Alphas.RsiAlphaModel import RsiAlphaModel from QuantConnect.Algorithm.Framework.Execution import ImmediateExecutionModel from QuantConnect.Algorithm.Framework.Execution import VolumeWeightedAveragePriceExecutionModel from QuantConnect.Algorithm.Framework.Risk import NullRiskManagementModel from datetime import datetime, timedelta import numpy as np ### <summary> ### Basic template framework algorithm uses framework components to define the algorithm. ### </summary> ### <meta name="tag" content="using data" /> ### <meta name="tag" content="using quantconnect" /> ### <meta name="tag" content="trading and orders" /> class AssetClassRotationFrameworkAlgorithm(QCAlgorithmFramework): '''Basic template framework algorithm uses framework components to define the algorithm.''' alpha = None def Initialize(self): ''' Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' # Set requested data resolution self.UniverseSettings.Resolution = Resolution.Daily self.UniverseSettings.Leverage = 1.0 self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.SetStartDate(2014,10,7) #Set Start Date self.SetEndDate(2018,7,18) #Set End Date self.SetCash(100000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data # Forex, CFD, Equities Resolutions: Tick, Second, Minute, Hour, Daily. # Futures Resolution: Tick, Second, Minute # Options Resolution: Minute Only. tickers = ['IWM', 'QQQ', 'EEM'] symbols = [ Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers ] # set algorithm framework models self.SetUniverseSelection(ManualUniverseSelectionModel(symbols)) #self.SetAlpha(IchimokuAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(days = 10), 0.025, None)) self.alpha = PPOAlphaModel() self.SetAlpha(self.alpha) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.SetRiskManagement(NullRiskManagementModel()) # will initialize a position immediately then on the given schedule self.alpha.rebalance_date = self.Time.date() self.rebalance_trading_day = 7 self.AddEquity('IWM') self.Schedule.On(self.DateRules.MonthStart('IWM'), self.TimeRules.AfterMarketOpen('IWM', 1), Action(self.ScheduleRebalance)) def ScheduleRebalance(self): month_last_day = DateTime(self.Time.year, self.Time.month, DateTime.DaysInMonth(self.Time.year, self.Time.month)) trading_days = self.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, self.Time, month_last_day) #get the correct trading_day day_count = 0 for x in trading_days: day_count = day_count + 1 if (day_count == self.rebalance_trading_day): self.alpha.rebalance_date = x.Date.date() self.alpha.rebalance_complete = False def OnOrderEvent(self, orderEvent): if orderEvent.Status == OrderStatus.Filled: #self.Debug("Purchased Stock: {0}, {1}".format(orderEvent.Symbol, orderEvent.FillQuantity)) return