| Overall Statistics |
|
Total Trades 3 Average Win 0.01% Average Loss 0% Compounding Annual Return 1.191% Drawdown 0.000% Expectancy 0 Net Profit 0.019% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -16.794 Tracking Error 0.059 Treynor Ratio 0 Total Fees $9.75 |
import pandas as pd
#https://www.quantconnect.com/forum/discussion/7867/tim-sykes-and-penny-stocks/p1
class CalibratedUncoupledCoreWave(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 5, 1) # Set Start Date
#self.SetEndDate(2020, 3, 11) # Set End Date
self.SetCash(100000) # Set Strategy Cash
# Setup universe
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.SelectCoarse,self.SelectFine)
self.AddEquity("SPY", Resolution.Minute)
# Liquidate all positions before the market close each day
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 30), self.ClosePositions)
self.coarseclose={} # Store yesterday's close in a dictionary for reference
self.volumeprior = {} # Last x days' average dollar volume
self.stddev={} # Standard Deviation
self.minmax={} # Ratio of Hi Lo of last x days' close price
self.cumvol={} # Cumulative volume throughout trading day
self.traded={} # Ensure only 1 trade per day per stock
self.targetentry=1.05 # Only enter a trade if today's price doubles yesterday's close
self.stops = {} # Keep track of stop loss orders so we can update them
#self.coarsefilter = 50 # return the top x stocks sorted by [momentum] etc
self.histlength = 60 # lngth of history to call to ensure sufficient data
def SelectCoarse(self, coarse):
# Penny Stock filter
myuniverse = [x for x in coarse if x.HasFundamentalData and \
x.DollarVolume > 1000 and \
x.DollarVolume < 50000 and \
x.Price > 0 and x.Price <= 2.0]
self.coarseclose.clear() # Clear the dictionary each day before re-populating it
self.volumeprior.clear()
self.stddev.clear()
self.minmax.clear()
stocks = {x.Symbol: x for x in myuniverse}
histStocks=list(stocks.keys())
history = self.History(histStocks, self.histlength, Resolution.Daily)
scam={}
for stock in histStocks:
if stock in history.index:
df = pd.DataFrame()
if not history.loc[stock].empty:
df = history.loc[stock].dropna()
if df.empty or len(df)<self.histlength:
continue
# Some alternative filters
self.volumeprior[stock] = df['volume'][-5:].mean()
self.stddev[stock]=((df["close"][-5:].pct_change()).std())*15.87*100
self.minmax[stock]=((df["close"][-10:].max()/df["close"][-10:].min())-1)*100
if self.minmax[stock] < 10.00 and self.volumeprior[stock]< 50000 :
scam[stock]= self.minmax[stock]
#scammed=[key for (key, value) in sorted(scam.items(),reverse=False)]
scammed=[key for (key, value) in scam.items()]
# Save yesterday's close
for c in myuniverse:
self.coarseclose[c.Symbol] = c.AdjustedPrice
return scammed[:] # Return filtered stocks for further filtering by the SelectFine
def SelectFine(self,fine):
'''
This function takes the stock of the CoarceFundamental function and narrow the list adding specific fundamental filters
Largely to ensure that only common stock is traded and not EG Preference Shares or ETFs
'''
# Primary share, common stock, not limited partnership, and not ADR
fine_filter = [x.Symbol for x in fine if x.SecurityReference.IsPrimaryShare == 1 and \
x.SecurityReference.SecurityType == 'ST00000001' and \
x.CompanyReference.IsLimitedPartnership == 0 and \
x.SecurityReference.IsDepositaryReceipt == 0 ]
self.traded.clear()
self.traded = {k: 0 for k in fine_filter}
self.cumvol.clear()
self.cumvol = {k: 0 for k in fine_filter}
return fine_filter
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
for kvp in data.Bars:
symbol = kvp.Key
close = kvp.Value.Close
if symbol in self.cumvol.keys():
self.cumvol[symbol]=self.cumvol[symbol]+(kvp.Value.Close*kvp.Value.Volume)
# Entry conditions:
# - We have no position in this stock
# - We haven't traded this symbol today
# - Bar closed above our target
# - Before 10:30am
# - Cumulative Volume for the day exceeds average total dollar volume for past x days
if (self.Portfolio[symbol].Quantity == 0.0 and
symbol in self.traded.keys() and
self.traded[symbol] == 0 and
close >= self.coarseclose[symbol]*self.targetentry and
self.Time.hour <= 10 and self.Time.minute <=30 and
self.cumvol[symbol] >= self.volumeprior[symbol]):
# Signal today's entry
self.traded[symbol] = 1
# Determine position size
quantity = int(self.Portfolio.TotalPortfolioValue / 100 / data[symbol].Close) #self.CalculateOrderQuantity(symbol, 0.01) // 2
if quantity < 4:
continue
# Enter with market order
enter_ticket = self.MarketOrder(symbol, quantity)
# Set profit targets
quarter = int(quantity / 4)
final = quantity - 3 * quarter
for i in range(3):
order = self.LimitOrder(symbol, -quarter, enter_ticket.AverageFillPrice * (1 + (i+1)*0.05))
updateSettings = UpdateOrderFields()
updateSettings.Tag = "pt"
order.Update(updateSettings)
order = self.LimitOrder(symbol, -final, enter_ticket.AverageFillPrice * 1.20)
order.Update(updateSettings)
# Set stop loss
self.stops[symbol] = self.StopMarketOrder(symbol, -quantity, enter_ticket.AverageFillPrice * 0.50)
updateSettings.Tag = "sl"
self.stops[symbol].Update(updateSettings)
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled:
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if order.Tag == 'pt': # If hit profit target, update stop order quantity
updateSettings = UpdateOrderFields()
updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
self.stops[orderEvent.Symbol].Update(updateSettings)
elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
def ClosePositions(self):
if self.Portfolio.Invested:
self.Transactions.CancelOpenOrders()
self.Liquidate()