Overall Statistics
Total Orders
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Start Equity
100000
End Equity
100000
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic 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
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
from AlgorithmImports import *
import csv
from io import StringIO
from datetime import time, timedelta, date, datetime

class FracSharesAlgorithm(QCAlgorithm):
    def Initialize(self):
        # User-defined variables for time calculations
        self.AdjustedCloseSubtractor = time(0, 15, 0)  # 00:15:00
        self.MarketCloseTime = time(16, 0, 0)  # 16:00:00

        # Calculate the adjusted close time
        close_minutes = self.MarketCloseTime.hour * 60 + self.MarketCloseTime.minute
        subtractor_minutes = self.AdjustedCloseSubtractor.hour * 60 + self.AdjustedCloseSubtractor.minute
        adjusted_minutes = close_minutes - subtractor_minutes
        self.AdjustedCloseTime = time(adjusted_minutes // 60, adjusted_minutes % 60)

        self.Log(f"Market Close Time: {self.MarketCloseTime}")
        self.Log(f"Adjusted Close Subtractor: {self.AdjustedCloseSubtractor}")
        self.Log(f"Adjusted Close Time: {self.AdjustedCloseTime}")

        # Get today's actual date
        today = datetime.now().date()
        self.Log(f"Today's Date: {today}")
        self.Log(f"Today - 1 day: {today - timedelta(days=1)}")
        self.Log(f"Today - 2 days: {today - timedelta(days=2)}")
        self.Log(f"Today - 3 days: {today - timedelta(days=3)}")
        self.Log(f"Today - 4 days: {today - timedelta(days=4)}")
        self.Log(f"Today - 5 days: {today - timedelta(days=5)}")
        self.Log(f"Today - 6 days: {today - timedelta(days=6)}")
        self.Log(f"Today - 7 days: {today - timedelta(days=7)}")
        self.Log(f"Today - 8 days: {today - timedelta(days=8)}")
        self.Log(f"Today - 9 days: {today - timedelta(days=9)}")
        self.Log(f"Today - 10 days: {today - timedelta(days=10)}")
        self.Log(f"Today - 11 days: {today - timedelta(days=11)}")

        # Get FetchEnd and FetchStart dates
        self.FetchEnd = self.GetFetchEnd(today)
        self.FetchStart = self.GetFetchStart(self.FetchEnd)

        # Set the date range
        self.SetStartDate(self.FetchStart)
        self.SetEndDate(today)

        self.Log(f"Start Date: {self.StartDate}")
        self.Log(f"End Date: {self.EndDate}")
        self.Log(f"FetchStart: {self.FetchStart}")
        self.Log(f"FetchEnd: {self.FetchEnd}")

        # Initialize the set to store Fracshares tickers
        self.frac_symbols = set()

        # Schedule the refresh of Fracshares data
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(self.AdjustedCloseTime), self.RefreshFracShares)

    def GetFetchEnd(self, start_date):
        if self.IsMarketOpen(start_date):
            return start_date
        elif self.IsMarketOpen(start_date - timedelta(days=1)):
            return start_date - timedelta(days=1)
        elif self.IsMarketOpen(start_date - timedelta(days=2)):
            return start_date - timedelta(days=2)
        elif self.IsMarketOpen(start_date - timedelta(days=3)):
            return start_date - timedelta(days=3)
        elif self.IsMarketOpen(start_date - timedelta(days=4)):
            return start_date - timedelta(days=4)
        elif self.IsMarketOpen(start_date - timedelta(days=5)):
            return start_date - timedelta(days=5)
        elif self.IsMarketOpen(start_date - timedelta(days=6)):
            return start_date - timedelta(days=6)
        elif self.IsMarketOpen(start_date - timedelta(days=7)):
            return start_date - timedelta(days=7)
        elif self.IsMarketOpen(start_date - timedelta(days=8)):
            return start_date - timedelta(days=8)
        elif self.IsMarketOpen(start_date - timedelta(days=9)):
            return start_date - timedelta(days=9)
        else:
            raise ValueError("FetchEnd: No market open days found in the last 10 days")

    def GetFetchStart(self, fetch_end):
        if self.IsMarketOpen(fetch_end - timedelta(days=1)):
            return fetch_end - timedelta(days=1)
        elif self.IsMarketOpen(fetch_end - timedelta(days=2)):
            return fetch_end - timedelta(days=2)
        elif self.IsMarketOpen(fetch_end - timedelta(days=3)):
            return fetch_end - timedelta(days=3)
        elif self.IsMarketOpen(fetch_end - timedelta(days=4)):
            return fetch_end - timedelta(days=4)
        elif self.IsMarketOpen(fetch_end - timedelta(days=5)):
            return fetch_end - timedelta(days=5)
        elif self.IsMarketOpen(fetch_end - timedelta(days=6)):
            return fetch_end - timedelta(days=6)
        elif self.IsMarketOpen(fetch_end - timedelta(days=7)):
            return fetch_end - timedelta(days=7)
        elif self.IsMarketOpen(fetch_end - timedelta(days=8)):
            return fetch_end - timedelta(days=8)
        elif self.IsMarketOpen(fetch_end - timedelta(days=9)):
            return fetch_end - timedelta(days=9)
        elif self.IsMarketOpen(fetch_end - timedelta(days=10)):
            return fetch_end - timedelta(days=10)
        else:
            raise ValueError("FetchStart: No market open days found in the 10 days before FetchEnd")

    def IsMarketOpen(self, date):
        return self.MarketHoursDatabase.GetExchangeHours(Market.USA, None, SecurityType.Equity).IsDateOpen(date)

    def RefreshFracShares(self):
        self.Log(f"Attempting to fetch Fracshares data on {datetime.now().date()} at {datetime.now().time()}")

        url = "http://www.ibkr.com/download/fracshare_stk.csv"
        content = self.Download(url)
        
        if content:
            old_fracshares = self.frac_symbols.copy()
            
            csv_reader = csv.reader(StringIO(content))
            next(csv_reader)  # Skip header
            
            new_tickers = [row[0] for row in csv_reader if row and row[0].isalpha()]
            
            if new_tickers:
                self.frac_symbols.clear()
                self.frac_symbols.update(new_tickers)
                
                self.Log(f"New Fracshares data found. Total number of Fracshares tickers: {len(self.frac_symbols)}")
                self.Log("--- Start of Fracshares Tickers ---")
                for ticker in self.frac_symbols:
                    self.Log(f"{ticker}")
                self.Log("--- End of Fracshares Tickers ---")
            else:
                self.Log("No new Fracshares data found. Using previous data.")
                self.frac_symbols = old_fracshares
        else:
            self.Log("Failed to download Fracshares data. Using previous data.")

        self.Log(f"Current number of Fracshares tickers: {len(self.frac_symbols)}")

    def OnData(self, data):
        # This method is required but can be left empty for this algorithm
        pass