Back to Community
I would really like to not invest 25% of $25,000 at my first live algo attempt!

Limiting account percentage with Robinhood Template Algo

The Robinhood algo, here: https://www.quantopian.com/posts/robinhood-live-trading-update-stop-waiting-3-days-with-robinhood-instant , uses this,

         # We will weight each asset equally and leave a 5% cash reserve.  
         context.weight = 0.95 / len(context.assets)

to equally distribute funds throughout the list of assets in our context. I would like to make this work with a Large cash reserve and a Small investment to limit my risk.

I've set the account starting amount at $26,000 and changed the context.weight = .038 to invest ~$1,000 of my cash. However, this results in having 0% returns throughout. I've also played with this and it seems like the magic number is around .25; so when I set context.weight = .25 , then I get returns, BUT not at .2

Does anyone know what is going on here? I would really like to not invest 25% of $25,000 at my first live algo attempt! hah...
(I have other questions/concerns about going live, but I will probably ask those in another thread)

Any ideas or workarounds are appreciated.

3 responses

The culprit is in the 'order_for_robinhood' method. There is a check to see if the amount to order is within 1% of the target. Since you start with such a small amount this check fails. It's commented out in the attached algorithm. There may be other issues but that one was the first I found.

    if abs(percent_to_order) < .01:  
        return

Clone Algorithm
3
Loading...
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
"""
UPDATE: For those with Robinhood Instant, this algorithm does
not contain a check for unsettled funds as with RI, you no
longer have to wait T+3 in order to deploy algorithms. 

This is a simple tactical asset allocation model that uses
simple timing rules to prevent extreme drawdowns and
volatility. 

It is based off of Mebane Faber's "Global Tactical Asset
Allocation" (GTAA). GTAA consists of five global asset
classes:  US stocks, foreign stocks, bonds, real estate
and commodities...it is either long the asset class or in cash 
with its allocation of the funds. 

The basics of the strategy go like this:
(1) Look at a 200 day trailing window (SA - Slow Average) versus
    a 20 day trailing window (FA - Fast Average).
    - We do this in `calculate_exposure`
(2) If the FA is greater than the SA, go long about 20% of your
    portfolio in that security
    - We do this in `open_new_positions`
(3) If the FA is less than the SA, have 0% of your portfolio in
    that security
    - We do this in `close_positions`

Check out Mr. Faber's website: http://www.cambriainvestments.com
for more information. The updated whitepaper can also be found:
- http://papers.ssrn.com/sol3/papers.cfm?abstract_id=962461

Specifically for Robinhood users we have a few measures in place:
(1) This algorithm will calculate order amounts only based on
    the amount of cash (settled_cash) and the positions you
    have in the securities listed under `context.assets`.
    This means you're existing positions will not be touched
    and all order calculations are based off (cash + value in
    context.asset securities).
    That can be found in `order_for_robinhood`
(2) If you currently hold positions in any security found in
    context.assets. We will not be entering into a trade on the
    first day.
(3) This algorithm is set in a "set it and forget it" style.
For more information, please visit:
- www.quantopian.com/help#overview-livetrading
"""

# The initialize function is the place to set your tradable
# universe and define any parameters. 
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 our five global assets.
    context.assets = [sid(8554),  # S&P 500 (SPY)
                      sid(22972), # Foreign developed (EFA)
                      sid(23870), # 7-10 year Treasury bond (IEF)
                      sid(28054), # Commodities (DBC)
                      sid(26669)] # Real Estate Invesment Trusts (VNQ)
              
    # We will weight each asset equally and leave a 5% cash
    # reserve.
    context.weight = 0.038 / len(context.assets)
    
    # Define our lookback period for the moving average rule.
    context.lookback = 200
    context.fast_lookback = 20
    
    # Initialize two collections of stocks that we want to buy
    # and sell. 
    context.reduce_exposure = []
    context.increase_exposure = []
    
    # This code is here so we enter into trades on the very
    # first day that this live algorithm gets deployed
    context.first_trade = True
    
    # Schedule function allows us to set when we want to 
    # execute our functions. In this case, we want it to 
    # check every day if it's the first trade date (when
    # you first launch the algo) and do it 60 minutes 
    # after market open. at 10:31 AM. 
    schedule_function(first_trade, date_rules.every_day(),
                      time_rules.market_open(minutes=60))
        
    # Schedule our functions so that we sell our old stocks,
    # settle the cash, and then buy our new stocks.
    schedule_function(calculate_exposure,
                      date_rules.month_end(days_offset=4),
                      time_rules.market_open())
    schedule_function(close_positions,
                      date_rules.month_end(days_offset=4),
                      time_rules.market_open(minutes=60))
    schedule_function(open_new_positions,
                      date_rules.month_end(),
                      time_rules.market_open(minutes=60))

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.assets:
        # 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)

