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

How do I make this take in account the Robinhood delay before funds are available to repurchase. I also want to make sure it takes in account the amount I already hold. I also do not want it to sell any stocks I already have purchased with Robinhood.

18 responses

Does anyone know if I apply this algorithm if it will make any changes to the shares I already hold?

Samuel,

As long as you're doing for stock in context.sids and not for stock in data you should only order stocks that are in your algorithm.

Anytime you do for stock in data, it will reference all your existing holdings.

Let me know if that helps

Seong

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.

Seong,

Thanks for your help. I turned it on and found out real quick it needs more work. apparently it looks at the total amount my whole portfolio is worth and tried to place trades based on the whole amount. The good news is I didn't have much for available funds so no trades were placed. I am now trying to get it to look at the total of all of the shares I hold in the context.sids plus any cash available for trade. That should give it what it needs to place trades. Can you please assist. It is above me in skills right now.

Thanks,
Samuel

Ah I see what you mean, you were attempting to use order_target_percent.

I would try taking a look at the order_for_robinhood method we have here: https://www.quantopian.com/posts/zero-commission-algorithmic-trading-robinhood-and-quantopian

Hi Seong,

I do want to purchase by percentage and re-balance every month. I want it do it proportionally. I really would like it to only look at cash and existing investments that are on the list only. I use this account for other things but I want it to still work as long as there is cash available. What can I do? I don't want to just buy the same percentage across the board.

Thanks,
Samuel

Hi Samuel,

My recommendation would be to modify our order for Robinhood method to fit your needs, for example, taking out the check for T+3 order settlement. You can find our post on that here: https://www.quantopian.com/posts/robinhood-live-trading-update-stop-waiting-3-days-with-robinhood-instant.

It's pretty well commented but I'm happy to help out if you have specific questions on how to modify it.

Seong

The thing I dont understand is how to use it and still place an order by percentage. I want to make sure I purchase a certain percentage of each stock.

Samuel,

