Overall Statistics |
Total Trades 72 Average Win 0.27% Average Loss -0.28% Compounding Annual Return 0.509% Drawdown 5.400% Expectancy 0.041 Net Profit 0.349% Sharpe Ratio 0.123 Probabilistic Sharpe Ratio 21.071% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 0.97 Alpha 0.006 Beta -0.005 Annual Standard Deviation 0.04 Annual Variance 0.002 Information Ratio -0.454 Tracking Error 0.358 Treynor Ratio -0.923 Total Fees $0.00 |
from clr import AddReference AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") AddReference("QuantConnect.Indicators") from QuantConnect import * from QuantConnect.Indicators import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Data.Consolidators import * from datetime import timedelta class MACDForexAlphaModel(AlphaModel): def __init__(self, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9, trendPeriod = 200, movingAverageType = MovingAverageType.Exponential, resolution = Resolution.Minute, difference = 0): self.fastPeriod = fastPeriod self.slowPeriod = slowPeriod self.signalPeriod = signalPeriod self.trendPeriod = trendPeriod self.movingAverageType = movingAverageType self.resolution = resolution self.insightPeriod = timedelta(days=10) self.bounceThresholdPercent = 0.000 self.differenceThreshold = difference self.symbolData = {} def Update(self, algorithm, data): ''' Determines an insight for each security based on it's current MACD signal Args: algorithm: The algorithm instance data: The new data available Returns: The new insights generated''' x = 1 insights = [] for key, sd in self.symbolData.items(): if sd.Security.Price == 0: continue if sd.fridayInsight: insights.append(sd.fridayInsight) sd.fridayInsight = None if data.Bars[key].Time.hour == 16 and data.Bars[key].Time.minute == 59: algorithm.Debug(algorithm.Time) sd.MACD.Update(data.Time, data.Bars[key].Close) sd.SMA.Update(data.Time, data.Bars[key].Close) sd.Values.append((data.Time, data.Bars[key].Close)) else: continue if sd.MACD.Samples < 26:# or not sd.Trend.IsReady: continue direction = InsightDirection.Flat if algorithm.Time.month == 4 and algorithm.Time.day == 13: x = 1 difference = sd.MACD.Current.Value - sd.MACD.Signal.Current.Value if difference * (1 + self.bounceThresholdPercent) > 0:# and sd.Security.Price > sd.Trend.Current.Value:# and sd.MACD.Current.Value < (0 + self.differenceThreshold): direction = InsightDirection.Up elif difference * (1 - self.bounceThresholdPercent) < 0:# and sd.Security.Price < sd.Trend.Current.Value:# and sd.MACD.Current.Value > (0 + self.differenceThreshold): direction = InsightDirection.Down if not algorithm.Portfolio[key].Invested and sd.PreviousDirection[1] and direction == sd.PreviousDirection[1]: continue if sd.PreviousDirection[0] and direction == sd.PreviousDirection[0]: if abs(difference) - abs(sd.Difference) < 0: sd.PreviousDirection[1] = direction direction = InsightDirection.Flat sd.Difference = 0 else: sd.Difference = difference continue else: sd.Difference = difference sd.PreviousDirection[0] = direction insight = Insight.Price(sd.Security.Symbol, self.insightPeriod, direction) if algorithm.Time.weekday() == 4: sd.fridayInsight = insight continue insights.append(insight) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed. This initializes the MACD for each added security and cleans up the indicator for each removed security. Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' for added in changes.AddedSecurities: self.symbolData[added.Symbol] = SymbolData(algorithm, added, self.fastPeriod, self.slowPeriod, self.signalPeriod, self.trendPeriod, self.movingAverageType, self.resolution) for removed in changes.RemovedSecurities: data = self.symbolData.pop(removed.Symbol, None) if data is not None: # clean up our consolidator algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) class SymbolData: def __init__(self, algorithm, security, fastPeriod, slowPeriod, signalPeriod, trendPeriod, movingAverageType, resolution): self.Security = security self.MACD = MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, signalPeriod, movingAverageType) self.SMA = SimpleMovingAverage(slowPeriod) # self.Trend = ExponentialMovingAverage(trendPeriod) # self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, Resolution.Daily) #resolveconsolidator vs addconsolidator #self.Consolidator = QuoteBarConsolidator(timedelta(days=1)) # Register consolidator to get automatically updated with minute data #algorithm.SubscriptionManager.AddConsolidator(self.Security.Symbol, self.Consolidator) # algorithm.RegisterIndicator(security.Symbol, self.MACD, timedelta(1)) # algorithm.RegisterIndicator(security.Symbol, self.Trend, self.Consolidator) self.fridayInsight = None self.PreviousDirection = [None, None] self.Difference = 0 self.Values = [] return
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel from G10CurrencySelectionModel import G10CurrencySelectionModel from MACDForexModel import MACDForexAlphaModel from RiskManagementModule import ModifiedTrailingStopRiskManagementModel import datetime class MACDTrendFollower(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 12, 1)# - timedelta(200)) # Set Start Date # self.SetEndDate(2020, 5, 20) self.SetCash(100000) # Set Strategy Cash #self.AddEquity("SPY", Resolution.Minute) self.SetExecution(ImmediateExecutionModel()) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.AddAlpha(MACDForexAlphaModel()) # self.SetRiskManagement(ModifiedTrailingStopRiskManagementModel(0.02, .04)) self.AddUniverseSelection( G10CurrencySelectionModel()) self.SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin) self.UniverseSettings.Leverage = 1 self.UniverseSettings.Resolution = Resolution.Minute #self.SetWarmUp(timedelta(200)) return self.pricePlot = Chart('Price') self.macdPlot = Chart('MACD') self.pricePlot.AddSeries(Series('Price', SeriesType.Line, 0)) self.macdPlot.AddSeries(Series('Difference', SeriesType.Line, 0))
from QuantConnect import * from Selection.ManualUniverseSelectionModel import ManualUniverseSelectionModel class G10CurrencySelectionModel(ManualUniverseSelectionModel): def __init__(self): super().__init__([Symbol.Create(x, SecurityType.Forex, Market.Oanda) for x in [ "EURJPY"]]) #super().__init__([Symbol.Create(x, SecurityType.Equity, Market.USA) for x in [ "AMD"]]) # super().__init__([Symbol.Create(x, SecurityType.Forex, Market.Oanda) for x in [ "EURUSD", "GBPUSD", "USDJPY", "AUDUSD", "NZDUSD","USDCAD", "USDCHF", "USDNOK", "USDSEK"]])
from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") 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 class ModifiedTrailingStopRiskManagementModel(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that limits the maximum possible loss measured from the highest unrealized profit''' def __init__(self, maximumDrawdownPercent = 0.01, takeProfitPercent = 0.01): '''Initializes a new instance of the TrailingStopRiskManagementModel class Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.takeProfitPercent = takeProfitPercent self.trailingHighs = dict() def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' riskAdjustedTargets = list() for kvp in algorithm.Portfolio: symbol = kvp.Key security = kvp.Value # Remove if not invested if not security.Invested: self.trailingHighs.pop(symbol, None) continue # Add newly invested securities if symbol not in self.trailingHighs: self.trailingHighs[symbol] = security.HoldingsCost # Set to average holding cost continue if security.UnrealizedProfitPercent >= self.takeProfitPercent: algorithm.Debug(f"{algorithm.Time}: 'take profit'") riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) continue bidPrice = algorithm.Securities[symbol].BidPrice askPrice = algorithm.Securities[symbol].AskPrice if security.IsLong: # Check for new highs and update - set to tradebar high algorithm.Debug(f"{algorithm.Time}: {symbol}: 'long'") if self.trailingHighs[symbol] < askPrice: self.trailingHighs[symbol] = askPrice continue # Check for securities past the drawdown limit securityHigh = self.trailingHighs[symbol] drawdown = (bidPrice / securityHigh) - 1 if security.IsShort: # Check for new lows and update - set to tradebar Low algorithm.Debug(f"{algorithm.Time}: {symbol}: 'short'") if self.trailingHighs[symbol] > bidPrice: self.trailingHighs[symbol] = bidPrice continue # Check for securities past the drawdown limit securityHigh = self.trailingHighs[symbol] drawdown = (securityHigh / askPrice) - 1 if drawdown < self.maximumDrawdownPercent: # liquidate algorithm.Debug(f"{algorithm.Time}: loss liquidate") riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) return riskAdjustedTargets