Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Perform sector neutral hedge

Requesting code review

# Morningstar Sector Codes  
# 101 Basic Materials, 102 Consumer Cyclical, 103 Financial Services, 104 Real Estate, 205 Consumer Defensive, 206 Healthcare, 207 Utilities, 308 COmmunication Services, 309 Energy, 310 Industrials, 311 Technology

def perform_sector_neutral_hedge(context):

    context.sector_etfs = {  
        101: sid(19654),    # XLB Materials SPDR Fund  
        102: sid(19662),    # XLY Consumer Discrectionary SPDR Fund  
        103: sid(19656),    # XLF Financial SPDR Fund  
        104: symbol('VNQ'), # real estate?  
        205: sid(19659),    #consumer defensive # XLP Consumer Staples SPDR Fund?  
        206: sid(19661),    # XLV Health Care SPRD Fund  
        207: sid(19660),    # XLU Utilities SPRD Fund  
        308: symbol('IYZ'), #communication services  
        309: sid(19655),    # XLE Energy SPDR Fund  
        310: sid(19657),    # XLI Industrial SPDR Fund  
        311: sid(19658)     # XLK Technology SPDR Fund  
    }  
    target_short = dict.fromkeys(context.sector_etfs.keys(),0)

    for purchase_record in context.purchase_history:  
        if purchase_record['stock'] in context.portfolio.positions:  
            position = purchase_record['stock']  
            target_short[purchase_record['sector']] = target_short[purchase_record['sector']] + context.portfolio.positions[position].cost_basis * context.portfolio.positions[position].amount       

    for sector in target_short:  
        sector_etf = context.sector_etfs[sector]  
        cancel_order(sector_etf)  
        if sector_etf not in get_open_orders():  
            order_target_value(sector_etf, -1 * target_short[sector])

21 responses

Post the complete code. How do you define and update purchase_history?

In initialize() I initialize context.purchase_history = []

Then every time I make a purchase, I also do:

                    purchase_record = {}  
                    purchase_record['date'] = todays_date  
                    purchase_record['order_id'] = stock_order # this is an Order  
                    purchase_record['stock'] = stock_to_buy # this is a Symbol  
                    purchase_record['sector'] = context.fundamental_df[stock_to_buy].morningstar_sector_code  
                    context.purchase_history.append(purchase_record)  

You should go over everything and check the types. What is a Security, as returned by sid or symbol; what is an int, eg. position; what is a float, eg. price; what is a purchase_record; and what is an order ID, as returned by order.

For example, sector_etf is a Security, but cancel_order requires an Order.

Python is a weakly-typed language, and mismatching types will be caught as runtime errors, and then only when an offending statement is executed. By contrast, strongly-typed languages like C, C++, Java, and Scala will catch them all at compile time.

That's a really helpful tip. Thanks André!

You're welcome. I would suggest you start with really simple code, where you know exactly what everything is and how everything works. Then add one thing, and work on it until again you know exactly what everything is and how everything works. Repeat until done.

Can you speak more to that please.

Declare one security. Every minute, calculate how many shares you can afford. If not 0, send an order.

Next version: don't trade when you have outstanding orders.

Next version: include money for commissions in your calculations.

Next: two assets.

Every minute, calculate how many shares you can afford. If not 0, send an order.

How do you calculate how many shares you can afford?
Right now, my code is extremely naive:

if context.portfolio.cash > target_purchase_size:  

I would like an improved code that properly takes into account ideas of leverage, etc.

Next version: don't trade when you have outstanding orders.

I already do this

                    if (stock_to_buy in get_open_orders()) or (stock_to_buy in context.portfolio.positions):  
                        log.info('EarlyReturn because we own or open order for this stock')  
                        continue

Next version: include money for commissions in your calculations.

This is an important critique. I will use the example from one of the Quantopian templates.

Next: two assets.

Right now the algo typically holds ~15 assets. Actually, I realize that "~15" is a total guess based on my visual scans of the Daily Positions/Transactions tab of the backtest. What's the best way to arrive at a precise number for this (amount of assets held on average)?

How to calculate the number of shares given a budget and, for now, disregarding commissions and slippage? Embarrassing a quant wouldn't know. Without commissions and slippage, the amount you will be charged for n shares at the price of p dollars per share is n*p, and it has to be <=budget. Divide both sides by p (no worries - it is never 0) to get n<=budget/p. The largest integer satisfying this (remember, you can only buy whole shares) is

n=int(budget/p)  

(You would use target_purchase_size in place of budget.).

This assignment statement, in various forms, is what I see in many places in code posted on Quantopian. I haven't seen any code that incorporates commissions into this calculation. Instead, some use context.portfolio. cash * 0.99 or 0.95 as their budget. With $100,000 initial capital, this sets aside $1000 or $5000 for commissions and slippage - probably too much.

Mr. Pajak,

Thank you for continuing to respond.

