Overall Statistics |
Total Trades 8 Average Win 0.13% Average Loss -0.41% Compounding Annual Return -16.751% Drawdown 0.900% Expectancy -0.335 Net Profit -0.551% Sharpe Ratio -2.891 Probabilistic Sharpe Ratio 18.226% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.33 Alpha -0.119 Beta 0.129 Annual Standard Deviation 0.041 Annual Variance 0.002 Information Ratio -1.404 Tracking Error 0.09 Treynor Ratio -0.919 Total Fees $8.00 |
from datetime import datetime, timedelta import numpy as np from Risk.MaximumSectorExposureRiskManagementModel import MaximumSectorExposureRiskManagementModel from QuantConnect.Data.Custom.Tiingo import * class Compbasealgo(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(2015, 8, 4) # 5 years up to the submission date self.SetEndDate(2015, 8, 14) self.SetCash(1000000) # Set $1m Strategy Cash to trade significant AUM self.SetBenchmark('SPY') # SPY Benchmark self.SetBrokerageModel(AlphaStreamsBrokerageModel()) self.UniverseSettings.Resolution = Resolution.Daily self.AddAlpha(MixedAlphaModel()) self.SetRiskManagement(MaximumDrawdownPercentPerSecurityCustom(0.01)) self.SetExecution(ImmediateExecutionModel()) self.SetUniverseSelection(LiquidETFUniverse()) self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel()) class MixedAlphaModel(AlphaModel): def __init__(self, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9, movingAverageType = MovingAverageType.Simple, resolution = Resolution.Daily): self.fastPeriod = fastPeriod self.slowPeriod = slowPeriod self.signalPeriod = signalPeriod self.movingAverageType = movingAverageType self.resolution = resolution self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod) self.bounceThresholdPercent = 0.1 self.symbolData2 = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) movingAverageTypeString = Extensions.GetEnumString(movingAverageType, MovingAverageType) self.Name = '{}({},{},{},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, signalPeriod, movingAverageTypeString, resolutionString) self.direction = InsightDirection.Flat self.newsData = {} self.wordScores = { "bad": -0.5, "good": 0.5, "negative": -0.5, "great": 0.5, "growth": 0.5, "fail": -0.5, "failed": -0.5, "success": 0.5, "nailed": 0.5, "beat": 0.5, "missed": -0.5, "profitable": 0.5, "beneficial": 0.5, "right": 0.5, "positive": 0.5, "large":0.5, "attractive": 0.5, "sound": 0.5, "excellent": 0.5, "wrong": -0.5, "unproductive": -0.5, "lose": -0.5, "missing": -0.5, "mishandled": -0.5, "un_lucrative": -0.5, "up": 0.5, "down": -0.5, "unproductive": -0.5, "poor": -0.5, "wrong": -0.5, "worthwhile": 0.5, "lucrative": 0.5, "solid": 0.5, "beat": 0.5, "missed": -0.5 } self.currentWindow=0.1 self.sentimentMean=0.1 self.symbol2="EURUSD" def Update(self, algorithm, data): insights = [] for key, sd in self.symbolData2.items(): self.symbol= key tiingoNews=algorithm.Securities[self.symbol].Data.GetAll(TiingoNews) for article in tiingoNews: words = article.Description.lower().split(" ") score = sum([self.wordScores[word] for word in words if word in self.wordScores]) if score == 0.0: continue symbol = article.Symbol.Underlying self.newsData[symbol].Window.Add(score) if self.newsData[symbol].Window.Count < 3: return insights self.currentWindow = self.newsData[symbol].Window[0] self.sentimentMean = sum(self.newsData[symbol].Window)/self.newsData[symbol].Window.Count if not (sd.MACD.IsReady and sd.Reg.IsReady): continue normalized_signal = sd.MACD.Signal.Current.Value / sd.Security.Price normalized_slope=sd.Reg.Slope.Current.Value/sd.Security.Price #if self.direction == sd.PreviousDirection: # continue if normalized_signal > self.bounceThresholdPercent and normalized_slope>0 and self.currentWindow > (self.sentimentMean*1.1): insight = Insight.Price(sd.Security.Symbol, timedelta(hours = 1), InsightDirection.Up, None, None, None, 0.05) self.direction = InsightDirection.Up insights.append(insight) sd.PreviousDirection = insight.Direction elif normalized_signal < -self.bounceThresholdPercent and normalized_slope<-0 and self.currentWindow < -1: self.direction = InsightDirection.Down insight = Insight.Price(sd.Security.Symbol, timedelta(hours = 1), InsightDirection.Down, None, None, None, 0.05) insights.append(insight) sd.PreviousDirection = insight.Direction elif normalized_signal>-self.bounceThresholdPercent and normalized_signal<self.bounceThresholdPercent: self.direction = InsightDirection.Flat insight = Insight.Price(sd.Security.Symbol, timedelta(hours = 1), InsightDirection.Flat) insights.append(insight) return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: self.symbol=added.Symbol self.symbolData2[added.Symbol] = SymbolData2(algorithm, added, self.fastPeriod, self.slowPeriod, self.signalPeriod, self.movingAverageType, self.resolution) newsAsset = algorithm.AddData(TiingoNews, self.symbol) self.newsData[self.symbol] = NewsData(newsAsset.Symbol) for removed in changes.RemovedSecurities: data = self.symbolData2.pop(removed.Symbol, None) if data is not None: algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) newsData = self.newsData.pop(removed.Symbol, None) if newsData is not None: algorithm.RemoveSecurity(newsData.Symbol) class SymbolData2(object): def __init__(self, algorithm, security, fastPeriod, slowPeriod, signalPeriod, movingAverageType, resolution): self.Security = security self.MACD = MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, signalPeriod, movingAverageType) self.Reg = RegressionChannel(50, 2) self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution) algorithm.RegisterIndicator(security.Symbol, self.MACD, self.Consolidator) algorithm.RegisterIndicator(security.Symbol, self.Reg, self.Consolidator) self.PreviousDirection = None history = algorithm.History(security.Symbol, 100, Resolution.Daily) self.WarmUpIndicators2(history) def WarmUpIndicators2(self, history): for index, row in history.loc[str(self.Security.Symbol)].iterrows(): self.MACD.Update(index, row["close"]) self.Reg.Update(index, row["close"]) class MaximumDrawdownPercentPerSecurityCustom(RiskManagementModel): def __init__(self, maximumDrawdownPercent = 0.001, reenter_after_days = 1): self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.maximumProfitPercent = abs(0.002) self.liquidated_dates_by_symbol = {} self.reenter_after_days = timedelta(reenter_after_days) def ManageRisk(self, algorithm, targets): symbols_to_pop = [] for symbol, liquidation_date in self.liquidated_dates_by_symbol.items(): if algorithm.Time - liquidation_date >= self.reenter_after_days: symbols_to_pop.append(symbol) for symbol in symbols_to_pop: self.liquidated_dates_by_symbol.pop(symbol, None) targets = [] for kvp in algorithm.Securities: security = kvp.Value pnl = security.Holdings.UnrealizedProfitPercent if pnl > self.maximumProfitPercent or pnl < self.maximumDrawdownPercent or security.Symbol in self.liquidated_dates_by_symbol: # liquidate targets.append(PortfolioTarget(security.Symbol, 0)) if algorithm.Securities[security.Symbol].Invested: self.liquidated_dates_by_symbol[security.Symbol] = algorithm.Time return targets class NewsData(): def __init__(self, symbol): self.Symbol = symbol self.Window = RollingWindow[float](100)