| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
import numpy as np
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from System.Collections.Generic import List
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders import OrderStatus
from QuantConnect.Orders.Fills import ImmediateFillModel
from operator import itemgetter, attrgetter
import decimal as d
class ParameterizedAlgorithm(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.'''
#Risk Management Parameters
TradingEquity = self.GetParameter("Starting Trading Equity") #Starting equity used for Trading
FixedFractionalRisk = self.GetParameter("Fixed Fractional Risk") #Fraction of the equity risked in trading
#Screening Parameters
MinVolumeDays = self.GetParameter("Days for Minimum Volume") #Number of days needed to compute the minimum number of volume (in shares and in dollar value) (default = 50 days)
MinStockPrice = self.GetParameter("Minimum Stock Price") #Minimum price of stock
MaxPosition = self.GetParameter("Maximum Number of Positions") #Number of positions allowed
#Entry Parameters
MADays = self.GetParameter("Moving Average Period") #Number of days needed to compute the simple moving average of stock price
ADXDays = self.GetParameter("ADX Period") #Number of days needed to compute the ADX
ADXThreshold = self.GetParameter("ADX Threshold") #Threshold used to determine if ADX produces buy signal. If ADX reaches above threshold, then the indicator produces a buy signal. (default = 45)
ATRDays = self.GetParameter("ATR Period") #Number of days needed to compute the ATR
RSIDays = self.GetParameter("RSI Period") #Number of days needed to compute the RSI
RSIThreshold = self.GetParameter("RSI Threshold") #Threshold used to determine if RSI produces buy signal. If RSI reaches below threshold, then the indicator produces a buy signal. (default = 30)
LimitOrderThreshold = self.GetParameter("Limit Order Threshold") #Threshold used to compute the limit price when the system signals to buy the stocks. The limit price = previous close - Limit Order Threshold*previous close (default = 4%)
#Exit Parameters
ATRMultiplier = self.GetParameter("ATR Stop Loss Factor") #Multiplier of ATR used for computing the stop-loss
ProfitTarget = self.GetParameter("Profit Target: ") #Threshold for Profit Target
ExitDays = self.GetParameter("Exit Signal Period") #Number of days to wait for an exit signal (either a stop-loss or hitting the profit target). If there is neither a stop-loss or profit target, the system will exit after the exit signal period.
#Set Default Parameter Values
self.value_TradingEquity = 100,000 if TradingEquity is None else float(TradingEquity)
self.value_FixedFractionalRisk = 0.02 if FixedFractionalRisk is None else float(FixedFractionalRisk)
self.value_MinVolumeDays = 50 if MinVolumeDays is None else int(MinVolumeDays)
self.value_MinStockPrice = 1 if MinStockPrice is None else float(MinStockPrice)
self.value_MaxPosition = 10 if MaxPosition is None else int(MaxPosition)
self.value_MADays = 150 if MADays is None else int(MADays)
self.value_ADXDays = 7 if ADXDays is None else int(ADXDays)
self.value_ADXThreshold = 45 if ADXThreshold is None else int(ADXThreshold)
self.value_ATRDays = 10 if ATRDays is None else int(ATRDays)
self.value_RSIDays = 3 if RSIDays is None else int(RSIDays)
self.value_RSIThreshold = 30 if RSIThreshold is None else int(RSIThreshold)
self.value_LimitOrderThreshold = 0.04 if LimitOrderThreshold is None else float(LimitOrderThreshold)
self.value_ATRMultiplier = 2.5 if ATRMultiplier is None else float(ATRMultiplier)
self.value_ProfitTarget = 0.03 if ProfitTarget is None else float(ProfitTarget)
self.value_ExitDays = 4 if ExitDays is None else int(ExitDays)
self.SetStartDate(2017, 1, 1) #Set Start Date
self.SetEndDate(2017, 6, 30) #Set End Date
self.SetCash(100000) #Set Strategy Cash
# use daily historical data and construct the universe according to the screennng criteria
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction)
#self.AddSecurity(SecurityType.Equity, "AAPL", Resolution.Daily)
#To determine the number of positions and update existing positions, make a storage for the list of entry orders and exit orders
self.__openLimitOrders = [] #Stores Entry Limit Orders not yet filled
self.__filledLimitOrders = [] #Stores Entry Limit Orders that are filled (i.e., existing positions)
self.__openStopMarketOrder = [] #Stores Exit Stop Market Orders not yet filled
self.__filledStopMarketOrder = [] #Stores Exit Stop Market Orders that are filled
#We also create a list of dates when there is no exit signal
self.__daysWithoutExitSignal = []
self.Initial_Universe = {}
def CoarseSelectionFunction(self, coarse):
Filtered_Universe_1 = [x for x in coarse if x.Volume > 500000 and x.DollarVolume > 2500000 and x.Value > 1]
return [i.Symbol for i in Filtered_Universe_1]
def OnSecuritiesChanged(self, changes):
self._changes = changes
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''
#Check for trade signals AS LONG AS the number of existing positions do not reach the maximum number of positions
while len(self.__filledLimitOrders) < self.value_MaxPosition:
for stock in self._changes.AddedSecurities:
# User defined universe has symbols from AddSecurity/AddEquity calls
if stock is UserDefinedUniverse:
continue
#Get the ticker symbol
stock_symbol = stock.Symbol
#Compute the indicators needed for trade signal
self.SimpleMA = self.SMA(stock_symbol, 150, Resolution.Daily)
self.RSIndex = self.RSI(stock_symbol, 3, Resolution.Daily)
self.AverageTrueRange = self.ATR(stock_symbol, 10, MovingAverageType.Exponential, Resolution.Daily)
#Wait for our indicators to ready
if not self.SimpleMA.IsReady or not self.RSIndex.IsReady or not self.AverageTrueRange.IsReady or not self.AverageDirectionalIndex.IsReady:
return
# Obtain the current value of the indicators
CurrentSimpleMA = float(self.SimpleMA.Current.Value)
CurrentRSIndex = float(self.RSIndex.Current.Value)
CurrentAverageTrueRange = float(self.AverageTrueRange.Current.Value)
CurrentAverageDirectionalIndex = float(self.AverageDirectionalIndex.Current.Value)
#Get the EOD close price
close = self.Securities[stock_symbol].Close
#Check if the following entry trade signal criteria are satisfied:
#Close of stock previous trading day must be above 150 day MA.
#7 day average directional index (ADX) must be above 45.
#Average true range (ATR) of last 10 days must be above 4% of last closing price.
#3 day RSI must be below 30.
if close > CurrentSimpleMA and CurrentAverageDirectionalIndex > self.value_ADXThreshold and CurrentAverageTrueRange > d.Decimal(0.04)*close and CurrentRSIndex < self.value_RSIThreshold:
#If the entry trade signal criteria are satisfied...
#Then, compute the Position Size,
PositionSize = (100000*self.value_FixedFractionalRisk)/(self.value_ATRMultiplier*CurrentAverageTrueRange)
#And, place a buy limit order at 4% below the previous close (4% can be tweaked using the parameter Limit Order Threshold = self.value_LimitOrderThreshold)
LimitPrice = close - self.value_LimitOrderThreshold*close
entryOrder = self.LimitOrder(stock_symbol, PositionSize, LimitPrice)
self.__openLimitOrders.append(entryOrder)
#And then, place a stop-loss for this trade
StopPrice = LimitPrice - self.value_ATRMultiplier*CurrentAverageTrueRange #Stop price calculation
StopLoss = self.StopMarketOrder(stock_symbol, -PositionSize, StopPrice) #Place stop loss
self.__openStopMarketOrder.append(StopLoss)
#Check FIRST if there are existing limit orders BEFORE exiting the trade
if len(self.__openLimitOrders) != 0 or len(self.__filledLimitOrders) != 0:
self.__LimitOrders = [x for x in self.__filledLimitOrders]
#Collect all limit (entry) orders whether it's filled or not
for orders in self.__openLimitOrders:
self.__LimitOrders.append(orders)
#Then, for every limit order...
for traded_stocks in self.__LimitOrders:
#check if the entry order is filled
if self.CheckPairOrdersForFills(traded_stocks):
#If entry order is filled...
#First, store it to the list of existing positions if it's not yet stored
if traded_stocks not in self.__filledLimitOrders:
self.__filledLimitOrders.append(traded_stocks)
#Then, retrieve the ticker symbol of the traded stock and the number of shares traded
traded_symbol = orderTicket.Get(OrderField.symbol) #ticker symbol
PositionSize = orderTicket.Get(OrderField.quantity) #number of shares traded
EntryTime = orderTicket.Get(OrderField.time)
EntryDate = EntryTime.date
CurrentDate = self.datetime.now()
#Also, Compute the desired price in order to reach the profit target
price_ProfitTarget = orderTicket.Get(OrderField.LimitPrice)*(1 + self.value_ProfitTarget)
#If the price reaches profit target, exit the trade
if self.closeWindow[0] > price_ProfitTarget:
self.Liquidate(traded_symbol)
self.__filledLimitOrders.remove(traded_stocks) #remove the trade from the list of existing positions
elif timedelta(CurrentDate - EntryDate) > self.value_ExitDays:
self.Liquidate(traded_symbol)
self.__filledLimitOrders.remove(traded_stocks) #remove the trade from the list of existing positions
#Finally remove the list from the list of entry orders that not yet filled
self.__openLimitOrders.remove(traded_stocks)
#Then, for every existing trades
for trades in self.__openStopMarketOrder:
#If the stop-loss is filled, then remove the trade from the list of existing positions
if self.CheckPairOrdersForFills(trades):
self.__filledLimitOrders.remove(trades)
class SymbolData(object):
def __init__(self, symbol):
self.Symbol = Symbol
self.RS_Index = RelativeStrengthIndex(3)
def update(self, time, value):
if self.RS_Index.Update(time, value):
self.RS_Index = self.RS_Index.Current.Value