Custom Factor question

Hello,
Karen Ruben originally shared below algo. I am very hard time understanding one line (line 41). How could denominator be 60 days old data? Could anyone explain to me how the data is arranged when you get "window_length = 60"? Thank you

12
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
 Returns 1 Month 3 Month 6 Month 12 Month
 Alpha 1 Month 3 Month 6 Month 12 Month
 Beta 1 Month 3 Month 6 Month 12 Month
 Sharpe 1 Month 3 Month 6 Month 12 Month
 Sortino 1 Month 3 Month 6 Month 12 Month
 Volatility 1 Month 3 Month 6 Month 12 Month
 Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This example comes from a request in the forums.
The post can be found here: https://www.quantopian.com/posts/ranking-system-based-on-trading-volume-slash-shares-outstanding

The request was:

I am stuck trying to build a stock ranking system with two signals:
2. Price of current day / Price of 60 days ago.
Then rank Russell 2000 stocks every month, long the top 5%, short the bottom 5%.

"""

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

# Create custom factor #1 Trading Volume/Shares Outstanding
class Factor1(CustomFactor):

# Pre-declare inputs and window_length
inputs = [USEquityPricing.volume, morningstar.valuation.shares_outstanding]
window_length = 1

# Compute factor1 value
def compute(self, today, assets, out, volume, shares):
out[:] = volume[-1]/shares[-1]

# Create custom factor #2 Price of current day / Price of 60 days ago.
class Factor2(CustomFactor):

# Pre-declare inputs and window_length
inputs = [USEquityPricing.close]
window_length = 60

# Compute factor2 value
def compute(self, today, assets, out, close):
out[:] = close[-1]/close[0]

# Create custom factor to calculate a market cap based on yesterday's close
# We'll use this to get the top 2000 stocks by market cap
class MarketCap(CustomFactor):

# Pre-declare inputs and window_length
inputs = [USEquityPricing.close, morningstar.valuation.shares_outstanding]
window_length = 1

# Compute market cap value
def compute(self, today, assets, out, close, shares):
out[:] = close[-1] * shares[-1]

def initialize(context):

context.long_leverage = 0.50
context.short_leverage = -0.50

pipe = Pipeline()
attach_pipeline(pipe, 'ranked_2000')

#add the two factors defined to the pipeline
factor1 = Factor1()
factor2 = Factor2()

# Create and apply a filter representing the top 2000 equities by MarketCap every day
# This is an approximation of the Russell 2000
mkt_cap = MarketCap()
top_2000 = mkt_cap.top(2000)
pipe.set_screen(top_2000)

# Rank factor 1 and add the rank to our pipeline
# Rank factor 2 and add the rank to our pipeline
# Take the average of the two factor rankings, add this to the pipeline
combo_raw = (factor1_rank+factor2_rank)/2
# Rank the combo_raw and add that to the pipeline

# Scedule my rebalance function
schedule_function(func=rebalance,
date_rule=date_rules.month_start(days_offset=0),
time_rule=time_rules.market_open(hours=0,minutes=30),
half_days=True)

# Call pipelive_output to get the output
# Note this is a dataframe where the index is the SIDs for all securities to pass my screen
# and the colums are the factors which I added to the pipeline
context.output = pipeline_output('ranked_2000')
#there are some NaNs in factor 2, I'm removing those
ranked_2000 = context.output.fillna(0)
ranked_2000 = context.output[context.output.factor_2 > 0]

# Narrow down the securities to only the top 500 & update my universe
context.long_list = ranked_2000.sort(['combo_rank'], ascending=False).iloc[:100]
context.short_list = ranked_2000.sort(['combo_rank'], ascending=False).iloc[-100:]

update_universe(context.long_list.index.union(context.short_list.index))

def handle_data(context, data):

# Record and plot the leverage of our portfolio over time.
record(leverage = context.account.leverage)

print "Long List"

print "Short List"

# This rebalancing is called according to our schedule_function settings.
def rebalance(context,data):

long_weight = context.long_leverage / float(len(context.long_list))
short_weight = context.short_leverage / float(len(context.short_list))

for long_stock in context.long_list.index:
if long_stock in data:
log.info("ordering longs")
log.info("weight is %s" % (long_weight))
order_target_percent(long_stock, long_weight)

for short_stock in context.short_list.index:
if short_stock in data:
log.info("ordering shorts")
log.info("weight is %s" % (short_weight))
order_target_percent(short_stock, short_weight)

for stock in context.portfolio.positions.iterkeys():
if stock not in context.long_list.index and stock not in context.short_list.index:
order_target(stock, 0)

There was a runtime error.
3 responses

In numpy array indexing, [0] is the top row and [-1] is the bottom row. If it's 60 days of data, arranged oldest to newest, the newest is at the bottom at [-1] and the oldest, 60 days old, is at the top, at [0].

Simon,
Then is the oldest called as [-60] or [0]? Would either work in this case?
Ujae

Should be equivalent yeah.