Overall Statistics Total Trades 3103 Average Win 0.57% Average Loss -0.57% Compounding Annual Return 0.037% Drawdown 30.300% Expectancy 0.010 Net Profit 0.471% Sharpe Ratio 0.037 Probabilistic Sharpe Ratio 0.002% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 1.00 Alpha 0.004 Beta -0.019 Annual Standard Deviation 0.067 Annual Variance 0.004 Information Ratio -0.568 Tracking Error 0.163 Treynor Ratio -0.13 Total Fees $1599.58 Estimated Strategy Capacity$100000000.00 Lowest Capacity Asset SYK R735QTJ8XC9X
# https://quantpedia.com/strategies/short-interest-effect-long-short-version/
#
# All stocks from NYSE, AMEX, and NASDAQ are part of the investment universe. Stocks are then sorted each month into short-interest deciles based on
# the ratio of short interest to shares outstanding. The investor then goes long on the decile with the lowest short ratio and short on the decile
# with the highest short ratio. The portfolio is rebalanced monthly, and stocks in the portfolio are weighted equally.

from AlgorithmImports import *

class ShortInterestEffect(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)

# NOTE: We use only s&p 100 stocks so it's possible to fetch short interest data from quandl.
self.symbols = [
'AAPL','MSFT','AMZN','FB','GOOGL','GOOG','JPM','JNJ','V','PG','XOM','UNH','BAC','MA','T','DIS','INTC','HD','VZ','MRK','PFE',
'COST','ABBV','ACN','HON','NKE','UNP','UTX','NEE','IBM','TXN','AVGO','LLY','ORCL','LIN','SBUX','AMT','LMT','GE','MMM','DHR','QCOM',
'COP','INTU','ISRG','CB','SO','D','FISV','PNC','DUK','SYK','ZTS','MS','RTN','AGN','BLK'
]

for symbol in self.symbols:
data.SetFeeModel(CustomFeeModel())
data.SetLeverage(5)

self.recent_month = -1

def OnData(self, data):
if self.recent_month == self.Time.month:
return
self.recent_month = self.Time.month

short_interest = {}
for symbol in self.symbols:
sym = 'FINRA/FNSQ_' + symbol
if sym in data and data[sym] and symbol in data and data[symbol]:
short_vol = data[sym].GetProperty("SHORTVOLUME")
total_vol = data[sym].GetProperty("TOTALVOLUME")

short_interest[symbol] = short_vol / total_vol

long = []
short = []
if len(short_interest) >= 10:
sorted_by_short_interest = sorted(short_interest.items(), key = lambda x: x, reverse = True)
decile = int(len(sorted_by_short_interest) / 10)
long = [x for x in sorted_by_short_interest[-decile:]]
short = [x for x in sorted_by_short_interest[:decile]]

stocks_invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]
for symbol in stocks_invested:
if symbol not in long + short:
self.Liquidate(symbol)

for symbol in long:
if symbol in data and data[symbol]:
self.SetHoldings(symbol, 1 / len(long))
for symbol in short:
if symbol in data and data[symbol]:
self.SetHoldings(symbol, -1 / len(short))

class QuandlFINRA_ShortVolume(PythonQuandl):
def __init__(self):
self.ValueColumnName = 'SHORTVOLUME'    # also 'TOTALVOLUME' is accesible

# Custom fee model.
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))