Overall Statistics |
Total Trades 29140 Average Win 0.01% Average Loss -0.02% Compounding Annual Return 0% Drawdown 100.000% Expectancy -0.953 Net Profit -100.021% Sharpe Ratio -0.41 Probabilistic Sharpe Ratio 0.000% Loss Rate 97% Win Rate 3% Profit-Loss Ratio 0.41 Alpha -0.387 Beta 2.249 Annual Standard Deviation 2.438 Annual Variance 5.941 Information Ratio -0.303 Tracking Error 2.4 Treynor Ratio -0.445 Total Fees $40701.97 |
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 = Time.Multiply(Extensions.ToTimeSpan(Resolution.Daily), 3) 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''' insights = [] for key, sd in self.symbolData.items(): if sd.Security.Price == 0: continue if not sd.MACD.IsReady and not sd.Trend.IsReady: continue direction = InsightDirection.Flat # normalized_signal = sd.MACD.Signal.Current.Value / sd.Security.Price if sd.MACD.Current.Value > sd.MACD.Signal.Current.Value * (1 + self.bounceThresholdPercent) and sd.Security.Price > sd.Trend.Current.Value:# and sd.MACD.Current.Value < (0 + self.differenceThreshold): direction = InsightDirection.Up elif sd.MACD.Current.Value < sd.MACD.Signal.Current.Value * (1 - self.bounceThresholdPercent) and sd.Security.Price < sd.Trend.Current.Value:# and sd.MACD.Current.Value > (0 + self.differenceThreshold): direction = InsightDirection.Down # ignore signal for same direction as previous signal if direction == sd.PreviousDirection and algorithm.Portfolio[key].Invested: continue # if not algorithm.Portfolio[key].Invested: # direction = InsightDirection.Flat insight = Insight.Price(sd.Security.Symbol, self.insightPeriod, direction) sd.PreviousDirection = insight.Direction 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.Trend = ExponentialMovingAverage(trendPeriod) # self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution) #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, self.Consolidator) algorithm.RegisterIndicator(security.Symbol, self.Trend, self.Consolidator) self.PreviousDirection = None
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel from G10CurrencySelectionModel import G10CurrencySelectionModel from MACDForexModel import MACDForexAlphaModel from RiskManagementModule import ModifiedTrailingStopRiskManagementModel class MACDTrendFollower(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) # Set Start Date 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.FxcmBrokerage, AccountType.Margin) self.UniverseSettings.Leverage = 1 self.UniverseSettings.Resolution = Resolution.Minute def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' # if not self.Portfolio.Invested: # self.SetHoldings("SPY", 1)
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.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