Overall Statistics
Total Trades
2339
Average Win
0.32%
Average Loss
-0.21%
Compounding Annual Return
7.590%
Drawdown
14.000%
Expectancy
0.023
Net Profit
3.133%
Sharpe Ratio
0.34
Probabilistic Sharpe Ratio
30.062%
Loss Rate
60%
Win Rate
40%
Profit-Loss Ratio
1.54
Alpha
-0.259
Beta
1.476
Annual Standard Deviation
0.255
Annual Variance
0.065
Information Ratio
-0.689
Tracking Error
0.214
Treynor Ratio
0.059
Total Fees
$4016.07
Estimated Strategy Capacity
$37000000.00
Lowest Capacity Asset
ADBE R735QTJ8XC9X
# region imports
from AlgorithmImports import *
# endregion

class SleepyYellowGreenGull(QCAlgorithm):

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

    def Initialize(self):
        self.SetStartDate(2021, 3, 1)  # Set Start Date
        self.SetEndDate(2021, 8, 1)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash

        good = float(self.GetParameter("good"))
        bad = float(self.GetParameter("bad"))
        self.word_scores["good"] = good
        self.word_scores["bad"] = bad * -1

        self.news_by_symbol = {}
        self.AddUniverse(self.Universe.ETF("QQQ", Market.USA, self.UniverseSettings, self.ETFConstituentsFilter))

    def OnData(self, data):
        
        symbols = []
        for kvp in data.Get(TiingoNews):
            symbol = kvp.Key
            title_words = kvp.Value.Description.lower()
            score = 0
            for word, word_score in self.word_scores.items():
                if word in title_words:
                    score += word_score
            
            # Contrarian: we are going to buy stocks with negative sentiment/score
            if score < 0:
                symbols.append(symbol.Underlying)

        count = len(symbols)
        if count == 0:    # Do nothing if there is no negative scores
            return

        targets = [PortfolioTarget(symbol, .90/count)
            for symbol in symbols]

        # Liquidate if invested and no new negative news
        for symbol, holdings in self.Portfolio.items():
            if holdings.Invested and symbol not in symbols:
                targets.append(PortfolioTarget(symbol, 0))

        self.SetHoldings(targets)


    def ETFConstituentsFilter(self, constituents):
        # Get the 10 securities with the largest weight in the index
        selected = sorted([c for c in constituents if c.Weight],
            key=lambda c: c.Weight, reverse=True)[:10]
        symbols = [c.Symbol for c in selected]
        return symbols

    def OnSecuritiesChanged(self, changes):
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if security.Invested:
                self.Liquidate(symbol, 'Removed From Universe')
            news_symbol = self.news_by_symbol.pop(symbol, None)
            if news_symbol:
                self.RemoveSecurity(news_symbol)

        for security in changes.AddedSecurities:
            symbol = security.Symbol
            if symbol not in self.news_by_symbol:
                self.news_by_symbol[symbol] = self.AddData(TiingoNews, symbol).Symbol