Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
AT Notes

Question 1 [40 points] – Follow Steps 1-4, then answer sub-questions 1.1-1.4.

Step 1. Select ‘New Algorithm’, name the algorithm ‘ Final Exam
Algorithm Basic Momentum’. For example, for me the name of the algorithm would read
‘Andrei Kirilenko Final Exam Algorithm Basic Momentum’.

Step 2. Cut and paste the code below into your algorithm.

# Final Exam Algorithm Basic Momentum starts here  
def initialize(context):  
    context.security = symbol('AAPL')  
def handle_data(context, data):  
    vwap_price_5 = data[context.security].vwap(5)  
    vwap_price_1 = data[context.security].vwap(1)

    open_orders = get_open_orders()

    if vwap_price_5 > vwap_price_1:  
        if context.security not in open_orders:  
            order_target_percent(context.security, 1.0)  
            log.info("Buying %s" % (context.security.symbol))  
    elif vwap_price_5 < vwap_price_1:  
        if context.security not in open_orders:  
            order_target_percent(context.security, -0.75)  
            log.info("Selling %s" % (context.security.symbol))

    record(stock_price=data[context.security].price)  
# Final Exam Algorithm Basic Momentum ends here  

Step 3. Set the settings for the algorithm to:
Dates: 01/01/2017 – 02/01/2017, i.e., January 1, 2017 to February 1, 2017
Initial capital: USD 1 million.
Assets: US Equities

Step 4. Press ‘Build Algorithm’.

1.1 [5 points] Your code will NOT initially run due a simple syntax error in one line of the code.
What is the syntax error? Type below the line of the code with the syntax error fixed.

Answer 1.1: The line ‘if context.security not in open_orders’ is missing a colon at the
end. Corrected line: ‘if context.security not in open_orders:’

1.2 [5 points] Fix the syntax error and press ‘Build Algorithm’ (remember that the
dates are January 1, 2017 to February 1, 2017 only). After your back-test has
finished running take a screenshot of your screen and place it below. Describe
in words what this algorithm does.

Answer 1.2: This algorithm codifies a basic momentum strategy for a single stock –
‘AAPL’. First, it computes two sets of closing prices for AAPL – the value-weighted average price (VWAP) for 5 days and the VWAP for 1 day. Then, it interprets the
difference between the two VWAPs as a signal to buy or sell AAPL. If the VWAP for 5
days is higher than the VWAP for 1 day, the algorithm generates instructions to send
orders to buy AAPL for up to the entire allocated amount (USD 1 million). If the VWAP
for 1 day is higher than the VWAP for 5 days, it sends orders to sell AAPL up for to 75
percent of the allocated amount.

