| 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