Overall Statistics
import numpy as np
import decimal
from datetime import datetime, timedelta
### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
class BasicTemplateAlgorithm(QCAlgorithm):
    '''Basic template algorithm simply initializes the date range and cash'''
    
    def myRound(val, place):
        x = decimal.Decimal(val)
        return round(x,place)
    
    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        self.Charting = True
        self.Logging = True
        self.FXSymbol = "EURUSD"                                                    # Set symbol
        self.SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin)    # Set Brokerage
        self.SetStartDate(2013,1,1)                                                 # Set Start Date
        self.SetEndDate(2013,1,5)                                                   # Set End Date
        self.SetWarmUp(60*60*21)                                                    # Set warmup time
        self.SetCash(100000)                                                        # Set Strategy Cash
        self.WindowSize = 5                                                         # Set size of rolling window                  
        self.GapSize = decimal.Decimal(0.0003)                                      # Set size of gap between trigger/stop and rolling/entry default 0.00003
        self.TakeProfitFactor = 2                                                   # Set take profit factor, takeProfit = x * risk
        self.BetSize = 100000                                                       # Set bet size
        # we could also try trailing stop lose after breaking even!!
        # https://www.youtube.com/watch?v=zhEukjCzXwM
        self.PreferedResolution = Resolution.Second                                  # set resolution WHY THIS CHANGES EMA'S VALUES
        self.AddForex(self.FXSymbol, Resolution.Second, Market.Oanda)

        consolidator5m = QuoteBarConsolidator(timedelta(minutes=5))
        self.price = self.Identity(self.FXSymbol, self.PreferedResolution)
        self.RegisterIndicator(self.FXSymbol, self.price, consolidator5m)
        
        self.ema8 = self.EMA(self.FXSymbol, 8, self.PreferedResolution)
        self.ema21 = self.EMA(self.FXSymbol, 21, self.PreferedResolution)
        self.RegisterIndicator(self.FXSymbol, self.ema8, consolidator5m)
        self.RegisterIndicator(self.FXSymbol, self.ema21, consolidator5m)
        
        consolidator1h = QuoteBarConsolidator(timedelta(hours=1))
        self.emah8 = self.EMA(self.FXSymbol, 8, self.PreferedResolution)
        self.emah21 = self.EMA(self.FXSymbol, 21, self.PreferedResolution)
        self.RegisterIndicator(self.FXSymbol, self.emah8, consolidator1h)
        self.RegisterIndicator(self.FXSymbol, self.emah21, consolidator1h)
        
        consolidator5m.DataConsolidated += self.OnDataConsolidated
        self.SubscriptionManager.AddConsolidator(self.FXSymbol, consolidator5m)
        self.SubscriptionManager.AddConsolidator(self.FXSymbol, consolidator1h)
        # Create a Rolling Window to keep the last x QuoteBars
        self.quoteBarWindow = RollingWindow[QuoteBar](self.WindowSize)
        
        
        self.StopLossOrder = None
        self.TakeProfitOrder = None
        self.BreakEvenOrder = None
        self.MainOrder = None
        
        self.StopLoss = None
        self.BreakEven = None
        self.TakeProfit = None
        if self.Charting:
            # Plotting
            # slow emas
            self.chartSlow = Chart("Slow")
            self.chartSlow.AddSeries(Series(self.price.Name, SeriesType.Line))
            self.chartSlow.AddSeries(Series(self.emah8.Name, SeriesType.Line))
            self.chartSlow.AddSeries(Series(self.emah21.Name, SeriesType.Line))
            self.AddChart(self.chartSlow)
            self.PlotIndicator("Slow", self.price, self.emah8, self.emah21)
            
            # fast emas
            self.chartFast = Chart("Fast")
            self.chartFast.AddSeries(Series(self.price.Name, SeriesType.Line))
            self.chartFast.AddSeries(Series(self.ema8.Name, SeriesType.Line))
            self.chartFast.AddSeries(Series(self.ema21.Name, SeriesType.Line))
            self.AddChart(self.chartFast)
            self.PlotIndicator("Fast", self.price, self.ema8, self.ema21)
            
            
            # orders
            self.chartOrders = Chart("Orders")
            self.chartOrders.AddSeries(Series(self.price.Name, SeriesType.Line))
            self.chartOrders.AddSeries(Series("Buy", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("Sell", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("BreakEven", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("StopLoss", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("TakeProfit", SeriesType.Scatter))
            self.PlotIndicator("Orders", self.price)
            self.AddChart(self.chartOrders)
        else:
            # Plotting just orders on hourly
            self.chartOrders = Chart("Orders")
            self.chartOrders.AddSeries(Series(self.price.Name, SeriesType.Line))
            self.chartOrders.AddSeries(Series("Buy", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("Sell", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("BreakEven", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("StopLoss", SeriesType.Scatter))
            self.chartOrders.AddSeries(Series("TakeProfit", SeriesType.Scatter))
            self.PlotIndicator("Orders", self.price)
            self.AddChart(self.chartOrders)
        

    

    def OnData(self, data):
        pass
            
    
    def OnDataConsolidated(self, sender, bar):
        # update RollingWindow
        self.quoteBarWindow.Add(bar)
        
        
        if self.Logging:
            #self.Log("Open - {}".format(bar.Open))
            #self.Log("Close - {}".format(bar.Close))
            #self.Log("Low - {}".format(bar.Low))
            #self.Log("High - {}".format(bar.High))
    
            #self.Log("BidOpen - {}".format(bar.Bid.Open))
            #self.Log("BidClose - {}".format(bar.Bid.Close))
            #self.Log("BidLow - {}".format(bar.Bid.Low))
            #self.Log("BidHigh - {}".format(bar.Bid.High))
            
            #self.Log("AskOpen - {}".format(bar.Ask.Open))
            #self.Log("AskClose - {}".format(bar.Ask.Close))
            #self.Log("AskLow - {}".format(bar.Ask.Low))
            #self.Log("AskHigh - {}".format(bar.Ask.High))
            
            self.Log("EMA8 - {}".format(self.ema8.Current.Value))
            self.Log("EMA21 - {}".format(self.ema21.Current.Value))
            self.Log("EMAH8 - {}".format(self.emah8.Current.Value))
            self.Log("EMAH21 - {}".format(self.emah21.Current.Value))
            self.Log("###################")
        
        
        # if still in warming up mode
        if self.IsWarmingUp:
            return
        # if previous entry was not filled, cancel it
        if self.MainOrder != None and self.MainOrder.Status != OrderStatus.Filled:
            self.Transactions.CancelOpenOrders(self.FXSymbol)
            
        # don't do anything if we have open orders
        if len(self.Transactions.GetOpenOrders()) > 0 or self.Portfolio[self.FXSymbol].Invested:
            return
        
        if self.ema8.IsReady and self.ema21.IsReady and self.emah8.IsReady and self.emah21.IsReady:
            # looking for going short
            if self.emah8.Current.Value > bar.High and self.emah21.Current.Value > bar.High and self.emah21.Current.Value > self.emah8.Current.Value:
                # trigger if touches ema8 from below but don't touch ema21
                if self.ema8.Current.Value < bar.High and self.ema21.Current.Value > bar.High:
                    # calculate entry point
                    lows = list()
                    for i in range(self.WindowSize):
                        lows.append(self.quoteBarWindow[i].Low)
                    minimum = min(lows)
                    entry = minimum - self.GapSize
                    # calculate stop loss x pi
                    self.StopLoss = bar.High + self.GapSize
                    # calculate break even at 1 x Risk
                    risk = self.StopLoss - entry
                    self.BreakEven = entry - risk
                    # calculate take profit at 2 x Risk
                    self.TakeProfit = entry - self.TakeProfitFactor * risk
                    
                    self.Log("Entry: {} StopLoss: {} BreakEven: {} TakeProfit: {} Risk: {} Direction: SHORT"
                                .format(entry,
                                       self.StopLoss,
                                       self.BreakEven,
                                       self.TakeProfit,
                                       risk
                                       ))
                                       
                    self.Log("EMA8: {} EMA21: {} EMAH8: {} EMAH21 {}"
                                .format(self.ema8.Current.Value,
                                        self.ema21.Current.Value,
                                        self.emah8.Current.Value,
                                        self.emah21.Current.Value
                                ))
                    # GO SHORT!
                    self.MainOrder = self.StopMarketOrder(self.FXSymbol, -self.BetSize, entry, "Entry")
                    
                else:
                    return
            # looking for going long 
            elif self.emah8.Current.Value < bar.Low and self.emah21.Current.Value < bar.Low and self.emah8.Current.Value > self.emah21.Current.Value:
                # trigger if touches ema8 from above but don't touch ema21
                if self.ema8.Current.Value > bar.Low and self.ema21.Current.Value < bar.Low:
                    # calculate entry point
                    highs = list()
                    for i in range(self.WindowSize):
                        highs.append(self.quoteBarWindow[i].High)
                    maximum = max(highs)
                    entry = maximum + self.GapSize
                    # calculate stop loss x pi
                    self.StopLoss = bar.Low - self.GapSize
                    # calculate break even at 1 x Risk
                    risk = entry - self.StopLoss
                    self.BreakEven = entry + risk
                    # calculate take profit at 2 x Risk
                    self.TakeProfit = entry + self.TakeProfitFactor * risk
                    self.Log("Entry: {} StopLoss: {} BreakEven: {} TakeProfit: {} Risk: {} Direction: LONG"
                                .format(entry,
                                       self.StopLoss,
                                       self.BreakEven,
                                       self.TakeProfit,
                                       risk
                                       ))
                    self.Log("EMA8: {} EMA21: {} EMAH8: {} EMAH21 {}"
                                .format(self.ema8.Current.Value,
                                        self.ema21.Current.Value,
                                        self.emah8.Current.Value,
                                        self.emah21.Current.Value
                                ))            
                    # GO LONG!
                    self.MainOrder = self.StopMarketOrder(self.FXSymbol, self.BetSize, entry, "Entry")
                else:
                    return
            # not trading
            else:
                return
            
            
    def OnOrderEvent(self, OrderEvent):
        """Event when the order is filled. Debug log the order fill. :OrderEvent:"""


        
        if OrderEvent.FillQuantity == 0:
            return
        
        fetched = self.Transactions.GetOrderById(OrderEvent.OrderId)
        # plot orders
        if OrderEvent.Direction == 0:
            if fetched.Tag == "Entry":
                self.Plot("Orders", "Buy", OrderEvent.FillPrice)
            elif fetched.Tag == "BreakEven":
                self.Plot("Orders", "BreakEven", OrderEvent.FillPrice)
            elif fetched.Tag == "TakeProfit":
                self.Plot("Orders", "TakeProfit", OrderEvent.FillPrice)
            elif fetched.Tag == "StopLoss":
                self.Plot("Orders", "StopLoss", OrderEvent.FillPrice)
            else:
                self.Plot("Orders", "xD", OrderEvent.FillPrice)
        else:
            if fetched.Tag == "Entry":
                self.Plot("Orders", "Sell", OrderEvent.FillPrice)
            elif fetched.Tag == "BreakEven":
                self.Plot("Orders", "BreakEven", OrderEvent.FillPrice)
            elif fetched.Tag == "TakeProfit":
                self.Plot("Orders", "TakeProfit", OrderEvent.FillPrice)
            elif fetched.Tag == "StopLoss":
                self.Plot("Orders", "StopLoss", OrderEvent.FillPrice)
            else:
                self.Plot("Orders", "xD", OrderEvent.FillPrice)
        
        #self.Log("{} was filled. Symbol: {}. Quantity: {}. Direction: {} Tag: {} Status: {}"
        #           .format(str(fetched.Type),
        #                   str(OrderEvent.Symbol),
        #                   str(OrderEvent.FillQuantity),
        #                   str(OrderEvent.Direction),
        #                   str(fetched.Tag),
        #                   str(OrderEvent.Status)))       
        # if entry got filled
        if fetched.Tag == "Entry" and fetched.Status == OrderStatus.Filled:
            # Entry was long
            if OrderEvent.Direction == 0:
                # set stop loss
                self.StopLossOrder = self.StopMarketOrder(self.FXSymbol, -1 * self.BetSize, self.StopLoss, "StopLoss")
                # set break even
                self.BreakEvenOrder = self.LimitOrder(self.FXSymbol, -1 * 0.5 * self.BetSize, self.BreakEven, "BreakEven")
                # set take profit 
                self.TakeProfitOrder = self.LimitOrder(self.FXSymbol, -1 * 0.5 * self.BetSize, self.TakeProfit, "TakeProfit")
            else:
                # Entry was short
                # set stop loss
                self.StopLossOrder = self.StopMarketOrder(self.FXSymbol, self.BetSize, self.StopLoss, "StopLoss")
                # set break even
                self.BreakEvenOrder = self.LimitOrder(self.FXSymbol, 0.5 * self.BetSize, self.BreakEven, "BreakEven")
                # set take profit 
                self.TakeProfitOrder = self.LimitOrder(self.FXSymbol, 0.5 * self.BetSize, self.TakeProfit, "TakeProfit")
        elif fetched.Tag == "StopLoss" and fetched.Status == OrderStatus.Filled:
            self.Transactions.CancelOpenOrders(self.FXSymbol)
            #self.BreakEvenOrder.Cancel()
            #self.TakeProfitOrder.Cancel()
        elif fetched.Tag == "BreakEven" and fetched.Status == OrderStatus.Filled:
            # TODO Trailing stop loss
            updateOrderFields = UpdateOrderFields()
            # if break even was long then entry was short so stop loss must be long
            if OrderEvent.Direction == 0:
                updateOrderFields.Quantity = decimal.Decimal(self.BetSize * 0.5)
            else:
                updateOrderFields.Quantity = decimal.Decimal(-1 * self.BetSize * 0.5)
            self.StopLossOrder.Update(updateOrderFields)
            pass
        elif fetched.Tag == "TakeProfit" and fetched.Status == OrderStatus.Filled:
            # self.StopLossOrder.Cancel()
            self.Transactions.CancelOpenOrders(self.FXSymbol)
        else:
             self.Log("ELSE")