The order_for_robinhood accepts a percentage value. So when you want to order 10% of your cash + context.sids value on sid(19662), you can say order_for_robinhood(context, sid(19662), context.sids[sid(19662)].

The order_for_robinhood method will only look at your existing cash value + the amount you hold in context.sids. The original method uses context.assets which I replaced with context.sids here:

def get_percent_held(context, security, portfolio_value):  
    """  
    This calculates the percentage of each security that we currently  
    hold in the portfolio.  
    """  
    if security in context.portfolio.positions:  
        position = context.portfolio.positions[security]  
        value_held = position.last_sale_price * position.amount  
        percent_held = value_held/float(portfolio_value)  
        return percent_held  
    else:  
        # If we don't hold any positions, return 0%  
        return 0.0

def order_for_robinhood(context, security, weight,  
                        order_style=None):  
    """  
    This is a custom order method for this particular algorithm and  
    places orders based on:  
    (1) How much of each position in context.assets we currently hold  
    (2) How much cash we currently hold

    This means that if you have existing positions (e.g. AAPL),  
    your positions in that security will not be taken into  
    account when calculating order amounts.

    The portfolio value that we'll be ordering on is labeled  
    `valid_portfolio_value`.  
    If you'd like to use a Stop/Limit/Stop-Limit Order please follow the  
    following format:  
    STOP - order_style = StopOrder(stop_price)  
    LIMIT - order_style = LimitOrder(limit_price)  
    STOPLIMIT - order_style = StopLimitOrder(limit_price=x, stop_price=y)  
    """  
    # We use .95 as the cash because all market orders are converted into  
    # limit orders with a 5% buffer. So any market order placed through  
    # Robinhood is submitted as a limit order with (last_traded_price * 1.05)  
    valid_portfolio_value = context.portfolio.cash * .95

    for s in context.sids:  
        # Calculate dollar amount of each position in context.assets  
        # that we currently hold  
        if s in context.portfolio.positions:  
            position = context.portfolio.positions[s]  
            valid_portfolio_value += position.last_sale_price * \  
                position.amount  
    # Calculate the percent of each security that we want to hold  
    percent_to_order = weight - get_percent_held(context,  
                                                 security,  
                                                 valid_portfolio_value)  
    # If within 1% of target weight, ignore.  
    if abs(percent_to_order) < .01:  
        return

    # Calculate the dollar value to order for this security  
    value_to_order = percent_to_order * valid_portfolio_value  
    if order_style:  
        return order_value(security, value_to_order, style=order_style)  
    else:  
        return order_value(security, value_to_order)  

Hi,

Thanks for this so where do I place the sids? Can you add in the example a couple of sids with differing percents so I can see in context. I am sorry to be asking so much of you. I am still really new to this. Once I see I will try to add in how to re-balance monthly.

So the above will not try to order as a percent of my entire portfolio and just a percent of the sids listed plus cash correct? This is important because I want to hold several other stocks by themselves.

Thanks,
Samuel

Samuel,

This will only look your CASH and value in the stocks you have defined in CONTEXT.SIDS as your portfolio value and will try to order X percent off of that. As for an example on how to use it:

order_for_robinhood(context, sid(19662), .10)  
order_for_robinhood(context, sid(25902), .10)  

This will take those two securities and try to order 10% in each.

Seong

One last thing, we have an awesome tutorial series that will help explain some of the fundamental concepts from above (https://www.quantopian.com/posts/quantopian-tutorials).

I would recommend checking those out as well!

Ok thanks I will take a look.

I don't know why but I have been unable to make it work. i have spent a lot of time with different changes and no go. Perhaps someone can use the information your provided. if so I hope they will publish it here for others to use.

Samuel,

I'll be happy to help you out. Do you already hold shares in the securities you listed in context.sids?

Thank you.
Yes I hold some of them. I have been trading in my robinhood account for some time manually. I want to see if I can create two different algorithms. One will be for this one I started working on here to allow me to weight a number of ETFs to make up my base line and I want it to re-balance them to the specified amount every 15 days. I also want to make sure the numbers it is working from are only what is in the list and then available cash. I do want it to take in account the ETFs that i hold that are on the list. I do not want it to touch my other holdings. I want to do them myself or with another algorithm.

I have been struggling with this trying to make sure I do not cause issues with my current holdings and every time I modify this algo I cause errors. I even tried to combine what you have and what I have to make but no go. Any assistance would be great.

Thanks,
Samuel

Any update I sent the reply 3 weeks ago. Do you need any more info from me?

Samuel,

I replaced your order method with order_for_robinhood as I recommended in previous posts.

''' 
    This algorithm defines a target long-only diversified portfolio and rebalances  
    it at a user-specified frequency.  
'''

import datetime  
import pytz  
import pandas as pd  
from zipline.utils.tradingcalendar import get_early_closes


def initialize(context):  
     # Robinhood only allows long positions, use this trading  
    # guard in case  
    set_long_only()  
    # Since we are trading with Robinhood we can set this to $0!  
    set_commission(commission.PerTrade(cost=0))  
    # Define the instruments in the portfolio:  
    context.sids = {  
        sid(19662): 0.1,  
        sid(25902): 0.1,  
        sid(19659): 0.1,  
        sid(25903): 0.1,  
        sid(25905): 0.05,  
        sid(19658): 0.05,  
        sid(41959): 0.05,  
        sid(25906): 0.05,  
        sid(32277): 0.05,  
        sid(28073): 0.05,  
        sid(19661): 0.05,  
        sid(25908): 0.04,  
        sid(19660): 0.04,  
        sid(16827): 0.01,  
        sid(41961): 0.01,  
        sid(19657): 0.01,  
        sid(25904): 0.01,  
        sid(27804): 0.01,  
        sid(40533): 0.01,  
        sid(40708): 0.01,  
        sid(26669): 0.01,  
        sid(26670): 0.01,  
        sid(28075): 0.05,  
    }  
    # Define the benchmark (used to get early close dates for reference).  
    context.spy           = sid(8554)  
    start_date = context.spy.security_start_date  
    end_date   = context.spy.security_end_date  
    # Initialize context variables the define rebalance logic:  
    context.rebalance_date = None  
    context.next_rebalance_Date = None  
    context.rebalance_days = 15  
    # Get the dates when the market closes early:  
    context.early_closes = get_early_closes(start_date, end_date).date

    set_commission(commission.PerTrade(cost=0))

def handle_data(context, data):  
    # Get the current exchange time, in local timezone:  
    exchange_time = pd.Timestamp(get_datetime()).tz_convert('US/Central')  
    # If it is rebalance day, rebalance:  
    if context.rebalance_date == None or exchange_time >= context.next_rebalance_date:  
       # If we are in rebalance window but there are open orders, wait til next minute  
       if has_open_orders(data,context) == True:  
            log.info('Has open orders, not rebalancing.')  
       else:  
           # If there are no open orders we can rebalance.  
           rebalance(context, data, exchange_time)  
           log.info('Rebalanced portfolio to target weights at %s' % exchange_time)

           # Update the current and next rebalance dates  
           context.rebalance_date = exchange_time  
           context.next_rebalance_date = context.rebalance_date + datetime.timedelta(days=context.rebalance_days)  
           print(context.next_rebalance_date)

def rebalance(context,data,exchange_time):  
    for sid in context.sids:  
        if data.can_trade(sid):  
            order_for_robinhood(context, sid, context.sids[sid])

def has_open_orders(data,context):  
    # Only rebalance when we have zero pending orders.  
    has_orders = False  
    open_orders = get_open_orders()  
    # open_orders is a dictionary keyed by sid, with values that are lists of orders.  
    if open_orders:  
        # iterate over the dictionary  
        for security, orders in open_orders.iteritems():  
            # iterate over the orders  
            for oo in orders:  
                message = 'Open order for {amount} shares in {stock}'  
                message = message.format(amount=oo.amount, stock=security)  
                log.info(message)  
                has_orders = True  
    return has_orders   

def get_percent_held(context, security, portfolio_value):  
    """  
    This calculates the percentage of each security that we currently  
    hold in the portfolio.  
    """  
    if security in context.portfolio.positions:  
        position = context.portfolio.positions[security]  
        value_held = position.last_sale_price * position.amount  
        percent_held = value_held/float(portfolio_value)  
        return percent_held  
    else:  
        # If we don't hold any positions, return 0%  
        return 0.0

def order_for_robinhood(context, security, weight,  
                        order_style=None):  
    """  
    This is a custom order method for this particular algorithm and  
    places orders based on:  
    (1) How much of each position in context.assets we currently hold  
    (2) How much cash we currently hold

    This means that if you have existing positions (e.g. AAPL),  
    your positions in that security will not be taken into  
    account when calculating order amounts.

    The portfolio value that we'll be ordering on is labeled  
    `valid_portfolio_value`.  
    If you'd like to use a Stop/Limit/Stop-Limit Order please follow the  
    following format:  
    STOP - order_style = StopOrder(stop_price)  
    LIMIT - order_style = LimitOrder(limit_price)  
    STOPLIMIT - order_style = StopLimitOrder(limit_price=x, stop_price=y)  
    """  
    # We use .95 as the cash because all market orders are converted into  
    # limit orders with a 5% buffer. So any market order placed through  
    # Robinhood is submitted as a limit order with (last_traded_price * 1.05)  
    valid_portfolio_value = context.portfolio.cash * .95

    for s in context.sids:  
        # Calculate dollar amount of each position in context.assets  
        # that we currently hold  
        if s in context.portfolio.positions:  
            position = context.portfolio.positions[s]  
            valid_portfolio_value += position.last_sale_price * \  
                position.amount  
    # Calculate the percent of each security that we want to hold  
    percent_to_order = weight - get_percent_held(context,  
                                                 security,  
                                                 valid_portfolio_value)  
    # If within 1% of target weight, ignore.  
    if abs(percent_to_order) < .01:  
        return

    # Calculate the dollar value to order for this security  
    value_to_order = percent_to_order * valid_portfolio_value  
    if order_style:  
        return order_value(security, value_to_order, style=order_style)  
    else:  
        return order_value(security, value_to_order)  

I recommend that you personally verify that this will serve the behavior that you want.

Hi Seong,

I am happy to report it is working as expected so far. I do have one question what should I do to buy only and not to sell? I want to add in the areas that are low if there is money to purchase with but I do not want to sell any as it does now. What should I change to accomplish this.

Thanks,
Samuel