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

I had a request for an algo that was dirt-simple. Buy a basket of stocks, hold them, and see how it does. Here it is!

If you want to try different stocks (these were chosen mostly at random) it's very easy. Click "clone algorithm" and edit the

sid()  

When you start typing s-i-d- in the code editor, you'll get an auto-complete window that will help you find the stock you want. Just type the company name and let the auto-complete do the work.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

13 responses

Hi Dan,
Could you help me write a line of code? I decide to sell stock when its price is larger than 1.1 times buying price. For example, I bought 500 shares of stock at $10 at the initial time, once it reaches $11, I would sell 500 shares. These are some of the codes I learned from your algorithm, but cannot build successfully.

def initialize(context):
# define which stocks you want
context.stocks = (sid(5729), sid(1637), sid(27558), sid(2190), sid(35920), sid(32146), sid(35902))
context.bought = False

def handle_data(context, data):
# buy them all on the first day, then stop
if not context.bought:
for stock in context.stocks:
log.info("buying 500 shares of " + str(stock))
order(stock, 500)
context.bought = True

if context.bought:  
    for stock in context.stocks:  
        if data[context.stocks].price > data[context.stocks].mavg(30):  
            order(stock,-500)  
    context.bought = False  

I've attached a modified version that randomly buys and holds the same securities in Dan's example above, over the same period of time. Perhaps someone can advise how I can handle the Python datetime objects more elegantly. I'd prefer not to specify as separate variables the hour & minute to submit the order.

By the way, I think it is important to distinguish between order submission and order fulfilment (buying/selling). For example, order(stock,500) only submits an order. It will be fulfilled in the next minute of trading for the security (unless the order is submitted on the last minute of the trading day, in which case, the submitted order is dropped...I'm told...never actually tested this).

Hello Weiyi Chen,

I don't have time right now to work up an example, but I think you should be able to store the purchase prices in a variable (e.g. context.basis) in def initialize(context). In the first iteration of the backtest, store the prices in context.basis, then define logic in your algorithm to sell when they reach a specified limit (e.g. 10% over the purchase price).

@Grant, I think this code does what you want, but uses a datetime.timedelta object. A timedelta represents a duration. You can do addition and subtraction of timedeltas, timedeltas with datetimes, and when you take the difference between datetimes it returns a timedelta. You'll see that I do a datetime difference in the code for this share.

I think I replicated the random behavior you wanted by generating a random duration of up to a week, and then waiting that long between placing orders.

Let me know what you think.

thanks,
fawce

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks Fawce,

I took a first pass at what you wrote, cloned it, and ran it a few times. I'll need to get back to it when I get the chance...seems to do the trick.

Grant

Hello Weiyi,

Here's an algorithm that hopefully does what you want. Just let me know if you can't sort out the flow or if you think that I've botched the logic. For a challenge, see if you can get the algorithm to run with:

context.stocks = [sid(41290),sid(41425),sid(39479),sid(33972),sid(41159)]  

They are thinly traded securities, so you'll need to add some logic to handle this case, since all securities do not have trades for all backtest minutes. Just plug the list of sids into the algorithm and try to run it. You'll get an error message with guidance on how to fix the problem. When I get the chance, I'll take a crack at the problem, too.

Hey Weiyi (and Dan & Fawce),

Note that in my algorithm above, I capture the estimated basis by saving the security prices at the time of order submission. For the securities selected, the order is fulfilled in the next minute of trading, so one would expect a small error. The actual basis is the price at the time of order fulfilment...I'm not yet sure how to capture that information in the backtester. Maybe somebody can fill me in? It may be an academic point for highly liquid securities, but for thinly traded ones, the price could change dramatically between the time of order submission and order fulfilment. There are other potentially important cases, as well.

Thanks Grant,

It's very kind of you. I learned a lot from your code.

Hi Grant - we do track the cost basis of your purchases. So you can have your code look at that instead if you want. I revised my original algo to buy the stocks, and then log the cost basis thereof.

Thanks Dan,

When I get the chance, I'll tweak my algorithm above to use the actual cost basis for the sell decision. I'll also see if I can handle the case of thinly traded securities (should be straightforward).

Grant

Hello Weiyi and all,

I've pieced together an algorithm that handles the case of thinly traded securities. It also uses the built-in cost basis computation provided by Quantopian (nice). I have a few more tweaks, so I am posting it here for review before doing a separate post. Let me know what you think. Instead of logging the cost basis at every tic, I plan to modify the code so that it only writes it out when there is a change (buy/sell). Also, I'd like to see if I can capture the datetimes when the orders are actually fulfilled.

I can't get the "Add Backtest" function to work, so I've pasted the code below.

import numpy as np

def initialize(context):

    #context.stocks = [sid(5729), sid(1637), sid(27558), sid(2190), sid(35920), sid(32146), sid(35902)]  
    context.stocks = [sid(41290),sid(41425),sid(39479),sid(33972),sid(41159)]  
    context.m = len(context.stocks)  
    context.basis = np.zeros(context.m)  
    context.bought = False  
    context.sold = [False]*context.m  
    context.sell_limit = 1.1  # relative price limit to submit sell order

def handle_data(context, data):  
    # record share prices at time of order fulfillment (0.0 if not yet fulfilled)  
    for i, stock in enumerate(context.stocks):  
        context.basis[i] = context.portfolio.positions[stock].cost_basis  
    log.info(context.basis)  
    # create numpy array of current security prices (0.0 if no tic)  
    current_prices = np.zeros(context.m) # set prices to 0.0  
    for i, stock in enumerate(context.stocks):  
        if stock in data:  
            current_prices[i] = data[stock].price  
    # submit sell order if relative security price reaches limit  
    if context.bought:  
        for i, stock in enumerate(context.stocks):  
            if context.basis[i] != 0.0 and current_prices[i] != 0.0:  
                relative_price = current_prices[i]/context.basis[i]  
                if relative_price >= context.sell_limit and context.sold[i] == False:  
                    order(stock, -500)  
                    context.sold[i] = True # switch flag if sell order submitted  
                    log.info(context.sold) # output sold flags  
    # submit initial order of basket of securities  
    if not context.bought:  
        for i, stock in enumerate(context.stocks):  
            order(stock, 500)  
            log.info("500 share buy order submitted: " + str(stock))  
        context.bought = True  

Hi Grant, sorry about the "Add Backtest" functionality. It should be fixed now.

thanks,
Jean

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Please see attached for the algorithm referenced in my most recent post above. --Grant