Overall Statistics
from AlgorithmImports import *
import pandas as pd
from datetime import datetime, timedelta

class ContinuousCompaniesQC500Algorithm(QCAlgorithm):
    def Initialize(self) -> None:
        self.SetStartDate(2006, 1, 1)
        self.SetEndDate(2024, 12, 31)
        self.SetCash(100000)
        
        # Use QC500 universe
        self.UniverseSettings.Resolution = Resolution.Daily
        self._universe = self.AddUniverseSelection(QC500UniverseSelectionModel())
        
        # Dictionary to track company existence
        self.company_tracker = {}
        
        # Check dates for continuous listing
        self.check_dates = [
            datetime(2006, 1, 1),
            datetime(2007, 1, 1),
            datetime(2008, 1, 1),
            datetime(2009, 1, 1),
            datetime(2010, 1, 1),
            datetime(2011, 1, 1),
            datetime(2012, 1, 1),
            datetime(2013, 1, 1),
            datetime(2014, 1, 1),
            datetime(2015, 1, 1),
            datetime(2016, 1, 1),
            datetime(2017, 1, 1),
            datetime(2018, 1, 1),
            datetime(2019, 1, 1),
            datetime(2020, 1, 1),
            datetime(2021, 1, 1),
            datetime(2022, 1, 1),
            datetime(2023, 1, 1),
            datetime(2024, 1, 1),
            datetime(2025, 1, 1)
        ]
        
        # Optimization: Prepare history request for all dates
        self.history_cache = {}
    
    def OnSecuritiesChanged(self, changes: SecurityChanges) -> None:
        # Track when companies first appear in the universe
        for security in changes.AddedSecurities:
            if security.Symbol not in self.company_tracker:
                self.company_tracker[security.Symbol] = {
                    'first_seen': self.Time,
                    'checked_dates': {}
                }
    
    def PrepareDateHistory(self):
        # Optimization: Bulk history request for all check dates
        symbols_to_check = list(self.company_tracker.keys())
        
        for check_date in self.check_dates:
            try:
                # Request history for a single day around the check date
                history = self.History(
                    symbols_to_check, 
                    check_date, 
                    check_date + timedelta(days=5),  # Allow some buffer for non-trading days
                    Resolution.Daily
                )
                
                # Cache the history results
                if not history.empty:
                    for symbol in symbols_to_check:
                        symbol_history = history.loc[history.index.get_level_values('symbol') == symbol]
                        if not symbol_history.empty:
                            if symbol not in self.history_cache:
                                self.history_cache[symbol] = {}
                            self.history_cache[symbol][check_date] = symbol_history
            
            except Exception as e:
                self.Debug(f"Error preparing history for {check_date}: {e}")
    
    def OnEndOfAlgorithm(self):
        # Prepare history cache first
        self.PrepareDateHistory()
        
        continuous_companies = []
        
        for symbol, data in self.company_tracker.items():
            exists_at_all_dates = True
            
            for check_date in self.check_dates:
                # Check if symbol has history for this date
                if (symbol not in self.history_cache or 
                    check_date not in self.history_cache[symbol]):
                    exists_at_all_dates = False
                    break
                
                # Optional: Add additional filtering criteria
                # For example, check if price is above a certain threshold
                price_data = self.history_cache[symbol][check_date]
                if price_data['close'].values[0] < 1:  # Optional price filter
                    exists_at_all_dates = False
                    break
            
            if exists_at_all_dates:
                continuous_companies.append({
                    'Symbol': symbol.Value,
                    'FirstSeen': data['first_seen']
                })
        
        # Convert to DataFrame and save
        if continuous_companies:
            df = pd.DataFrame(continuous_companies)
            filename = "continuous_companies_qc500_2006_2024.csv"
            df.to_csv(filename, index=False)
            self.Debug(f"Found {len(df)} companies continuously in QC500-like universe")
            self.Debug(f"Companies: {[company['Symbol'] for company in continuous_companies]}")
        else:
            self.Debug("No companies found continuous throughout all check dates")
from AlgorithmImports import *
from QuantConnect.DataSource import *

class TiingoNewsDataAlgorithm(QCAlgorithm):

    current_holdings = 0
    target_holdings = 0
    word_scores = {'good': 1, 'great': 1, 'best': 1, 'growth': 1,
                   'bad': -1, 'terrible': -1, 'worst': -1, 'loss': -1}

    def initialize(self) -> None:
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2021, 6, 1)
        self.set_cash(100000)
        
        # Requesting data
        self.aapl = self.add_equity("AAPL", Resolution.MINUTE).symbol
        self.tiingo_symbol = self.add_data(TiingoNews, self.aapl).symbol
        
        # Historical data
        history = self.history(self.tiingo_symbol, 14, Resolution.DAILY)
        self.debug(f"We got {len(history)} items from our history request")
        
        
    def on_data(self, slice: Slice) -> None:
        if slice.contains_key(self.tiingo_symbol):
            # Assign a sentiment score to the news article
            title_words = slice[self.tiingo_symbol].description.lower()
            score = 0
            for word, word_score in self.word_scores.items():
                if word in title_words:
                    score += word_score
                    
            if score > 0:
                self.target_holdings = 1
                
            elif score < 0:
                self.target_holdings = -1
        
        # Buy or short sell if the sentiment has changed from our current holdings
        if slice.contains_key(self.aapl) and self.current_holdings != self.target_holdings:
            self.set_holdings(self.aapl, self.target_holdings)
            self.current_holdings = self.target_holdings