| Overall Statistics |
|
Total Trades 1128 Average Win 1.11% Average Loss -0.62% Compounding Annual Return 173.305% Drawdown 17.400% Expectancy 0.321 Net Profit 196.849% Sharpe Ratio 3.976 Probabilistic Sharpe Ratio 95.385% Loss Rate 53% Win Rate 47% Profit-Loss Ratio 1.79 Alpha 1.195 Beta 1.318 Annual Standard Deviation 0.365 Annual Variance 0.133 Information Ratio 3.893 Tracking Error 0.323 Treynor Ratio 1.102 Total Fees $0.00 Estimated Strategy Capacity $52000.00 Lowest Capacity Asset KVSB XMWYVA1XG4MD |
import pandas as pd
from io import StringIO
class CathieWoods1YearBacktest1Kcapital(QCAlgorithm):
def Initialize(self):
#BackTest start date one year
self.SetStartDate(2020, 9, 1)
# Target market
self.SetCash(100000)
#Universe selection
self.AddUniverse(self.Coarse)
#using Hourly resolution for more data points.
self.UniverseSettings.Resolution = Resolution.Hour
self.run = False
self.tickers = []
self.tickers_value = []
self.tickers_list = []
self.date_list = []
self.direction_list = []
self.buying_stocks = []
self.invested_stocks = []
self.is_downloaded = False
#Run everyday at midnight to scrape the daily updates
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.At(0, 0),
self.DownloadTickers)
# Set Fee Model to No trading fees to mimic new fee model
self.SetSecurityInitializer(lambda x: x.SetFeeModel(ConstantFeeModel(0)))
def DownloadTickers(self):
#Reset
self.run = False
self.buying_stocks = []
self.invested_stocks = []
#Check if downloaded
if self.is_downloaded == False:
csv = self.Download("https://www.dropbox.com/s/sqjb76w2faer76l/Trade_Log.csv?dl=1")
df = pd.read_csv(StringIO(csv))
self.tickers_list = df["Ticker"].to_list()
self.date_list = df["Date"].to_list()
self.direction_list = df["Direction"].to_list()
self.is_downloaded = True
#once downloaded mark as downloaded
def Coarse(self, coarse):
filtered = [x for x in coarse if x.Symbol.Value in self.tickers_list and x.HasFundamentalData]
return [x.Symbol for x in filtered]
# Filter for stocks in the universe
def OnSecuritiesChanged(self, changes):
for stock in changes.RemovedSecurities:
pass
history = self.History([stock.Symbol for stock in changes.AddedSecurities], 50, Resolution.Hour)
for stock in changes.AddedSecurities:
symbol = stock.Symbol
if symbol in history.index:
self.tickers.append(symbol)
self.tickers_value.append(symbol.Value)
# make list of symbols and value
def OnData(self, data):
#Reset invested stocks list
self.invested_stocks = []
#Check order fills
for kvp in self.Portfolio:
security_holding = kvp.Value
if security_holding.Invested:
symbol = security_holding.Symbol
self.invested_stocks.append(symbol.Value)
average_price = security_holding.AveragePrice
current_price = self.Securities[symbol].Price
change = current_price / average_price
#Check if invested stock's current price greater than or less than average price by 10% 0r 5%, if so, sell
if change > 1.1 or change < 0.95:
self.Liquidate(symbol)
#Check if logic ran today
if self.run == False:
today_date = (str(self.Time.month) + "/" + str(self.Time.day) + "/" + str(self.Time.year))
for i in range(len(self.date_list)):
if self.date_list[i] == today_date:
ticker = self.tickers_list[i]
direction = self.direction_list[i]
if ticker in self.tickers_value:
index = self.tickers_value.index(ticker)
if direction == "Buy" and ticker not in self.buying_stocks and ticker not in self.invested_stocks:
# if self.Portfolio.Cash > 1000:
self.SetHoldings(str(self.tickers[index]), 0.1)
self.buying_stocks.append(ticker)
# Code is front heavy, not true reflection of strategy
# set entry_price. Not yet code. If need to code, for change of strategy will change data.Pls ignore.
#Only run logic once per day
self.run = True