Overall Statistics
Total Trades
196
Average Win
0.79%
Average Loss
-0.41%
Compounding Annual Return
-0.386%
Drawdown
5.800%
Expectancy
-0.013
Net Profit
-0.418%
Sharpe Ratio
-0.033
Probabilistic Sharpe Ratio
9.890%
Loss Rate
66%
Win Rate
34%
Profit-Loss Ratio
1.93
Alpha
0.006
Beta
-0.039
Annual Standard Deviation
0.048
Annual Variance
0.002
Information Ratio
-0.66
Tracking Error
0.285
Treynor Ratio
0.04
Total Fees
$0.00
Estimated Strategy Capacity
$12000000.00
Lowest Capacity Asset
EURCAD 8G
from datetime import timedelta
from AlgorithmImports import *
#from params import tp,sl

STOCK = "EURCAD"

class DayOpenEma(QCAlgorithm):
    
    def Initialize(self):
        
        self.SetStartDate(2020, 2, 1)  # Set Start Date
        self.SetEndDate(2021, 3, 1)  # Set End Date
        
        self.SetCash(10000)  # Set Strategy Cash
        
        #self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
        
        self.AddForex(STOCK, Resolution.Minute)
        
        #constructing 3h candles
        self.Consolidate(STOCK,timedelta(hours=3),self.OnThreeHourCandle)
        
        self.ema = self.EMA(STOCK,72,Resolution.Hour)

        # warming up the ema
        self.SetWarmup(72, Resolution.Hour)
            
        '''
        overlayPlot = Chart("Overlay Plot")
        
        self.AddChart(overlayPlot)
        overlayPlot.AddSeries(Series(STOCK, SeriesType.Line, 0))
        overlayPlot.AddSeries(Series("EMA",SeriesType.Line, 0))
        overlayPlot.AddSeries(Series("Day Open", SeriesType.Line, 0))
        overlayPlot.AddSeries(Series("BUY", SeriesType.Scatter, "$", Color.Green, ScatterMarkerSymbol.Triangle))
        overlayPlot.AddSeries(Series("SELL", SeriesType.Scatter, "$", Color.Red, ScatterMarkerSymbol.TriangleDown))
        #overlayPlot.AddSeries(Series("Position", SeriesType.Line, 1))
        '''
        #self.tp = float(self.GetParameter("tp",0.5))
        #self.sl = float(self.GetParameter("sl",0.25))
        #self.Log(self.tp)
        #self.Log(self.sl)
        self.tp = 80
        self.sl = 40

        # used to create daily open
        self.previous_day = 0
        self.day_open = 0
        
        # used to create bracket orders
        self.entry_ticket = None
        self.tp_order = None
        self.sl_order = None
    
        # used to cancel the limit order after 24h
        self.entry_ticket_time = None
        self.order_timer = False
        
        self.previous_close = None
        
    
    # this thing is here because quantconnect gets angry if the price
    # has more than 6 numbers in it
    # when it gets angry it does a manual conversion and somehow that 
    # conversion creates a bug when placing tp and sl orders
    @staticmethod
    def round_price(num):
        return round(num, 6-(len(str(num).split(".")[0])))

    # handles the orders
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return
        
        if self.entry_ticket is not None:
    
            # if main order is filled
            if orderEvent.OrderId == self.entry_ticket.OrderId:
                
                # cancelling the 24h order expiration
                self.order_timer = False
                self.entry_ticket_time = None
                
                # getting price and quantity of the fill
                price = self.round_price(orderEvent.FillPrice)
                quantity = self.entry_ticket.Quantity
                #self.Log(str(self.Time))
                #self.Log("Fill Price: "+str(price))
                #self.Log("Price: "+str(self.Securities[STOCK].Price))

                
                # if order was long
                if quantity>0:
                    self.Plot("Overlay Plot", "BUY", price-0.005)
                    # placing TP and SL
                    self.tp_order = self.LimitOrder(STOCK, -quantity, self.round_price(price*(1+self.tp/10000)))
                    self.sl_order = self.StopMarketOrder(STOCK, -quantity, self.round_price(price*(1-self.sl/10000)))

                # if order was short
                if quantity<0:
                    self.Plot("Overlay Plot", "SELL", price+0.005)
                    # placing TP and SL
                    self.tp_order = self.LimitOrder(STOCK, -quantity, self.round_price(price*(1-self.tp/10000)))
                    self.sl_order = self.StopMarketOrder(STOCK, -quantity, self.round_price(price*(1+self.sl/10000)))
                
            # if TP or SL order is filled
            else:
                price = orderEvent.FillPrice
                '''
                if orderEvent.FillQuantity > 0:
                    self.Plot("Overlay Plot", "BUY", price-0.005)
                else:
                    self.Plot("Overlay Plot", "SELL", price+0.005)
                '''
                self.Transactions.CancelOpenOrders(STOCK)
                self.entry_ticket = None          
        
        
    # cancels orders, closes positions and resets bools
    def ResetEverything(self):
    
        # cancelling the orders
        self.Transactions.CancelOpenOrders(STOCK)
        
        # resetting the orders
        self.entry_ticket = None
        self.tp_order = None
        self.sl_order = None

        
        # liquidating position
        if self.Portfolio.Invested:
            self.Liquidate(STOCK)
        
        # timer is stopped
        self.entry_ticket_time = None
        self.order_timer = False
        

    # every 3h candle
    def OnThreeHourCandle(self,data):
        
        
        # getting the data
        candleOpen = self.previous_close
        candleClose = round(self.Securities[STOCK].Price,5)
        self.previous_close = candleClose
        #self.Log("Price: "+str(self.Securities[STOCK].Price))

        # warming up the ema indicator
        if self.IsWarmingUp:
            return
        

        candleTime = self.Time
        ema = round(self.ema.Current.Value,5)
        
        if ema == None or ema is None:
            return
        
        dayOpen = self.day_open

        # creating day open
        if candleTime.day != self.previous_day:
            self.previous_day = candleTime.day
            self.day_open = candleOpen
            dayOpen = candleOpen

        '''
        # showing the data
        self.Plot("Overlay Plot", STOCK, candleClose)
        self.Plot("Overlay Plot", "EMA", ema)    
        self.Plot("Overlay Plot", "Day Open", dayOpen)
        '''
        #self.Log("Candle Open:" + str(candleOpen))
        #self.Log("Candle Close:" + str(candleClose))
        #self.Log("EMA:" + str(ema))
        #self.Log("Day Open:" + str(self.dayOpen))


        # handles the order expiration
        if self.order_timer:
            # if todays day is greater than the day of the order
            # if today hour is equal or bigger than the hour of the order
            # means that 24 hours have passed from the order submission to now
            if candleTime.day > self.entry_ticket_time.day:
                if candleTime.hour >= self.entry_ticket_time.hour:
                    # the order is cancelled 
                    self.Transactions.CancelOpenOrders(STOCK)
                    # order is removed
                    self.entry_ticket = None
                    # order timer is cancelled
                    self.order_timer = False
                    self.entry_ticket_time = None
        
    

        # if there is no order or the position or order is short
        if self.entry_ticket is None:
                
            # long signal
            if candleClose > dayOpen and candleClose > ema:
                
                # SIGNAL CANDLE LONG TRIGGERED
                
                self.ResetEverything()
                
                candleRange = round(Math.Abs(candleClose - candleOpen),5)
                limitPrice = self.round_price(candleClose - 0.25 * candleRange)
                quantity = self.CalculateOrderQuantity(STOCK, 1)
                
                self.entry_ticket = self.LimitOrder(STOCK, quantity, limitPrice)
                self.entry_ticket_time = candleTime
                self.order_timer = True
                
                
                #self.Log("Open: "+str(candleOpen))
                #self.Log("Close: "+str(candleClose))
                #self.Log("Candle Range: "+ str(candleRange))
                #self.Log("Long opened with limit: " + str(limitPrice))