1.3 [10 points] Comment out (by placing # in front of the line) two
occurrences of the following line in the code: ‘if context.security not in
open_orders:’
Note: After being commented out, the two occurrences of the line above
should turn grey.
Then, press ‘Run Full Backtest’ and after your back-test has finished running
take a screenshot of your full back-test screen (‘Results Overview’) and place
it below.
Did the performance of your algorithm change? If yes, how?

Answer 1.3: Yes, the algorithm performed dramatically worse after the two occurrences
of the line were commented out as directed. Total returns of the modified algorithm
changed to -392.4 percent compared to 4.4 percent of the original algorithm. Similarly,
alpha, Sharpe ratio and max drawdown of the modified algorithm suffered dramatic
declines.

1.4. [20 points] What, if anything, does the algorithm with the commented out
occurrences of the ‘open_orders’ line do differently than the original algorithm?

Answer 1.4: Compared to the original algorithm, the algorithm with the commented out
occurrences of the ‘open_orders’ line does not keep track of ‘open orders’ – orders that
have been already sent for execution.

As a result, the modified algorithm keeps sending orders to be executed as directed by the
lines:

if vwap_price_5 > vwap_price_1:
order_target_percent(context.security, 1.0)
elif vwap_price_5 < vwap_price_1:
order_target_percent(context.security, -0.75)

without regard for any outstanding orders already in the execution queue.

As a result, the algorithm ends up trading tens and sometimes hundreds of millions of the
stock in each direct, essentially without any check on the leverage of this trading strategy.

Question 2 [40 points] – Follow Steps 1-4, then answer sub-questions 2.1-2.4.

Step 1. Select ‘New Algorithm’, name the algorithm ‘ Final Exam
Algorithm Pipeline Basic’. For example, for me the name of the algorithm would read
‘Andrei Kirilenko Final Exam Algorithm Pipeline Basic’.

Step 2. Cut and paste the code below into your algorithm.

# Final Exam Algorithm Pipeline Basic starts here  
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.factors import CustomFactor, SimpleMovingAverage, AverageDollarVolume  
from quantopian.pipeline.data import morningstar  
from quantopian.pipeline.filters.morningstar import IsPrimaryShare  
from quantopian.pipeline.classifiers.morningstar import Sector  
import numpy as np  
import pandas as pd  
def initialize(context):  
    """  
    Called once at the start of the program. Any one-time  
    startup logic goes here.  
    """  
    # Define context variables that can be accessed in other methods of  
    # the algorithm.  
    context.long_leverage = 0.5  
    context.short_leverage = -0.5  
    #context.returns_lookback = 5  
    # Rebalance on the first trading day of each week at 11AM.  
    schedule_function(rebalance, date_rules.week_start(days_offset=0), time_rules.market_open(hours=1, minutes=30))  
    # Record tracking variables at the end of each day.  
    schedule_function(record_vars, date_rules.every_day(), time_rules.market_close(minutes=1))  
    # Create and attach an empty Pipeline.  
    pipe = Pipeline()  
    pipe = attach_pipeline(pipe, name='my_pipeline')  
    sma_10 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=10)  
    sma_30 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=30)  
    sma_10_30 = sma_10/sma_30  
    low_sma = sma_10_30.percentile_between(0,10)  
    high_sma = sma_10_30.percentile_between(90,100)

    # Construct a Filter.  
    prices_under_5 = (sma_10 < 5)  
    # Register outputs.  
    #pipe.add(sma_10, 'sma_10')  
    #pipe.add(sma_30, 'sma_30')  
    pipe.add(low_sma, 'low_sma')  
    pipe.add(high_sma, 'high_sma')  
    #pipe.add(securities_to_trade, 'securities_to_trade')  
    # Remove rows for which the Filter returns False.  
    pipe.set_screen(prices_under_5)  
def before_trading_start(context, data):  
    # Access results using the name passed to `attach_pipeline`.  
    context.output = pipeline_output('my_pipeline')  
    #print context.output.head(5)  
    # Store pipeline results for use by the rest of the algorithm.  
    #context.pipeline_results = context.output  
    # Sets the list of securities we want to long as the securities with a 'True'  
    # value in the high_sma column.  
    context.long_secs = context.output[context.output['high_sma']]

    # Sets the list of securities we want to short as the securities with a 'True'  
    # value in the low_sma column.  
    context.short_secs = context.output[context.output['low_sma']]  
    # A list of the securities that we want to order today.  
    context.security_list = context.long_secs.index.union(context.short_secs.index).tolist()  
    # A set of the same securities, sets have faster lookup.  
    context.security_set = set(context.security_list)  
def compute_weights(context):  
    """  
    Compute weights to our long and short target positions.  
    """  
    # Set the allocations to even weights for each long position, and even weights  
    # for each short position.  
    long_weight = context.long_leverage / len(context.long_secs)  
    short_weight = context.short_leverage / len(context.short_secs)

    return long_weight, short_weight  
