| Overall Statistics |
|
Total Trades 972 Average Win 0.41% Average Loss -0.28% Compounding Annual Return 56.304% Drawdown 15.600% Expectancy 0.303 Net Profit 46.848% Sharpe Ratio 1.845 Probabilistic Sharpe Ratio 76.459% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 1.45 Alpha 0.353 Beta 0.187 Annual Standard Deviation 0.213 Annual Variance 0.045 Information Ratio 0.79 Tracking Error 0.228 Treynor Ratio 2.098 Total Fees $0.00 Estimated Strategy Capacity $2400000.00 Lowest Capacity Asset CADJPY 8G |
class HyperActiveApricotFalcon(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 1, 1)
self.SetEndDate(2021, 11, 10)
self.SetCash(100000)
self.pair = 'CADJPY'
self.forex = self.AddForex(self.pair, Resolution.Minute, Market.Oanda).Symbol
self.quantity = 170000 # $300 Stop Loss = $26.63 avg cost per trade (commission and spread)
# Long / Short - True = Live
self.Long = True
self.Short = False
# Indicators
self.rsi = RelativeStrengthIndex(14, MovingAverageType.Wilders)
self.macdfiveminute = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential)
self.macdonehour = self.MACD(self.forex, 12, 26, 9, MovingAverageType.Exponential, Resolution.Hour)
self.macdonehourlong = self.MACD(self.forex, 50, 100, 20, MovingAverageType.Exponential, Resolution.Hour)
self.macdonehourtrend = self.MACD(self.forex, 200, 400, 80, MovingAverageType.Exponential, Resolution.Hour)
self.rsionehour = self.RSI(self.forex, 14, MovingAverageType.Wilders, Resolution.Hour)
self.atr = AverageTrueRange(14, MovingAverageType.Wilders)
self.emafast = ExponentialMovingAverage(9)
self.emaslow = ExponentialMovingAverage(50)
self.stc = SchaffTrendCycle( 10, 23, 50, MovingAverageType.Exponential)
self.stchour = SchaffTrendCycle( 10, 23, 50, MovingAverageType.Exponential, Resolution.Hour)
# One Hour Consolidator and Indicator Registrations
oneHourConsolidator = QuoteBarConsolidator(timedelta(minutes=60))
oneHourConsolidator.DataConsolidated += self.OneHourBarHandler
self.SubscriptionManager.AddConsolidator(self.pair, oneHourConsolidator)
# Five Minute Consolidator and Indicator Registrations
fiveMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=5))
fiveMinuteConsolidator.DataConsolidated += self.FiveMinuteBarHandler
self.SubscriptionManager.AddConsolidator(self.pair, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.rsi, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.atr, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.macdfiveminute, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.emafast, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.emaslow, fiveMinuteConsolidator)
self.RegisterIndicator(self.pair, self.stc, fiveMinuteConsolidator)
# One Hour Window
self.rsiLastHourWindow = RollingWindow[float](2)
self.stchourLastHourWindow = RollingWindow[float](2)
self.macdLastHourWindow = RollingWindow[float](2)
self.macdHourSignal = RollingWindow[float](2)
self.macdLastHourLongWindow = RollingWindow[float](2)
self.macdHourLongSignal = RollingWindow[float](2)
self.macdLastHourTrendWindow = RollingWindow[float](2)
self.macdHourTrendSignal = RollingWindow[float](2)
# Random Crap
self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.BeforeMarketClose(self.pair), self.WeekendLiquidation)
self.fiveminbaropen = 0
self.SetWarmUp(50)
self.lastfiveminutemacdvalues = []
self.lastonehourmacdvalues = []
self.lastonehourmacdlongvalues = []
self.macdLastFiveBar = None
self.entryTicket = None
self.SLTicket = None
self.TPTicket = None
self.entryTickets = []
self.entryTicketIDs = {}
self.SLTickets = {}
self.TPTickets = {}
def OneHourBarHandler(self, sender, consolidated):
# RSI 1 Hour
self.rsiLastHourWindow.Add(self.rsionehour.Current.Value)
# STC 1 Hour
self.stchourLastHourWindow.Add(self.stchour.Current.Value)
# Short 1 Hour
self.macdLastHourWindow.Add(self.macdonehour.Current.Value)
self.macdHourSignal.Add(self.macdonehour.Signal.Current.Value)
# Long 1 Hour
self.macdLastHourLongWindow.Add(self.macdonehourlong.Current.Value)
self.macdHourLongSignal.Add(self.macdonehourlong.Signal.Current.Value)
# Trend 1 Hour
self.macdLastHourTrendWindow.Add(self.macdonehourtrend.Current.Value)
self.macdHourTrendSignal.Add(self.macdonehourtrend.Signal.Current.Value)
def FiveMinuteBarHandler(self, sender, consolidated):
if not self.macdonehour.IsReady:
return
if self.macdLastFiveBar == None or self.macdLastHourWindow.Count <= 1:
self.macdLastFiveBar = self.macdfiveminute.Current.Value
return
# Bar Values
Close = (consolidated.Bid.Close+consolidated.Ask.Close)/2
Open = (consolidated.Bid.Open+consolidated.Ask.Open)/2
Low = (consolidated.Bid.Low+consolidated.Ask.Low)/2
High = (consolidated.Bid.High+consolidated.Ask.High)/2
Price = consolidated.Price
# Indicator Shortcuts
emaFast = self.emafast.Current.Value
emaSlow = self.emaslow.Current.Value
rsiValue = self.rsi.Current.Value
macdFive = self.macdfiveminute.Current.Value
# Long Entry Bars
if self.Long and Close > emaFast and Open > emaFast and Close < Open and emaSlow < emaFast and rsiValue < 64 and rsiValue > 54:
self.GoLong(Close)
# Short Entry Bars
elif self.Short and Close < emaFast and Open < emaFast and Close > Open and emaSlow > emaFast and rsiValue > 38 and rsiValue < 45:
self.GoShort(Close)
# Record MACD values to compare at next datapoint
self.macdLastFiveBar = self.macdfiveminute.Current.Value
''' LONG STRATEGY '''
def GoLong(self, Close):
FiveMACD = self.macdfiveminute.Current.Value
FiveMACDdifference = self.macdfiveminute.Current.Value - self.macdfiveminute.Signal.Current.Value
PrevMACDValue = self.macdLastHourWindow[self.macdLastHourWindow.Count-1]
HourMACDdifference = self.macdLastHourWindow[0] - self.macdHourSignal[0]
PrevMACDdifference = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] - self.macdHourSignal[self.macdLastHourWindow.Count-1]
PrevLongMACDValue = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1]
LongMACDdifference = self.macdLastHourLongWindow[0] - self.macdHourLongSignal[0]
PrevLongMACDdifference = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] - self.macdHourLongSignal[self.macdLastHourLongWindow.Count-1]
PrevTrendMACDValue = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1]
TrendMACDdifference = self.macdLastHourTrendWindow[0] - self.macdHourTrendSignal[0]
PrevTrendMACDdifference = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] - self.macdHourTrendSignal[self.macdLastHourTrendWindow.Count-1]
'No Long Entry'
'Entry Bar Setup'
if FiveMACD > self.macdLastFiveBar and FiveMACD > .005 and self.atr.Current.Value > .02 and FiveMACDdifference > 0 and self.stc.Current.Value > 20 and self.stchour.Current.Value < 85:
'(12, 26, 9) MACD Setup'
if self.macdLastHourWindow[0] > PrevMACDValue or HourMACDdifference > PrevMACDdifference:
'(50, 100, 20) MACD Setup'
if self.macdLastHourLongWindow[0] > PrevLongMACDValue or LongMACDdifference > PrevLongMACDdifference:
if LongMACDdifference > .005 or LongMACDdifference < -.005:
if self.macdLastHourLongWindow[0] > .03 or LongMACDdifference > .04:
'(200,400, 80) MACD Setup'
if TrendMACDdifference > PrevTrendMACDdifference or self.macdLastHourTrendWindow[0] > PrevTrendMACDValue:
if TrendMACDdifference > -.1 :
self.MadeEntry()
self.BuyPrice = Close
self.SLPrice = self.BuyPrice - .25
self.TPPrice = self.BuyPrice + .35
self.entryTicket = self.LimitOrder(self.pair, self.quantity, self.BuyPrice, str(self.stchour.Current.Value) + " " + str(self.stc.Current.Value))
self.entryTickets.append(self.entryTicket)
self.entryTicketIDs[self.entryTicket.OrderId] = True
else:
self.NoEntry()
''' SHORT STRATEGY '''
def GoShort(self, Close):
FiveMACD = self.macdfiveminute.Current.Value
FiveMACDdifference = self.macdfiveminute.Current.Value - self.macdfiveminute.Signal.Current.Value
PrevMACDValue = self.macdLastHourWindow[self.macdLastHourWindow.Count-1]
HourMACDdifference = self.macdLastHourWindow[0] - self.macdHourSignal[0]
PrevMACDdifference = self.macdLastHourWindow[self.macdLastHourWindow.Count-1] - self.macdHourSignal[self.macdLastHourWindow.Count-1]
PrevLongMACDValue = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1]
LongMACDdifference = self.macdLastHourLongWindow[0] - self.macdHourLongSignal[0]
PrevLongMACDdifference = self.macdLastHourLongWindow[self.macdLastHourLongWindow.Count-1] - self.macdHourLongSignal[self.macdLastHourLongWindow.Count-1]
PrevTrendMACDValue = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1]
TrendMACDdifference = self.macdLastHourTrendWindow[0] - self.macdHourTrendSignal[0]
PrevTrendMACDdifference = self.macdLastHourTrendWindow[self.macdLastHourTrendWindow.Count-1] - self.macdHourTrendSignal[self.macdLastHourTrendWindow.Count-1]
'No Short Entry'
'Entry Bar Setup'
if FiveMACD < self.macdLastFiveBar and FiveMACD < -.005 and self.atr.Current.Value > .02 and FiveMACDdifference > 0: #and self.stc.Current.Value < 80
'(12, 26, 9) MACD Setup'
if self.macdLastHourWindow[0] < PrevMACDValue or HourMACDdifference < PrevMACDdifference:
'(50, 100, 20) MACD Setup'
if self.macdLastHourLongWindow[0] < PrevLongMACDValue or LongMACDdifference < PrevLongMACDdifference:
if LongMACDdifference < -.005 or LongMACDdifference > .005:
if self.macdLastHourLongWindow[0] < .03 or LongMACDdifference < -.04:
'(200,400, 80) MACD Setup'
if TrendMACDdifference < PrevTrendMACDdifference or self.macdLastHourTrendWindow[0] < PrevTrendMACDValue:
if TrendMACDdifference < .1:
self.MadeEntry()
self.BuyPrice = Close
self.SLPrice = self.BuyPrice + .20
self.TPPrice = self.BuyPrice - .35
self.entryTicket = self.LimitOrder(self.pair, -self.quantity, self.BuyPrice)
self.entryTickets.append(self.entryTicket)
self.entryTicketIDs[self.entryTicket.OrderId] = False
else:
self.NoEntry()
''' Close ALL Open Positions Before Weekend '''
def WeekendLiquidation(self):
self.Liquidate()
def MadeEntry(self):
return
self.Debug("ENTRY APPROVED ON " + str(self.Time))
self.Debug(f"STC Value : {self.stc.Current.Value}")
def NoEntry(self):
return
self.Debug("No Entry: " + str(self.Time) + ". ENTRY TICKET: " + str(self.entryTicket))
self.Debug(f"STC Value : {self.stc.Current.Value}")
def OnOrderEvent(self, orderEvent):
if orderEvent.Status != OrderStatus.Filled:
return
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if orderEvent.OrderId in self.entryTicketIDs:
if self.entryTicketIDs[orderEvent.OrderId] == True:
self.Debug("Number of open limit orders: " + str(len(self.entryTickets)))
# Enter Stop Loss Order
self.SLTicket = self.StopMarketOrder( self.pair, -self.quantity, self.SLPrice)
# Enter Take Profit Order
self.TPTicket = self.LimitOrder( self.pair, -self.quantity, self.TPPrice)
elif self.entryTicketIDs[orderEvent.OrderId] == False:
self.Debug("Number of open limit orders: " + str(len(self.entryTickets)))
# Enter Stop Loss Order
self.SLTicket = self.StopMarketOrder( self.pair, self.quantity, self.SLPrice)
# Enter Take Profit Order
self.TPTicket = self.LimitOrder( self.pair, self.quantity, self.TPPrice)
else:
self.Debug("ERROR")
return
self.SLTickets[self.SLTicket] = self.TPTicket
self.TPTickets[self.TPTicket] = self.SLTicket
remove = None
for entryTicket in self.entryTickets:
if entryTicket.Status == OrderStatus.Filled:
remove = entryTicket
break
if remove != None:
self.entryTickets.remove(remove)
self.entryTicketIDs.pop(remove.OrderId, None)
return
SLOrders = list(self.SLTickets.keys())
SLOrderIds = [x.OrderId for x in SLOrders]
if orderEvent.OrderId in SLOrderIds:
for ticket in SLOrders:
if ticket.Status == OrderStatus.Filled:
self.TPTickets[self.SLTickets[ticket]].Cancel()
self.TPTickets.pop(self.SLTickets[ticket])
self.SLTickets[ticket].Cancel()
self.SLTickets.pop(ticket, None)
return
TPOrders = list(self.TPTickets.keys())
TPOrderIds = [x.OrderId for x in TPOrders]
if orderEvent.OrderId in TPOrderIds:
for ticket in TPOrders:
if ticket.Status == OrderStatus.Filled:
self.SLTickets[self.TPTickets[ticket]].Cancel()
self.SLTickets.pop(self.TPTickets[ticket])
self.TPTickets[ticket].Cancel()
self.TPTickets.pop(ticket, None)
return