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