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