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")