Diff
checker
文本
文本
圖像
文檔
Excel
文件夾
Legal
Enterprise
桌面版
定價
登入
下載 Diffchecker 桌面版
比較文本
尋找兩個文字檔案之間的差異
工具
歷史
即時編輯器
摺疊未變更行
關閉換行
檢視
拆分
統一
比對精度
智能
單詞
字符
語法突出顯示
選擇語法
忽略
文字轉換
前往第一個差異
編輯輸入
Diffchecker Desktop
執行Diffchecker最安全的方式。取得Diffchecker桌面應用程式:您的差異永遠不會離開您的電腦!
取得桌面版
main.py
建立於
4 年前
差異永不過期
清除
匯出
分享
解釋
74 刪除
行
總計
刪除
字符
總計
刪除
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
294 行
全部複製
25 新增
行
總計
新增
字符
總計
新增
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
284 行
全部複製
複製
已複製
複製
已複製
Charts
Statistics
Code
##########################################################################
##########################################################################
# Scheduled Intraday Universe Screening
# Scheduled Intraday Universe Screening
# ---------------------------------------------
# ---------------------------------------------
# FOR EDUCATIONAL PURPOSES ONLY. DO NOT DEPLOY.
# FOR EDUCATIONAL PURPOSES ONLY. DO NOT DEPLOY.
#
#
# Entry:
# Entry:
# ------
# ------
# Daily: At midnight, screen for stocks trading above daily EMA
# Daily: At midnight, screen for stocks trading above daily EMA
# Intraday: In the afternoon, screen those daily stocks for postive momentum
# Intraday: In the afternoon, screen those daily stocks for postive momentum
# Open positions for the top 'X' stocks with highest positive momentum
# Open positions for the top 'X' stocks with highest positive momentum
#
#
# Exit:
# Exit:
# -----
# -----
# Exit when price falls below EMA.
# Exit when price falls below EMA.
# Optionally: exit at End of day if EoDExit flag is set.
# Optionally: exit at End of day if EoDExit flag is set.
#
#
# ................................................................
# ................................................................
# Copyright(c) 2021 Quantish.io - Granted to the public domain
# Copyright(c) 2021 Quantish.io - Granted to the public domain
# Do not remove this copyright notice | info@quantish.io
# Do not remove this copyright notice | info@quantish.io
#########################################################################
#########################################################################
from SymbolData import *
from SymbolData import *
class EMAMOMUniverse(QCAlgorithm):
class EMAMOMUniverse(QCAlgorithm):
def Initialize(self):
def Initialize(self):
self.InitBacktestParams()
self.InitBacktestParams()
self.InitAssets()
self.InitAssets()
self.InitAlgoParams()
self.InitAlgoParams()
self.InitUniverse()
self.InitUniverse()
self.ScheduleRoutines()
self.ScheduleRoutines()
def InitBacktestParams(self):
def InitBacktestParams(self):
self.SetStartDate(2020, 1, 1)
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2021, 1, 1)
self.SetEndDate(2021, 1, 1)
self.SetCash(100000)
self.SetCash(100000)
def InitAssets(self):
def InitAssets(self):
self.AddEquity("SPY", Resolution.Hour) # benchmark
self.AddEquity("SPY", Resolution.Hour) # benchmark
self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
def InitAlgoParams(self):
def InitAlgoParams(self):
self.dailyEMAPeriod = 10
self.dailyEMAPeriod = 10
self.hourlyMomPeriod = 4
self.hourlyMomPeriod = 4
self.minsAfterOpen = 300
self.minsAfterOpen = 300
複製
已複製
複製
已複製
self.useEoDExit =
0
self.useEoDExit =
False
self.maxCoarseSelections = 30
self.maxCoarseSelections = 30
複製
已複製
複製
已複製
self.minAssetPrice = 50.0
self.maxFineSelections = 10
self.maxFineSelections = 10
self.maxIntradaySelections = 5
self.maxIntradaySelections = 5
self.maxOpenPositions = 5
self.maxOpenPositions = 5
def InitUniverse(self):
def InitUniverse(self):
## Init universe configuration, selectors
## Init universe configuration, selectors
self.UniverseSettings.Resolution = Resolution.Minute
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.CoarseUniverseSelection, self.FineUniverseSelection)
self.AddUniverse(self.CoarseUniverseSelection, self.FineUniverseSelection)
self.EnableAutomaticIndicatorWarmUp = True
self.EnableAutomaticIndicatorWarmUp = True
## Init vars for tracking universe state
## Init vars for tracking universe state
self.symDataDict = { }
self.symDataDict = { }
self.screenedDailyStocks = []
self.screenedDailyStocks = []
self.screenedIntradayStocks = []
self.screenedIntradayStocks = []
self.queuedPositions = []
self.queuedPositions = []
## Schedule screening and liquidation routines, as needed.
## Schedule screening and liquidation routines, as needed.
## -------------------------------------------------------
## -------------------------------------------------------
def ScheduleRoutines(self):
def ScheduleRoutines(self):
## Intraday selection
## Intraday selection
self.Schedule.On(self.DateRules.EveryDay(),
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.AfterMarketOpen("SPY", self.minsAfterOpen),
self.TimeRules.AfterMarketOpen("SPY", self.minsAfterOpen),
self.IntraDaySelection)
self.IntraDaySelection)
## End of Day Liquidation
## End of Day Liquidation
if(self.useEoDExit):
if(self.useEoDExit):
self.Schedule.On(self.DateRules.EveryDay(),
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.BeforeMarketClose("SPY", 2),
self.TimeRules.BeforeMarketClose("SPY", 2),
self.LiquidateAtEoD)
self.LiquidateAtEoD)
## ----------------------
## ----------------------
def LiquidateAtEoD(self):
def LiquidateAtEoD(self):
複製
已複製
複製
已複製
self.Liquidate(tag="EoD liquidat
at
ion")
self.Liquidate(tag="EoD liquidat
ion")
## Process our queued positions, check for exits for held positions
## Process our queued positions, check for exits for held positions
## ----------------------------------------------------------------
## ----------------------------------------------------------------
def OnData(self, dataSlice):
def OnData(self, dataSlice):
self.ProcessQueuedPositions()
self.ProcessQueuedPositions()
for symbol in dataSlice.Keys:
for symbol in dataSlice.Keys:
if symbol in self.symDataDict:
if symbol in self.symDataDict:
symbolData = self.symDataDict[symbol]
symbolData = self.symDataDict[symbol]
複製
已複製
複製
已複製
if
( (symbol in
dataSlice
) and (dataSlice
[symbol] is not None
))
:
if
dataSlice
[symbol] is not None
:
symbolData.lastClosePrice = dataSlice[symbol].Close
symbolData.lastClosePrice = dataSlice[symbol].Close
複製
已複製
複製
已複製
if
(
symbolData.ExitCriteriaMet
() )
:
if
symbolData.ExitCriteriaMet
:
self.Liquidate(symbol, tag=symbolData.ClosePositionMessage)
self.Liquidate(symbol, tag=symbolData.ClosePositionMessage)
複製
已複製
複製
已複製
# del self.symDataDict[symbol]
self.RemoveSecurity(symbol)
self.RemoveSecurity(symbol)
## Check if we are already holding the max # of open positions.
## Check if we are already holding the max # of open positions.
## ------------------------------------------------------------
## ------------------------------------------------------------
複製
已複製
複製
已複製
@property
def PortfolioAtCapacity(self):
def PortfolioAtCapacity(self):
numHoldings = len([x.Key for x in self.Portfolio if x.Value.Invested])
numHoldings = len([x.Key for x in self.Portfolio if x.Value.Invested])
複製
已複製
複製
已複製
return
(
numHoldings >= self.maxOpenPositions
)
return
numHoldings >= self.maxOpenPositions
## Coarse universe selection. Replace with your own universe filters.
## Coarse universe selection. Replace with your own universe filters.
## ------------------------------------------------------------------
## ------------------------------------------------------------------
def CoarseUniverseSelection(self, universe):
def CoarseUniverseSelection(self, universe):
複製
已複製
複製
已複製
if
self.PortfolioAtCapacity
:
if
(
self.PortfolioAtCapacity
()):
return []
return []
else:
else:
coarseuniverse = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
coarseuniverse = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
複製
已複製
複製
已複製
coarseuniverse = [c for c in coarseuniverse if c.Price >
50
][:self.maxCoarseSelections]
coarseuniverse = [c for c in coarseuniverse if c.Price >
= self.minAssetPrice
][:self.maxCoarseSelections]
return [x.Symbol for x in coarseuniverse]
return [x.Symbol for x in coarseuniverse]
## Fine universe selection. Replace with your own universe filters.
## Fine universe selection. Replace with your own universe filters.
## ----------------------------------------------------------------
## ----------------------------------------------------------------
def FineUniverseSelection(self, universe):
def FineUniverseSelection(self, universe):
複製
已複製
複製
已複製
if
(
self.PortfolioAtCapacity
()):
if
self.PortfolioAtCapacity
:
return []
return []
else:
else:
複製
已複製
複製
已複製
# Modify this to fit your criteria
fineUniverse = [x for x in universe if x.SecurityReference.IsPrimaryShare
fineUniverse = [x for x in universe if x.SecurityReference.IsPrimaryShare
and x.SecurityReference.SecurityType == "ST00000001"
and x.SecurityReference.SecurityType == "ST00000001"
and x.SecurityReference.IsDepositaryReceipt == 0
and x.SecurityReference.IsDepositaryReceipt == 0
and x.CompanyReference.IsLimitedPartnership == 0]
and x.CompanyReference.IsLimitedPartnership == 0]
## Fetch the stocks that match our daily screening criteria
## Fetch the stocks that match our daily screening criteria
screenedStocks = self.GetDailyScreenedStocks(fineUniverse)
screenedStocks = self.GetDailyScreenedStocks(fineUniverse)
self.screenedDailyStocks = screenedStocks[:self.maxFineSelections]
self.screenedDailyStocks = screenedStocks[:self.maxFineSelections]
## NOTE:
## NOTE:
## If you plan to do intraday selection, then
## If you plan to do intraday selection, then
## return a blank array otherwise, comment out this line
## return a blank array otherwise, comment out this line
## ...........................................................
## ...........................................................
return []
return []
## NOTE:
## NOTE:
## If there is no need for intraday selection, then
## If there is no need for intraday selection, then
## uncomment the below line to return daily screened stocks
## uncomment the below line to return daily screened stocks
## ...........................................................
## ...........................................................
## return self.screenedDailyStocks
## return self.screenedDailyStocks
## Intraday universe selection. Replace with your own Criteria.
## Intraday universe selection. Replace with your own Criteria.
## ------------------------------------------------------------
## ------------------------------------------------------------
def IntraDaySelection(self):
def IntraDaySelection(self):
複製
已複製
複製
已複製
if
not self.PortfolioAtCapacity
:
if
(
not self.PortfolioAtCapacity
()):
## Fetch the stocks that meet intraday screening criteria
## Fetch the stocks that meet intraday screening criteria
複製
已複製
複製
已複製
screenedStocks
= self.GetIntraDayScreenedStocks(self.screenedDailyStocks)
screenedStocks
= self.GetIntraDayScreenedStocks(self.screenedDailyStocks)
## Get the symboldata for the screened stocks, and rank by momentum
## Get the symboldata for the screened stocks, and rank by momentum
複製
已複製
複製
已複製
screenedStockData
= [
self.symDataDict[symbol] for symbol in screenedStocks]
screenedStockData
= [
self.symDataDict[symbol] for symbol in screenedStocks]
screenedDataSorted = sorted(screenedStockData, key=lambda x: x.momentum, reverse=True)
screenedDataSorted = sorted(screenedStockData, key=lambda x: x.momentum, reverse=True)
複製
已複製
複製
已複製
screenedSymbolsSorted = [
stockData.symbol for stockData in screenedDataSorted
]
screenedSymbolsSorted = [
stockData.symbol for stockData in screenedDataSorted
]
self.screenedIntradayStocks = screenedSymbolsSorted[:self.maxIntradaySelections]
self.screenedIntradayStocks = screenedSymbolsSorted[:self.maxIntradaySelections]
for stock in self.screenedIntradayStocks:
for stock in self.screenedIntradayStocks:
self.AddSecurity(SecurityType.Equity, stock, Resolution.Minute)
self.AddSecurity(SecurityType.Equity, stock, Resolution.Minute)
self.screenedDailyStocks = []
self.screenedDailyStocks = []
## Screen the given array of stocks for those matching *Daily*
## Screen the given array of stocks for those matching *Daily*
## screening criteria, and return them.
## screening criteria, and return them.
##
##
## Seeds the stock symboldata class with daily history, and then
## Seeds the stock symboldata class with daily history, and then
## calls the class's DailyScreeningCriteriaMet() method, where
## calls the class's DailyScreeningCriteriaMet() method, where
## the actual daily screening logic lives (eg: indicator checks).
## the actual daily screening logic lives (eg: indicator checks).
## --------------------------------------------------------------
## --------------------------------------------------------------
def GetDailyScreenedStocks(self, stocksToScreen):
def GetDailyScreenedStocks(self, stocksToScreen):
複製
已複製
複製
已複製
screenedStocks = []
screenedStocks = []
for stock in stocksToScreen:
for stock in stocksToScreen:
symbol = stock.Symbol
symbol = stock.Symbol
## If we are already invested in this, skip it
## If we are already invested in this, skip it
複製
已複製
複製
已複製
if
(
symbol in self.Portfolio
)
and
(
self.Portfolio[symbol].Invested
)
:
if
symbol in self.Portfolio
and
self.Portfolio[symbol].Invested
:
continue
continue
else:
else:
## Store data for this symbol in our dictionary, seed it with some history
## Store data for this symbol in our dictionary, seed it with some history
if symbol not in self.symDataDict:
if symbol not in self.symDataDict:
self.symDataDict[symbol] = SymbolData(symbol, self)
self.symDataDict[symbol] = SymbolData(symbol, self)
symbolData = self.symDataDict[symbol]
symbolData = self.symDataDict[symbol]
## we need at least 2 values for EMA for our
## we need at least 2 values for EMA for our
## first signal, so we get the required history + 1 day
## first signal, so we get the required history + 1 day
複製
已複製
複製
已複製
dailyHistory = self.History(symbol, self.dailyEMAPeriod
+
1, Resolution.Daily)
dailyHistory = self.History(symbol, self.dailyEMAPeriod
+
1, Resolution.Daily)
## Seed daily indicators so they can be calculated
## Seed daily indicators so they can be calculated
symbolData.SeedDailyIndicators(dailyHistory)
symbolData.SeedDailyIndicators(dailyHistory)
## If the daily screening criteria is met, we return it
## If the daily screening criteria is met, we return it
複製
已複製
複製
已複製
if symbolData.DailyIndicatorsAreReady
():
if symbolData.DailyIndicatorsAreReady
:
if symbolData.DailyScreeningCriteriaMet
()
:
if symbolData.DailyScreeningCriteriaMet
:
screenedStocks.append(symbol)
screenedStocks.append(symbol)
else:
else:
## if the criteria isnt met, we dont need this symboldata
## if the criteria isnt met, we dont need this symboldata
del self.symDataDict[symbol]
del self.symDataDict[symbol]
return screenedStocks
return screenedStocks
## Screen the given array of stocks for those matching *Intraday*
## Screen the given array of stocks for those matching *Intraday*
## screening criteria, and return them.
## screening criteria, and return them.
##
##
## Seeds the stock symboldata class with intraday history, and then
## Seeds the stock symboldata class with intraday history, and then
## calls the class's IntradayScreeningCriteriaMet() method, where
## calls the class's IntradayScreeningCriteriaMet() method, where
## the actual intraday screening logic lives (eg indicator checks).
## the actual intraday screening logic lives (eg indicator checks).
## --------------------------------------------------------------
## --------------------------------------------------------------
def GetIntraDayScreenedStocks(self, stocksToScreen):
def GetIntraDayScreenedStocks(self, stocksToScreen):
複製
已複製
複製
已複製
screenedStockSymbols = []
screenedStockSymbols = []
## loop through stocks and seed their indicators
## loop through stocks and seed their indicators
複製
已複製
複製
已複製
for symbol in stocksToScreen:
for symbol in stocksToScreen:
## If we are already invested in this, skip it
## If we are already invested in this, skip it
複製
已複製
複製
已複製
if
(
symbol in self.Portfolio
)
and
(
self.Portfolio[symbol].Invested
)
:
if
symbol in self.Portfolio
and
self.Portfolio[symbol].Invested
:
continue
continue
else:
else:
複製
已複製
複製
已複製
if
(
symbol in self.symDataDict
)
:
if
symbol in self.symDataDict
:
symbolData = self.symDataDict[symbol]
symbolData = self.symDataDict[symbol]
history = self.History(symbol, self.hourlyMomPeriod, Resolution.Hour)
history = self.History(symbol, self.hourlyMomPeriod, Resolution.Hour)
symbolData.SeedIntradayIndicators(history)
symbolData.SeedIntradayIndicators(history)
複製
已複製
複製
已複製
if
(
symbolData.IntradayIndicatorsAreReady
() )
:
if
(
symbolData.IntradayScreeningCriteriaMet
() )
:
if
symbolData.IntradayIndicatorsAreReady
:
screenedStockSymbols.append(
symbolData.symbol
)
if
symbolData.IntradayScreeningCriteriaMet
:
screenedStockSymbols.append(
symbolData.symbol
)
else:
else:
## if the criteria isnt met, we dont need this symboldata
## if the criteria isnt met, we dont need this symboldata
del self.symDataDict[symbol]
del self.symDataDict[symbol]
else:
else:
self.Log(f"- - - - No symdata for {symbol}")
self.Log(f"- - - - No symdata for {symbol}")
return screenedStockSymbols
return screenedStockSymbols
## Called when we add/remove a security from the algo
## Called when we add/remove a security from the algo
## --------------------------------------------------
## --------------------------------------------------
def OnSecuritiesChanged(self, changes):
def OnSecuritiesChanged(self, changes):
複製
已複製
複製
已複製
## The trade actually takes place here, when the symbol
## The trade actually takes place here, when the symbol
## passes all our screenings, and we call AddSecurity
## passes all our screenings, and we call AddSecurity
複製
已複製
複製
已複製
if
(
not self.PortfolioAtCapacity
())
:
if
not self.PortfolioAtCapacity
:
for security in changes.AddedSecurities:
for security in changes.AddedSecurities:
複製
已複製
複製
已複製
if
(
security.Symbol
!= "SPY"
):
if
security.Symbol
.Value
!= "SPY"
:
# if we havent already queued this position, queue it.
# if we havent already queued this position, queue it.
## we queue it instead of opening the position, because
## we queue it instead of opening the position, because
## we dont yet have data for this symbol. We will get
## we dont yet have data for this symbol. We will get
## data for it in the next call to OnData, where we do
## data for it in the next call to OnData, where we do
## open the position
## open the position
複製
已複製
複製
已複製
if
(
security.Symbol not in self.queuedPositions
)
:
if
security.Symbol not in self.queuedPositions
:
self.queuedPositions.append(security.Symbol)
self.queuedPositions.append(security.Symbol)
for security in changes.RemovedSecurities:
for security in changes.RemovedSecurities:
複製
已複製
複製
已複製
if
(
security.Symbol
!= "SPY"
):
if
security.Symbol
.Value
!= "SPY"
:
if security.Symbol in self.symDataDict:
if security.Symbol in self.symDataDict:
symbol = security.Symbol
symbol = security.Symbol
symbolData = self.symDataDict[symbol]
symbolData = self.symDataDict[symbol]
symbolData.OnPositionClosed()
symbolData.OnPositionClosed()
## remove this sumbol from our local cache
## remove this sumbol from our local cache
del self.symDataDict[symbol]
del self.symDataDict[symbol]
複製
已複製
複製
已複製
self.screenedDailyStocks = [
x for x in self.screenedDailyStocks if x != symbol]
self.screenedDailyStocks = [
x for x in self.screenedDailyStocks if x != symbol]
self.screenedIntradayStocks = [
x for x in self.screenedIntradayStocks if x != symbol]
self.screenedIntradayStocks = [
x for x in self.screenedIntradayStocks if x != symbol]
## Loop through queued positions and open new trades
## Loop through queued positions and open new trades
## -------------------------------------------------
## -------------------------------------------------
def ProcessQueuedPositions(self):
def ProcessQueuedPositions(self):
複製
已複製
複製
已複製
for symbol in
list(
self.queuedPositions
)
:
for symbol in
[*
self.queuedPositions
]
:
if self.CurrentSlice.ContainsKey(symbol) and self.CurrentSlice[symbol] is not None:
if self.CurrentSlice.ContainsKey(symbol) and self.CurrentSlice[symbol] is not None:
複製
已複製
複製
已複製
symbolData = self.symDataDict[symbol]
## extra check to make sure we arent going above capacity
## extra check to make sure we arent going above capacity
複製
已複製
複製
已複製
if
(
not self.PortfolioAtCapacity
()):
if
not self.PortfolioAtCapacity
and symbol in self.symDataDict:
symbolData = self.symDataDict[symbol]
self.SetHoldings(symbol, 1/self.maxOpenPositions, tag=symbolData.OpenPositionMessage)
self.SetHoldings(symbol, 1/self.maxOpenPositions, tag=symbolData.OpenPositionMessage)
symbolData.OnPositionOpened()
symbolData.OnPositionOpened()
self.queuedPositions.remove(symbol)
self.queuedPositions.remove(symbol)
複製
已複製
複製
已複製
已保存差異
原始文本
開啟檔案
Charts Statistics Code ########################################################################## # Scheduled Intraday Universe Screening # --------------------------------------------- # FOR EDUCATIONAL PURPOSES ONLY. DO NOT DEPLOY. # # Entry: # ------ # Daily: At midnight, screen for stocks trading above daily EMA # Intraday: In the afternoon, screen those daily stocks for postive momentum # Open positions for the top 'X' stocks with highest positive momentum # # Exit: # ----- # Exit when price falls below EMA. # Optionally: exit at End of day if EoDExit flag is set. # # ................................................................ # Copyright(c) 2021 Quantish.io - Granted to the public domain # Do not remove this copyright notice | info@quantish.io ######################################################################### from SymbolData import * class EMAMOMUniverse(QCAlgorithm): def Initialize(self): self.InitBacktestParams() self.InitAssets() self.InitAlgoParams() self.InitUniverse() self.ScheduleRoutines() def InitBacktestParams(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) def InitAssets(self): self.AddEquity("SPY", Resolution.Hour) # benchmark self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))) def InitAlgoParams(self): self.dailyEMAPeriod = 10 self.hourlyMomPeriod = 4 self.minsAfterOpen = 300 self.useEoDExit = 0 self.maxCoarseSelections = 30 self.maxFineSelections = 10 self.maxIntradaySelections = 5 self.maxOpenPositions = 5 def InitUniverse(self): ## Init universe configuration, selectors self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.CoarseUniverseSelection, self.FineUniverseSelection) self.EnableAutomaticIndicatorWarmUp = True ## Init vars for tracking universe state self.symDataDict = { } self.screenedDailyStocks = [] self.screenedIntradayStocks = [] self.queuedPositions = [] ## Schedule screening and liquidation routines, as needed. ## ------------------------------------------------------- def ScheduleRoutines(self): ## Intraday selection self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", self.minsAfterOpen), self.IntraDaySelection) ## End of Day Liquidation if(self.useEoDExit): self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 2), self.LiquidateAtEoD) ## ---------------------- def LiquidateAtEoD(self): self.Liquidate(tag="EoD liquidatation") ## Process our queued positions, check for exits for held positions ## ---------------------------------------------------------------- def OnData(self, dataSlice): self.ProcessQueuedPositions() for symbol in dataSlice.Keys: if symbol in self.symDataDict: symbolData = self.symDataDict[symbol] if( (symbol in dataSlice) and (dataSlice[symbol] is not None)): symbolData.lastClosePrice = dataSlice[symbol].Close if( symbolData.ExitCriteriaMet() ): self.Liquidate(symbol, tag=symbolData.ClosePositionMessage) # del self.symDataDict[symbol] self.RemoveSecurity(symbol) ## Check if we are already holding the max # of open positions. ## ------------------------------------------------------------ def PortfolioAtCapacity(self): numHoldings = len([x.Key for x in self.Portfolio if x.Value.Invested]) return ( numHoldings >= self.maxOpenPositions ) ## Coarse universe selection. Replace with your own universe filters. ## ------------------------------------------------------------------ def CoarseUniverseSelection(self, universe): if (self.PortfolioAtCapacity()): return [] else: coarseuniverse = sorted(universe, key=lambda c: c.DollarVolume, reverse=True) coarseuniverse = [c for c in coarseuniverse if c.Price > 50][:self.maxCoarseSelections] return [x.Symbol for x in coarseuniverse] ## Fine universe selection. Replace with your own universe filters. ## ---------------------------------------------------------------- def FineUniverseSelection(self, universe): if (self.PortfolioAtCapacity()): return [] else: fineUniverse = [x for x in universe if x.SecurityReference.IsPrimaryShare and x.SecurityReference.SecurityType == "ST00000001" and x.SecurityReference.IsDepositaryReceipt == 0 and x.CompanyReference.IsLimitedPartnership == 0] ## Fetch the stocks that match our daily screening criteria screenedStocks = self.GetDailyScreenedStocks(fineUniverse) self.screenedDailyStocks = screenedStocks[:self.maxFineSelections] ## NOTE: ## If you plan to do intraday selection, then ## return a blank array otherwise, comment out this line ## ........................................................... return [] ## NOTE: ## If there is no need for intraday selection, then ## uncomment the below line to return daily screened stocks ## ........................................................... ## return self.screenedDailyStocks ## Intraday universe selection. Replace with your own Criteria. ## ------------------------------------------------------------ def IntraDaySelection(self): if (not self.PortfolioAtCapacity()): ## Fetch the stocks that meet intraday screening criteria screenedStocks = self.GetIntraDayScreenedStocks(self.screenedDailyStocks) ## Get the symboldata for the screened stocks, and rank by momentum screenedStockData = [ self.symDataDict[symbol] for symbol in screenedStocks] screenedDataSorted = sorted(screenedStockData, key=lambda x: x.momentum, reverse=True) screenedSymbolsSorted = [ stockData.symbol for stockData in screenedDataSorted ] self.screenedIntradayStocks = screenedSymbolsSorted[:self.maxIntradaySelections] for stock in self.screenedIntradayStocks: self.AddSecurity(SecurityType.Equity, stock, Resolution.Minute) self.screenedDailyStocks = [] ## Screen the given array of stocks for those matching *Daily* ## screening criteria, and return them. ## ## Seeds the stock symboldata class with daily history, and then ## calls the class's DailyScreeningCriteriaMet() method, where ## the actual daily screening logic lives (eg: indicator checks). ## -------------------------------------------------------------- def GetDailyScreenedStocks(self, stocksToScreen): screenedStocks = [] for stock in stocksToScreen: symbol = stock.Symbol ## If we are already invested in this, skip it if (symbol in self.Portfolio) and (self.Portfolio[symbol].Invested): continue else: ## Store data for this symbol in our dictionary, seed it with some history if symbol not in self.symDataDict: self.symDataDict[symbol] = SymbolData(symbol, self) symbolData = self.symDataDict[symbol] ## we need at least 2 values for EMA for our ## first signal, so we get the required history + 1 day dailyHistory = self.History(symbol, self.dailyEMAPeriod+1, Resolution.Daily) ## Seed daily indicators so they can be calculated symbolData.SeedDailyIndicators(dailyHistory) ## If the daily screening criteria is met, we return it if symbolData.DailyIndicatorsAreReady(): if symbolData.DailyScreeningCriteriaMet(): screenedStocks.append(symbol) else: ## if the criteria isnt met, we dont need this symboldata del self.symDataDict[symbol] return screenedStocks ## Screen the given array of stocks for those matching *Intraday* ## screening criteria, and return them. ## ## Seeds the stock symboldata class with intraday history, and then ## calls the class's IntradayScreeningCriteriaMet() method, where ## the actual intraday screening logic lives (eg indicator checks). ## -------------------------------------------------------------- def GetIntraDayScreenedStocks(self, stocksToScreen): screenedStockSymbols = [] ## loop through stocks and seed their indicators for symbol in stocksToScreen: ## If we are already invested in this, skip it if (symbol in self.Portfolio) and (self.Portfolio[symbol].Invested): continue else: if( symbol in self.symDataDict ): symbolData = self.symDataDict[symbol] history = self.History(symbol, self.hourlyMomPeriod, Resolution.Hour) symbolData.SeedIntradayIndicators(history) if( symbolData.IntradayIndicatorsAreReady() ): if ( symbolData.IntradayScreeningCriteriaMet() ): screenedStockSymbols.append( symbolData.symbol ) else: ## if the criteria isnt met, we dont need this symboldata del self.symDataDict[symbol] else: self.Log(f"- - - - No symdata for {symbol}") return screenedStockSymbols ## Called when we add/remove a security from the algo ## -------------------------------------------------- def OnSecuritiesChanged(self, changes): ## The trade actually takes place here, when the symbol ## passes all our screenings, and we call AddSecurity if (not self.PortfolioAtCapacity()): for security in changes.AddedSecurities: if(security.Symbol != "SPY"): # if we havent already queued this position, queue it. ## we queue it instead of opening the position, because ## we dont yet have data for this symbol. We will get ## data for it in the next call to OnData, where we do ## open the position if( security.Symbol not in self.queuedPositions ): self.queuedPositions.append(security.Symbol) for security in changes.RemovedSecurities: if(security.Symbol != "SPY"): if security.Symbol in self.symDataDict: symbol = security.Symbol symbolData = self.symDataDict[symbol] symbolData.OnPositionClosed() ## remove this sumbol from our local cache del self.symDataDict[symbol] self.screenedDailyStocks = [ x for x in self.screenedDailyStocks if x != symbol] self.screenedIntradayStocks = [ x for x in self.screenedIntradayStocks if x != symbol] ## Loop through queued positions and open new trades ## ------------------------------------------------- def ProcessQueuedPositions(self): for symbol in list(self.queuedPositions): if self.CurrentSlice.ContainsKey(symbol) and self.CurrentSlice[symbol] is not None: symbolData = self.symDataDict[symbol] ## extra check to make sure we arent going above capacity if(not self.PortfolioAtCapacity()): self.SetHoldings(symbol, 1/self.maxOpenPositions, tag=symbolData.OpenPositionMessage) symbolData.OnPositionOpened() self.queuedPositions.remove(symbol)
更改後文本
開啟檔案
########################################################################## # Scheduled Intraday Universe Screening # --------------------------------------------- # FOR EDUCATIONAL PURPOSES ONLY. DO NOT DEPLOY. # # Entry: # ------ # Daily: At midnight, screen for stocks trading above daily EMA # Intraday: In the afternoon, screen those daily stocks for postive momentum # Open positions for the top 'X' stocks with highest positive momentum # # Exit: # ----- # Exit when price falls below EMA. # Optionally: exit at End of day if EoDExit flag is set. # # ................................................................ # Copyright(c) 2021 Quantish.io - Granted to the public domain # Do not remove this copyright notice | info@quantish.io ######################################################################### from SymbolData import * class EMAMOMUniverse(QCAlgorithm): def Initialize(self): self.InitBacktestParams() self.InitAssets() self.InitAlgoParams() self.InitUniverse() self.ScheduleRoutines() def InitBacktestParams(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) def InitAssets(self): self.AddEquity("SPY", Resolution.Hour) # benchmark self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))) def InitAlgoParams(self): self.dailyEMAPeriod = 10 self.hourlyMomPeriod = 4 self.minsAfterOpen = 300 self.useEoDExit = False self.maxCoarseSelections = 30 self.minAssetPrice = 50.0 self.maxFineSelections = 10 self.maxIntradaySelections = 5 self.maxOpenPositions = 5 def InitUniverse(self): ## Init universe configuration, selectors self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.CoarseUniverseSelection, self.FineUniverseSelection) self.EnableAutomaticIndicatorWarmUp = True ## Init vars for tracking universe state self.symDataDict = { } self.screenedDailyStocks = [] self.screenedIntradayStocks = [] self.queuedPositions = [] ## Schedule screening and liquidation routines, as needed. ## ------------------------------------------------------- def ScheduleRoutines(self): ## Intraday selection self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", self.minsAfterOpen), self.IntraDaySelection) ## End of Day Liquidation if(self.useEoDExit): self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 2), self.LiquidateAtEoD) ## ---------------------- def LiquidateAtEoD(self): self.Liquidate(tag="EoD liquidation") ## Process our queued positions, check for exits for held positions ## ---------------------------------------------------------------- def OnData(self, dataSlice): self.ProcessQueuedPositions() for symbol in dataSlice.Keys: if symbol in self.symDataDict: symbolData = self.symDataDict[symbol] if dataSlice[symbol] is not None: symbolData.lastClosePrice = dataSlice[symbol].Close if symbolData.ExitCriteriaMet: self.Liquidate(symbol, tag=symbolData.ClosePositionMessage) self.RemoveSecurity(symbol) ## Check if we are already holding the max # of open positions. ## ------------------------------------------------------------ @property def PortfolioAtCapacity(self): numHoldings = len([x.Key for x in self.Portfolio if x.Value.Invested]) return numHoldings >= self.maxOpenPositions ## Coarse universe selection. Replace with your own universe filters. ## ------------------------------------------------------------------ def CoarseUniverseSelection(self, universe): if self.PortfolioAtCapacity: return [] else: coarseuniverse = sorted(universe, key=lambda c: c.DollarVolume, reverse=True) coarseuniverse = [c for c in coarseuniverse if c.Price >= self.minAssetPrice][:self.maxCoarseSelections] return [x.Symbol for x in coarseuniverse] ## Fine universe selection. Replace with your own universe filters. ## ---------------------------------------------------------------- def FineUniverseSelection(self, universe): if self.PortfolioAtCapacity: return [] else: # Modify this to fit your criteria fineUniverse = [x for x in universe if x.SecurityReference.IsPrimaryShare and x.SecurityReference.SecurityType == "ST00000001" and x.SecurityReference.IsDepositaryReceipt == 0 and x.CompanyReference.IsLimitedPartnership == 0] ## Fetch the stocks that match our daily screening criteria screenedStocks = self.GetDailyScreenedStocks(fineUniverse) self.screenedDailyStocks = screenedStocks[:self.maxFineSelections] ## NOTE: ## If you plan to do intraday selection, then ## return a blank array otherwise, comment out this line ## ........................................................... return [] ## NOTE: ## If there is no need for intraday selection, then ## uncomment the below line to return daily screened stocks ## ........................................................... ## return self.screenedDailyStocks ## Intraday universe selection. Replace with your own Criteria. ## ------------------------------------------------------------ def IntraDaySelection(self): if not self.PortfolioAtCapacity: ## Fetch the stocks that meet intraday screening criteria screenedStocks = self.GetIntraDayScreenedStocks(self.screenedDailyStocks) ## Get the symboldata for the screened stocks, and rank by momentum screenedStockData = [self.symDataDict[symbol] for symbol in screenedStocks] screenedDataSorted = sorted(screenedStockData, key=lambda x: x.momentum, reverse=True) screenedSymbolsSorted = [stockData.symbol for stockData in screenedDataSorted] self.screenedIntradayStocks = screenedSymbolsSorted[:self.maxIntradaySelections] for stock in self.screenedIntradayStocks: self.AddSecurity(SecurityType.Equity, stock, Resolution.Minute) self.screenedDailyStocks = [] ## Screen the given array of stocks for those matching *Daily* ## screening criteria, and return them. ## ## Seeds the stock symboldata class with daily history, and then ## calls the class's DailyScreeningCriteriaMet() method, where ## the actual daily screening logic lives (eg: indicator checks). ## -------------------------------------------------------------- def GetDailyScreenedStocks(self, stocksToScreen): screenedStocks = [] for stock in stocksToScreen: symbol = stock.Symbol ## If we are already invested in this, skip it if symbol in self.Portfolio and self.Portfolio[symbol].Invested: continue else: ## Store data for this symbol in our dictionary, seed it with some history if symbol not in self.symDataDict: self.symDataDict[symbol] = SymbolData(symbol, self) symbolData = self.symDataDict[symbol] ## we need at least 2 values for EMA for our ## first signal, so we get the required history + 1 day dailyHistory = self.History(symbol, self.dailyEMAPeriod + 1, Resolution.Daily) ## Seed daily indicators so they can be calculated symbolData.SeedDailyIndicators(dailyHistory) ## If the daily screening criteria is met, we return it if symbolData.DailyIndicatorsAreReady: if symbolData.DailyScreeningCriteriaMet: screenedStocks.append(symbol) else: ## if the criteria isnt met, we dont need this symboldata del self.symDataDict[symbol] return screenedStocks ## Screen the given array of stocks for those matching *Intraday* ## screening criteria, and return them. ## ## Seeds the stock symboldata class with intraday history, and then ## calls the class's IntradayScreeningCriteriaMet() method, where ## the actual intraday screening logic lives (eg indicator checks). ## -------------------------------------------------------------- def GetIntraDayScreenedStocks(self, stocksToScreen): screenedStockSymbols = [] ## loop through stocks and seed their indicators for symbol in stocksToScreen: ## If we are already invested in this, skip it if symbol in self.Portfolio and self.Portfolio[symbol].Invested: continue else: if symbol in self.symDataDict: symbolData = self.symDataDict[symbol] history = self.History(symbol, self.hourlyMomPeriod, Resolution.Hour) symbolData.SeedIntradayIndicators(history) if symbolData.IntradayIndicatorsAreReady: if symbolData.IntradayScreeningCriteriaMet: screenedStockSymbols.append(symbolData.symbol) else: ## if the criteria isnt met, we dont need this symboldata del self.symDataDict[symbol] else: self.Log(f"- - - - No symdata for {symbol}") return screenedStockSymbols ## Called when we add/remove a security from the algo ## -------------------------------------------------- def OnSecuritiesChanged(self, changes): ## The trade actually takes place here, when the symbol ## passes all our screenings, and we call AddSecurity if not self.PortfolioAtCapacity: for security in changes.AddedSecurities: if security.Symbol.Value != "SPY": # if we havent already queued this position, queue it. ## we queue it instead of opening the position, because ## we dont yet have data for this symbol. We will get ## data for it in the next call to OnData, where we do ## open the position if security.Symbol not in self.queuedPositions: self.queuedPositions.append(security.Symbol) for security in changes.RemovedSecurities: if security.Symbol.Value != "SPY": if security.Symbol in self.symDataDict: symbol = security.Symbol symbolData = self.symDataDict[symbol] symbolData.OnPositionClosed() ## remove this sumbol from our local cache del self.symDataDict[symbol] self.screenedDailyStocks = [x for x in self.screenedDailyStocks if x != symbol] self.screenedIntradayStocks = [x for x in self.screenedIntradayStocks if x != symbol] ## Loop through queued positions and open new trades ## ------------------------------------------------- def ProcessQueuedPositions(self): for symbol in [*self.queuedPositions]: if self.CurrentSlice.ContainsKey(symbol) and self.CurrentSlice[symbol] is not None: ## extra check to make sure we arent going above capacity if not self.PortfolioAtCapacity and symbol in self.symDataDict: symbolData = self.symDataDict[symbol] self.SetHoldings(symbol, 1/self.maxOpenPositions, tag=symbolData.OpenPositionMessage) symbolData.OnPositionOpened() self.queuedPositions.remove(symbol)
尋找差異