| Overall Statistics |
|
Total Trades 5427 Average Win 0.12% Average Loss -0.05% Compounding Annual Return 11.580% Drawdown 11.400% Expectancy 0.061 Net Profit 9.258% Sharpe Ratio 0.747 Probabilistic Sharpe Ratio 39.957% Loss Rate 68% Win Rate 32% Profit-Loss Ratio 2.29 Alpha 0.122 Beta -0.119 Annual Standard Deviation 0.131 Annual Variance 0.017 Information Ratio -0.532 Tracking Error 0.189 Treynor Ratio -0.825 Total Fees $24453.80 |
from Execution.StandardDeviationExecutionModel import StandardDeviationExecutionModel
from Portfolio.MeanVarianceOptimizationPortfolioConstructionModel import MeanVarianceOptimizationPortfolioConstructionModel
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget
from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel
from datetime import *
import numpy as np
import pandas as pd
maximumDrawdownPercent = float(0.03)
profitTargetPercent = float(0.01)
executionReferencePeriod = int(60)
deviations = int(2)
resolution = Resolution.Minute
zero = int(0)
bufferBetweenOrders = int(60) #in universe resolution slices
stopMarketTicket = None
class CommunityTrailingStop(QCAlgorithm):
def Initialize(self):
stockPlot_1 = Chart('Price Vs. Stop')
stockPlot_2 = Chart('Research')
stockPlot_3 = Chart('Research 2')
self.SetStartDate(2019, 1, 1) # Set Start Date
self.SetCash(1000000) # Set Strategy Cash
self.UniverseSettings.Resolution = resolution
#self.SetExecution(StandardDeviationExecutionModel(executionReferencePeriod, deviations, resolution))
#self.SetPortfolioConstruction(MeanVarianceOptimizationPortfolioConstructionModel())
self.__numberOfSymbols = int(1000)
self.__numberOfSymbolsFine = int(25)
self.SetUniverseSelection(FineFundamentalUniverseSelectionModel(self.CoarseSelectionFunction, self.FineSelectionFunction, None, None))
self.RiskManagementDict = {}
self.maximumDictionarySize = self.__numberOfSymbolsFine
self.equalWeight = round(1/self.__numberOfSymbolsFine,2)
self.dayEndPortfolioValue = self.Portfolio.TotalPortfolioValue
self.changes = None
def OnData(self, data):
for Symbol in self.RiskManagementDict:
if not data.ContainsKey(Symbol) or data[Symbol] is None: return
if self.RiskManagementDict[Symbol].timeBuffer != zero:
self.RiskManagementDict[Symbol].updateBuffer()
continue
self.TrailingStop(data[Symbol], Symbol)
if not self.Portfolio[Symbol].Invested and self.RiskManagementDict[Symbol].timeBuffer == zero and self.RiskManagementDict[Symbol].continueTrading:
self.SetHoldings(Symbol, self.equalWeight)
def CoarseSelectionFunction(self, coarse):
preScreen = [x for x in coarse if (x.HasFundamentalData)
and (float(x.AdjustedPrice) > int(5))]
sortedByDollarVolume = sorted(preScreen, key=lambda x: x.DollarVolume, reverse=True)
# return the symbol objects of the top entries from our sorted collection
return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]
def FineSelectionFunction(self, fine):
fine = [x for x in fine if (float(x.FinancialStatements.BalanceSheet.CurrentAssets.Value) > zero)
and (float(x.EarningReports.BasicAverageShares.Value) > zero)
and (float(x.FinancialStatements.BalanceSheet.CurrentLiabilities.Value) > zero)
and (float(x.FinancialStatements.BalanceSheet.TotalNonCurrentLiabilitiesNetMinorityInterest.Value) > zero)
and (x.CompanyReference.IndustryTemplateCode!="B")
and (x.CompanyReference.IndustryTemplateCode!="I")]
for i in fine:
#calculates the net current asset value per share
total_liabilities = float(i.FinancialStatements.BalanceSheet.CurrentLiabilities.Value)+float(i.FinancialStatements.BalanceSheet.TotalNonCurrentLiabilitiesNetMinorityInterest.Value)
i.ncav = (float(i.FinancialStatements.BalanceSheet.CurrentAssets.Value) - total_liabilities)/float(i.EarningReports.BasicAverageShares.Value)
#keeps all symbols that have a NCAV/MV higher than 1.5
fineScreen = [i for i in fine if (i.ncav > float(1.5))]
sortedByPeRatio = sorted(fineScreen, key=lambda x: x.ValuationRatios.PERatio, reverse=True)
return [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ]
def OnSecuritiesChanged(self, changes):
self.Plot("Research", "Active Securities", self.ActiveSecurities.Count)
self.changes = changes
#Securities Removed
for x in changes.RemovedSecurities:
self.Liquidate(x.Symbol)
if x.Symbol in self.RiskManagementDict:
del self.RiskManagementDict[x.Symbol]#.pop(x.Symbol)
self.Plot('Research 2', 'Dictionary Size', len(self.RiskManagementDict))
#Securities Added
for x in self.changes.AddedSecurities:
self.RiskManagementDict[x.Symbol] = StopManagement(x.Symbol, maximumDrawdownPercent)
self.Plot('Research 2', 'Dictionary Size', len(self.RiskManagementDict))
def TrailingStop(self, price, symbol):
if self.Portfolio[symbol].Invested:
if self.RiskManagementDict[symbol].orderID is None:
self.RiskManagementDict[symbol].captureStop(self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, self.Securities[symbol].Holdings.AveragePrice * round(1-maximumDrawdownPercent)),
self.Securities[symbol].Holdings.AveragePrice, self.Portfolio[symbol].Quantity)
self.RiskManagementDict[symbol].trackStopMarketOrder(self.RiskManagementDict[symbol].stopMarketTicket.OrderId)
self.RiskManagementDict[symbol].updateStopPrice(price)
def OnOrderEvent(self, orderEvent):
if orderEvent.Status != OrderStatus.Filled:
return
for Security in self.RiskManagementDict:
if self.RiskManagementDict[Security].stopMarketTicket is not None and self.RiskManagementDict[Security].stopMarketTicket.OrderId == orderEvent.OrderId:
self.RiskManagementDict[Security].executedStopOrder(bufferBetweenOrders)
def OnEndOfDay(self):
for Security in self.RiskManagementDict:
self.RiskManagementDict[Security].endOfDay()
self.dayEndPortfolioValue = self.Portfolio.TotalPortfolioValue
class StopManagement:
def __init__(self, symbol, riskTolerance):
self.Symbol = symbol
self.StopPrice = zero
self.HighestPrice = zero
self.LowestPrice = zero
self.riskTolerance = round(1-riskTolerance,2)
self.stopMarketTicket = None
self.orderID = None
self.timeBuffer = zero
self.continueTrading = True
self.LongEquity = True
def trackStopMarketOrder(self, orderID):
self.orderID = orderID
def updateStopPrice(self, price):
if self.LongEquity:
if price.High > self.HighestPrice:
self.HighestPrice = price.High
self.StopPrice = self.HighestPrice * self.riskTolerance
if self.stopMarketTicket is not None:
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.StopPrice
self.stopMarketTicket.Update(updateFields)
if not self.LongEquity:
if price.Low < self.LowestPrice:
self.LowestPrice = price.Low
self.StopPrice = self.LowestPrice * round(1/self.riskTolerance,2)
if self.stopMarketTicket is not None:
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.StopPrice
self.stopMarketTicket.Update(updateFields)
def trackOrder(self, orderID):
self.orderID = orderID
def captureStop(self, stopMarketTicket, avgprice, qty):
if qty >= zero:
self.LongEquity = True
self.HighestPrice = avgprice
self.StopPrice = self.HighestPrice * self.riskTolerance
elif qty < zero:
self.LongEquity = False
self.LowestPrice = avgprice
self.StopPrice = self.LowestPrice * round(1/self.riskTolerance,2)
self.stopMarketTicket = stopMarketTicket
def executedStopOrder(self, bufferBetweenOrders):
self.stopMarketTicket = None
self.orderID = None
self.timeBuffer = bufferBetweenOrders
self.continueTrading = False
def updateBuffer(self):
self.timeBuffer = self.timeBuffer - int(1)
def endOfDay(self):
self.continueTrading = True
def reset(self):
self.StopPrice = zero
self.HighestPrice = zero
self.LowestPrice = zero
self.stopMarketTicket = None
self.orderID = None
self.continueTrading = True
self.LongEquity = True