Overall Statistics
Total Trades
53
Average Win
3.90%
Average Loss
-4.59%
Compounding Annual Return
-6.354%
Drawdown
24.900%
Expectancy
-0.017
Net Profit
-6.354%
Sharpe Ratio
-0.015
Probabilistic Sharpe Ratio
12.957%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
0.85
Alpha
0.019
Beta
-0.151
Annual Standard Deviation
0.315
Annual Variance
0.099
Information Ratio
-0.512
Tracking Error
0.322
Treynor Ratio
0.032
Total Fees
$0.00
from collections import *
import math

class MulitTimeFrameForexScalping(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2017, 1, 1)    #Set Start Date
        self.SetEndDate(2017, 12, 31)      #Set End Date
        self.SetCash(10000)             #Set Strategy Cash
        
        pairs = ["EURUSD", "GBPUSD", "AUDUSD", "NZDUSD"]
        
        self.forexPair = "EURUSD"
        self.AddForex(self.forexPair, Resolution.Minute, Market.Oanda)
        self.SetBrokerageModel(BrokerageName.OandaBrokerage);
        
    
        self.Consolidate(self.forexPair,timedelta(minutes=5),self.fiveMinutesBarHandler)
        self.Consolidate(self.forexPair, timedelta(minutes=60),self.sixtyMinutesBarHandler)
      
       
        self.BarHistoryWindow = 5 
        #Set up EMA indicators for lookback periods 21, 13 and 8 for both five minutes and 60 minutes time frames
        self.longLookBackPeriod = 21
        self.mediumLookBackPeriod = 13
        self.shortLookBackPeriod = 8
        
        self.percentageOfPortfolioRiskedPerTrade = 0.01
        
        self.emaFiveMinsLong = ExponentialMovingAverage(self.longLookBackPeriod)
        self.RegisterIndicator(self.forexPair, self.emaFiveMinsLong ,timedelta(minutes=5))
        self.emaFiveMinsMedium = ExponentialMovingAverage(self.mediumLookBackPeriod)
        self.RegisterIndicator(self.forexPair, self.emaFiveMinsMedium ,timedelta(minutes=5))
        self.emaFiveMinsShort = ExponentialMovingAverage(self.shortLookBackPeriod)
        self.RegisterIndicator(self.forexPair, self.emaFiveMinsShort ,timedelta(minutes=5))
        
        self.emaSixtyMinsLong = ExponentialMovingAverage(self.longLookBackPeriod)
        self.RegisterIndicator(self.forexPair, self.emaSixtyMinsLong ,timedelta(minutes=60))
        self.emaSixtyMinsShort = ExponentialMovingAverage(self.shortLookBackPeriod)
        self.RegisterIndicator(self.forexPair, self.emaSixtyMinsShort ,timedelta(minutes=60))
        
        self.historyFiveMinuteBars =   deque(maxlen=  self.BarHistoryWindow ) 
        self.historySixtyMinuteBars = deque(maxlen=  self.BarHistoryWindow ) 
        self.historyEmaSixtyMinsLong =  deque(maxlen=  self.BarHistoryWindow)
        self.historyEmaSixtyMinsShort = deque(maxlen=  self.BarHistoryWindow)
        self.historyEmaFiveMinsLong =  deque(maxlen=  self.BarHistoryWindow)
        self.historyEmaFiveMinsMedium = deque(maxlen=  self.BarHistoryWindow)
        self.historyEmaFiveMinsShort = deque(maxlen=  self.BarHistoryWindow)
        
        self.pipsAtRiskPerTrade  = 3
        self.numberOfprofitTarget1Pips = 1
        self.numberOfprofitTarget2Pips = 2
        self.pips = 0.0001
        
        self.stopBuyPrice = 0
        self.stopLossPrice = 0 
        self.profitTarget1 = 0
        self.profitTarget2  = 0
        
        self.orderSize = 100000
        
        self.entryTicket = None
        self.stoplossTicket = None
        self.profit1Ticket = None
        self.profit2Ticket = None
        
    def fiveMinutesBarHandler(self,consolidated):
        self.historyFiveMinuteBars.append(consolidated)
        self.historyEmaFiveMinsLong.append(self.emaFiveMinsLong.Current.Value)
        self.historyEmaFiveMinsMedium.append(self.emaFiveMinsMedium.Current.Value)
        self.historyEmaFiveMinsShort.append(self.emaFiveMinsShort.Current.Value)
        self.Plot("5m","5mEMA21",self.emaFiveMinsLong.Current.Value)
        self.Plot("5m","5mEMA13", self.emaFiveMinsMedium.Current.Value)
        self.Plot("5m","5mEMA8", self.emaFiveMinsShort.Current.Value)
        self.Plot("5m","EURUSD", consolidated.Close)
        if self.entryTicket == None and self.longEntrySetup() and self.longEntryTrigger():
            entryPrice = max([quoteBar.High for quoteBar in  self.historyFiveMinuteBars])
            self.stopBuyPrice = entryPrice + 0.0001*3
            self.stopLossPrice =  consolidated.Low - self.pipsAtRiskPerTrade  * self.pips
            R = self.stopBuyPrice - self.stopLossPrice
            self.profitTarget1 = self.stopBuyPrice + self.numberOfprofitTarget1Pips * R
            self.profitTarget2 = self.stopBuyPrice + self.numberOfprofitTarget2Pips * 2*R
            self.orderSize = self.CalculateOrderSize()
            self.entryTicket = self.StopMarketOrder( self.forexPair, self.orderSize, self.stopBuyPrice)
        elif self.entryTicket is not None and not self.longEntrySetup() and self.entryTicket.Status != OrderStatus.Filled:
            self.Transactions.CancelOrder(self.entryTicket.OrderId)
            self.entryTicket = None
            
    def longEntrySetup(self):
        fiveMinFannedOut =   all([x > y > z for x,y,z in zip(list(self.historyEmaFiveMinsShort),list(self.historyEmaFiveMinsMedium),list(self.historyEmaFiveMinsLong))])
        sixtyMinFannedOut =  all([x > y for x,y in zip(list(self.historyEmaSixtyMinsShort),list(self.historyEmaSixtyMinsLong))])
        prevBarsAboveShortEMA = all([x > y for x,y in zip([bar.Low for bar in list(self.historyFiveMinuteBars)[0:4]],list(self.historyEmaFiveMinsShort)[:4])])
        return fiveMinFannedOut and sixtyMinFannedOut and prevBarsAboveShortEMA
    
    def longEntryTrigger(self):
        return self.historyFiveMinuteBars[-1].Low <= self.historyEmaFiveMinsShort[-1]
    
    def CalculateOrderSize(self):
        #https://www.thebalance.com/how-to-determine-proper-position-size-when-forex-trading-1031023
        totalPortfolioValue = self.Portfolio.TotalPortfolioValue 
        amountAtRisk =  totalPortfolioValue *  self.percentageOfPortfolioRiskedPerTrade
        standardLot = 100000
        pipValueForTrade = 10
        lots =  amountAtRisk/(self.pipsAtRiskPerTrade * pipValueForTrade ) * standardLot
        rounded = math.ceil(lots / 2.) * 2
        return  rounded
    
    
    def OnOrderEvent(self, orderevent):
        if orderevent.Status != OrderStatus.Filled:
            return
        
        if self.entryTicket != None and self.entryTicket.OrderId == orderevent.OrderId:
           # Enter stop loss order
           self.stoplossTicket = self.StopMarketOrder(self.forexPair,-self.orderSize,self.stopLossPrice)
           # Enter limit order 1
           self.profit1Ticket = self.LimitOrder(self.forexPair,-self.orderSize/2,self.profitTarget1)
           # Enter limit order 2
           self.profit2Ticket = self.LimitOrder(self.forexPair,-self.orderSize/2,self.profitTarget2)
        
        if self.profit1Ticket != None and self.profit1Ticket.OrderId == orderevent.OrderId:
            self.stoplossTicket.UpdateQuantity(-self.orderSize/2)
            
        if self.stoplossTicket != None and self.stoplossTicket.OrderId == orderevent.OrderId:
            self.profit1Ticket.Cancel()
            self.profit2Ticket.Cancel()
            self.entryTicket = None
        
        if self.profit2Ticket != None and self.profit2Ticket.OrderId == orderevent.OrderId:
            self.stoplossTicket.Cancel()
            self.entryTicket = None
    
    def sixtyMinutesBarHandler(self,consolidated):
        self.historySixtyMinuteBars.append(consolidated)
        self.historyEmaSixtyMinsLong.append(self.emaSixtyMinsLong.Current.Value)
        self.historyEmaSixtyMinsShort.append(self.emaSixtyMinsShort.Current.Value)
        self.Plot("60m","EMA21",self.emaSixtyMinsLong.Current.Value)
        self.Plot("60m","EMA8", self.emaSixtyMinsShort.Current.Value)
        self.Plot("60m","EURUSD", consolidated.Close)