| 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 1.436 Tracking Error 0.14 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
from AlgorithmImports import *
from EnumFunc import *
class NasdaqAlpha(AlphaModel):
def __init__(self, lumberDataClass):
self.insights = []
self.securities = []
self.lumberDataClass = lumberDataClass # Passed the Lumber Data Class
# Handles security changes in from your universe model.
def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
# This code runs everytime there is a contract rollover but does it know which symbol has switched
for changed_event in algorithm.CurrentSlice.SymbolChangedEvents.Values:
# algorithm.Debug(f"Contract rollover from (AM- OnSecuritiesChanged) {changed_event.OldSymbol} to {changed_event.NewSymbol}, Time:{algorithm.Time}")
pass
# Everytime Contract rollsOver (any Lumber or Nasdaq), the following line runs, but ...
# algorithm.Debug(f"Count AM: {changes.Count}, changes:{changes}")
# .. this code only runs Once at the very start not when future contracts roll!
for security in changes.AddedSecurities:
# algorithm.Debug(f"In OnSecuritiesChanged(AM) @ DateTime:{algorithm.Time}, Mapped/ID: {security.Mapped}, Canonical: {security.Mapped.Canonical} \
# Symbol: {security.Symbol}, Value: {security.Mapped.Value}, SecurityType: {getSecurityType(security.Mapped.SecurityType)}")
pass
for security in changes.RemovedSecurities:
pass
def Update(self, algorithm, data):
# https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/quantconnect/us-futures-security-master#05-Data-Point-Attributes
# This Code runs everytime there is a futures rollover
# BEAWARE SymbolChangedEvents may also be linked to other events?
# algorithm.Debug(f"data.SymbolChangedEvents.Keys:{data.SymbolChangedEvents.Keys}")
if data.Keys[0] == self.lumberDataClass.Symbol:
for changed_event in data.SymbolChangedEvents.Values:
algorithm.Debug(f"Contract rollover (AM- Update Method) from {changed_event.OldSymbol} to {changed_event.NewSymbol}")
security = data.Keys[0]
self.securities.append(security.Value)
algorithm.Debug(f"In Update (AM) @ DateTime:{algorithm.Time}, security:{security}, ID:{security.ID},Canonical:{security.Canonical} \
+ Value:{security.Value},Underlying:{security.Underlying}. SecurityType:{getSecurityType(security.SecurityType)}")
insight = None
return self.insights
from AlgorithmImports import *
import math
from collections import deque
from EnumFunc import *
from functools import wraps
# A skeleton class for storing Futures Data - Shared by all Models
class DataClass:
def __init__(self, Algorithm, continuous_contract):
self.algo = Algorithm # This is Our Instance of QCAlgorithm
# self.algo.UniverseSettings.ExtendedMarketHours = True
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/requesting-data#09-Properties
self.continuous_contract = continuous_contract
# Symbols for securities:
self.Symbol = self.continuous_contract.Symbol
self.tickSize = self.continuous_contract.SymbolProperties.MinimumPriceVariation
# Index, askclose, askhigh, asklow, askopen, asksize, bidclose, bidhigh, bidlow, bidopen, bidsize, close, high, low, open, volume)
# Index, Value:(Timestamp('2022-11-15 00:00:00'), 'LBS Y3IN813DW4QP', Timestamp('2022-10-26 19:00:00'))
self.yesterday = dotdict(dict.fromkeys(['open', 'high', 'low', 'close', 'volume']))
# Make sure to use self.Mapped and not self.Symbol since using BackwardPanama
self.lastBid = dotdict(dict.fromkeys(['time', 'price', 'size']))
self.lastAsk = dotdict(dict.fromkeys(['time','price', 'size']))
self._bestBid = dotdict(dict.fromkeys(['time', 'price', 'size']))
self._bestAsk = dotdict(dict.fromkeys(['time','price', 'size']))
self._trade = dotdict(dict.fromkeys(['time','price', 'size']))
# self.trade = dotdict(dict.fromkeys(['time','price', 'size']))
self._WAP = None
# https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/supported-indicators/average-true-range
# This should be yesterday's
# self.atr = self.algo.ATR(self.Symbol, Resolution.Daily)
# quoteEvent is triggered everytime a new Quote is placed not only when the best quote is changed/placed- I think?
# self.quoteEvent = TickQuoteBarConsolidator(1)
# self.quoteEvent.DataConsolidated += self.quoteEventHandler
# self.algo.SubscriptionManager.AddConsolidator(self.Symbol, self.quoteEvent)
# tradeEvent is triggered everytime a Trade is placed?
# self.tradeEvent = TickConsolidator(1)
# self.tradeEvent.DataConsolidated += self.tradeEventHandler
# self.algo.SubscriptionManager.AddConsolidator(self.Symbol, self.tradeEvent)
# To Update Yesterday: At Midnight the contract Rolls and pulls the correct data for Lumber - The issue is other futures may have different Open Close timings
# self.algo.Schedule.On(self.algo.DateRules.EveryDay(), self.algo.TimeRules.Midnight, self.updateYesterday)
# Update at a specific Time - Symbol agnostic - This is 10 minutes before Lumber Open - Change when daylight savings
# self.algo.Schedule.On(self.algo.DateRules.EveryDay(), self.algo.TimeRules.At(8,59), self.updateYesterday)
# Get Yesterday's Settlement - Make it a Property
# self.Securities[self.lumber.Mapped].Expiry # Get contract's expiry?
# Update Yesterday Price 10 minutes before Market Opens - Can even use 'LBS' in TimeRules.AfterMarketOpen
self.algo.Schedule.On(self.algo.DateRules.EveryDay(self.Symbol), self.algo.TimeRules.AfterMarketOpen(self.Symbol, -10), self.updateYesterday)
# Reset BBO dicts 10 minutes after market close - Not sure if it impacts extendedMarketHours
self.algo.Schedule.On(self.algo.DateRules.EveryDay(self.Symbol), self.algo.TimeRules.BeforeMarketClose(self.Symbol, -10), self.resetTickDict)
# Nasdaq - closes at 4 pm & opens at 8:30 Chicago, Also trades at 11 pm till not sure when?
# OnSecuritiesChanged: Date:2022-12-19 23:00:00, security:MNQ Y6URRFPZ86BL
def quoteEventHandler(self, sender: object, Qbar: QuoteBar) -> None:
if self.algo.CurrentSlice.Ticks.ContainsKey(self.Symbol) and self.algo.CurrentSlice.Ticks[self.Symbol] is not None:
ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
for tick in ticks:
tick_type = getTickType(tick.TickType)
if tick_type == 'Quote':
if int(getattr(self.algo.Securities[self.Mapped], 'AskSize')) != 0:
for key,prop in zip(list(self._bestAsk.keys()),['LocalTime','AskPrice', 'AskSize']):
setattr(self._bestAsk,str(key),getattr(self.algo.Securities[self.Mapped], prop))
if int(getattr(self.algo.Securities[self.Mapped], 'BidSize')) != 0:
for key,prop in zip(list(self._bestBid.keys()),['LocalTime','BidPrice', 'BidSize']):
setattr(self._bestBid,str(key),getattr(self.algo.Securities[self.Mapped], prop))
# Code to store Last Bid & Ask - switching it off for the time being
# if int(getattr(tick, 'AskPrice')) != 0:
# # In DateTime - microseconds missing leading zeros in our dict versus reported
# for key,prop in zip(list(self.lastAsk.keys()),['EndTime','AskPrice', 'AskSize']):
# setattr(self.lastAsk,str(key),getattr(tick, prop))
# if int(getattr(tick, 'BidPrice')) != 0:
# for key,prop in zip(list(self.lastBid.keys()),['EndTime','BidPrice', 'BidSize']):
# setattr(self.lastBid,str(key),getattr(tick, prop))
def tradeEventHandler(self, sender: object, Tbar: TradeBar) -> None:
if self.algo.CurrentSlice.Ticks.ContainsKey(self.Symbol) and self.algo.CurrentSlice.Ticks[self.Symbol] is not None:
ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
for tick in ticks:
tick_type = getTickType(tick.TickType)
if tick_type == 'Trade':
self.algo.tradeCount += 1
if int(getattr(tick, 'Quantity')) != 0:
for key,prop in zip(list(self.trade.keys()),['EndTime','Price','Quantity']):
setattr(self.trade,str(key),getattr(tick, prop))
# Resetting Best Bid/Ask at MarketClose
def resetTickDict(self):
# Resetting After Market Close
# self.lastAsk = self.lastAsk.fromkeys(self.lastAsk, None)
# self.lastBid = self.lastBid.fromkeys(self.lastBid, None)
self._bestAsk = self._bestAsk.fromkeys(self._bestAsk, None)
self._bestBid = self._bestBid.fromkeys(self._bestBid, None)
self._trade = self._trade.fromkeys(self._trade, None)
self._WAP = None
# self.algo.Debug(f"Ask Reset:{self.Symbol} :{self.algo.Time}:{self._bestAsk}")
# self.algo.Debug(f"Bid Reset :{self.Symbol} :{self.algo.Time}:{self._bestBid}")
# self.algo.Debug(f"Trade Reset :{self.Symbol} :{self.algo.Time}:{self._trade}")
def updateYesterday(self):
# self.algo.Debug(f"Updated Yesterday price for:{self.Symbol} @ {self.algo.Time}")
# Stores Contracts Yesterday's OHCLV
# Note that Volume doesn't match with reported in our Database (atleast for Lumber)
if self.Mapped is not None:
# self.algo.Debug(f"ctrctHistory Symbol:{self.Mapped},{self.continuous_contract}")
ctrctHistory = self.algo.History(self.Mapped, 1, Resolution.Daily )
for bar in ctrctHistory.itertuples():
for property in ['open', 'high', 'low', 'close', 'volume']:
if not math.isnan(float(getattr(bar, property))): # Required since updateYesterday is called even on Non trading days
self.yesterday[str(property)] = getattr(bar, property)
# for prop in dir(bar):
# value = getattr(bar, prop)
# self.algo.Debug(f"prop:{prop}, value:{value}")
# Checking if we get same data
# if self.algo.CurrentSlice[self.Mapped].High is not None:
# self.algo.Debug(f"{self.algo.CurrentSlice[self.Mapped].High}")
# RealOnly RealTime
@property
def Mapped(self):
return getattr(self.continuous_contract, 'Mapped')
@property
def Canonical(self):
return getattr(self.Symbol, 'Canonical')
# @property
def Underlying(self):
return getattr(self, 'Underlying')
@property
def bestBid(self):
# Not using this since somehow when we club 2 futures, this wasn't updating correctly or giving None
# Also using getattr(self.algo.Securities[self.Mapped], prop)) instead of
# if self.algo.CurrentSlice.Ticks.ContainsKey(self.Symbol) and self.algo.CurrentSlice.Ticks[self.Symbol] is not None:
# ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
# for tick in ticks:
# tick_type = getTickType(tick.TickType)
# if tick_type == 'Quote' and int(getattr(self.algo.Securities[self.Mapped], 'BidSize')) != 0:
# for key,prop in zip(list(self._bestBid.keys()),['LocalTime','BidPrice', 'BidSize']):
# setattr(self._bestBid,str(key),getattr(self.algo.Securities[self.Mapped], prop))
# Only updating if Bid price and Size changed so as to keep the original Time of last update
if int(getattr(self.algo.Securities[self.Mapped], 'BidSize')) != 0 and not self.alreadyUpdated('BidPrice', 'BidSize', self._bestBid):
for key,prop in zip(list(self._bestBid.keys()),['LocalTime','BidPrice', 'BidSize']):
setattr(self._bestBid,str(key),getattr(self.algo.Securities[self.Mapped], prop))
return self._bestBid
@property
def bestAsk(self):
# Only updating if Ask price and Size changed so as to keep the original Time of last update
if int(getattr(self.algo.Securities[self.Mapped], 'AskSize')) != 0 and not self.alreadyUpdated('AskPrice', 'AskSize', self._bestAsk):
for key,prop in zip(list(self._bestBid.keys()),['LocalTime','AskPrice', 'AskSize']):
setattr(self._bestAsk,str(key),getattr(self.algo.Securities[self.Mapped], prop))
return self._bestAsk
# This is not entirely correct as someone may have canceled and others may have added a bid with net being affect 0
def alreadyUpdated(self, price, size, dictionary):
return getattr(self.algo.Securities[self.Mapped], price) == dictionary.price and getattr(self.algo.Securities[self.Mapped], size) == dictionary.size
@property
def trade(self):
# TO DO: Need to make it work like Quotes - Ask/Bid - getattr(self.algo.Securities[self.Mapped], prop))
# Ideally this should use self.Mapped but it doesn't take that.
if self.algo.CurrentSlice.Ticks.ContainsKey(self.Symbol) and self.algo.CurrentSlice.Ticks[self.Symbol] is not None:
ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
for tick in ticks:
tick_type = getTickType(tick.TickType)
if tick_type == 'Trade' and int(getattr(tick, 'Quantity')) != 0:
for key,prop in zip(list(self._trade.keys()),['Time','Price','Quantity']):
setattr(self._trade,str(key),getattr(tick, prop))
# setattr(self._trade,str(key),getattr(self.algo.Securities[self.Mapped], prop))
# https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/history-requests
# end_time = self.algo.Time
# start_time = end_time - timedelta(seconds=1)
# ticks = self.algo.History[Tick](self.Mapped, start_time, end_time, Resolution.Tick)
# count = 0
# # self.algo.Debug(f"type of ticks:{type(Ticks)}")
# for tick in ticks:
# if getTickType(tick.TickType) == 'Trade':
# self.algo.Debug(f"tick{count}:{tick}")
# count +=1
# if getTickType(tick.TickType) == 'Trade':
# for prop in dir(tick):
# try:
# value = getattr(tick, prop)
# self.algo.Debug(f"Tprop:{prop}, Tvalue:{value}")
# except:
# pass
# tick.set_Symbol(self.Mapped)
# tick_type = getTickType(tick.TickType)
# and int(getattr(tick, 'Quantity')) != 0
# if tick_type == 'Trade':
# count +=1
# dic = {k:getattr(tick, k) for k in ['EndTime','Price','Quantity'] if getattr(tick, k) is not None}
# # self.algo.Debug(f"Tickcount:{count}, time:{self.algo.Time} {dic}")
# for key,prop in zip(list(self._trade.keys()),['EndTime','Price','Quantity']):
# setattr(self._trade,str(key),getattr(tick, prop))
return self._trade
@property
def WAP(self):
if None not in (self.bestAsk.size,self.bestBid.size):
self._WAP = round(((self.bestBid.price * self.bestAsk.size) + (self.bestAsk.price * self.bestBid.size))/(self.bestBid.size + self.bestAsk.size),1)
return self._WAP
# @property
# def Bid(self):
# return self._Bid
# @Bid.setter
# def Bid(self, bid):
# # if bid == 0 or bid is None:
# # self._Bid = 0 # Pull this from other rolling?
# # pass
# # self._Bid = bid
# # self.WAP = None # Invalidate previously Calculated WAP
# # return self._Bid
# pass
# Links to documentation pertaining
# Time Modeling
# https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices#03-Properties
# Futures - Handling Data
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/handling-data
# To get the current Slice object, define an OnData method or use the CurrentSlice property of your algorithm (outside of the OnData method).
# If the data object doesn't contain any market data but it contains auxiliary data, the slice.ContainsKey(symbol) method can return true while slice[symbol] returns None.
class dotdict(dict):
"""dot.notation access to dictionary attributes"""
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
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]
# This dictionary is Used to detrmine the Upside of Lumber Prices versus Yesterday's Settle:
# From there we assume, TP,
def get_upside(index):
return {
'1.5%':10,
'2%':12,
'3%':15
}[index]
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/key-concepts
def getSecurityType(index):
return {
0: 'Base',
1: 'Equity',
2: 'Option',
3: 'Commodity',
4: 'Forex',
5: 'Future',
6: 'Cfd',
7: 'Crypto',
8: 'FutureOption',
9: 'Index',
10: 'IndexOption',
'CryptoFuture': 'CryptoFuture'
}[index]
def getDataType(index):
return {
0: 'Base',
1: 'TradeBar',
2: 'Tick',
3: 'Auxiliary', # Data associated with an instrument
4: 'QuoteBar',
5: 'OptionChain',
6: 'FuturesChain'
}[index]
def getTickType(index):
return {
0: 'Trade',
1: 'Quote',
2: 'OpenInterest' # Open Interest type tick object (for options, futures)
}[index]
from AlgorithmImports import *
import math
from collections import deque
from EnumFunc import *
from functools import wraps
# A skeleton class for storing Futures Data - Shared by all Models
class DataClass:
def __init__(self, Algorithm, continuous_contract):
self.algo = Algorithm # This is Our Instance of QCAlgorithm
self.continuous_contract = continuous_contract
self.Symbol = self.continuous_contract.Symbol
self.tickSize = self.continuous_contract.SymbolProperties.MinimumPriceVariation
self.yesterday = dotdict(dict.fromkeys(['open', 'high', 'low', 'close', 'volume']))
self._bestBid = dotdict(dict.fromkeys(['time', 'price', 'size']))
self._bestAsk = dotdict(dict.fromkeys(['time','price', 'size']))
self._trade = dotdict(dict.fromkeys(['time','price', 'size']))
self._WAP = None
self.atrPeriod = 2
self._atr = self.algo.ATR(self.Symbol, self.atrPeriod, MovingAverageType.Simple, Resolution.Daily)
self._atr.Updated += self.update_event_handler
# self._switched = True # So all related indicators will be updated at the start of the Algorithm
# Update Yesterday Price 10 minutes before Market Opens - Can even use 'LBS' in TimeRules.AfterMarketOpen
self.algo.Schedule.On(self.algo.DateRules.EveryDay(self.Symbol), self.algo.TimeRules.AfterMarketOpen(self.Symbol, -10), self.updateYesterday)
# Reset BBO dicts 10 minutes after market close - Not sure if it impacts extendedMarketHours
self.algo.Schedule.On(self.algo.DateRules.EveryDay(self.Symbol), self.algo.TimeRules.BeforeMarketClose(self.Symbol, -10), self.resetTickDict)
def update_event_handler(self, indicator: object, indicator_data_point: IndicatorDataPoint) -> None:
if indicator.IsReady:
self.algo.Debug(f"Indicator Value: {indicator_data_point.Value}")
# Resetting Best Bid/Ask at MarketClose
def resetTickDict(self):
self._bestAsk = self._bestAsk.fromkeys(self._bestAsk, None)
self._bestBid = self._bestBid.fromkeys(self._bestBid, None)
self._trade = self._trade.fromkeys(self._trade, None)
self._WAP = None
# Can even combine with ATR since both use history
def updateYesterday(self):
# Note that Volume doesn't match with reported in our Database (atleast for Lumber)
if self.Mapped is not None:
ctrctHistory = self.algo.History(self.Mapped, 1, Resolution.Daily )
for bar in ctrctHistory.itertuples():
for property in ['open', 'high', 'low', 'close', 'volume']:
if not math.isnan(float(getattr(bar, property))): # Required since updateYesterday is called even on Non trading days
self.yesterday[str(property)] = getattr(bar, property)
# RealOnly RealTime
@property
def Mapped(self):
return getattr(self.continuous_contract, 'Mapped')
@property
def Canonical(self):
return getattr(self.Symbol, 'Canonical')
# ToDo: Issues - Make it work for self.Symbol - for now it only works for self.Mapped
# @property
# def atr(self):
# # Load History if either the contract switched or Indicator not ready yet
# if not self._atr.IsReady:
# historyATR = self.algo.History[TradeBar](self.Mapped, self.atrPeriod, Resolution.Daily)
# # https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/rolling-window#09-Cast-to-Other-Types
# historyATR = self.algo.PandasConverter.GetDataFrame[TradeBar](list(historyATR)[::-1])
# for bar in historyATR.itertuples():
# tradebar = TradeBar(bar.Index[1], self.Mapped, float(bar.open), float(bar.high), float(bar.low), float(bar.close), float(bar.volume))
# self._atr.Update(tradebar)
# # self._switched = False # Turn it off so unless its not set to true in Main it remains off
# return self._atr
@property
def bestBid(self):
# Only updating if Bid price and Size changed so as to keep the original Time of last update
if int(getattr(self.algo.Securities[self.Mapped], 'BidSize')) != 0 and not self.alreadyUpdated('BidPrice', 'BidSize', self._bestBid):
for key,prop in zip(list(self._bestBid.keys()),['LocalTime','BidPrice', 'BidSize']):
setattr(self._bestBid,str(key),getattr(self.algo.Securities[self.Mapped], prop))
return self._bestBid
@property
def bestAsk(self):
# Only updating if Ask price and Size changed so as to keep the original Time of last update
if int(getattr(self.algo.Securities[self.Mapped], 'AskSize')) != 0 and not self.alreadyUpdated('AskPrice', 'AskSize', self._bestAsk):
for key,prop in zip(list(self._bestBid.keys()),['LocalTime','AskPrice', 'AskSize']):
setattr(self._bestAsk,str(key),getattr(self.algo.Securities[self.Mapped], prop))
return self._bestAsk
# This is not entirely correct as someone may have canceled and others may have added a bid with net being affect 0
def alreadyUpdated(self, price, size, dictionary):
return getattr(self.algo.Securities[self.Mapped], price) == dictionary.price and getattr(self.algo.Securities[self.Mapped], size) == dictionary.size
# TO DO: Incorrect since when we BackwardsPanamaCanal for DataNormalizationMode, trade prices for older contracts wille be adjusted unless we use self.Mapped just like Quotes - Ask/Bid - getattr(self.algo.Securities[self.Mapped], prop))
# However, self.Securities option doesn't take self.Mapped while ticks don't seem to have a property that matches last traded price. LastPrice gives BestBid/Ask
@property
def trade(self):
if self.algo.CurrentSlice.Ticks.ContainsKey(self.Symbol) and self.algo.CurrentSlice.Ticks[self.Symbol] is not None:
ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
for tick in ticks:
tick_type = getTickType(tick.TickType)
if tick_type == 'Trade' and int(getattr(tick, 'Quantity')) != 0:
for key,prop in zip(list(self._trade.keys()),['Time','Price','Quantity']):
setattr(self._trade,str(key),getattr(tick, prop))
# setattr(self._trade,str(key),getattr(self.algo.Securities[self.Mapped], prop))
# end_time = self.algo.Time
# start_time = end_time - timedelta(seconds=1)
# self.History[Tick](self.Mapped, start_time,end_time, Resolution.Tick)
return self._trade
@property
def WAP(self):
if None not in (self.bestAsk.size,self.bestBid.size):
self._WAP = round(((self.bestBid.price * self.bestAsk.size) + (self.bestAsk.price * self.bestBid.size))/(self.bestBid.size + self.bestAsk.size),1)
return self._WAP
class dotdict(dict):
"""dot.notation access to dictionary attributes"""
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
#region imports
from AlgorithmImports import *
#endregion
# NEED HELP
# 1. Done: Get Yesterday's Close Price for Lumber Contracts - 2 ways to acheive.
# 1a. Use history fuction everyday - Works Fine
# 2a. Use Identity Indicator - Its partially correct when using Resolution.Daily but incorrect On days when the contract rolls.
# i.e. it still shows yesterday's close for previous contract on RollOverDays. Also would require a day or 2 of warmuP
# Secondly, if I use Resolution.Tick in Lumber Contract definition, it shows 2 days ago prices when called before market Open
# 3. Find trading days when both Nasdaq and Lumber were open (keeping in mind yesterday's data) and only trade when both are available atleast for backtesting
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/market-hours/cme/mnq
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/market-hours/cme/lbs
# 4. Nasdaq data not available on first day since it gets added at 2300 hours while Lumber gets added at 00 hours.
# 5. Didn't check if Nasdaq prices are fine or if Nasdaq yesterday contract prices match the rolled over contract
# 6. Whats the difference between getting Bids & Asks from ticks like below - Is the first one Time&Sales (for quotes) while second one gives Best Bids/Asks?
# ticks = self.algo.CurrentSlice.Ticks[self.Symbol]
# for tick in ticks:
# tick.AskPrice
# versus getting bids/asks from self.Securities[security].AskPrice
# 7. # Questions on quoteEvent (TickQuoteBarConsolidator):
# 1. Does this tell you total number of best bids/asks at any moment in time or are these just seperate orders and their corresponding sizes?
# 2. Quotes are for mapped rolled contracts?
# 3. Also these are not all quotes as placed but only Top Bids/Asks. So for example, they are only generated if someone has topped a previous bid/offer?
# Some other references:
# 1. Tick Data related
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/handling-data#07-Ticks
# LastPrice - Alias for "Value" - the last sale for this asset. Same as Price
# IsFillForward - True if this is a fill forward piece of data
# 'Time','EndTime' - for Trade Tick is same as self.Time but for time use this property only
# 'Symbol' - Not available but has other sub properties
# ,'SaleCondition','Suspicious' - Not relevant
# tickTradeProps = ['Price','Quantity']
# tickQuoteProps = ['BidPrice','BidSize','AskPrice','AskSize']
# tickOIProps = ['Value'] # Not Getting Data for OpenInterest
# Other Notes to self:
# 1. Since Resolution is for Ticks, we won't be getting Trade & Quote Bars
# 2. 'LocalTime': Local time for this market
# 3. Properties of self.Securities - https://www.quantconnect.com/docs/v2/writing-algorithms/securities/properties#02-Security-Properties
# 4. Nasdaq - closes at 4 pm & opens at 8:30 Chicago, Also trades at 11 pm till not sure when?
# OnSecuritiesChanged: Date:2022-12-19 23:00:00, security:MNQ Y6URRFPZ86BL
# 5. # Links to documentation pertaining
# Time Modeling
# https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices#03-Properties
# Futures - Handling Data
# https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/futures/handling-data
# To get the current Slice object, define an OnData method or use the CurrentSlice property of your algorithm (outside of the OnData method).
# If the data object doesn't contain any market data but it contains auxiliary data, the slice.ContainsKey(symbol) method can return true while slice[symbol] returns None.
# Indicator Help
# In QuantConnect/Lean, we have shortcut methods for indicators, they belong to the QCAlgorithm class (use self) and name are upper-cased. These helper methods create a new instance of a indicator object and hook it up to a data consolidator so that the indicator is automatically updated by the engine.
# Since these methods create a new instance, we just should only to call it once (normally in Initialize) and assign it to a class variable to be accessed throughout the algorithm.
# 1. AverageTrueRange:
# https://www.quantconnect.com/forum/discussion/7972/using-atr-and-other-039-complex-039-indicators-with-history/p1
# https://www.quantconnect.com/forum/discussion/11457/warmup-atr-with-history
# https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/supported-indicators/average-true-range
# region imports
from AlgorithmImports import *
from AlphaModel import *
from DataClass import *
import math
class NasdaqStrategy(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022,12,19)
self.SetEndDate(2023,1,5)
self.SetCash(100000)
self.SetTimeZone(TimeZones.Chicago) # If TimeZone is Chicago - Algo Time and Data End Time are same at 1800 hours
self.SetWarmUp(timedelta(days=1))
self.Data = {}
# FutureSymbols = {'Lumber':Futures.Forestry.RandomLengthLumber,'Nasdaq':Futures.Indices.NASDAQ100EMini}
FutureSymbols = {'Lumber':Futures.Forestry.RandomLengthLumber}
# For Nasdaq we need DataMappingMode.OpenInterest or LastTradingDay - How to change?
for key, value in FutureSymbols.items():
dataMappingMode_ = DataMappingMode.FirstDayMonth if key == 'Lumber' \
else DataMappingMode.OpenInterest if key == 'Nasdaq' else DataMappingMode.LastTradingDay
# dataMappingMode_ = DataMappingMode.FirstDayMonth if key == 'Lumber' \
# else DataMappingMode.LastTradingDay
# BackwardsPanamaCanal
future = self.AddFuture(value, Resolution.Tick,dataMappingMode = dataMappingMode_, contractDepthOffset=0,
dataNormalizationMode = DataNormalizationMode.Raw, extendedMarketHours=True, fillDataForward = True)
self.Data[key] = DataClass(self, future) # Initiating DataClass for each Future & Passing our instance of QCAlgorithm Class
# NOT SURE IF WORKING CORRECTLY
# To trade the contract in the same time step you subscribe to the contract - Since GetLastKnowPrice makes a history request, it may slow the algorithm down.
# self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
# Set alpha model - This also gives you access to the AlphaModel Instance
# self.alpha = NasdaqAlpha(self.Data['Lumber'])
# self.SetAlpha(self.alpha)
# Printing Yesterday data
# self.Schedule.On(self.DateRules.EveryDay(self.Data['Lumber'].Symbol), self.TimeRules.AfterMarketOpen(self.Data['Lumber'].Symbol, -1), self.beforeLumberOpen)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(8,55), self.beforeLumberOpen)
# self.TimeRules.BeforeMarketClose(symbol: Symbol, minutesBeforeClose: float = 0, extendedMarketOpen: bool = False)
self.tradeCount = 0
# Check Entry Condition only 30 seconds prior to Market Open
self.entryTimeStart = self.Time.replace(hour=9, minute=0, second=0, microsecond=55000)
self.entryTimeEnd = self.Time.replace(hour=9, minute=1, second=0, microsecond=0)
def beforeLumberOpen(self):
if self.IsWarmingUp: return
# Works - Get Yesterdays' data keeping in mind Rolled Over Contracts
for symbol in self.Data.keys():
# self.Debug(f"Yester Time:{self.Time}, {self.Data[symbol].Mapped}.yesterday:{self.Data[symbol].yesterday}")
pass
# Works
# for security in self.ActiveSecurities.Values:
# self.Debug(f"self.Time:{self.Time} ActiveSecurity:{security}")
def OnSecuritiesChanged(self, changes: SecurityChanges) -> None:
# Only runs at the start of program not when Contract rolls
for security in changes.AddedSecurities:
if len(changes.AddedSecurities) == 0: return
self.Debug(f"In Main: OnSecuritiesChanged: Date:{self.Time}, security:{changes.AddedSecurities[0].Mapped}")
def OnEndOfDay(self, symbol):
# self.Debug(f"OnEndOfDay self.Time:{self.Time}, Symbol:{self.Data['Lumber'].Mapped.Value}")
pass
def OnData(self, data):
# Useless
# self.Debug("Hello")
# for chain in data.FutureChains:
# contracts = list(chain.Value)
# self.Debug(f"Last contracts: {contracts}")
# for contract in contracts:
# self.Debug(f"contract:{contract}, Last Price: {contract.LastPrice}")
# https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/warm-up-periods#03-Warm-Up-Vs-Reality
# In OnData: Don't run if the indicators aren't ready
if self.IsWarmingUp: return
# Below code important to compare Ticks with whats reported from DataClass
tickTradeProps = ['LastPrice','Quantity']
tickQuoteProps = ['BidPrice','BidSize','AskPrice','AskSize']
# tickOIProps = ['Value'] # Not Getting Data for OpenInterest
# for k in data.Ticks.Keys:
# self.Debug(f"keys:{k}")
# self.Debug(f"Underlying:{k.Underlying}")
# if data.Ticks.ContainsKey(k) and data.Ticks[k] is not None:
# self.Debug("yes")
for security in data.Keys:
# if self.Time < self.entryTimeStart or self.Time > self.entryTimeEnd: return
# pass
# self.Debug(f"security:{security}")
# for prop in dir(security):
# value = getattr(security, prop)
# self.Debug(f"prop:{prop}, value:{value}")
if security == self.Data['Lumber'].Mapped:
self.Debug(f"security Matched:{security}")
if data.Ticks.ContainsKey(security) and data.Ticks[security] is not None:
ticks = data.Ticks[security]
for tick in ticks:
previous_time = self.Time
tick_type = getTickType(tick.TickType)
if tick_type == 'Trade' and int(getattr(tick, 'Quantity')) != 0:
# This is for Trade Data
dic = {k:getattr(tick, k) for k in tickTradeProps if getattr(tick, k) is not None}
self.Debug(f"TradeTick:{self.Time} {dic}")
# self.Debug(f"self.Data['Lumber'].Underlying:{self.Data['Lumber'].Underlying} ")
# elif tick_type == 'Quote':
# This if for Last Bid & Ask
# dic = {k:getattr(tick, k) for k in tickQuoteProps if getattr(tick, k) is not None}
# self.Debug(f"*QuoteTick*: {self.Time}, security:{security}, {dic}")
# This if for Best Bid & Ask
# dic2 = {k:getattr(self.Securities[security], k) for k in tickQuoteProps}
# self.Debug(f"+QuoteTick2+:{self.Time}, security:{security}, {dic2}")
for symbol in self.Data.keys():
if self.Time < self.entryTimeStart or self.Time > self.entryTimeEnd: return
# self.Debug(f"SYMBOL:{symbol}")
# self.Debug(f"++BestBid:{symbol}:{self.Time}:{self.Data[symbol].bestBid}")
# self.Debug(f"^^BestAsk:{symbol}:{self.Time}:{self.Data[symbol].bestAsk}")
self.Debug(f"**trade:{symbol}:{self.Time}:{self.Data[symbol].trade}")
# self.Debug(f"**WAP:{symbol}:{self.Time}:{self.Data[symbol].WAP}")
# self.Debug(f"**ATR:{symbol}:{self.Time}:{self.Data[symbol].atr.Current.Value}")
# self.Debug(f"**LastAsk:{self.Data[symbol].lastAsk}")
# self.Debug(f"**LastBid:{self.Data[symbol].lastBid}")
# self.Debug(f" BestBid == LastBid:{self.Data[symbol].bestBid.price == self.Data[symbol].lastBid.price}")
# self.Debug(f" BestAsk == LastAsk:{self.Data[symbol].bestAsk.price == self.Data[symbol].lastAsk.price}")
# Just to check if FuncSecuritySeeder gets us GetLastKnownPrices
# for security in self.ActiveSecurities.Values:
# self.Debug(f"Todays Close:{self.Securities[security.Symbol].Close}, Date:{self.Time}, security:{security}")
# if security == 'LBS Y54QLJOCEN7L':
# self.Debug(f"Mapped:{self.Data['Lumber'].Mapped}")
# self.Debug(f"security == self.Data['Lumber'].Mapped:{security.Symbol == self.Data['Lumber'].Mapped}")
# if security.Symbol == self.Data['Lumber'].Mapped:
# self.Debug(f"Todays Close:{self.Securities[security.Symbol].Close}, Date:{self.Time}, security:{security}")
# self.Debug("Yes")
# b = self.Securities[self.Data['Lumber'].Mapped]
# for prop in dir(b):
# value = getattr(b, prop)
# self.Debug(f"prop11:{prop}, value:{value}")
# WORKS - Remove from here since updated several times in a day
# self.Debug(f"Todays ____Close:{self.Securities[self.Data['Lumber'].Mapped].Price}, Date:{self.Time}")
if data.Ticks.ContainsKey(self.Data['Lumber'].Mapped):
if data.Ticks[self.Data['Lumber'].Symbol] is not None:
self.Debug(f"**MAIN** Date:{self.Time}, MappedValue:{self.Data['Lumber'].Mapped.Value}, MappedID:{self.Data['Lumber'].Mapped.ID}, ")
# b = data.Bars[self.Data['Lumber'].Mapped]
# for prop in dir(b):
# value = getattr(b, prop)
# self.algo.Debug(f"prop:{prop}, value:{value}")
# Works
# if data.Ticks.ContainsKey(self.Data['Lumber'].Symbol):
# if data.Ticks[self.Data['Lumber'].Symbol] is not None:
# self.Debug(f"**MAIN** Date:{self.Time}, MappedValue:{self.Data['Lumber'].Mapped.Value}, MappedID:{self.Data['Lumber'].Mapped.ID}, ")
# https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/quantconnect/us-futures-security-master#05-Data-Point-Attributes
for symbol in self.Data.keys():
if data.SymbolChangedEvents.ContainsKey(self.Data[symbol].Symbol):
symbolChangedEvent = data.SymbolChangedEvents[self.Data[symbol].Symbol]
self.Debug(f"In MAIN Symbol changed: {symbolChangedEvent.OldSymbol} -> {symbolChangedEvent.NewSymbol} \
EndTime:{symbolChangedEvent.EndTime} DataType:{getDataType(symbolChangedEvent.DataType)}, Expiry: {self.Securities[self.Data[symbol].Mapped].Expiry}")
# if data[self.Data['Lumber'].Mapped] is not None:
# self.Debug(f"data123Map: {data[self.Data['Lumber'].Mapped]}")
# When your algorithm stops executing, LEAN calls the OnEndOfAlgorithm method.
def OnEndOfAlgorithm(self) -> None:
# self.Debug(f"self.Alpha.securities:{self.alpha.securities}")
# self.Debug(f"self.count:{self.count}")
self.Debug(f"self.TradeCount:{self.tradeCount}")
def OnWarmUpFinished(self) -> None:
self.Debug(f"Algorithm Ready@{self.Time}")
pass
# region imports
from AlgorithmImports import *
from AlphaModel import *
from DataClass import *
import math
class NasdaqStrategy(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022,12,26)
self.SetEndDate(2023,1,5)
self.SetCash(100000)
self.SetTimeZone(TimeZones.Chicago) # If TimeZone is Chicago - Algo Time and Data End Time are same at 1800 hours
self.SetWarmUp(timedelta(days=1))
self.Data = {}
# FutureSymbols = {'Lumber':Futures.Forestry.RandomLengthLumber,'Nasdaq':Futures.Indices.NASDAQ100EMini}
FutureSymbols = {'Lumber':Futures.Forestry.RandomLengthLumber}
for key, value in FutureSymbols.items():
dataMappingMode_ = DataMappingMode.FirstDayMonth if key == 'Lumber' \
else DataMappingMode.OpenInterest if key == 'Nasdaq' else DataMappingMode.LastTradingDay
# Use BackwardsPanamaCanal for DataNormalizationMode when "Trade" PROPERTY is able to map to Mapped contract
future = self.AddFuture(value, Resolution.Tick,dataMappingMode = dataMappingMode_, contractDepthOffset=0,
dataNormalizationMode = DataNormalizationMode.Raw, extendedMarketHours=True, fillDataForward = True)
self.Data[key] = DataClass(self, future) # Initiating DataClass for each Future & Passing our instance of QCAlgorithm Class
# Set alpha model - This also gives you access to the AlphaModel Instance
self.alpha = NasdaqAlpha(self.Data['Lumber'])
self.SetAlpha(self.alpha)
# Printing Yesterday data
self.Schedule.On(self.DateRules.EveryDay(self.Data['Lumber'].Symbol), self.TimeRules.AfterMarketOpen(self.Data['Lumber'].Symbol, -1), self.beforeLumberOpen)
# self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(8,55), self.beforeLumberOpen)
# Temporary
self.entryTimeStart = self.Time.replace(hour=8, minute=59, second=0, microsecond=55000)
self.entryTimeEnd = self.Time.replace(hour=9, minute=3, second=0, microsecond=0)
def beforeLumberOpen(self):
# if self.IsWarmingUp: return
# Works - Get Yesterdays' data keeping in mind Rolled Over Contracts
for symbol in self.Data.keys():
pass
# self.Debug(f"Yester Time:{self.Time}, {self.Data[symbol].Mapped}.yesterday:{self.Data[symbol].yesterday}")
# self.Debug(f"Calculated Yesterday's High-Low:{self.Time}, {round(float(self.Data[symbol].yesterday.high) - float(self.Data[symbol].yesterday.low),1)}")
# self.Debug(f"ATR Yesterday:{round(self.Data[symbol]._atr.TrueRange.Current.Value,1)}, ATR {self.Data[symbol].atrPeriod} days:{round(self.Data[symbol]._atr.Current.Value,1)}")
# Works
# for security in self.ActiveSecurities.Values:
# self.Debug(f"self.Time:{self.Time} ActiveSecurity:{security}")
def OnSecuritiesChanged(self, changes: SecurityChanges) -> None:
# Only runs at the start of program not when Contract rolls
for security in changes.AddedSecurities:
if len(changes.AddedSecurities) == 0: return
self.Debug(f"In Main: OnSecuritiesChanged: Date:{self.Time}, security:{changes.AddedSecurities[0].Mapped}")
def OnEndOfDay(self, symbol):
# self.Debug(f"OnEndOfDay self.Time:{self.Time}, Symbol:{self.Data['Lumber'].Mapped.Value}")
pass
def OnData(self, data):
# https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/warm-up-periods#03-Warm-Up-Vs-Reality
if self.IsWarmingUp: return
# Below code important to compare Ticks with whats reported from DataClass
tickTradeProps = ['LastPrice','Quantity']
tickQuoteProps = ['BidPrice','BidSize','AskPrice','AskSize']
# tickOIProps = ['Value'] # Not Getting Data for OpenInterest
for security in data.Keys:
# if self.Time < self.entryTimeStart or self.Time > self.entryTimeEnd: return # temporary
if data.Ticks.ContainsKey(security) and data.Ticks[security] is not None:
ticks = data.Ticks[security]
for tick in ticks:
tick_type = getTickType(tick.TickType)
if tick_type == 'Trade' and int(getattr(tick, 'Quantity')) != 0:
# For Trade Data
dic = {k:getattr(tick, k) for k in tickTradeProps if getattr(tick, k) is not None}
self.Debug(f"TradeTick:{self.Time} {dic}")
elif tick_type == 'Quote':
# For Best Bid & Ask
dic2 = {k:getattr(self.Securities[security], k) for k in tickQuoteProps}
self.Debug(f"QuoteTick:{self.Time}, security:{security}, {dic2}")
for symbol in self.Data.keys():
# if self.Time < self.entryTimeStart or self.Time > self.entryTimeEnd: return # temporary
self.Debug(f"++BestBid:{symbol}:{self.Time}:{self.Data[symbol].bestBid}")
self.Debug(f"^^BestAsk:{symbol}:{self.Time}:{self.Data[symbol].bestAsk}")
self.Debug(f"**trade:{symbol}:{self.Time}:{self.Data[symbol].trade}")
# self.Debug(f"**WAP:{symbol}:{self.Time}:{self.Data[symbol].WAP}")
# self.Debug(f"**ATR:{symbol}:{self.Time}:{self.Data[symbol].atr.Current.Value}")
# WORKS - Updated several times in a day - Doesn't give last traded price - gives bid or ask
# self.Debug(f"Todays ____Close:{self.Securities[self.Data['Lumber'].Mapped].Price}, Date:{self.Time}")
# Works
# if data.Ticks.ContainsKey(self.Data['Lumber'].Symbol):
# if data.Ticks[self.Data['Lumber'].Symbol] is not None:
# self.Debug(f"**MAIN** Date:{self.Time}, MappedValue:{self.Data['Lumber'].Mapped.Value}, MappedID:{self.Data['Lumber'].Mapped.ID}, ")
# https://www.quantconnect.com/docs/v2/writing-algorithms/datasets/quantconnect/us-futures-security-master#05-Data-Point-Attributes
for symbol in self.Data.keys():
if data.SymbolChangedEvents.ContainsKey(self.Data[symbol].Symbol):
symbolChangedEvent = data.SymbolChangedEvents[self.Data[symbol].Symbol]
self.Debug(f"In MAIN Symbol changed: {symbolChangedEvent.OldSymbol} -> {symbolChangedEvent.NewSymbol} \
EndTime:{symbolChangedEvent.EndTime} DataType:{getDataType(symbolChangedEvent.DataType)}, Expiry: {self.Securities[self.Data[symbol].Mapped].Expiry}")
# https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/key-concepts#09-Reset-Indicators
self.Data[symbol]._atr.Reset() # Since after swicthing don't want the old data
# When your algorithm stops executing, LEAN calls the OnEndOfAlgorithm method.
def OnEndOfAlgorithm(self) -> None:
# self.Debug(f"self.Alpha.securities:{self.alpha.securities}")
pass
def OnWarmUpFinished(self) -> None:
self.Debug(f"Algorithm Ready@{self.Time}")
pass