Overall Statistics
Total Trades
1185
Average Win
0.36%
Average Loss
-0.04%
Compounding Annual Return
6.057%
Drawdown
2.200%
Expectancy
0.975
Net Profit
24.167%
Sharpe Ratio
1.926
Probabilistic Sharpe Ratio
97.509%
Loss Rate
82%
Win Rate
18%
Profit-Loss Ratio
10.12
Alpha
0.059
Beta
0.013
Annual Standard Deviation
0.032
Annual Variance
0.001
Information Ratio
-0.482
Tracking Error
0.206
Treynor Ratio
4.847
Total Fees
$1990.69
import pandas as pd
import numpy as np
from io import StringIO

class RedditStockSentiment(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2017,1, 10)  # Set Start Date
        self.SetEndDate(2020, 9, 14) #Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.tickers = ["SPCE", "LULU", "CCL", "SDC", "NKLA", "TSLA", "F", "BA", "PTON", "CHWY", "RKT"] #Stocks picked by briefly looking through the wallstreetbets reddit and finding frequently mentioned stocks
        self.investP = 1/len(self.tickers) #Equal weight portfolio
        self.SetTimeZone(TimeZones.Chicago) #Set to Chicago time
        
        for stock in self.tickers:
            self.AddEquity(stock, Resolution.Hour) #Sets resolution to hour bars
        
        self.AddRiskManagement(TrailingStopRiskManagementModel(0.08)) #Risk management
        
        self.trade = True #OnData will run when the program when the program is first executed
        
        csv = self.Download("https://www.dropbox.com/s/ibd2zty0ytoqsos/The_Wall_Street_Bets_Sentiment.csv?dl=1") #Downloads data
        self.df = pd.read_csv(StringIO(csv)) #Read into a dataframe
        
        self.Schedule.On(self.DateRules.EveryDay(), 
                 self.TimeRules.At(8, 30),        
                 self.runDaily) #Runs runDaily (sets self.trade to True) at 8:30am Chicago time
        
    def OnData(self, data):
        
        if self.trade != True: #Runs daily at 8:30am Chicago time
            return
        
        #Assigns three variables with the current time(year, month, day)
        algYear = self.Time.year
        algMonth = self.Time.month
        algDay = self.Time.day
        
        #Iterates through the dataframe tuples
        for row in self.df.itertuples():
            try: #If there is an error with dates a tuple(row) then continue to the next row
                date = row[-1] #Date is the index of the tuple(final colum in the dataframe)
                
                #Date is parsed as a string and assigned to three variables
                year = date[0:4]
                month = date[5:7]
                day = date[8:10]
            except:
                continue
            
            #Compares current date with the date from the tuple
            if (int(year) != algYear) or (int(month) != algMonth) or (int(day) != algDay):
                continue
            
            '''
            averageSentiment is calculated by averaging the sentiment of the submission title, body text, and all comments.
            This process can be very time consuming. 
            '''
            
            #Assigns several variables with data from the tuple
            stock = str(row[1])
            averageSentiment = float(row[4]) 
            numberOfComments = int(row[3])
            score = int(row[7])
            
            adjust = 1
            
            #If score is low, allocate a smaller percentage to the position taken for the underlying equity
            if score <= 20:
                adjust = 0.5
        
            if(averageSentiment >= 0.1) and not self.Portfolio[stock].IsLong:
                self.SetHoldings(stock, self.investP*adjust, True)
            if(averageSentiment <= -0.1) and not self.Portfolio[stock].IsShort:
                self.SetHoldings(stock, -(self.investP*0.4)*adjust, True) #40% leverage
            if (-0.1 < averageSentiment < 0.1):
                self.Liquidate(stock)
                
            self.trade = False
                
    def runDaily(self):
        self.trade = True