| Overall Statistics |
|
Total Trades 756 Average Win 0.13% Average Loss -0.14% Compounding Annual Return -99.802% Drawdown 33.400% Expectancy -0.436 Net Profit -22.631% Sharpe Ratio -16.118 Probabilistic Sharpe Ratio 0% Loss Rate 71% Win Rate 29% Profit-Loss Ratio 0.95 Alpha -5.17 Beta 0.361 Annual Standard Deviation 0.303 Annual Variance 0.092 Information Ratio -17.682 Tracking Error 0.321 Treynor Ratio -13.509 Total Fees $3170.90 |
# 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.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
class MovingAverageCrossAlphaModel(AlphaModel):
'''Alpha model that uses an EMA cross to create insights'''
def __init__(self,
fastPeriod = 12,
slowPeriod = 26,
resolution = Resolution.Daily):
'''Initializes a new instance of the EmaCrossAlphaModel class
Args:
fastPeriod: The fast EMA period
slowPeriod: The slow EMA period'''
self.fastPeriod = fastPeriod
self.slowPeriod = slowPeriod
self.resolution = resolution
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod)
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'''
insights = []
for chain in data.FutureChains:
contracts = [contract for contract in chain.Value]
frontContract = contracts[0]
symbol = frontContract.Symbol
if chain.Key not in self.symbolDataBySymbol:
self.symbolDataBySymbol[chain.Key] = SymbolData(algorithm, symbol, self.fastPeriod, self.slowPeriod, self.resolution)
else:
if symbol != self.symbolDataBySymbol[chain.Key].frontContractSymbol:
self.symbolDataBySymbol[chain.Key].frontContractSymbol = symbol
self.symbolDataBySymbol[chain.Key].WarmUp()
symbolData = self.symbolDataBySymbol[chain.Key]
bars = chain.Value.TradeBars
if symbol in bars.Keys:
bar = chain.Value.TradeBars[symbol]
symbolData.Update(bar.Time, bar.Close)
if symbolData.IsReady:
if symbolData.ShortCrossOver:
insights.append(Insight(symbolData.frontContractSymbol, self.predictionInterval, InsightType.Price, InsightDirection.Down, -0.0025, 1.00, None, 0.05))
elif symbolData.LongCrossOver:
insights.append(Insight(symbolData.frontContractSymbol, self.predictionInterval, InsightType.Price, InsightDirection.Up, 0.0025, 1.00, None, 0.05))
return insights
class SymbolData:
'''Contains data specific to a symbol required by this model'''
def __init__(self, algorithm, symbol, fastPeriod, slowPeriod, resolution):
self.algorithm = algorithm
self.frontContractSymbol = symbol
self.resolution = resolution
self.fastPeriod = fastPeriod
self.slowPeriod = slowPeriod
self.Fast = ExponentialMovingAverage(self.fastPeriod)
self.Slow = ExponentialMovingAverage(self.slowPeriod)
self.fastWindow = RollingWindow[IndicatorDataPoint](2)
self.slowWindow = RollingWindow[IndicatorDataPoint](2)
self.Fast.Updated += self.OnFastEMA
self.Slow.Updated += self.OnSlowEMA
self.WarmUp()
def WarmUp(self):
history = self.algorithm.History(self.frontContractSymbol, self.slowPeriod, self.resolution)
if not history.empty:
history = history.close.unstack(1)
if not history.empty:
df = history[self.frontContractSymbol].dropna()
if not df.empty:
for time, close in df.iteritems():
self.Update(time[1], close)
@property
def IsReady(self):
return self.fastWindow.IsReady and self.slowWindow.IsReady
def Update(self, time, close):
self.Fast.Update(time, close)
self.Slow.Update(time, close)
@property
def LongCrossOver(self):
return self.fastWindow[1].Value < self.slowWindow[1].Value \
and self.fastWindow[0].Value > self.slowWindow[0].Value
@property
def ShortCrossOver(self):
return self.fastWindow[1].Value > self.slowWindow[1].Value \
and self.fastWindow[0].Value < self.slowWindow[0].Value
def OnFastEMA(self, sender, updated):
if self.Fast.IsReady:
self.fastWindow.Add(updated)
def OnSlowEMA(self, sender, updated):
if self.Slow.IsReady:
self.slowWindow.Add(updated)from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.MeanVarianceOptimizationPortfolioConstructionModel import MeanVarianceOptimizationPortfolioConstructionModel
from Risk.MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity
from FuturesUniverseSelectionModel import FuturesUniverseSelectionModel
from ATRBasedPositionSizing import ATRBasedPositionSizing
from MovingAverageCrossAlphaModel import MovingAverageCrossAlphaModel
class MovingAverageCrossTrendFollowing(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1) # Set Start Date
self.SetEndDate(2019, 1, 15) # Set End Date
self.SetCash(100000) # Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Minute
self.SetUniverseSelection(FuturesUniverseSelectionModel(self.SelectFuturesSymbols))
self.AddAlpha(MovingAverageCrossAlphaModel(50, 200, Resolution.Minute))
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
def SelectFuturesSymbols(self, utcTime):
tickers = [Futures.Indices.SP500EMini,
Futures.Grains.BlackSeaCornFinanciallySettledPlatts,
Futures.Grains.Wheat,
Futures.Grains.Corn,
Futures.Grains.Soybeans,
Futures.Grains.SoybeanMeal,
Futures.Grains.SoybeanOil,
Futures.Grains.Oats,
Futures.Currencies.USD,
Futures.Currencies.GBP,
Futures.Currencies.CAD,
Futures.Currencies.JPY,
Futures.Currencies.CHF,
Futures.Currencies.EUR,
Futures.Softs.Cocoa,
Futures.Dairy.CashSettledButter,
Futures.Dairy.CashSettledCheese,
Futures.Dairy.ClassIIIMilk,
Futures.Dairy.DryWhey,
Futures.Dairy.ClassIVMilk,
Futures.Dairy.NonfatDryMilk]
return [ Symbol.Create(ticker, SecurityType.Future, Market.USA) for ticker in tickers]from Selection.FutureUniverseSelectionModel import FutureUniverseSelectionModel
from datetime import date, timedelta
class FuturesUniverseSelectionModel(FutureUniverseSelectionModel):
def __init__(self, select_future_chain_symbols):
super().__init__(timedelta(1), select_future_chain_symbols)
def Filter(self, filter):
return (filter.FrontMonth())from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from Portfolio.MinimumVariancePortfolioOptimizer import MinimumVariancePortfolioOptimizer
from datetime import timedelta
import numpy as np
import pandas as pd
### <summary>
### </summary>
class ATRBasedPositionSizing(PortfolioConstructionModel):
def __init__(self,
riskFactor = 0.2,
lookbackPeriod = 100):
"""Initialize the model
Args:
lookback(int): Historical return lookback period
period(int): The time interval of history price to calculate the weight
resolution: The resolution of the history price
optimizer(class): Method used to compute the portfolio weights"""
self.atrs = {}
self.lookbackPeriod = lookbackPeriod
self.riskFactor = riskFactor
def CreateTargets(self, algorithm, insights):
"""
Create portfolio targets from the specified insights
Args:
algorithm: The algorithm instance
insights: The insights to create portfolio targets from
Returns:
An enumerable of portfolio targets to be sent to the execution model
"""
targets = []
for insight in insights:
symbol = insight.Symbol
if symbol in self.atrs.keys():
direction = 1 if InsightDirection.Up else -1
price = algorithm.Securities[symbol].Price
atr = self.atrs[symbol].Current.Value
numberOfContracts = np.floor((direction * (self.riskFactor*algorithm.Portfolio.TotalPortfolioValue)/(atr*price )))
target = PortfolioTarget(insight.Symbol, numberOfContracts)
if target is not None:
targets.append(target)
return targets
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'''
for addedSecurity in changes.AddedSecurities:
ticker = addedSecurity.Symbol
if ticker not in self.atrs.keys():
self.atrs[ticker] = algorithm.ATR(ticker, self.lookbackPeriod)