Overall Statistics |
Total Trades 972 Average Win 0.41% Average Loss -0.28% Compounding Annual Return 56.304% Drawdown 15.600% Expectancy 0.303 Net Profit 46.848% Sharpe Ratio 1.845 Probabilistic Sharpe Ratio 76.459% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 1.45 Alpha 0.353 Beta 0.187 Annual Standard Deviation 0.213 Annual Variance 0.045 Information Ratio 0.79 Tracking Error 0.228 Treynor Ratio 2.098 Total Fees $0.00 Estimated Strategy Capacity $2400000.00 Lowest Capacity Asset CADJPY 8G |
class HyperActiveApricotFalcon(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 1, 1) self.SetEndDate(2021, 11, 10) self.SetCash(100000) self.pair = 'CADJPY' self.forex = self.AddForex(self.pair, Resolution.Minute, Market.Oanda).Symbol self.quantity = 170000 # $300 Stop Loss = $26.63 avg cost per trade (commission and spread) # Long / Short - True = Live self.Long = True self.Short = False # Indicators self.rsi = RelativeStrengthIndex(14, MovingAverageType.Wilders) self.macdfiveminute = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential) self.macdonehour = self.MACD(self.forex, 12, 26, 9, MovingAverageType.Exponential, Resolution.Hour) self.macdonehourlong = self.MACD(self.forex, 50, 100, 20, MovingAverageType.Exponential, Resolution.Hour) self.macdonehourtrend = self.MACD(self.forex, 200, 400, 80, MovingAverageType.Exponential, Resolution.Hour) self.rsionehour = self.RSI(self.forex, 14, MovingAverageType.Wilders, Resolution.Hour) self.atr = AverageTrueRange(14, MovingAverageType.Wilders) self.emafast = ExponentialMovingAverage(9) self.emaslow = ExponentialMovingAverage(50) self.stc = SchaffTrendCycle( 10, 23, 50, MovingAverageType.Exponential) self.stchour = SchaffTrendCycle( 10, 23, 50, MovingAverageType.Exponential, Resolution.Hour) # One Hour Consolidator and Indicator Registrations oneHourConsolidator = QuoteBarConsolidator(timedelta(minutes=60)) oneHourConsolidator.DataConsolidated += self.OneHourBarHandler self.SubscriptionManager.AddConsolidator(self.pair, oneHourConsolidator) # Five Minute Consolidator and Indicator Registrations fiveMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=5)) fiveMinuteConsolidator.DataConsolidated += self.FiveMinuteBarHandler self.SubscriptionManager.AddConsolidator(self.pair, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.rsi, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.atr, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.macdfiveminute, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.emafast, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.emaslow, fiveMinuteConsolidator) self.RegisterIndicator(self.pair, self.stc, fiveMinuteConsolidator) # One Hour Window self.rsiLastHourWindow = RollingWindow[float](2) self.stchourLastHourWindow = RollingWindow[float](2) self.macdLastHourWindow = RollingWindow[float](2) self.macdHourSignal = RollingWindow[float](2) self.macdLastHourLongWindow = RollingWindow[float](2) self.macdHourLongSignal = RollingWindow[float](2) self.macdLastHourTrendWindow = RollingWindow[float](2) self.macdHourTrendSignal = RollingWindow[float](2) # Random Crap self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.BeforeMarketClose(self.pair), self.WeekendLiquidation) self.fiveminbaropen = 0 self.SetWarmUp(50) self.lastfiveminutemacdvalues = [] self.lastonehourmacdvalues = [] self.lastonehourmacdlongvalues = [] self.macdLastFiveBar = None self.entryTicket = None self.SLTicket = None self.TPTicket = None self.entryTickets = [] self.entryTicketIDs = {} self.SLTickets = {} self.TPTickets = {} def OneHourBarHandler(self, sender, consolidated): # RSI 1 Hour self.rsiLastHourWindow.Add(self.rsionehour.Current.Value) # STC 1 Hour self.stchourLastHourWindow.Add(self.stchour.Current.Value) # Short 1 Hour self.macdLastHourWindow.Add(self.macdonehour.Current.Value) self.macdHourSignal.Add(self.macdonehour.Signal.Current.Value) # Long 1 Hour self.macdLastHourLongWindow.Add(self.macdonehourlong.Current.Value) self.macdHourLongSignal.Add(self.macdonehourlong.Signal.Current.Value) # Trend 1 Hour self.macdLastHourTrendWindow.Add(self.macdonehourtrend.Current.Value) self.macdHourTrendSignal.Add(self.macdonehourtrend.Signal.Current.Value) def FiveMinuteBarHandler(self, sender, consolidated): if not self.macdonehour.IsReady: return if self.macdLastFiveBar == None or self.macdLastHourWindow.Count <= 1: self.macdLastFiveBar = self.macdfiveminute.Current.Value return # Bar Values Close = (consolidated.Bid.Close+consolidated.Ask.Close)/2 Open = (consolidated.Bid.Open+consolidated.Ask.Open)/2 Low = (consolidated.Bid.Low+consolidated.Ask.Low)/2 High = (consolidated.Bid.High+consolidated.Ask.High)/2 Price = consolidated.Price # Indicator Shortcuts emaFast = self.emafast.Current.Value emaSlow = self.emaslow.Current.Value rsiValue = self.rsi.Current.Value macdFive = self.macdfiveminute.Current.Value # Long Entry Bars if self.Long and Close > emaFast and Open > emaFast and Close < Open and emaSlow < emaFast and rsiValue < 64 and rsiValue > 54: self.GoLong(Close) # Short Entry Bars elif self.Short and Close < emaFast and Open < emaFast and Close > Open and emaSlow > emaFast and rsiValue > 38 and rsiValue < 45: self.GoShort(Close) # Record MACD values to compare at next datapoint self.macdLastFiveBar = self.macdfiveminute.Current.Value ''' LONG STRATEGY ''' def GoLong(self, Close): FiveMACD = self.macdfiveminute.Current.Value FiveMACDdifference = self.macdfiveminute.Current.Value - self.macdfiveminute.Signal.Current.Value PrevMACDValue = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] HourMACDdifference = self.macdLastHourWindow[0] - self.macdHourSignal[0] PrevMACDdifference = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] - self.macdHourSignal[self.macdLastHourWindow.Count-1] PrevLongMACDValue = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] LongMACDdifference = self.macdLastHourLongWindow[0] - self.macdHourLongSignal[0] PrevLongMACDdifference = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] - self.macdHourLongSignal[self.macdLastHourLongWindow.Count-1] PrevTrendMACDValue = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] TrendMACDdifference = self.macdLastHourTrendWindow[0] - self.macdHourTrendSignal[0] PrevTrendMACDdifference = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] - self.macdHourTrendSignal[self.macdLastHourTrendWindow.Count-1] 'No Long Entry' 'Entry Bar Setup' if FiveMACD > self.macdLastFiveBar and FiveMACD > .005 and self.atr.Current.Value > .02 and FiveMACDdifference > 0 and self.stc.Current.Value > 20 and self.stchour.Current.Value < 85: '(12, 26, 9) MACD Setup' if self.macdLastHourWindow[0] > PrevMACDValue or HourMACDdifference > PrevMACDdifference: '(50, 100, 20) MACD Setup' if self.macdLastHourLongWindow[0] > PrevLongMACDValue or LongMACDdifference > PrevLongMACDdifference: if LongMACDdifference > .005 or LongMACDdifference < -.005: if self.macdLastHourLongWindow[0] > .03 or LongMACDdifference > .04: '(200,400, 80) MACD Setup' if TrendMACDdifference > PrevTrendMACDdifference or self.macdLastHourTrendWindow[0] > PrevTrendMACDValue: if TrendMACDdifference > -.1 : self.MadeEntry() self.BuyPrice = Close self.SLPrice = self.BuyPrice - .25 self.TPPrice = self.BuyPrice + .35 self.entryTicket = self.LimitOrder(self.pair, self.quantity, self.BuyPrice, str(self.stchour.Current.Value) + " " + str(self.stc.Current.Value)) self.entryTickets.append(self.entryTicket) self.entryTicketIDs[self.entryTicket.OrderId] = True else: self.NoEntry() ''' SHORT STRATEGY ''' def GoShort(self, Close): FiveMACD = self.macdfiveminute.Current.Value FiveMACDdifference = self.macdfiveminute.Current.Value - self.macdfiveminute.Signal.Current.Value PrevMACDValue = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] HourMACDdifference = self.macdLastHourWindow[0] - self.macdHourSignal[0] PrevMACDdifference = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] - self.macdHourSignal[self.macdLastHourWindow.Count-1] PrevLongMACDValue = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] LongMACDdifference = self.macdLastHourLongWindow[0] - self.macdHourLongSignal[0] PrevLongMACDdifference = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] - self.macdHourLongSignal[self.macdLastHourLongWindow.Count-1] PrevTrendMACDValue = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] TrendMACDdifference = self.macdLastHourTrendWindow[0] - self.macdHourTrendSignal[0] PrevTrendMACDdifference = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] - self.macdHourTrendSignal[self.macdLastHourTrendWindow.Count-1] 'No Short Entry' 'Entry Bar Setup' if FiveMACD < self.macdLastFiveBar and FiveMACD < -.005 and self.atr.Current.Value > .02 and FiveMACDdifference > 0: #and self.stc.Current.Value < 80 '(12, 26, 9) MACD Setup' if self.macdLastHourWindow[0] < PrevMACDValue or HourMACDdifference < PrevMACDdifference: '(50, 100, 20) MACD Setup' if self.macdLastHourLongWindow[0] < PrevLongMACDValue or LongMACDdifference < PrevLongMACDdifference: if LongMACDdifference < -.005 or LongMACDdifference > .005: if self.macdLastHourLongWindow[0] < .03 or LongMACDdifference < -.04: '(200,400, 80) MACD Setup' if TrendMACDdifference < PrevTrendMACDdifference or self.macdLastHourTrendWindow[0] < PrevTrendMACDValue: if TrendMACDdifference < .1: self.MadeEntry() self.BuyPrice = Close self.SLPrice = self.BuyPrice + .20 self.TPPrice = self.BuyPrice - .35 self.entryTicket = self.LimitOrder(self.pair, -self.quantity, self.BuyPrice) self.entryTickets.append(self.entryTicket) self.entryTicketIDs[self.entryTicket.OrderId] = False else: self.NoEntry() ''' Close ALL Open Positions Before Weekend ''' def WeekendLiquidation(self): self.Liquidate() def MadeEntry(self): return self.Debug("ENTRY APPROVED ON " + str(self.Time)) self.Debug(f"STC Value : {self.stc.Current.Value}") def NoEntry(self): return self.Debug("No Entry: " + str(self.Time) + ". ENTRY TICKET: " + str(self.entryTicket)) self.Debug(f"STC Value : {self.stc.Current.Value}") def OnOrderEvent(self, orderEvent): if orderEvent.Status != OrderStatus.Filled: return order = self.Transactions.GetOrderById(orderEvent.OrderId) if orderEvent.OrderId in self.entryTicketIDs: if self.entryTicketIDs[orderEvent.OrderId] == True: self.Debug("Number of open limit orders: " + str(len(self.entryTickets))) # Enter Stop Loss Order self.SLTicket = self.StopMarketOrder( self.pair, -self.quantity, self.SLPrice) # Enter Take Profit Order self.TPTicket = self.LimitOrder( self.pair, -self.quantity, self.TPPrice) elif self.entryTicketIDs[orderEvent.OrderId] == False: self.Debug("Number of open limit orders: " + str(len(self.entryTickets))) # Enter Stop Loss Order self.SLTicket = self.StopMarketOrder( self.pair, self.quantity, self.SLPrice) # Enter Take Profit Order self.TPTicket = self.LimitOrder( self.pair, self.quantity, self.TPPrice) else: self.Debug("ERROR") return self.SLTickets[self.SLTicket] = self.TPTicket self.TPTickets[self.TPTicket] = self.SLTicket remove = None for entryTicket in self.entryTickets: if entryTicket.Status == OrderStatus.Filled: remove = entryTicket break if remove != None: self.entryTickets.remove(remove) self.entryTicketIDs.pop(remove.OrderId, None) return SLOrders = list(self.SLTickets.keys()) SLOrderIds = [x.OrderId for x in SLOrders] if orderEvent.OrderId in SLOrderIds: for ticket in SLOrders: if ticket.Status == OrderStatus.Filled: self.TPTickets[self.SLTickets[ticket]].Cancel() self.TPTickets.pop(self.SLTickets[ticket]) self.SLTickets[ticket].Cancel() self.SLTickets.pop(ticket, None) return TPOrders = list(self.TPTickets.keys()) TPOrderIds = [x.OrderId for x in TPOrders] if orderEvent.OrderId in TPOrderIds: for ticket in TPOrders: if ticket.Status == OrderStatus.Filled: self.SLTickets[self.TPTickets[ticket]].Cancel() self.SLTickets.pop(self.TPTickets[ticket]) self.TPTickets[ticket].Cancel() self.TPTickets.pop(ticket, None) return