Back to Community
Getting the hang of Quantopian

Just tried literally the first algo in the tutorial (under what is a trading algorithm). 100% long static apple. From 1/4/2005 it shows a return of -1482%. Also it is incredibly slow and shows trying to buy and sell shares in the log. What am I missing here?

def initialize(context):
# Reference to AAPL
context.aapl = sid(24)

def handle_data(context, data):
# Position 100% of our portfolio to be long in AAPL
order_target_percent(context.aapl, 1.00)

6 responses

Altan

Welcome, and yes, that algorithm in the tutorial is pretty simplistic and misleading. As you found out it doesn't work as it would seem on the surface.

First off, the handle_data function is automatically called every minute. Ultimately you may want to put your trading logic there, but for starters it's easiest to put it into a scheduled function. Attached is a sample algorithm.

You noted three things that are happening in your algorithm. 1) slow 2) a lot of buying and selling 3) huge losses. As far as why, here's my guess...

1) its slow because the handle_data function is called every minute and you are placing orders every minute of every day. Normally, there would be some logic like "if price is less than x then place order" so your orders would be much less frequent.

2) its buying and selling a lot because the order_target_percent function doesn't check for outstanding orders. It only looks at cash and equities currently in the portfolio. If you start with $1M cash then the very first minute of the algorithm an order for $1M worth of shares is placed. The very next minute, only some of that order would be filled based upon the slippage model. Lets assume $100k. So, the second minute, you still have $900k in cash in your portfolio so the algorithm places an order for $900k worth of shares. As the orders are filled your portfolio now has way too many shares so the order_target_percent now starts selling shares. That cycle keeps repeating. Note that all outstanding full and partial orders are always cancelled at the end of each day so that makes for a sort of "reset".

3) it has huge losses partly because of commissions. It's often helpful while testing an algorithm to set the commissions to zero using the set_commission function.

By using a scheduled function to trade once a day all the above issues are eliminated (potentially the same could happen however if it wasn't for all outstanding orders being canceled at end of day).

Hope that helps. Good luck.

Clone Algorithm
3
Loading...
Backtest from to with initial capital
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
"""
This is a template algorithm on Quantopian for you to adapt and fill in.
"""
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
 
def initialize(context):
    """
    Called once at the start of the algorithm.
    """   
    
    # Reference to AAPL
    context.aapl = sid(24)
    
    # Set benchmark to be the same as the buy and hold stock to see how well it tracks
    set_benchmark(context.aapl)
    
    # Rebalance every day, 1 hour after market open.
    schedule_function(
        my_rebalance, 
        date_rules.every_day(), 
        time_rules.market_open(hours=1)
        )

 
def my_rebalance(context,data):
    """
    Execute orders according to our schedule_function() timing. 
    """
    order_target_percent(context.aapl, 1.00)


 

There was a runtime error.

Thanks. The minute resolution would certainly explain the speed but how a backtest can generate beyond -100% is quite enigmatic. The logic must be acquiring and disposing of quite a bit over and above the value of the portfolio since buying and selling a fraction of the portfolio would not result in a loss greater than the portfolio itself - (unless transaction costs have a minimal value rather than a % of portfolio value but even then it should stop at -100% - final tr costs). I would have expected that once 100% of the portfolio is allocated to apple the portfolio should track apple's performance statically. Is there a way to write the daily portfolio value and buy and sell orders to a csv file to audit the results?

Altan,

Maybe attach a backtest highlighting your concerns. Attached here is a minute version of simply buying 100% AAPL and it seems to work as expected?

Look at the "transaction details" tab in the left menu area of the full backtest and you can see exactly the minute by minute trades. This often helps in troubleshooting. Notice in this backtest the order_by_percent does overshoot so after a few minutes it is actually selling shares (which it over bought previously). Notice too that the constant compounding of orders does NOT happen probably because there is so much volume in AAPL and your order gets filled in a few minutes.

Clone Algorithm
1
Loading...
Backtest from to with initial capital
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
"""
This is an algorithm which tries to keep 100% of portfolio into one stock.
"""
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
 
def initialize(context):
    """
    Called once at the start of the algorithm.
    """   
    
    # Reference to AAPL
    context.aapl = sid(24)
    
    # Set benchmark to be the same as the buy and hold stock to see how well it tracks
    set_benchmark(context.aapl)

 
def handle_data(context,data):
    """
    Execute orders according to our schedule_function() timing. 
    """
    order_target_percent(context.aapl, 1.00)

There was a runtime error.

Thanks. The algo doesn't stop buying after it reaches the portfolio amount. It also ends up net short and static short Apple (adjusted for dividends and splits presumably) until the end. I read your solution of reducing the trade frequency with the schedule function to end of day, but this is sidestepping the problem. Even on a minute basis if target portfolio is 100% the algo should buy up until the % amount (save for the fraction of Apple share that can't be bought). On default behaviour, a model like this should be able to get all the units it needs by the end of the day (perhaps with some cost adjustment to the closing price). Continuous compounding must still work with one minute resolution.

Clone Algorithm
1
Loading...
Backtest from to with initial capital
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
def initialize(context):
# Reference to AAPL
    context.aapl = sid(24)

def handle_data(context, data):
# Position 100% of our portfolio to be long in AAPL
    order_target_percent(context.aapl, 1.00) 
There was a runtime error.

Hi Altan,

The algorithm is creating new orders every minute, even if there are current open orders being placed..

Think about it like this:

Let's say Stock J's share price is $1000.
With $1m starting capital, the following will happen.

Start of Minute 1:  
# Order 100% of portfolio value  
order_target_percent(symbol("J"),1)  
50 seconds after the start of minute 1:  
There is an open order for 1000 shares of Stock J,  
Start of Minute 2:  
500 shares of Stock J have been filled.  
# This means that there is still an open order for 1000 shares of Stock J, but it is partially filled.  
order_target_percent(symbol("J"), 1)

# Your portfolio value is still $1m, so this targets to $1m based on the number of shares in the portfolio.  
# 500 shares of Stock J are ordered  
50 seconds after the start of Minute 2:  
The previous order from Minute 1 has been completely filled. (1000/1000)  
There is an open order for 500 shares of Stock J  
Start of Minute 3:  
400 Shares of the order were filled. (400/500)  
# Portfolio value at $~1.4m  
order_target_percent(symbol("J"), 1)  
# Order placed to make ~$1.4m to $1m  
(-400 shares)
50 seconds after minute 3:  
Order for 500 shares filled.  
Open order for -400 shares.  

This is all assuming that the price doesn't change from minute to minute, in which case it would rarely converge to a correct price.

If you were to change handle_data to return when there are open orders, you'll get the correct behavior.

def handle_data(context, data):  
        if get_open_orders():  
            return  
        order_target_percent(symbol("J"), 1)  

This should converge to your target price.

Best,
Lotanna Ezenwa

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.

Controlling for open orders does indeed stop the issue. Thanks.