| Overall Statistics |
|
Total Trades 16 Average Win 0% Average Loss -0.03% Compounding Annual Return -4.079% Drawdown 0.200% Expectancy -1 Net Profit -0.217% Sharpe Ratio -11.326 Probabilistic Sharpe Ratio 0% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.025 Beta -0.006 Annual Standard Deviation 0.003 Annual Variance 0 Information Ratio -9.117 Tracking Error 0.095 Treynor Ratio 5.282 Total Fees $0.00 Estimated Strategy Capacity $630000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 8.54% |
# region imports
from AlgorithmImports import *
import datetime
from datetime import timedelta
# endregion
class Yahoodata(QCAlgorithm):
def Initialize(self):
# Locally Lean installs free sample data, to download more data please visit https://www.quantconnect.com/docs/v2/lean-cli/datasets/downloading-data
self.SetStartDate(2023, 7, 1) # Set Start Date
self.SetEndDate(2023, 7, 19) # Set End Date
self.SetCash(100000) # Set Strategy Cash
self.SetBenchmark("QQQ")
self.symbol = self.AddEquity(
"QQQ",
Resolution.Minute,
extendedMarketHours=True,
dataNormalizationMode=DataNormalizationMode.Raw,
).Symbol
security = self.AddEquity("QQQ", Resolution.Daily, dataNormalizationMode=DataNormalizationMode.Raw)
security.SetFillModel(EquityFillModel())
self.SetWarmUp(timedelta(weeks=5))
self.SetBrokerageModel(BrokerageName.TDAmeritrade, AccountType.Cash)
self.sma5_week = SimpleMovingAverage(5)
self.sma5_day = SimpleMovingAverage(5)
self.sma5_15m = SimpleMovingAverage(5)
self.consolidator = TradeBarConsolidator(Calendar.Weekly)
self.consolidator.DataConsolidated += self.OnWeeklyData
self.Consolidate(self.symbol, timedelta(minutes=15), self.OnFifteenMinuteData)
self.quantity = 0
self.max_shot_num = 1
self.today_shot_num = 0
self.today_open_order = False
self.today_stop_order = None
self.dailyBars = {}
self.last_week_close = None
self.last_week_sma5 = None
self.last_day_close = None
self.last_day_sma5 = None
self.window = RollingWindow[TradeBar](4)
self.last_15m_sma5 = 0
self.this_week_long = False
self.this_week_short = False
self.today_long = False
self.fourhour_long = False
self.fourhour_color = None
def OnWeeklyData(self, sender, tradeBar):
self.last_week_close = tradeBar.Close
self.sma5_week.Update(tradeBar.EndTime, tradeBar.Close)
if self.sma5_week.IsReady:
self.last_week_sma5 = self.sma5_week.Current.Value
if self.last_week_close >= self.last_week_sma5:
self.this_week_long = True
else:
self.this_week_long = False
def OnDailyData(self, tradeBar):
self.last_day_close = tradeBar.Close
self.sma5_day.Update(tradeBar.EndTime, tradeBar.Close)
if self.sma5_day.IsReady:
self.last_day_sma5 = self.sma5_day.Current.Value
if tradeBar.Close > tradeBar.Open and self.last_day_close >= self.last_day_sma5:
self.today_long = True
else:
self.today_long = False
def OnFifteenMinuteData(self, tradeBar):
self.last_15m_close = tradeBar.Close
self.last_15m_low = tradeBar.Low
self.sma5_15m.Update(tradeBar.EndTime, tradeBar.Close)
if self.sma5_15m.IsReady:
self.last_15m_sma5 = self.sma5_15m.Current.Value
def OnWarmupFinished(self) -> None:
self.quantity = self.CalculateOrderQuantity("QQQ", 0.1)
self.Log(f"********* Warm up Finished and one shot quantity: {self.quantity} **********")
def OnOrderEvent(self, orderEvent: OrderEvent) -> None:
order_tickets = self.Transactions.GetOrderTickets().ToList()
open_order_tickets = self.Transactions.GetOpenOrderTickets().ToList()
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if orderEvent.Status == OrderStatus.Filled:
if order.Type == 2:
self.Log(f"OnOrderEvent {self.Time}: {order.Type}: StopPrice:{orderEvent.StopPrice}")
else:
self.Log(f"OnOrderEvent {self.Time}: {order.Type}: FillPrice:{orderEvent.FillPrice}")
def OnEndOfDay(self, symbol):
# reset
self.today_shot_num = 0
self.today_open_order = False
self.today_stop_order = None
self.today_long = False
def OnData(self, data: Slice):
"""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
"""
# last trading day 00:00:00 receive daily data.
# this week first trading day pre market opened, emit a weekly bar.
if self.Time.time() == datetime.time(4, 1, 0):
self.consolidator.Scan(self.Time)
# 00:00:00 receive daily data and update weekly consolidator
if self.Time.time() == datetime.time(0, 0, 0) and data.Bars.ContainsKey(self.symbol):
dailybar = data.Bars[self.symbol]
self.OnDailyData(dailybar)
self.consolidator.Update(dailybar)
# In OnData: Don't run if the indicators aren't ready
if self.IsWarmingUp:
return
if self.IsMarketOpen(self.symbol):
assert self.sma5_15m.IsReady
if self.today_stop_order != None:
# if today stop order filled
# not filled then return
if self.today_stop_order.Status == 3:
self.today_stop_order = None
else:
return
# reach max shot num, stop make order
if self.today_shot_num >= self.max_shot_num:
return
if self.this_week_long:
# check is able to buy
quantity = self.CalculateOrderQuantity("QQQ", 1)
if quantity > self.quantity:
# if self.today_long and self.fourhour_long and self.Time.time() >= datetime.time(9, 45, 0):
if self.today_long and self.Time.time() >= datetime.time(9, 45, 0):
# check is a buy point
if self.last_15m_close > self.last_15m_sma5:
orderticket = self.MarketOrder("QQQ", self.quantity)
self.today_stop_order = self.StopMarketOrder("QQQ", -self.quantity, self.last_15m_low)
self.today_shot_num += 1
else:
order_id = self.Transactions.LastOrderId
ticket = self.Transactions.GetOrderTicket(order_id)
# ticket_time = ticket.get_Time()
# order_events = ticket.OrderEvents()
order_tickets = self.Transactions.GetOrderTickets()
# sell all
if self.Portfolio["QQQ"].Quantity > 0:
orderticket = self.MarketOrder("QQQ", -self.Portfolio["QQQ"].Quantity)
import pandas as pd
from pathlib import Path
from datetime import timedelta
from yahoo_fin.stock_info import get_data
data_folder = '../data'
yahoo_dir = './yahoo'
def get_yahoo_ticker(ticker, folder, start_date, end_date):
# check if the ticker file exists
fname = ticker.lower() + '.csv'
path = Path(folder)/fname
# get the dates if the file aready exists
if path.exists():
# open the file and get the dates
df = pd.read_csv(path, index_col=0)
dates = pd.DatetimeIndex(df.index.sort_values(ascending=True))
else:
dates = None
start_date = pd.to_datetime(start_date)
end_date = pd.to_datetime(end_date)
# if the range is not included in the file or if there is no file at all
if dates is None or start_date < dates[0] or end_date > dates[-1]:
# try to retrieve the data from Yahoo_fin
try:
delta = timedelta(days=3)
df = get_data(ticker, start_date=start_date-delta, end_date=end_date+delta)
df.to_csv(path)
print(f'Retrieving ticker: {ticker}')
except BaseException as e:
print(f'Problem getting ticker {ticker}')
return None
else:
print(f'Ticker {ticker} already loaded')
return ticker
def get_yahoo_data(tickers: list, start_date, end_date):
"""Get a list of tickers from yahoo and save them in the Default LEAN data directory"""
# transform tickers into a list (if it is not)
tickers = tickers if isinstance(tickers, list) else [tickers]
# check the directory
folder = Path(data_folder)/yahoo_dir
if not folder.exists():
folder.mkdir()
print(f'Folder {str(folder)} - Created')
else:
print(f'Folder {str(folder)} - Ok')
# create a list to store all loaded tickers
loaded_tickers = []
for ticker in tickers:
loaded_tickers.append(get_yahoo_ticker(ticker, folder, start_date, end_date))
return [ticker for ticker in loaded_tickers if ticker is not None]
from AlgorithmImports import *
from pathlib import Path
from datetime import datetime, timedelta
class YahooData(PythonData):
def GetSource(self, config, date, isLiveMode):
# print(f'GetSource YAHOO for date {date}')
# The name of the asset is the symbol in lowercase .csv (ex. spy.csv)
fname = config.Symbol.Value.lower() + '.csv'
# The source folder depends on the directory initialized in lean-cli
# https://www.quantconnect.com/docs/v2/lean-cli/tutorials/local-data/importing-custom-data
source = Path(Globals.DataFolder)/'yahoo'/fname
# The subscription method is LocalFile in this case
return SubscriptionDataSource(source.as_posix(), SubscriptionTransportMedium.LocalFile)
def Reader(self, config, line, date, isLiveMode):
# print(f'Reading date {date}')
# print(f'line ==> {line}')
equity = YahooData()
equity.Symbol = config.Symbol
# Parse the Line from the Yahoo CSV
try:
data = line.split(',')
# If value is zero, return None
value = data[4]
if value == 0: return None
equity.Time = datetime.strptime(data[0], "%Y-%m-%d")
equity.EndTime = equity.Time + timedelta(days=1)
equity.Value = value
equity["Open"] = float(data[1])
equity["High"] = float(data[2])
equity["Low"] = float(data[3])
equity["Close"] = float(data[4])
equity["AdjClose"] = float(data[5])
equity["VolumeUSD"] = float(data[6])
# print(f'Returning --> {coin.EndTime} - {coin}')
return equity
except ValueError:
# Do nothing, possible error in csv decoding
return None