Overall Statistics |
Total Trades 190 Average Win 1.08% Average Loss -0.94% Compounding Annual Return 16.712% Drawdown 6.400% Expectancy 0.190 Net Profit 16.859% Sharpe Ratio 1.086 Probabilistic Sharpe Ratio 50.668% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 1.14 Alpha 0.12 Beta 0.129 Annual Standard Deviation 0.133 Annual Variance 0.018 Information Ratio -0.163 Tracking Error 0.29 Treynor Ratio 1.121 Total Fees $246.75 |
class TrailingStopRiskManagementModel(RiskManagementModel): def __init__(self): self.liquidated = set() self.lastmonth=-1 def ManageRisk(self, algorithm, targets): month= algorithm.Time.month if month!= self.lastmonth: self.liquidated.clear() self.lastmonth= month riskAdjustedTargets = list() for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value if security.Holdings.UnrealizedProfitPercent > 0.04 or security.Holdings.UnrealizedProfitPercent < -0.03 or security.Symbol in self.liquidated: riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) if algorithm.Securities[security.Symbol].Invested: self.liquidated.add(security.Symbol) return riskAdjustedTargets
class FibonacciOptionStraddle(QCAlgorithm): def __init__(self,period=15, resolution=Resolution.Hour): self.period=period self.resolution=resolution self.symbolDataBySymbol = {} self.optionDataBySymbol={} self.hour = None self.removed = [] def Update(self, algorithm, data): insights = [] if algorithm.Time.hour == self.hour: return [] for symbol, sd in self.symbolDataBySymbol.items(): maximum=sd.max value=algorithm.Securities[symbol].Price error=value*0.30 call=None for contract ,info in self.optionDataBySymbol.items(): if info.Underlying.Value==symbol.Value: call=info continue if (value < (maximum.Current.Value)) and call is not None: if (maximum.Current.Value+error) >= call.BidPrice >= (maximum.Current.Value-error): insights.append(Insight.Price(symbol,timedelta(hours=1), InsightDirection.Up)) else: insights.append(Insight.Price(symbol,timedelta(hours=1), InsightDirection.Flat)) else: insights.append(Insight.Price(symbol,timedelta(hours=1), InsightDirection.Flat)) if insights: self.hour = algorithm.Time.hour return insights def OnSecuritiesChanged(self, algorithm, changes): for y in changes.RemovedSecurities: if y.Symbol.SecurityType ==SecurityType.Equity: self.removed.clear() for contract ,info in self.optionDataBySymbol.items(): if info.Underlying.Value==y.Symbol.Value: self.removed.append(info.Underlying) for x in self.removed : optionData=self.optionDataBySymbol.pop(x,None) symbolData = self.symbolDataBySymbol.pop(y.Symbol, None) if symbolData: algorithm.SubscriptionManager.RemoveConsolidator(y.Symbol, symbolData.Consolidator) elif y.Symbol.SecurityType ==SecurityType.Option: if y.Underlying not in [x.Symbol for x in changes.RemovedSecurities]: optionData=self.optionDataBySymbol.pop(y.Underlying,None) addedSymbols = [ x.Symbol for x in changes.AddedSecurities if (x.Symbol not in self.symbolDataBySymbol and x.Symbol.SecurityType ==SecurityType.Equity)] if len(addedSymbols) == 0: return history = algorithm.History(addedSymbols, self.period, self.resolution) for symbol in addedSymbols: Max=Maximum(5) Min=Minimum(5) consolidator = algorithm.ResolveConsolidator(symbol, Resolution.Daily) algorithm.RegisterIndicator(symbol, Max, consolidator) algorithm.RegisterIndicator(symbol, Min, consolidator) if not history.empty: ticker = SymbolCache.GetTicker(symbol) for tuple in history.loc[ticker].itertuples(): Max.Update(tuple.Index, tuple.close) Min.Update(tuple.Index, tuple.close) self.symbolDataBySymbol[symbol] = SymbolData(symbol,Max,Min,consolidator) options= [ x.Symbol for x in changes.AddedSecurities if (x.Symbol not in self.optionDataBySymbol and x.Symbol.SecurityType ==SecurityType.Option)] if len(options) == 0: return for option in options: algorithm.Securities[option].Underlying = algorithm.Securities[option.Underlying] newhistory = algorithm.History(options, self.period, Resolution.Minute) if newhistory.empty: return for contract in options: underlying=contract.Underlying bidPrice= algorithm.Securities[contract].BidPrice self.optionDataBySymbol[underlying] = OptionData(contract, underlying,bidPrice) class SymbolData: def __init__(self, symbol, Max,Min,consolidator): self.Symbol = symbol self.max = Max self.min = Min self.Consolidator=consolidator class OptionData: def __init__(self,contract, underlying,bidPrice): self.Contract=contract self.Underlying=underlying self.BidPrice=bidPrice
from CustomUniverse import OptionsUniverse from CustomAlpha import fib from CustomRiskManagement import takeprofit class test (QCAlgorithm): def Initialize(self): self.SetStartDate(2019,8,13) self.SetEndDate(2020,8,13) self.SetCash(100000) self.SetTimeZone(TimeZones.Chicago) self.SetSecurityInitializer(lambda s: s.SetMarketPrice(self.GetLastKnownPrice(s))) self.AddUniverseSelection(OptionsUniverse.universe()) self.UniverseSettings.Resolution = Resolution.Minute self.UniverseSettings.DataNormalizationMode=DataNormalizationMode.Raw self.UniverseSettings.FillForward = True self.UniverseSettings.ExtendedMarketHours = False self.UniverseSettings.MinimumTimeInUniverse = 1 self.UniverseSettings.Leverage=1 self.AddAlpha(fib.FibonacciOptionStraddle()) self.Settings.RebalancePortfolioOnInsightChanges = False; self.Settings.RebalancePortfolioOnSecurityChanges = False; self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetRiskManagement(takeprofit.TrailingStopRiskManagementModel()) self.SetExecution(ImmediateExecutionModel()) self.SetWarmUp(timedelta(days=5)) def OnData(self, slice): if self.IsWarmingUp: return
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel from datetime import timedelta, datetime from math import ceil from itertools import chain import numpy as np class universe(FundamentalUniverseSelectionModel): def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None): super().__init__(filterFineData, universeSettings, securityInitializer) self.NumberOfSymbolsCoarse = 2500 self.NumberOfSymbolsFine = 100 self.NumberOfSymbolsInPortfolio = 15 self.lastmonth = -1 self.dollarVolumeBySymbol = {} def SelectCoarse(self, algorithm, coarse): month= algorithm.Time.month/6 if month == self.lastmonth: return Universe.Unchanged self.lastmonth= month top = sorted([x for x in coarse if x.HasFundamentalData], key=lambda x: x.DollarVolume, reverse=True)[:self.NumberOfSymbolsCoarse] self.dollarVolumeBySymbol = { i.Symbol: i.DollarVolume for i in top } return list(self.dollarVolumeBySymbol.keys()) def SelectFine(self, algorithm, fine): self.priceAllowance = 100 filteredFine = [x for x in fine if x.CompanyReference.CountryId == "USA" and x.Price > self.priceAllowance and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS") and (algorithm.Time - x.SecurityReference.IPODate).days > 1200 and (x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio >= 5e10) ] self.valuationRatio = { i.Symbol: i.ValuationRatios.SustainableGrowthRate for i in filteredFine } count = len(filteredFine) if count == 0: return [] myDict = dict() percent = self.NumberOfSymbolsFine / count value3 = sorted(filteredFine, key = lambda x: self.valuationRatio[x.Symbol], reverse = True) value4 = value3[:ceil(len(value3) * percent)] self.stocks = value4[:self.NumberOfSymbolsInPortfolio] self.contract=[] for x in self.stocks: self.currentSymbol = x.Symbol self.contract.append(self.GetContract(algorithm)) self.newstocks= [x.Symbol for x in self.stocks] return [x for x in self.newstocks + self.contract] def GetContract(self, algorithm): contracts=algorithm.OptionChainProvider.GetOptionContractList(self.currentSymbol, algorithm.Time) call = [x for x in contracts if x.ID.OptionRight ==OptionRight.Call] call = sorted(sorted(call, key = lambda x: x.ID.Date), key = lambda x: x.ID.StrikePrice) if not call: return return call[0]