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