| 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)