from AlgorithmImports import *
import numpy as np
class MyExecution(ExecutionModel):
def __init__(self,algo):
self.algo = algo # create the algo instance
self.orderCounter = 1
def Execute(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> None:
# update the complete set of portfolio targets with the new targets
self.algo.targetsCollection.AddRange(targets)
if not self.algo.targetsCollection.IsEmpty:
for target in self.algo.targetsCollection.Values:
# check order entry conditions
if target.Quantity != 0: # Is this neccessary?
self.algo.Debug(f"target.Quantity:{target.Quantity}")
for _ in range(abs(int(target.Quantity))*self.algo.orderMultiplier):
orderPrice = self.GetOrderPrice(target, algorithm)
orderProperties = self.GetOrderProperties(target, algorithm)
# Only Place Order as Long as Some conditions are met - Here only time should be before say 1 hour after market opens &
#initiate Trade class
trade = Trade(algorithm)
ticket = trade.placeMainOrder(target.Symbol, np.sign(target.Quantity)*1, orderPrice, orderProperties)
self.algo.tradesCollection[str(ticket.OrderId)] = trade
# ticket.UpdateTag('LumberCopyNasdaq' + '_ID_' + str(ticket.OrderId))
self.algo.targetsCollection.Clear()
def GetOrderPrice(self, target, algorithm):
orderPrice = None
bid = algorithm.Securities[target.Symbol].BidPrice
ask = algorithm.Securities[target.Symbol].AskPrice
minOrderPrice = min(bid,ask)
maxOrderPrice = max(bid,ask)
if target.Quantity > 0:
orderPrice = round(minOrderPrice*(1+self.algo.premiumDiscount),1)
elif target.Quantity < 0:
if self.orderCounter == 1: # This is temporary so we can see 2 different Asks for 2 positions
orderPrice = round(maxOrderPrice*(1-self.algo.premiumDiscount),1)
else:
orderPrice = round(maxOrderPrice*(1-self.algo.premiumDiscount+0.01),1) # Less Competitive
self.orderCounter +=1
return orderPrice
def GetOrderProperties(self, target, algorithm):
orderProperties = None
# Set a Limit Order (MainOrder) to be good until Lumber Close
self.algo.order_properties.TimeInForce = TimeInForce.GoodTilDate(algorithm.Time.replace(hour=16, minute=0, second= 0, microsecond=0))
orderProperties = self.algo.order_properties
return orderProperties
class Trade():
def __init__(self,algo):
self.mainOrderTicket=None
self.stopLossTicket=None
self.takeProfitTicket=None
self.algo=algo
def placeMainOrder(self,symbol,quantity,orderPrice, orderProperties=None,tag=None):
self.mainOrderTicket=self.algo.LimitOrder(symbol=symbol, quantity=quantity, limitPrice=orderPrice, orderProperties = orderProperties,tag=tag) # , orderProperties= self.algo.order_properties
return self.mainOrderTicket
def updateMainOrder(self, price):
response = self.mainOrderTicket.UpdateLimitPrice(price)
if response.IsSuccess:
self.algo.Debug("MainOrder with Order_id {} Updated Successfully".format(self.mainOrderTicket.OrderId))
return True
def getMainOrderId(self):
self.mainOrderTicket.OrderId
def placeStopLossOrder(self,quantity,stopPrice,limitPrice,orderProperties=None):
self.stopLossTicket=self.algo.StopLimitOrder(symbol=self.mainOrderTicket.Symbol, quantity=quantity, stopPrice=stopPrice, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId)) #, orderProperties= self.algo.order_properties
return self.stopLossTicket
def placeTakeProfitOrder(self,quantity,limitPrice,orderProperties=None):
self.takeProfitTicket=self.algo.LimitOrder( symbol=self.mainOrderTicket.Symbol, quantity=quantity, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId)) #, orderProperties= self.algo.order_properties
return self.takeProfitTicket
def cancelStopLoss(self):
response=self.stopLossTicket.Cancel()
if response.IsSuccess:
self.algo.Debug("StopLossOrder with Order_id {} connected to main order {} Cancelled Successfully".format(self.stopLossTicket.OrderId,self.stopLossTicket.Tag))
self.stopLossTicket=None
return True
def cancelTakeProfit(self):
response=self.takeProfitTicket.Cancel()
if response.IsSuccess:
self.algo.Debug("TakeProfit Order with Order_id {} connected to main order {} Cancelled Successfully".format(self.takeProfitTicket.OrderId,self.takeProfitTicket.Tag))
self.takeProfitTicket = None
return True
def cancelMainOrder(self):
response=self.MainOrderTicket.Cancel()
if response.IsSuccess:
self.algo.Debug("MainOrder with Order_id {} Cancelled Successfully".format(self.mainOrderTicket.OrderId))
# del self.algo.tradesCollection[main_id]
return True
#return main order ticket
def getMainOrderTicket(self):
return self.algo.Transactions.GetOrderTicket(self.mainOrderTicket.OrderId)
#return stop loss ticket
def getStopLossOrderTicket(self):
return self.algo.Transactions.GetOrderTicket(self.stopLossOrderTicket.OrderId)
#return take profit ticket
def getTakeProfitTicket(self):
self.algo.Transactions.GetOrderTicket(self.takeProfitTicket.OrderId)
#cancel order if it voilates condition of fill
def cancelIfVoilates(self,percent):
#get main order ticket
ticket=self.getMainOrderTicket()
#get open price of security
openPrice=self.algo.Securities[ticket.Symbol].Open
# calculate the percentage change between the fill and open price
changeInFillOpen= ((ticket.AverageFillPrice-openPrice)/openPrice)*100
if changeInFillOpen > abs(percent):
# cancel main order
response=self.cancelMainOrder()
return True
else:
return False
from AlgorithmImports import *
class NasdaqAlpha(AlphaModel):
def __init__(self, algo):
# Save an Instance of our Main Algorithm
self.algo = algo
# variable to hold nasdaq percentage change
self.algo.percentageChange=None
# Check Entry Condition only 30 seconds prior to Market Open
self.entryTimeStart = self.algo.Time.replace(hour=9, minute=59, second=30, microsecond=0)
self.entryTimeEnd = self.algo.Time.replace(hour=10, minute=0, second= 1, microsecond=0)
# Rollin windows for yesterday's close
self.nasdaqYesterdayClose = RollingWindow[float](1)
self.lumberYesterdayClose = RollingWindow[float](1)
#insight arguments
self.insightPeriod = timedelta(hours = 1)
self.insightDailyCount = 0
# DICT TO HOLD INSIGHT TIME
self.insightsTimeBySymbol = {}
#rolling window to handle latest bid and ask
self.latestBidRolling = RollingWindow[float](1)
self.latestAskRolling = RollingWindow[float](1)
self.latestBidSizeRolling = RollingWindow[float](1)
self.latestAskSizeRolling = RollingWindow[float](1)
# LIST AND COLLECTION FOR INSIGHTS
self.insights = []
self.insightCollection = InsightCollection()
def OnLumberOpen(self):
#Resetting Latest Bid And Ask Rolling Window
self.latestAskRolling.Reset()
self.latestBidRolling.Reset()
# GET LUMBER YESTERDAY'S CLOSE
lumber_history = self.algo.History(self.algo.lumberSymbol,7,Resolution.Daily)
for bar in lumber_history.itertuples():
self.lumberYesterdayClose.Add(bar.close)
# GET NASDAQ'S YESTERDAY CLOSE
nasdaq_history = self.algo.History(self.algo.nasdaqSymbol,7,Resolution.Daily)
for bar in nasdaq_history.itertuples():
self.nasdaqYesterdayClose.Add(bar.close)
self.insightDailyCount = 0 # Reset it to 0 every morning
# self.algo.Debug(f"Yesterday's Date:{self.algo.Time} Nasdaq Close:{self.nasdaqYesterdayClose[0]}, Lumber Close: {self.lumberYesterdayClose[0]}")
def OnLumberClose(self):
# Ideally this code should be inside EndOfDay in our Main class
# GeneratedTimeUtc : Gets the utc time this insight was generated
# CloseTimeUtc : Gets the insight's prediction end time. This is the time when this insight prediction
# is expected to be fulfilled. This time takes into account market hours, weekends, as well as the symbol's data resolution
insight_properties = ['Symbol','GeneratedTimeUtc','CloseTimeUtc','Direction','EstimatedValue','Weight','Id','Magnitude','Confidence','Period','Score','IsActive','IsExpired']
for insight in self.insights:
for prop in insight_properties:
if prop in ['GeneratedTimeUtc','CloseTimeUtc']:
value = getattr(insight, prop) - timedelta(hours = 5) # Converting UTC to EST
else:
value = getattr(insight, prop)
# self.algo.Debug(f"{prop}:{value}")
def OnSecuritiesChanged(self, algorithm,changes):
for security in changes.AddedSecurities:
if security.Symbol == self.algo.lumberSymbol:
# schedule an event to trigger before lumber market opens to get yesterday close for both nasdaq and lumber
algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.AfterMarketOpen(security.Symbol, -1), self.OnLumberOpen)
# algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.BeforeMarketClose(security.Symbol, 2), self.OnLumberClose)
for security in changes.RemovedSecurities:
if security.Symbol in self.insightsTimeBySymbol:
# REMOVE SECURITY FROM DICT
self.insightsTimeBySymbol.pop(security.Symbol)
def Update(self, algorithm, data):
# Return empty list if outside our CheckTime (just 30 seconds prior to MarketOpen)
if algorithm.Time < self.entryTimeStart or algorithm.Time > self.entryTimeEnd:
return []
insight = None
# Check if yesterday's Lumber & Nasdaq close if ready
if self.lumberYesterdayClose.IsReady and self.nasdaqYesterdayClose.IsReady:
for security in data.Keys:
# algorithm.Debug(f'{security}')
ticks=data.Ticks[security]
if security == self.algo.nasdaqSymbol:
for tick in ticks:
if tick.TickType == TickType.Trade:
self.algo.percentageChange=((tick.Price - self.nasdaqYesterdayClose[0])/self.nasdaqYesterdayClose[0])*100
# if int(self.algo.nasdaqROCP.Current.Value) != 0:
# algorithm.Debug(f"self.algo.percentageChange:{self.algo.percentageChange}, \
# self.algo.nasdaqROCP:{self.algo.nasdaqROCP.Current.Value}, self.algo.nasdaqDailyChange52High:{self.algo.nasdaqDailyChange52High.Current.Value}, self.algo.nasdaqDailyChange52Low:{self.algo.nasdaqDailyChange52Low.Current.Value} ")
if security == self.algo.lumberSymbol:
for tick in ticks:
if tick.TickType == TickType.Quote:
# algorithm.Debug(f"bid is {tick.BidPrice} bidVolume {tick.BidSize} ask is {tick.AskPrice} askVolume:{tick.AskSize}")
# check if tick ask is equal to 0 and there is no ask price in rolling window
if int(tick.AskPrice) == 0 and not self.latestAskRolling.IsReady:
ask = algorithm.Securities[security].AskPrice
# askVol = algorithm.Securities[security].AskVolume
# algorithm.Debug(f"ask was {tick.AskPrice} so using last ask {ask}")
# check if tick ask is equal to 0 & there is ask price in rolling window
elif int(tick.AskPrice) == 0 and self.latestAskRolling.IsReady:
ask = self.latestAskRolling[0]
# algorithm.Debug(f"ask was {tick.AskPrice} so using last ask from rolling window {ask}")
else:
ask = tick.AskPrice
askVol = tick.AskSize
self.latestAskRolling.Add(ask) # adding the ask to rolling window
self.latestAskSizeRolling.Add(askVol)
# check if tick bid is equal to 0 & there is no bid price in rolling window
if int(tick.BidPrice) == 0 and not self.latestBidRolling.IsReady:
bid = algorithm.Securities[security].BidPrice
# algorithm.Debug(f"bid was {tick.BidPrice} so using last bid {bid}")
# check if tick bid is equal to 0 & there is Bid price in rolling window
elif int(tick.BidPrice) == 0 and self.latestBidRolling.IsReady:
bid = self.latestBidRolling[0]
# algorithm.Debug(f"bid was {tick.BidPrice} so using last bid from rolling window {bid}")
else:
bid = tick.BidPrice
bidVol = tick.BidSize
self.latestBidSizeRolling.Add(bidVol)
self.latestBidRolling.Add(bid) # adding the bid to rolling window
# algorithm.Debug(f'ask:{tick.AskPrice} bid:{tick.BidPrice} time:{algorithm.Time}')
# insightFlag = self.ShouldEmitInsight(algorithm.Time,security)
# conditionLong = ask > self.lumberYesterdayClose[0] and bid > self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange > 1 and insightFlag
# conditionShort = bid < self.lumberYesterdayClose[0] and ask < self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange < -1 and insightFlag
# Weighed Average Price
# WAP
if ask > self.lumberYesterdayClose[0] and bid > self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange > 1 and self.ShouldEmitInsight(algorithm.Time,security):
algorithm.Debug(f"Position Up: Date{algorithm.Time} Nasdaq ∆:{self.algo.percentageChange},Lumber Yesterday Close:{self.lumberYesterdayClose[0]}, Lumber Ask:{ask}, Lumber Bid:{bid}")
insight = Insight(self.algo._lumberContract.Mapped,self.insightPeriod, InsightType.Price, InsightDirection.Up)
algorithm.Debug(f"Up Insight generated at: {algorithm.Time}")
self.insights.append(insight)
elif bid < self.lumberYesterdayClose[0] and ask < self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange < -1 and self.ShouldEmitInsight(algorithm.Time,security):
algorithm.Debug(f"Position Down: Date{algorithm.Time} Nasdaq ∆:{self.algo.percentageChange},Lumber Yesterday Close:{self.lumberYesterdayClose[0]}, Lumber Ask:{ask}, Lumber Bid:{bid}")
# Insight(symbol, period, type, direction, magnitude=None, confidence=None, sourceModel=None, weight=None)
insight = Insight(self.algo._lumberContract.Mapped,self.insightPeriod, InsightType.Price, InsightDirection.Down)
algorithm.Debug(f"Down Insight generated at: {algorithm.Time}")
self.insights.append(insight)
else:
# algorithm.Debug(f"No Condition Met, Date:{algorithm.Time}")
pass
if insight is not None: self.insightCollection.Add(insight)
return self.insights
def ShouldEmitInsight(self, utcTime, symbol):
generatedTimeUtc = self.insightsTimeBySymbol.get(symbol)
self.insightDailyCount +=1
if generatedTimeUtc is not None:
# we previously emitted a insight for this symbol, check it's period to see if we should emit another insight
if utcTime - generatedTimeUtc < self.insightPeriod and self.insightDailyCount > 1:
return False
# we either haven't emitted a insight for this symbol or the previous insight's period has expired, so emit a new insight now for this symbol
self.insightsTimeBySymbol[symbol] = utcTime
return True
from AlgorithmImports import *
class MyPortfolio(PortfolioConstructionModel):
def __init__(self,algo,rebalancingFunc=None,portfolioBias=PortfolioBias.LongShort):
# rebalancingFunc=Resolution.Daily
self.algo=algo # create the algo instance
self.portfolioBias=portfolioBias
self.setTargets = False
def CreateTargets(self, algorithm, insights):
tempCounter = 1
""" This method is used to analyze the insights and determine for which insight
we need to create portfolio target i.e based on weight magnitude confidence etc.."""
targets = []
for insight in insights:
# check if insight respects the portifolio bias
if self.RespectPortfolioBias(insight) :
# Fills up self.algo.positionCount
self.GetPositionCount()
# self.algo.Debug(f"Count of positionCount in CreateTargets of PortfolioModel: {abs(self.algo.positionCount)}")
# Append PortfolioTargets All Order Quantity
if not self.setTargets:
# self.algo.Debug(f"tempCounter in CreateTargets of PortfolioModel: {tempCounter}")
targets.append(PortfolioTarget(insight.Symbol,self.algo.positionCount))
# self.algo.Debug(f"Count of Insights in CreateTargets of PortfolioModel: {len(insights)} at Time: {self.algo.Time}")
self.setTargets = True
# if targets and not self.setTargets:
# for target in targets:
# self.algo.Debug(f"Target in Portfolio Construction-:-{target}")
# pass
# self.setTargets = True
return targets
def GetPositionCount(self):
if np.sign(self.algo.percentageChange * 1) == -1:
self.algo.positionCount = math.ceil(self.algo.percentageChange) * 1
elif np.sign(self.algo.percentageChange * 1) == 1:
self.algo.positionCount = math.floor(self.algo.percentageChange) * 1
def RespectPortfolioBias(self, insight):
"""method is used to check if the long,short or both position are allowed by portifolio"""
return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == PortfolioBias.Long or insight.Direction == PortfolioBias.Short
def ShouldCreateTargetForInsight(self, insight: Insight) -> bool:
""" This method is used to check for which insight we are supposed to generate the
portfolio target we can use magnitude, weight and other aspects for this"""
return True
def DetermineTargetPercent(self, activeInsights):
"""This method is used to calculate the %age of portifolio or no of stocks we want to set"""
pass
from AlgorithmImports import *
class MyRiskManagementModel(RiskManagementModel):
def __init__(self, algo):
self.algo = algo # Save an Instance of our Main Algorithm
self.count = 0
self.target_modified = []
# Adjust the portfolio targets and return them. If no changes emit nothing.
def ManageRisk(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> List[PortfolioTarget]:
for target in targets:
# self.algo.Debug(f"target in RiskManagamenet-:-{target}")
pass
return targets
from AlgorithmImports import *
from QuantConnect.Statistics import *
from NasdaqAlpha import *
from PortfolioModel import *
from ExecutionModel import *
from RiskModel import *
from orderEnum import *
import numpy as np
class NasdaqStrategy(QCAlgorithm):
def Initialize(self):
# Order is valid until filled or the market closes
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.DefaultOrderProperties = InteractiveBrokersOrderProperties()
# Order is valid until filled or the market closes
# self.DefaultOrderProperties.TimeInForce = TimeInForce.Day
# self.DefaultOrderProperties.OutsideRegularTradingHours = True
# Set a Limit Order to be good until Lumber Close
self.order_properties = OrderProperties()
# Set start and end time for backtest
# self.SetEndDate(datetime.now() - timedelta(2))
self.SetCash(1000000)
# TradeBuilder tracks the trades of your algorithm and calculates some statistics.
# https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/trade-statistics
tradeBuilder = TradeBuilder(FillGroupingMethod.FillToFill,FillMatchingMethod.FIFO)
self.SetTradeBuilder(tradeBuilder)
# Lumber security
self._lumberContract=self.AddFuture(Futures.Forestry.RandomLengthLumber,
Resolution.Tick,dataMappingMode=DataMappingMode.FirstDayMonth,contractDepthOffset=0,
dataNormalizationMode=DataNormalizationMode.Raw,extendedMarketHours=True, fillDataForward = True)
self.tickSize = self._lumberContract.SymbolProperties.MinimumPriceVariation
# Nasdaq security
self._nasdaqContract=self.AddFuture(Futures.Indices.MicroNASDAQ100EMini,
Resolution.Tick,dataMappingMode = DataMappingMode.OpenInterest, contractDepthOffset=0,
dataNormalizationMode = DataNormalizationMode.Raw, extendedMarketHours=True)
# Set security initializer
seeder = FuncSecuritySeeder(self.GetLastKnownPrices)
self.SetSecurityInitializer(lambda security: seeder.SeedSecurity(security))
# Symbols for securities:
self.lumberSymbol = self._lumberContract.Symbol
self.nasdaqSymbol = self._nasdaqContract.Symbol
# Get 52 Week High and 52 Week Low of Nasdaq
self.nasdaqROCP = self.ROCP(self.nasdaqSymbol,1, Resolution.Daily)
self.nasdaqDailyChange52High = IndicatorExtensions.MAX(self.nasdaqROCP, 252)
self.RegisterIndicator(self.nasdaqSymbol, self.nasdaqDailyChange52High, Resolution.Daily)
self.nasdaqDailyChange52Low = IndicatorExtensions.MIN(self.nasdaqROCP, 252)
self.RegisterIndicator(self.nasdaqSymbol, self.nasdaqDailyChange52Low, Resolution.Daily)
# Warm-Up the algorithm
self.SetWarmup(timedelta(253),resolution=Resolution.Minute)
self.positionCount = 0
self.orderMultiplier = 1
# "Order To Market Price" represents Order Price Competitiveness
self.premiumDiscount = -0.01 # In decimals: +0.01 (More Competitive) represents 1% premium to Bid/ 1 % discount to Ask
# while -0.01 (Less Competitive) represents 1% discount to Bid/ 1% premium to Ask
# example for buy orders
self.TARGET_LIMIT_OFFSET = 10
self.STOPLOSS_STOP_OFFSET = 5 # This will be the actual stop loss - this is called the stop price of the stop loss order
self.STOPLOSS_LIMIT_OFFSET = 2 # Maximum allowed below stop loss so its called Limit price of the stop loss
self.targetsCollection = PortfolioTargetCollection()
self.tradesCollection = {}
# Set portifolio consruction model
self.SetPortfolioConstruction(MyPortfolio(self))
# Set risk management model
# self.AddRiskManagement(TrailingStopRiskManagementModel(maximumDrawdownPercent=0.05))
# self.AddRiskManagement(MaximumUnrealizedProfitPercentPerSecurity(maximumUnrealizedProfitPercent = 0.05))
self.AddRiskManagement(NullRiskManagementModel()) # Default
# Set execution model
# self.SetExecution(ImmediateExecutionModel())
self.SetExecution(MyExecution(self))
# Set alpha model
self.alpha= NasdaqAlpha(self)
self.SetAlpha(self.alpha)
def OnData(self, slice: Slice) -> None:
for changed_event in slice.SymbolChangedEvents.Values:
# self.Debug(f"Contract rollover from {changed_event.OldSymbol} to {changed_event.NewSymbol}")
pass
for key in self.tradesCollection.keys(): # These are ID's of only MainTicket
ticket = self.Transactions.GetOrderTicket(key)
trade = self.tradesCollection[str(key)]
if ticket.Status == OrderStatus.Submitted:
LimitPrice = ticket.Get(OrderField.LimitPrice)
# To Check if this Ask & Bid Prices are consistent with Tick Data
LatestAsk = self.Securities[ticket.Symbol].AskPrice
LatestBid = self.Securities[ticket.Symbol].BidPrice
minOrderPrice = min(LatestBid,LatestAsk)
maxOrderPrice = max(LatestBid,LatestAsk)
# Update LimitPrice if we are Long and Best Bid has Changed
if ticket.Quantity > 0: # Its a buy order
orderPrice = round(minOrderPrice*(1+self.premiumDiscount),1)
# Update LimitPrice if we are Short and Best Ask has Changed
elif ticket.Quantity < 0: # Its a Sell order
orderPrice = round(maxOrderPrice*(1-self.premiumDiscount),1)
else: # No Order
orderPrice = 0
LimitPrice = 0
# self.Debug(f"Not Updating order: LatestAsk:{LatestAsk}, LatestBid:{LatestBid} ,LimitPrice:{LimitPrice}")
if LimitPrice != orderPrice:
self.Debug(f"Updating order since LatestAsk/LatestBid/orderPrice {LatestAsk},{LatestBid},{orderPrice} ≠ LimitPrice {LimitPrice}")
trade.updateMainOrder(round(orderPrice))
# For Trailing Stop
elif ticket.Status == OrderStatus.Filled:
# mainOrderFillPrice = trade.mainOrderTicket.FillPrice
# currentPrice = self.Securities[trade.mainOrderTicket.Symbol].Price
# changeInPrice=((currentPrice-mainOrderFillPrice)/mainOrderFillPrice)*100
pass
# OnEndOfDay notifies when (Time) each security has finished trading for the day
def OnEndOfDay(self, symbol: Symbol) -> None:
# self.Debug(f"Finished Trading on {self.Time} for security {symbol}")
pass
# When your algorithm stops executing, LEAN calls the OnEndOfAlgorithm method.
def OnEndOfAlgorithm(self) -> None:
# self.Debug("Printing tradesCollection")
# for key,value in self.tradesCollection.items():
# self.Debug(f"key:{key}, Value:{value}")
for trade in self.TradeBuilder.ClosedTrades:
self.Debug(self.trade_to_string(trade))
self.Debug("Algorithm done")
def trade_to_string(self, trade):
return 'Symbol: {0} EntryTime: {1} EntryPrice {2} Direction: {3} Quantity: {4} ExitTime: {5} ExitPrice: {6} ProfitLoss: {7} TotalFees: {8} MAE: {9} MFE: {10} EndTradeDrawdown: {11}'.format(
trade.Symbol, trade.EntryTime - timedelta(hours=5), trade.EntryPrice, get_order_direction_name(trade.Direction),
trade.Quantity, trade.ExitTime - timedelta(hours=5), trade.ExitPrice, trade.ProfitLoss, trade.TotalFees,
trade.MAE, trade.MFE, trade.EndTradeDrawdown)
def OnOrderEvent(self, orderEvent):
ticket=self.Transactions.GetOrderTicket(orderEvent.OrderId)
self.Debug(f"OrderType:{get_order_type_name(ticket.OrderType)},OrderId:{ticket.OrderId},tradesCollection:{self.tradesCollection}")
# If order is main
if ticket.OrderType == OrderType.Limit and str(orderEvent.OrderId) in self.tradesCollection:
# get trade
trade=self.tradesCollection[str(orderEvent.OrderId)]
if ticket.Status == OrderStatus.Filled:
# check if price of lumber since open and fill price
# is more than counted percent down or up
voilationCheck=trade.cancelIfVoilates(percent=5.0)
if not voilationCheck:
self.Debug("Main Order Filled")
# Calculate TakeProfit and Stop - Limit & Stop price
fillPrice = orderEvent.FillPrice
stopLossStopPrice = fillPrice- np.sign(ticket.Quantity * 1) * self.STOPLOSS_STOP_OFFSET
stopLossLimijitPrice = stopLossStopPrice - np.sign(ticket.Quantity * 1) * self.STOPLOSS_LIMIT_OFFSET
takeProfitPrice = fillPrice+ np.sign(ticket.Quantity * 1) * self.TARGET_LIMIT_OFFSET
# Place stoploss order
trade.placeStopLossOrder(-ticket.Quantity,stopLossStopPrice,stopLossLimitPrice,orderProperties = self.order_properties)
# Place Take Profit
trade.placeTakeProfitOrder(-ticket.Quantity,takeProfitPrice,orderProperties = self.order_properties)
elif ticket.Status == OrderStatus.UpdateSubmitted:
self.Debug(f"Main Order UpdateSubmitted")
elif ticket.Status == OrderStatus.Submitted:
self.Debug(f"Main Order Submitted")
elif ticket.Status == OrderStatus.Canceled:
self.Debug(f"Main Order Canceled")
# If order is Take Profit
elif ticket.OrderType == OrderType.Limit and ticket.Tag in self.tradesCollection:
if ticket.Status == OrderStatus.Filled:
# self.Debug(f"tradesCollection in TakeProfit:{self.tradesCollection}")
self.Debug(f"take profit placed with order_id {ticket.OrderId}")
# get Main trade & Cancel StopLoss as Take Profit Filled
trade=self.tradesCollection[str(ticket.Tag)]
trade.cancelStopLoss()
# If order is StopLoss
elif ticket.OrderType == OrderType.StopLimit:
if ticket.Status == OrderStatus.Filled:
# self.Debug(f"tradesCollection in StopLoss:{self.tradesCollection}")
self.Debug(f"Stop loss placed with order_id={ticket.OrderId}")
# get Main trade & Cancel Take Profit as StopLoss Filled
trade=self.tradesCollection[str(ticket.Tag)]
trade.cancelTakeProfit()
from AlgorithmImports import *
# https://github.com/QuantConnect/Lean/blob/master/Common/Orders/OrderTypes.cs#L87
def get_order_status_name(index):
return {
0: 'New',
1: 'Submitted',
2: 'PartiallyFilled',
3: 'Filled',
4: 'None',
5: 'Canceled',
6: 'None',
7: 'Invalid',
8: 'CancelPending',
9: 'UpdateSubmitted '
}[index]
def get_order_direction_name(index):
return {
0: 'Buy',
1: 'Sell',
2: 'Hold',
}[index]
def get_order_type_name(index):
return {
0: 'Market',
1: 'Limit',
2: 'StopMarket',
3: 'StopLimit',
4: 'MarketOnOpen',
5: 'MarketOnClose',
6: 'OptionExercise',
7: 'LimitIfTouched'
}[index]