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