def check_if_etf_positions_are_held(context):
    # If you currently hold positions in any of the securites
    # found in context.assets, we will not be trading on
    # the first day
    for stock in context.assets:
        if stock in context.portfolio.positions:
            return True
    return False

def first_trade(context, data):
    # If it's the very first day of this algorithm, equally
    # weight our portfolio in our ETFs.
    if context.first_trade:
        # If we already hold assets from context.assets
        # on the first trade date, assume that we've already
        # traded and don't try and make a trade
        if check_if_etf_positions_are_held(context):
            log.info("Already hold context.asset positions. Skipping"
                     " first trade.")
        else:
            log.info("First day of trading, going long on our assets")
            for security in context.assets:
                if data.can_trade(security):
                    o_id = order_for_robinhood(context, security,
                                               context.weight,
                                               LimitOrder(data.current(security, 'price')))
                    if o_id:
                        log.info("Ordering %s shares of %s" %
                                 (get_order(o_id).amount,
                                  security.symbol))
        context.first_trade = False

# Calculate the new exposures for each asset.
def calculate_exposure(context, data):    
    # Let's create two collections of assets: stocks that we
    # need to sell, 
    # and stocks that we need to buy.
    context.reduce_exposure = []
    context.increase_exposure = []
    
    # Get price history for calculating the moving average.
    prices = data.history(context.assets, "price", context.lookback, "1d")
    
    # Loop through our assets and compute each ones new
    # exposure.    
    log.info("Calculating exposure for assets")
    for security in context.assets:        
        
        # Here we check whether or not the latest month's
        # price is greater or less than the entire lookback
        # period
        latest_months_price = prices[security][
            -context.fast_lookback:].mean()
        moving_average_rule = prices[security].mean()
        
        # If latest month's price is greater than the
        # lookback, add the security to the increase_exposure
        # list
        if latest_months_price > moving_average_rule and \
          context.portfolio.positions[security].amount == 0:
            log.info("Adding security %s to the "
                     "increase_exposure list with latest month's"
                     " price at %s and lookback at %s" %
                     (security.symbol, latest_months_price,
                      moving_average_rule))
            context.increase_exposure.append(security)
        # If latest month's price is less than the lookback,
        # add the security to the reduce_exposure list
        elif latest_months_price < moving_average_rule and \
          context.portfolio.positions[security].amount > 0:
            context.reduce_exposure.append(security)
            log.info("Adding security %s to the "
                     "reduce_exposure list with latest month's"
                     " price at %s and lookback at %s" %
                     (security.symbol, latest_months_price,
                      moving_average_rule))
            
    
# Closes current positions. We need to have a separate
# function for this so that cash has time to settle before
# we add new positions.
def close_positions(context, data):
    record(leverage=context.account.leverage)
    log.info("Attempting to reduce exposure in %s positions"
             % len(context.reduce_exposure))
    for security in context.reduce_exposure:
        if security in data:
            o_id = order_for_robinhood(context, security, 0.0,
                                       LimitOrder(data[security].price))
            log.info("Ordering %s shares of %s" %
                     (get_order(o_id).amount, security.symbol))
    
    
# Opens new positions. Again this is a separate function
# so that we only buy when we have the available cash.
def open_new_positions(context, data):
    if len(context.increase_exposure) > 0:
        log.info("Attempting to increase exposure in %s "
                 "positions" % len(context.increase_exposure))
    else:
        log.info("No securities matched our exposure positions,"
                 "not trading for this time.")
    for security in context.increase_exposure:
        if data.can_trade(security):
            o_id = order_for_robinhood(context,
                                       security,
                                       context.weight,
                                       LimitOrder(data.current(security, 'price')))
            #log.info("Ordering %s shares of %s" %
            #         (get_order(o_id).amount, security.symbol))
There was a runtime error.

It's possible that your orders are being rounded down. You can't buy partial shares so for example, if you had $100 and wanted to use 1% of that to buy $100/share, you'll order nothing! I would advise to make an order function that manually targets a certain amount of shares instead of a target percent.

Okay. Thank you both. I'll look into those and see if it helps.