Overall Statistics |
Total Trades 3 Average Win 0% Average Loss -0.25% Compounding Annual Return -16.913% Drawdown 0.500% Expectancy -1 Net Profit -0.490% Sharpe Ratio -5.86 Probabilistic Sharpe Ratio 1.048% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.079 Beta -0.361 Annual Standard Deviation 0.032 Annual Variance 0.001 Information Ratio -4.861 Tracking Error 0.1 Treynor Ratio 0.516 Total Fees $8.82 |
from datetime import timedelta import numpy as np import pandas as pd class ModelA(AlphaModel): def __init__(self, resolution, insightsTimeDelta ): self.symbolDataBySymbol = {} self.modelResolution = resolution self.insightsTimeDelta = insightsTimeDelta def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: symbolData = self.symbolDataBySymbol.get(added.Symbol) if symbolData is None: symbolData = SymbolData(added.Symbol, algorithm, self.modelResolution) self.symbolDataBySymbol[added.Symbol] = symbolData def Update(self, algorithm, data): insights=[] for symbol, symbolData in self.symbolDataBySymbol.items(): symbolData.getInsight(algorithm.Securities[symbol].Price) # Latest known price; we are at 12:00 and the last trade at 10.57 algorithm.Log(f"{symbol}\tMOM\t[{symbolData.fmom}]\t{round(symbolData.mom.Current.Value,2)}\tKAMA\t[{symbolData.fkama}]\t{round(symbolData.kama.Current.Value,2)}\ \tPrice\t{symbolData.price}\tROC\t[{symbolData.froc}]\t{round(symbolData.roc.Current.Value,4)}\tEMA\t[{symbolData.fema}]\tEMA-13\t{round(symbolData.ema13.Current.Value,2)}\ \tEMA-63\t{round(symbolData.ema63.Current.Value,2)}\tEMA-150\t{round(symbolData.ema150.Current.Value,2)}\taction\t{symbolData.InsightDirection}") if symbolData.tradeSecurity: insights.append(Insight(symbol, self.insightsTimeDelta, InsightType.Price, symbolData.InsightDirection, 0.0025,None, "ModelA",None)) return insights class FrameworkAlgorithm(QCAlgorithm): def Initialize(self): #qb = QuantBook() #beta - volatility property tickers = ["MSFT","MRNA","MELI","FSLY"] symbols = [Symbol.Create(x, SecurityType.Equity, Market.USA) for x in tickers] resolution = Resolution.Hour #10-11, etc Daily data is midnight to mifnight, 12AM EST warmup = 28 insightsTimeDelta = timedelta(hours=1) fallback_barrier = 1000 self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(TimeSpan.FromMinutes(60)), self.hourlyHousekeeping) self.SetStartDate(2020, 12, 20) self.SetCash(100000) self.SetBenchmark("SPY") self.UniverseSettings.Resolution = resolution self.SetWarmUp(timedelta(warmup)) self.SetUniverseSelection(ManualUniverseSelectionModel(symbols)) self.SetAlpha(ModelA(resolution,insightsTimeDelta)) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) #self.SetPortfolioConstruction(MeanVarianceOptimizationPortfolioConstructionModel(resolution,PortfolioBias.LongShort,1,63,resolution,0.02,MaximumSharpeRatioPortfolioOptimizer(0,1,0))) self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.02)) # drop in profit from the max / done daily > redo hourly? self.SetExecution(ImmediateExecutionModel()) def hourlyHousekeeping(self): # Fail Safe - If our strategy is losing than acceptable (something is wrong) # Strategy suddenly losing moiney or logic problem/bug we did't carch i testing if self.LiveMode: if (self.Portfolio.UnrealizedProfit+self.Portfolio.TotalProfit < -1000):# does not work self.Log(f"Fallback event triggered, liqudating {self.Portfolio.UnrealizedProfit} {self.Portfolio.TotalProfit}") self.Liquidate() self.Quit() #dt=int(str(self.Time)[11:13]) dt=int(self.Time.hour) if dt >9 and dt<18: if (self.IsMarketOpen("SPY") and self.Portfolio.Invested): self.Log("\n\nPortfolio") summary = {} invested = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ] for symbol in invested: hold_val = round(self.Portfolio[symbol].HoldingsValue, 2) abs_val = round(self.Portfolio[symbol].AbsoluteHoldingsValue, 2) pnl = round(self.Portfolio[symbol].UnrealizedProfit, 2) qty = self.Portfolio[symbol].Quantity price = self.Portfolio[symbol].Price summary[symbol]=[hold_val,abs_val,pnl,qty,price] df=pd.DataFrame(summary) df.index = ['hold_val', 'abs_val', 'pnl', 'qty','price'] df=df.T hold_val_total= abs(df['hold_val']).sum() df = df.assign(weight=abs(df['hold_val'])/hold_val_total) self.Log(df) self.Log("\n\n") class SymbolData: def __init__(self, symbol, algorithm, resolution): self.symbol = symbol self.price = 0.00 self.kama = algorithm.KAMA(symbol, 10,2,30, resolution) self.kama_factor = 1.01 # tolerance level to avoid buy and immediate sell scenario self.mom = algorithm.MOM(symbol, 14, resolution) self.roc = algorithm.ROC(symbol, 9, resolution) self.ema13 = algorithm.EMA(symbol, 13, resolution) self.ema63 = algorithm.EMA(symbol, 63, resolution) self.ema150 = algorithm.EMA(symbol, 150, resolution) self.fkama = False self.fmom = False self.froc = False self.fema = False self.held = False # to ensure we only sell what we have def getInsight(self, price): self.price = price self.fkama = self.price>self.kama.Current.Value*self.kama_factor self.fmom = self.mom.Current.Value>0 self.froc = self.roc.Current.Value>0 self.fema = self.ema13.Current.Value>self.ema63.Current.Value>self.ema150.Current.Value self.tradeSecurity = False # helps to avoid liqudating when InsightDirection.Flat self.InsightDirection = InsightDirection.Flat # liqudates unless self.tradeSecurity flag is False if self.fmom and self.fkama and self.fema and self.froc: self.InsightDirection = InsightDirection.Up self.tradeSecurity = True self.held = True if self.held and (not self.fmom or not self.fkama or not self.fema or not self.froc): self.InsightDirection = InsightDirection.Down self.tradeSecurity = True self.held = False