| Overall Statistics |
|
Total Trades 287 Average Win 0.10% Average Loss -0.10% Compounding Annual Return -10.524% Drawdown 2.000% Expectancy -0.100 Net Profit -1.452% Sharpe Ratio -3.026 Probabilistic Sharpe Ratio 2.619% Loss Rate 54% Win Rate 46% Profit-Loss Ratio 0.95 Alpha -0.113 Beta 0.123 Annual Standard Deviation 0.028 Annual Variance 0.001 Information Ratio -3.732 Tracking Error 0.081 Treynor Ratio -0.701 Total Fees $530.95 Estimated Strategy Capacity $2500000000.00 Lowest Capacity Asset NQ XRX5ODZTG8OX |
# example - https://www.quantconnect.com/forum/discussion/5257/futures-algorithm-with-indicator-and-consolidator-for-python/p1
# add MACD cross for close or lower TP/SL to see how it handles new order
# entries are going off not on the cross because it's waiting for open order to close.
# Once closed it then sees if MACD & RSI match and enters, often not right after a MACD cross
# compare RSI and MACD values with SSE & ToS for most recent contract
# MACD does not line up with SSE or ToS at all. SEE & ToS MACD match up
# RSI is using closing value of the day before. does keep one value for different trades on the same day & only buys/sells on >/< 50 as it should.
# SSE uses reg. avg for RSI and ToS uses Wilders avg for RSI.
### mostly just about matches SSE/Tos, a few days really far off in the beginning. Warm up probably didn't work.
# NQ17U21 prices matches NQU21
from System.Drawing import Color
class FocusedApricotAlpaca(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 7, 1)
self.SetEndDate(2021, 8, 18)
self.SetCash(1000000)
self.SetWarmUp(timedelta(days = 15))
self.nq = self.AddFuture(Futures.Indices.NASDAQ100EMini)
self.nq.SetFilter(5, 120)
self.oi_contract = None
self.macd = None
self.takeProfit = None
self.stopLoss = None
stockPlot = Chart('Price Plot')
stockPlot.AddSeries(Series('Price', SeriesType.Line, '$', Color.Green))
self.AddChart(stockPlot)
def OnData(self, slice):
for chain in slice.FutureChains:
contracts = [contract for contract in chain.Value]
if len(contracts) == 0:
self.oi_contract = None
self.macd = None
break
contract = sorted(contracts, key=lambda k : k.OpenInterest, reverse=True)[0]
if self.oi_contract is not None and contract.Symbol == self.oi_contract.Symbol:
break
self.oi_contract = contract
#set up consolidators
fifteenMinute = TradeBarConsolidator(timedelta(minutes=15))
fifteenMinute.DataConsolidated += self.fifteenMinuteBarHandler #need to def fifteenMinuteBarHandler
self.SubscriptionManager.AddConsolidator(contract.Symbol, fifteenMinute)
# Set up Indicators
self.macd = self.MACD(contract.Symbol, 12, 26, 9, MovingAverageType.Exponential)
self.RegisterIndicator(contract.Symbol, self.macd, fifteenMinute)
self.rsi = self.RSI(contract.Symbol, 9, MovingAverageType.Wilders, Resolution.Daily)
def fifteenMinuteBarHandler(self, sender, bar):
if self.macd is None or not self.macd.IsReady:
return
symbol = self.oi_contract.Symbol
security = self.Securities[symbol]
price = security.Price
# Only new positions not invested
if security.Invested:
# Look to exit position
return
tolerance = 0.003
signalDeltaPercent = self.macd.Current.Value - self.macd.Signal.Current.Value
if signalDeltaPercent > tolerance and self.rsi.Current.Value > 50:
#Go long
self.MarketOrder(symbol, 1)
self.takeProfit = self.LimitOrder(symbol, -1, price+50) # 1% is too far for day trades
self.stopLoss = self.StopMarketOrder(symbol, -1, price-50)
self.Log(str(self.Time) + " buy " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value))
if signalDeltaPercent < -tolerance and self.rsi.Current.Value < 50:
#Go short
self.MarketOrder(symbol, -1)
self.takeProfit = self.LimitOrder(symbol, 1, price-50)
self.stopLoss = self.StopMarketOrder(symbol, 1, price+50)
self.Log(str(self.Time) + " sell " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value))
self.Log(str(self.Time) + " Price: " + str(price))
def OnOrderEvent(self, orderEvent):
if orderEvent.Status != OrderStatus.Filled:
return
self.Cancel(orderEvent.OrderId)
def Cancel(self, id):
'''cancel one order if the other was filled'''
if self.takeProfit is not None and id == self.takeProfit.OrderId:
self.stopLoss.Cancel()
elif self.stopLoss is not None and id == self.stopLoss.OrderId:
self.takeProfit.Cancel()
else:
return
self.takeProfit = None
self.stopLoss = None