| Overall Statistics |
|
Total Trades 2250 Average Win 0.78% Average Loss -0.23% Compounding Annual Return 4.379% Drawdown 18.600% Expectancy 0.094 Net Profit 23.982% Sharpe Ratio 0.354 Probabilistic Sharpe Ratio 7.471% Loss Rate 75% Win Rate 25% Profit-Loss Ratio 3.41 Alpha 0.119 Beta -0.517 Annual Standard Deviation 0.155 Annual Variance 0.024 Information Ratio -0.282 Tracking Error 0.245 Treynor Ratio -0.106 Total Fees $54875.09 |
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
from FollowTheLeaderAlphaV1 import FollowTheLeaderAlphaV1
class FollowTheLeader(QCAlgorithm):
def Initialize(self):
# Set Start Date so that backtest has 5+ years of data
self.SetStartDate(2015, 2, 15)
# No need to set End Date as the final submission will be tested
# up until the review date
# Set $1m Strategy Cash to trade significant AUM
self.SetCash(1000000)
# Use the Alpha Streams Brokerage Model, developed in conjunction with
# funds to model their actual fees, costs, etc.
# Please do not add any additional reality modelling, such as Slippage, Fees, Buying Power, etc.
self.SetBrokerageModel(AlphaStreamsBrokerageModel())
self.SetExecution(ImmediateExecutionModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
usoil = self.AddCfd('USOIL')
exxon = self.AddEquity('XOM')
symbols = [ usoil, exxon ]
pairs_map = [[usoil.Symbol, exxon.Symbol]]
self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )
self.SetRiskManagement(TrailingStopRiskManagementModel(0.03))
self.AddAlpha(FollowTheLeaderAlphaV1(pairs_map))
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
# if not self.Portfolio.Invested:
# self.SetHoldings("SPY", 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.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import AlphaModel, Insight, InsightType, InsightDirection
from datetime import timedelta
import numpy as np
from scipy import stats
import pandas as pd
from time import strftime
class FollowTheLeaderAlphaV1(AlphaModel):
def __init__(self, pairs_map, meanPeriod = 400, std_threshold = 1.75, std_reset_threshold = 0.25, min_percentage_distance = 0.1, resolution = timedelta(hours=4)):
self.meanPeriod = meanPeriod
self.std_threshold = std_threshold
self.std_reset_threshold = std_reset_threshold
self.min_percentage_distance = min_percentage_distance
self.resolution = resolution
self.pairs_map = pairs_map
self.securityPairs = {}
def Update(self, algorithm, data):
insights = []
for identifier, securityPair in self.securityPairs.items():
commodityNormalized = securityPair.CommodityPriceNormalized
equityNormalized = securityPair.EquityPriceNormalized
distance = equityNormalized - commodityNormalized
securityPair.MeanDistance.Update(algorithm.Time, distance)
securityPair.StandDevDistance.Update(algorithm.Time, distance)
if securityPair.MeanDistance.IsReady:
upperThreshold = securityPair.MeanDistance.Current.Value + (securityPair.StandDevDistance.Current.Value * self.std_threshold)
lowerThreshold = securityPair.MeanDistance.Current.Value - (securityPair.StandDevDistance.Current.Value * self.std_threshold)
upperResetThreshold = securityPair.MeanDistance.Current.Value + (securityPair.StandDevDistance.Current.Value * self.std_reset_threshold)
lowerResetThreshold = securityPair.MeanDistance.Current.Value + (securityPair.StandDevDistance.Current.Value * self.std_reset_threshold)
if distance > upperThreshold:
if not securityPair.shortTaken and distance > self.min_percentage_distance:
securityPair.shortTaken = True
estimatedMagnitude = securityPair.EstimateMagnitude(distance)
insights.append(Insight.Price(securityPair.equity.Symbol, self.resolution*10, InsightDirection.Down, estimatedMagnitude))
elif securityPair.shortTaken and distance < upperResetThreshold:
securityPair.shortTaken = False
if distance < lowerThreshold:
if not securityPair.longTaken and distance < self.min_percentage_distance*-1:
securityPair.longTaken = True
estimatedMagnitude = securityPair.EstimateMagnitude(distance)
insights.append(Insight.Price(securityPair.equity.Symbol, self.resolution*10, InsightDirection.Up, estimatedMagnitude))
elif securityPair.longTaken and distance > lowerResetThreshold:
securityPair.longTaken = False
return insights
def OnSecuritiesChanged(self, algorithm, changes):
for pair in self.pairs_map:
securityOne = None
securityTwo = None
for added in changes.AddedSecurities:
if added.Symbol == pair[0]:
securityOne = added
if added.Symbol == pair[1]:
securityTwo = added
if securityOne is not None and securityTwo is not None:
identifier = '{0}/{1}'.format(securityOne.Symbol, securityTwo.Symbol)
algorithm.Log(identifier)
securityPair = self.securityPairs.get(identifier)
if securityPair is None:
securityPair = SecurityPair(securityOne, securityTwo)
securityPair.MeanDistance = SimpleMovingAverage(self.meanPeriod)
securityPair.StandDevDistance = StandardDeviation(self.meanPeriod)
securityPair.commodityMax = Maximum(self.meanPeriod)
securityPair.equityMax = Maximum(self.meanPeriod)
securityPair.commodityMin = Minimum(self.meanPeriod)
securityPair.equityMin = Minimum(self.meanPeriod)
securityOneHistory = algorithm.History(securityOne.Symbol, self.meanPeriod, Resolution.Hour)
securityTwoHistory = algorithm.History(securityTwo.Symbol, self.meanPeriod, Resolution.Hour)
for index, row in securityOneHistory.iterrows():
securityPair.commodityMax.Update(row.time, row.close)
securityPair.commodityMin.Update(row.time, row.close)
securityPair.equityMax.Update(securityTwoHistory[index].time, securityTwoHistory[index].close)
securityPair.equityMin.Update(securityTwoHistory[index].time, securityTwoHistory[index].close)
for index, row in securityOneHistory.iterrows():
commodityNormalized = (row.close -
securityPair.commodityMin.Current.Value) / (securityPair.commodityMax.Current.Value
- securityPair.commodityMin.Current.Value)
equityNormalized = (securityTwoHistory[index].close -
securityPair.equityMin.Current.Value) / (securityPair.equityMax.Current.Value
- securityPair.equityMin.Current.Value)
securityPair.MeanDistance.Update(row.time, equityNormalized-commodityNormalized)
securityPair.StandDevDistance.Update(row.time, equityNormalized-commodityNormalized)
self.securityPairs[identifier] = securityPair
else:
securityPair.MeanDistance.Reset()
securityPair.StandDevDistance.Reset()
break
class SecurityPair:
def __init__(self, commodity, equity):
self.commodity = commodity
self.equity = equity
self.longTaken = False
self.shortTaken = False
self.MeanDistance = None
self.StandDevDistance = None
self.commodityMax = None
self.commodityMin = None
self.equityMax = None
self.equityMin = None
def EstimateMagnitude(self, distance):
maximum = self.equityMax.Current.Value
minimum = self.equityMin.Current.Value
return ((abs(distance) * (maximum - minimum)) * 0.8) / self.equity.Price
@property
def CommodityPriceNormalized(self):
maximum = self.commodityMax.Current.Value
minimum = self.commodityMin.Current.Value
if maximum == 0:
maximum = 1
minimum = 0
return (self.commodity.Price - minimum) / (maximum - minimum)
@property
def EquityPriceNormalized(self):
maximum = self.equityMax.Current.Value
minimum = self.equityMin.Current.Value
if maximum == 0:
maximum = 1
minimum = 0
return (self.equity.Price - minimum) / (maximum - minimum)# Your New Python File