def rebalance(context,data):  
    """  
    This rebalancing function is called according to our schedule_function settings.  
    """  
    long_weight, short_weight = compute_weights(context)  
    # For each security in our universe, order long or short positions according  
    # to our context.long_secs and context.short_secs lists.  
    for stock in context.security_list:  
        if data.can_trade(stock):  
            if stock in context.long_secs.index:  
                order_target_percent(stock, long_weight)  
            elif stock in context.short_secs.index:  
                order_target_percent(stock, short_weight)  
    # Sell all previously held positions not in our new context.security_list.  
    for stock in context.portfolio.positions:  
        if stock not in context.security_set and data.can_trade(stock):  
            order_target_percent(stock, 0)  
    # Log the long and short orders each week.  
    log.info("This week's longs: "+", ".join([long_.symbol for long_ in context.long_secs.index]))  
    log.info("This week's shorts: " +", ".join([short_.symbol for short_ in context.short_secs.index]))  
def record_vars(context, data):  
    """  
    This function is called at the end of each day and plots certain variables.  
    """  
    # Check how many long and short positions we have.  
    longs = shorts = 0  
    for position in context.portfolio.positions.itervalues():  
        if position.amount > 0:  
            longs += 1  
        if position.amount < 0:  
            shorts += 1  
    # Record and plot the leverage of our portfolio over time as well as the  
    # number of long and short positions. Even in minute mode, only the end-of-day  
    # leverage is plotted.  
    record(leverage = context.account.leverage, long_count=longs, short_count=shorts)  
# Final Exam Algorithm Pipeline Basic ends here  

Step 3. Set the settings for the algorithm to:
Dates: 01/01/2017 – 02/01/2017, i.e., January 1, 2017 to February 1, 2017
Initial capital: USD 1 million.
Assets: US Equities

Step 4. Press ‘Run Full Backtest’ and after your back-test has finished running take a
screenshot of your full back-test screen (‘Results Overview’) and place it below.

2.1 [5 points] Explain what the block of code below does and what are the inputs and
outputs for this block of code. Is the output for this block of the code used as an
input elsewhere in the algorithm?
sma_10 = SimpleMovingAverage(inputs=[USEquityPricing.close],
window_length=10)
sma_30 = SimpleMovingAverage(inputs=[USEquityPricing.close],
window_length=30)
sma_10_30 = sma_10/sma_30

Answer 2.1: This block of code begins to construct factors for subsequent use in portfolio
selection. Inputs into this block of code are closing prices of US equities. Output for this
block of code is a factor sma_10_30, which is calculated as the ratio of a simple 10-day
moving average of closing prices of US equities to their simple 30-day moving average
for each stock-day. Across all US stocks for each day, the output forms a distribution
(histogram) on a positive support interval, e.g., [0.2, 1.6]. The output for this block of the code is used to create high and low sma filters in the lines of the code that immediately
follow the creation of the sma_10-30 distribution, i.e.
‘low_sma = sma_10_30.percentile_between(0,10) high_sma = sma_10_30.percentile_between(90,100)’

2.2 [10 points] Set high sma filter to the top 1% of securities [by changing 90 to 99]
(make no other changes to the code), then press ‘Build Algorithm.’ Take the screen shot of the modified code so that the changed line in the code is clearly
visible on the left side of the screen (white symbols against black background)
and the results of the backtest are clearly visible on the right side of the screen
(symbols and lines of different colors against white background). Did the performance algorithm change compared to the baseline that you
computed in Step 4? In terms of constructing the portfolio of stocks, what does
the modified algorithm do differently compared to the original algorithm?

Answer 2.2: After the filter was modified to select only the top 1 percent of the stocks of
the sma filter, the performance of the algorithm has worsened. Returns declined from -1.9
percent to -3.3 percent and alpha declined from -0.2 to -0.39.
The original algorithm is roughly balanced in terms of long and short allocations. The
modified algorithm goes at lot more short - short 389 stocks and long only 50 stocks at
the end of the backtest run.

