| 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 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
class WeeklyScreener(QCAlgorithm):
MAX_INVESTED_SYMBOLS = 10
TAKE_PROFIT_PERCENTAGE = 0.05
STOP_LOSS_PERCENTAGE = 0.02
Symbols_To_Protect = dict()
averages = dict()
def Initialize(self):
self.SetStartDate(2019, 2, 21) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
# At each end of week, liquidate
self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.At(15, 45), Action(self.Liquidate))
def OnData(self, data):
all_symbols = [ x.Value for x in self.Securities.Keys ]
invested_symbols = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ]
self.Debug("ALL SYMBOLS: " + str(all_symbols))
self.Debug("INVESTED SYMBOLS: " + str(invested_symbols))
# If portfolio already full, return
if len(invested_symbols) == self.MAX_INVESTED_SYMBOLS: return
# Else get diff between all and invested
new_symbols = list(set(all_symbols)-set(invested_symbols))
# If no new symbols, return
if len(new_symbols) == 0: return
# Add new positions
for symbol in new_symbols:
# if data.ContainsKey(symbol) is False: continue
# if data[symbol] is None: continue
# # TODO: If day > wednesday, return
# if data[symbol].Time > 3: return
# BUY
self.SetHoldings(symbol, 1/self.MAX_INVESTED_SYMBOLS)
# Handle risk management in OnOrderEvent
self.Symbols_To_Protect[symbol] = True
# Creates stop losses and take profits for opened long orders
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
# If it's an order to protect and that it's filled
if self.Symbols_To_Protect.get(order.Symbol.Value, None) is not None and orderEvent.Status == OrderStatus.Filled:
# Remove order from dict
del self.Symbols_To_Protect[order.Symbol.Value]
# SET TAKE PROFIT
take_profit_price = order.Price * (1 + self.TAKE_PROFIT_PERCENTAGE)
self.StopMarketOrder(order.Symbol, -order.QuantityFilled, take_profit_price)
# SET STOP LOSS
stop_loss_price = order.Price * (1 - self.STOP_LOSS_PERCENTAGE)
self.StopMarketOrder(order.Symbol, -order.QuantityFilled, stop_loss_price)
# this event fires whenever we have changes to our universe
def OnSecuritiesChanged(self, changes):
self.Debug("Universe change event Added: " + str([s.Symbol.Value for s in changes.AddedSecurities]))
def CoarseSelectionFunction(self, coarse):
# We are going to use a dictionary to refer the object that will keep the moving averages
for cf in coarse:
if cf.Symbol not in self.averages:
self.averages[cf.Symbol] = SymbolData(cf.Symbol, self)
# Updates the SymbolData object with price and volume
avg = self.averages[cf.Symbol]
avg.update(cf.EndTime, cf.Price, cf.Volume)
# Filter the values of the dict: we only want up-trending securities
values = list(filter(lambda x: x.is_uptrend, self.averages.values()))
selected_symbols = [ x.symbol for x in values[:self.MAX_INVESTED_SYMBOLS] ]
return selected_symbols
def FineSelectionFunction(self, fine):
selected_symbols = [f.Symbol for f in fine]
# self.Debug(str([s.Value for s in selected_symbols]))
return selected_symbols
class SymbolData:
def __init__(self, symbol, algo):
self.algo = algo
self.symbol = symbol
self.priceEMA = ExponentialMovingAverage(10)
self.volEMA = ExponentialMovingAverage(10)
self.rsi = RelativeStrengthIndex(14)
self.macd = MovingAverageConvergenceDivergence(12,26,9)
self.priceWin = RollingWindow[float](10)
self.is_uptrend = False
def update(self, time, price, volume):
self.priceWin.Add(price)
self.priceEMA.Update(time, price)
self.volEMA.Update(time, volume)
self.rsi.Update(time, price)
self.macd.Update(time, price)
if self.rsi.IsReady and self.macd.IsReady and self.priceWin.IsReady:
rsi = self.rsi.Current.Value
signal = self.macd.Signal.Current.Value
macd = self.macd.Current.Value
self.is_uptrend = rsi < 60 and rsi > 40 and (signal > macd) and price > self.priceWin[1]
# if self.is_uptrend:
# self.algo.Debug("---- IS UPTREND ---- " + self.symbol.Value + ": RSI=" + str(rsi) + " MACD=" + str(macd) + " SIGNAL=" + str(signal))
# if self.priceEMA.IsReady and self.volEMA.IsReady and self.priceWin.IsReady:
# EMAprice = self.priceEMA.Current.Value
# EMAvol = self.volEMA.Current.Value
# # current price > 10-days moving average price
# # current volume > 10-days moving average volume
# # current price > yesterday's close
# # current price > 10-days maximum price
# self.is_uptrend = price > EMAprice and volume > EMAvol and price > self.priceWin[1] and price > max(self.priceWin)