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