| Overall Statistics |
|
Total Trades 112 Average Win 0.50% Average Loss -3.53% Compounding Annual Return 5.904% Drawdown 31.100% Expectancy -0.032 Net Profit 24.241% Sharpe Ratio 0.522 Loss Rate 15% Win Rate 85% Profit-Loss Ratio 0.14 Alpha 0.066 Beta -0.836 Annual Standard Deviation 0.1 Annual Variance 0.01 Information Ratio 0.358 Tracking Error 0.1 Treynor Ratio -0.062 Total Fees $189.04 |
# 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,
slowPeriod = 26,
trigger = 0.0,
consolidationPeriod = 7,
resolution = Resolution.Daily):
self.lookback = (slowPeriod * consolidationPeriod)
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)
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
@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):
#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):
#index = 0
#for tuple in history.itertuples():
for index, tuple in history.iterrows():
#index = index + 1
#if index % consolidationPeriod == 0:
#self.PPO.Update(tuple.Index, tuple.close)
tradeBar = TradeBar()
tradeBar.Close = tuple['close']
tradeBar.Open = tuple['open']
tradeBar.High = tuple['high']
tradeBar.Low = tuple['low']
tradeBar.Volume = tuple['volume']
tradeBar.Time = index
self.Consolidator.Update(tradeBar)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 Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
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','SCHH', 'USO', 'VDE', 'XBI', 'AAXJ', 'DBA', 'DBB', 'DBC', 'DOG', 'EEM', 'EFA', 'EWH', 'EWJ', 'EWZ', 'EZU', 'FXI', 'GDX', 'GLD', 'HYG', 'IEF', 'IEFA', 'LQD', 'SH', 'SLV', 'TAN', 'TIP', 'TLT', 'UUP', 'VAW', 'VEU', 'VNQ', 'XLE', 'XLK', 'XLY', 'XLB', 'XLF', 'XLI', 'XLP', 'XLU', 'XLV']
tickers = ['IWM', 'XLK', 'DOG', '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