2.3 [10 points] Reset high sma filter to the top 10% of securities as in the original
code [by changing 99 back to 90]. Find the block of code that reads:

schedule_function(rebalance,
date_rules.week_start(days_offset=0),
time_rules.market_open(hours=1, minutes=30))

and modify this block of code as follows:

schedule_function(rebalance,
date_rules.week_start(days_offset=0),
time_rules.market_open(hours=5, minutes=30))

then press ‘Run Full Backtest.’ Take the screen shot of full backtest results and
place it below.
Did the performance algorithm change compared to the baseline that you
computed in Step 4? If yes, why did the performance of this strategy change?

Answer 2.3: Yes, the performance of the algorithm improved compared to the baseline
computed in Step 4. Total returns improved to -1 percent compared to -1.9 percent in the
baseline and both alpha and the Sharpe ratio improved as well. Judging by leverage, this
strategy is more conservative: the leverage of this strategy is 0.46 compared to 0.83 of the
baseline strategy. Explanation: Rebalancing the portfolio at 3pm resulted in fewer
executed transactions as it is close to the end of the trading day and some orders did end
up being executed and were cancelled at the end of the trading day as can be seen in the
Logs. Namely, in the baseline strategy, transactions include $310,030 bought and
$238,787 sold. In the modified strategy above, transactions include $221,439 bought and $252,069 sold.

2.4 [15 points] Reset the time of rebalancing back to the original 11 am on the first
trading day of the week. Simply changing back to the original block of code:

schedule_function(rebalance,
date_rules.week_start(days_offset=0),
time_rules.market_open(hours=1, minutes=30))

Now, change ‘context.short_leverage’ from -0.5 to 1.5 and press ‘Build
Algorithm’. Take a screen snapshot of place it below. Then proceed to read the
text and answer the sub-question.

According to BlackRock, “Smart Beta strategies aim to capture drivers of return through
rules-based, transparent strategies. They are benchmark-driven versions of factor
strategies, generally long only and usually implemented within an asset class.”

According to AQR, “Most Smart Beta funds today are long-only equity strategies
focused on one investment style or factor. To be considered Smart Beta, we believe that
these factors must also be simple and transparent.”
Can this strategy be characterized as a Smart Beta strategy?

Answer 2.4: Yes, this strategy can be characterized as a Smart Beta strategy. It is a longonly
equity strategy focused on one factor. It is rule-based, simple and transparent. It also
significantly improves total return compared to the original long-short strategy.

Question 3 [5 points] Consider the following statement: “Beta neutral is a flavor of the
ever-popular long/short equity strategy, dictated by beta, or the degree of correlation of
volatility between the portfolio and market. Managers enter into long and short trades
such that the net beta of all positions is zero, with the goal of creating a portfolio
uncorrelated with the movement of the market.”

A. True.
B. False.
Answer: A

Question 4 [5 points] Consider the following statement: “Only about 15 percent of a
company's stock is typically available for shorting. As a result, there is much more
inventory for long trades than there is for short trades.”

A. True.
B. False.
Answer: A

Question 5 [5 points] Consider the following statement: “When trading a highly illiquid
volatile security, there are two extreme strategies: trade everything now at a known but
high cost, or trade in equal-sized packets in the course of a trading day at relatively lower
cost. The latter strategy has both lower expected cost and lower uncertainty in final
revenue.”

A. True.
B. False.
Answer: B. False: The latter strategy has higher uncertainty in final revenue as it is being
executed in the course of a trading day and future trading conditions may change
dramatically, especially for a highly illiquid volatile security.

Question 6 [5 points] Consider the following statement: “There are at least two
competing theories about why short-term mean-reversion strategies work: (i) because of
behavioral biases (for example, investors overweight recent information), the market
overreacts to both good news and bad news; and (ii) because liquidity shocks (for
example, a large portfolio rebalancing trade by an uniformed trader) lead to temporary
moves that get reversed.”

A. True.
B. False.
Answer: A