# 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.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data import *
from QuantConnect.Indicators import *
from QuantConnect.Orders import *
from QuantConnect.Securities import *
import decimal as d
###
### Regression test for history and warm up using the data available in open source.
###
###
###
###
###
class HistoryAndWarmupRegressionAlgorithm(QCAlgorithm):
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.'''
self.SetStartDate(2013, 10, 8) #Set Start Date
self.SetEndDate(2013, 10, 11) #Set End Date
self.SetCash(1000000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.AddEquity("SPY")
self.AddEquity("IBM")
self.AddEquity("BAC")
self.AddEquity("GOOG", Resolution.Daily)
self.AddEquity("GOOGL", Resolution.Daily)
self.__sd = { }
for security in self.Securities:
self.__sd[security.Key] = self.SymbolData(security.Key, self)
# we want to warm up our algorithm
self.SetWarmup(self.SymbolData.RequiredBarsWarmup)
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
'''
# we are only using warmup for indicator spooling, so wait for us to be warm then continue
if self.IsWarmingUp: return
for sd in self.__sd.values():
lastPriceTime = sd.Close.Current.Time
if self.RoundDown(lastPriceTime, sd.Security.SubscriptionDataConfig.Increment):
sd.Update()
def OnOrderEvent(self, fill):
sd = self.__sd.get(fill.Symbol, None)
if sd is not None:
sd.OnOrderEvent(fill)
def RoundDown(self, time, increment):
if increment.days != 0:
return time.hour == 0 and time.minute == 0 and time.second == 0
else:
return time.second == 0
class SymbolData:
RequiredBarsWarmup = 40
PercentTolerance = 0.001
PercentGlobalStopLoss = 0.01
LotSize = 10
def __init__(self, symbol, algorithm):
self.Symbol = symbol
self.__algorithm = algorithm # if we're receiving daily
self.__currentStopLoss = None
self.Security = algorithm.Securities[symbol]
self.Close = algorithm.Identity(symbol)
self.ADX = algorithm.ADX(symbol, 14)
self.EMA = algorithm.EMA(symbol, 14)
self.MACD = algorithm.MACD(symbol, 12, 26, 9)
self.IsReady = self.Close.IsReady and self.ADX.IsReady and self.EMA.IsReady and self.MACD.IsReady
self.IsUptrend = False
self.IsDowntrend = False
def Update(self):
self.IsReady = self.Close.IsReady and self.ADX.IsReady and self.EMA.IsReady and self.MACD.IsReady
tolerance = d.Decimal(1 - self.PercentTolerance)
self.IsUptrend = self.MACD.Signal.Current.Value > self.MACD.Current.Value * tolerance and\
self.EMA.Current.Value > self.Close.Current.Value * tolerance
self.IsDowntrend = self.MACD.Signal.Current.Value < self.MACD.Current.Value * tolerance and\
self.EMA.Current.Value < self.Close.Current.Value * tolerance
self.TryEnter()
self.TryExit()
def TryEnter(self):
# can't enter if we're already in
if self.Security.Invested: return False
qty = 0
limit = 0.0
if self.IsUptrend:
# 100 order lots
qty = self.LotSize
limit = self.Security.Low
elif self.IsDowntrend:
qty = -self.LotSize
limit = self.Security.High
if qty != 0:
ticket = self.__algorithm.LimitOrder(self.Symbol, qty, limit, "TryEnter at: {0}".format(limit))
def TryExit(self):
# can't exit if we haven't entered
if not self.Security.Invested: return
limit = 0
qty = self.Security.Holdings.Quantity
exitTolerance = d.Decimal(1 + 2 * self.PercentTolerance)
if self.Security.Holdings.IsLong and self.Close.Current.Value * exitTolerance < self.EMA.Current.Value:
limit = self.Security.High
elif self.Security.Holdings.IsShort and self.Close.Current.Value > self.EMA.Current.Value * exitTolerance:
limit = self.Security.Low
if limit != 0:
ticket = self.__algorithm.LimitOrder(self.Symbol, -qty, limit, "TryExit at: {0}".format(limit))
def OnOrderEvent(self, fill):
if fill.Status != OrderStatus.Filled: return
qty = self.Security.Holdings.Quantity
# if we just finished entering, place a stop loss as well
if self.Security.Invested:
stop = fill.FillPrice*d.Decimal(1 - self.PercentGlobalStopLoss) if self.Security.Holdings.IsLong \
else fill.FillPrice*d.Decimal(1 + self.PercentGlobalStopLoss)
self.__currentStopLoss = self.__algorithm.StopMarketOrder(self.Symbol, -qty, stop, "StopLoss at: {0}".format(stop))
# check for an exit, cancel the stop loss
elif (self.__currentStopLoss is not None and self.__currentStopLoss.Status is not OrderStatus.Filled):
# cancel our current stop loss
self.__currentStopLoss.Cancel("Exited position")
self.__currentStopLoss = None