| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
class DataTrader30minEURUSDStrategy(QCAlgorithm):
def Initialize(self):
# Define conditions for the backtest
self.SetStartDate(2020, 1, 1) # Set Start Date
self.SetEndDate(2020, 1, 31) # Set End Date
self.SetCash(5000) # Set Strategy Cash
# Define the currency pair to use to trade and set leverage to 2
self.pair = self.AddForex("EURUSD", Resolution.Minute, Market.Oanda).Symbol
# Define Broker to be used for trading
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
#self.SetSecurityInitializer(self.CustomSecurityInitializer)
#self.Securities[self.pair].SetLeverage(200)
# Create 30 min consolidator
thirtyMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=30))
thirtyMinuteConsolidator.DataConsolidated += self.thirtyMinuteHandler
self.SubscriptionManager.AddConsolidator(self.pair, thirtyMinuteConsolidator)
# Define the Indicators needed for the strategy
self.sto30min = Stochastic(14, 14, 3)
self.rsi30min = RelativeStrengthIndex(14, MovingAverageType.Simple)
self.macd30min = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential)
self.atr30min = AverageTrueRange(14)
# Create 10 period Rolling Windows for all the parameters we will need
self.rsi30minWin = RollingWindow[float](10)
self.macd30minHistWin = RollingWindow[float](10)
self.stoK30minWin = RollingWindow[float](10)
self.stoD30minWin = RollingWindow[float](10)
self.atr30minWin = RollingWindow[float](10)
self.price30minWin = RollingWindow[float](10)
# Set the warm-up time
self.SetWarmUp(10)
# Create placeholders for the orders
self.currentOrder = None
self.stopLossOrder = None
self.takeProfitOrder = None
orderQuantity = 0
def thirtyMinuteHandler(self, sender, bar):
# Check if Stochastic Indicator is ready to start populating the Rolling Window
if not self.macd30min.IsReady:
return
else:
# Update all the indicators
self.sto30min.Update(bar.EndTime, bar.Close)
self.rsi30min.Update(bar.EndTime, bar.Close)
self.macd30min.Update(bar.EndTime, bar.Close)
self.atr30min.Update(bar.EndTime, bar.Close)
# Update all the Rolling Windows
self.rsi30minWin.Add(self.rsi30min.Current.Value)
self.macd30minHistWin.Add(self.macd30min.Histogram.Current.Value)
self.stoK30minWin.Add(self.sto30min.StochK.Current.Value)
self.stoD30minWin.Add(self.sto30min.StochD.Current.Value)
self.atr30minWin.Add(self.atr30min.Current.Value)
self.price30minWin.Add(bar.Close)
def OnData(self, data):
pass
# Check if Stochastic Indicator is ready to start populating the Rolling Window
if not self.macd30min.IsReady:
return
#else:
# self.stoKWin.Add(self.sto.StochK.Current.Value)
# self.stoDWin.Add(self.sto.StochD.Current.Value)
# self.rsiWin.Add(self.rsi.Current.Value)
# self.macdHistWin.Add(self.macd.Histogram.Current.Value)
# self.atrWin.Add(self.atr.Current.Value)
# self.priceWin.Add(data[self.pair].Close)
# Let's define the entry and exit logic
# Check if the Rolling Windows are ready (using the method)
if self.stoK30minWin.IsReady and self.stoD30minWin.IsReady:
# We want to hold only one position at the time for each currency pair
if not self.Portfolio[self.pair].Invested:
# The algo should take a Long position if RSI >50 and the MACD Histogram is > 0
if self.rsi30min.Current.Value > 50 and self.rsi30minWin[1] < 50 and self.macd30min.Histogram.Current.Value > 0:
# The algo should take a Long position if both sto K & D are between 20 and 80
if self.sto30min.StochK.Current.Value > 20 and self.sto30min.StochK.Current.Value < 80 and self.sto30min.StochD.Current.Value > 20 and self.sto30min.StochD.Current.Value < 80:
# Looping through the Rolling Window we'll see if the crossover happened from the oversold (< 20) or the overbought (>80)
for i in range(1, len(list(self.stoK30minWin))):
# Here we check if the crossover happened from below to enter a long position
if self.stoK30minWin[i-1] > 20 and self.stoK30minWin[i] < 20:
for i in range (1, len(list(self.stoD30minWin))):
# Here we check if the crossover happened from below to enter a long position
if self.stoD30minWin[i-1] > 20 and self.stoD30minWin[i] < 20:
# Define order quantity, entry price and exit prices
orderQuantity = self.CalculateOrderQuantity(self.pair, 0.02)
entryPrice = data[self.pair].Close
longTakeProfitPrice = entryPrice + (1.5 * self.atr30min.Current.Value)
longStopLossPrice = entryPrice - (1 * self.atr30min.Current.Value)
# Place Order
self.currentOrder = self.MarketOrder(self.pair, orderQuantity)
# Stop Loss Order
self.stopLossOrder = self.StopMarketOrder(self.pair, -orderQuantity, longStopLossPrice)
# Take Profit Order
self.takeProfitOrder = self.LimitOrder(self.pair, -orderQuantity, longTakeProfitPrice)
# Print some useful information for the Log
self.Log(" ")
self.Log("Enter Long Position")
self.Log("Stoch K Value: " + str(self.sto30min.StochK.Current.Value))
self.Log("Stoch D Value: " + str(self.sto30min.StochD.Current.Value))
self.Log("RSI: " + str(self.rsi30min.Current.Value))
self.Log("MACD Histogram: " + str(self.macd30min.Histogram.Current.Value))
self.Log("ATR: " + str(self.atr30min.Current.Value))
self.Log("Entry Price: " + str(entryPrice))
self.Log("Take Profit Price: " + str(longTakeProfitPrice))
self.Log("Stop Loss Price: " + str(longStopLossPrice))
self.Log("Order Quantity: " + str(orderQuantity))
# # The algo should take a Short position if RSI < 50 and the MACD Histogram is < 0
# elif self.rsi30min.Current.Value < 50 and self.rsi30minWin[1] > 50 and self.macd30min.Histogram.Current.Value < 0:
# # The algo should take a Long position if both sto K & D are between 20 and 80
# if self.sto30min.StochK.Current.Value > 20 and self.sto30min.StochK.Current.Value < 80 and self.sto30min.StochD.Current.Value > 20 and self.sto30min.StochD.Current.Value < 80:
# # Looping through the Rolling Window we'll see if the crossover happened from the oversold (< 20) or the overbought (>80)
# for i in range(1, len(list(self.stoK30minWin))):
# # Here we check if the crossover happened from above to enter a short position
# if self.stoK30minWin[i-1] < 80 and self.stoK30minWin[i] > 80:
# for i in range (1, len(list(self.stoD30minWin))):
# # Here we check if the crossover happened from below to enter a long position
# if self.stoD30minWin[i-1] < 80 and self.stoD30minWin[i] > 80:
# # Define order quantity, entry price and exit prices
# orderQuantity = self.CalculateOrderQuantity(self.pair, 0.02)
# entryPrice = data[self.pair].Close
# shortTakeProfitPrice = entryPrice - (1.5 * self.atr30min.Current.Value)
# shortStopLossPrice = entryPrice + (1 * self.atr30min.Current.Value)
# # Place Order
# self.currentOrder = self.MarketOrder(self.pair, -orderQuantity)
# # Stop Loss Order
# self.stopLossOrder = self.StopMarketOrder(self.pair, orderQuantity, shortStopLossPrice)
# # Take Profit Order
# self.takeProfitOrder = self.LimitOrder(self.pair, orderQuantity, shortTakeProfitPrice)
# # Print some useful information for the Log
# self.Log(" ")
# self.Log("Enter Short Position")
# self.Log("Stoch K Value: " + str(self.sto30min.StochK.Current.Value))
# self.Log("Stoch D Value: " + str(self.sto30min.StochD.Current.Value))
# self.Log("RSI: " + str(self.rsi30min.Current.Value))
# self.Log("MACD Histogram: " + str(self.macd30min.Histogram.Current.Value))
# self.Log("ATR: " + str(self.atr30min.Current.Value))
# self.Log("Entry Price: " + str(entryPrice))
# self.Log("Take Profit Price: " + str(shortTakeProfitPrice))
# self.Log("Stop Loss Price: " + str(shortStopLossPrice))
# self.Log("Order Quantity: " + str(orderQuantity))
def OnOrderEvent(self, orderEvent):
# Ignore events that are not closed
if orderEvent.Status != OrderStatus.Filled:
return
# Sanity check
if self.takeProfitOrder == None or self.stopLossOrder == None:
return
filledOrderId = orderEvent.OrderId
# If takeProfitOrder was filled, cancel stopLossOrder
if self.takeProfitOrder.OrderId == filledOrderId and orderEvent.Status == OrderStatus.Filled:
self.stopLossOrder.Cancel()
# If stopLossOrder was filled, cancel takeProfitOrder
if self.stopLossOrder.OrderId == filledOrderId and orderEvent.Status == OrderStatus.Filled:
self.takeProfitOrder.Cancel()