I will add that model performs better when taking into account commissions and slippage, using these values:

    set_commission(commission.PerTrade(cost=1))  
    set_slippage(slippage.VolumeShareSlippage(volume_limit=0.25, price_impact=0.1))

I asked for a sophisticated "shares you can afford" code that takes into account considerations of leverage - i.e., do not buy or sell if leverage would pass a certain threshold (e.g. the 1.05 limit imposed by the Open contest).

Of course I am familiar with simple ideas of rounding and dividing cash by whole number of shares in order to determine a purchase size, but I am using the affordances of the Quantopian platform (e.g., the order_target_value function) to simulate my orders.

Finally, I will add that I do not appreciate the tone. The attempted reframe of my inquiry as "embarrassing" is not only an inaccurate reflection of our unique skills and abilities (though it does shed some light on your assessment skills) but it is just not productive for building community.

The astute observer will notice that you did not provide a single critique of the core ideas that the original post implemented; i.e., perform a sector-neutral short hedge of any long positions.

Your comment about the dangers of duck typing in a financial environment is nonetheless appreciated.

Sincerely,

Zachary Burt

Step by step. If you use a per-trade commission model, just subtract the per-trade fee from your budget:

n=int((budget-commission_per_trade)/p)  

One problem is that Quantopian does not allow you to call set_commission (even to the default values) in the contest, and there is no get_commission function you could call to find out what the commissions are, whether default or set by you.

My workaround is to set variables to per-trade and per-share commissions (one of them is usually zero), and use them in calculations. Then I have code like

cpt, cps = 0, 0.03  # Quantopian default: 3 cents per share  
#cpt, cps = 7.95, 0  # Fidelity: $7.95 per trade  
#cpt, cps = 1.0, 0  # Zachary Burt  
n = int((budget-cpt)/(p+cps))  

Mr. Burt - I do not appreciate your tone. I have no way of knowing what you do and do not know. I only know what you wrote. And if you read enough posts on this forum, you will notice that some are embarrassing.

Please also note that you're getting from me more than you've paid for. Further, Quantopian employees (distinguished with a logo icon next to their names) get a salary. I get nothing.

Leverage can be incorporated into your budget by something like

max_leverage=1.05. # or 3  
budget=context.portfolio.cash*max_leverage  

Some information about me is in my profile and website. I apologize if I came across as overzealous.

Slippage is the difference between the price per share you have been or will be charged and the latest price known to you at the time you make your order. Because you can't know the price you will be charged, you can, at best, only estimate it.

Quantopian lets you choose between two slippage models they provide, or let you write your own. All are deterministic - they calculate an amount intended to simulate the actual slippage. Using the details of such a deterministic slippage model as if you knew exactly what the slippage will be may lead to unrealistic backtest results and lower-than-expected performance in live trading.

I haven't had time to incorporate slippage estimates into my calculations. I would use something like

cpt, cps = 0, 0.03  # Quantopian default: 3 cents per share  
#cpt, cps = 7.95, 0  # Fidelity: $7.95 per trade  
#cpt, cps = 1.0, 0  # Zachary Burt  
estimated_slippage=p*0.01 # 1% of the latest price  
n = int((budget-cpt)/(p+estimated_slippage+cps))  

You're welcome. Have in mind that this is a public forum, and I'm writing not only for your benefit, but also for others. As the Quantopian user base grows, there are also more and more newbies. I wouldn't bother writing for just one person, unless I was getting similar instruction in return or a fee was involved.

What's the best way to arrive at a precise number for this (amount of assets held on average)?

Save (append to a list) your context.portfolio.portfolio_value as often as you think proper, eg. daily, and calculate the average.

If you meant to ask "how to know precisely how many assets I hold when", do

record(n_assets=len(context.portfolio.positions))  

at the end of the day.

If you meant to ask "what is the best number of assets to hold", I'll say, experiment, or ask somebody who knows more about finance and trading than I do.

I tend to answer the questions that are actually asked.

Thanks Andre.

I am working on incorporating these ideas into my algo and I will post an updated code sample as soon as possible.

If you meant to ask "what is the best number of assets to hold", I'll say, experiment, or ask somebody who knows more about finance and trading than I do.

I was actually just wondering about the best way to measure # of assets and your answer was helpful.

My business/research partner Cameron Gilbert sent me a good math paper on "best number of assets" recently. I'll see if I can find the link.

Edit: This wasn't the paper I was referring to, and in fact it is almost 30 years old, but it argues for 30-40 stocks:
https://www.wiso.uni-hamburg.de/fileadmin/sozialoekonomie/bwl/bassen/Lehre/International_Finance_I/Lectures/20080506_Number_of_stocks_in_a_diversified_portfolio.pdf

This textbook (wps.prenhall.com/wps/media/objects/13070/13384693/Chapter17.pdf) says that unsystematic risk can be decreased by increasing holdings to about 20 different securities.