Back to Community
Cash vs Returns

I am trying to get familiar with quantopian. I cloned an algorithm and I would like to understand differences between cash and returns. Why in this algorithm cash is almost 0 and returns goes up?

Clone Algorithm
9
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
# P/E Ratio mean reversion

from collections import deque
import pandas as pd

def initialize(context):
   # Import a CSV containing the reported and operational earnings per share of the S&P 500
   # This is only updated quarterly since that's when earnings announcements occur
   # I'm just using reported EPS, but I've included operational EPS for those interested
    # 45 day delay to account for announcement delay
    fetch_csv('https://gist.githubusercontent.com/gusgordon/eda583be659f6f38c243/raw/110c1955cd864b2edd652b897922eeb691325f25/gistfile1.txt', symbol='eps')
    
    context.stock = sid(8554) # S&P 500
    
    # Store past PE ratios, have some finite limit on the amount of past day's ratios to keep
    context.recent_PE_ratios = deque(maxlen=2000)
    
def handle_data(context, data):
    # Get the most recent earnings per share
    try:
        eps = data['eps']['eps'].split('|')
        recent_reported_EPS = float(eps[0][1:])
        #recent_operational_EPS = float(eps[1][1:])
        
        active = 1
    except:
        active = 0

    if active == 1:
        # Calculate price/earnings
        PE_ratio = data[context.stock].price / recent_reported_EPS
        
        # Calculate the average past P/E ratio to use for reference
        avg_PE_ratio = pd.Series(context.recent_PE_ratios).mean()
        
        # Store today's PE ratio to use in future averages
        context.recent_PE_ratios.append(PE_ratio)
        
        # Buy if the PE ratio is low, sell if the PE ratio is high
        # Use a leverage of 1
        if  PE_ratio < avg_PE_ratio:
            order_target_percent(context.stock, 1) # Long
        elif PE_ratio > avg_PE_ratio:
            order_target_percent(context.stock, -1) # Short

        #record(avg_PE_ratio=avg_PE_ratio,
               #current_PE_ratio=PE_ratio)
        record(cash = context.portfolio.cash)
        
    # If we don't have an EPS, don't take any position
    else:
        order_target_percent(context.stock, 0)
There was a runtime error.
7 responses

One day and no replies. Is my question too stupid?

Hi Emanuele,

The reason is the simulated broker calculates returns based on the total value of all your holdings - cash plus stock. Your algo used all your starting cash to buy stock, so your cash is 0. But the value of the stock you bought has increased, so your returns are positive. These are "unrealized gains" - gains from the stock price changing. If your algo manged to sell at the same price, your returns would be unchanged but they would be "realized gains" in the form of cash.

Another confusing bit: The simulator also allows you to borrow cash and buy more stock. This approximates a margin account, where your broker allows you to borrow cash to buy stock. If you start with $1M and buy $2M in stock, your cash balance would be negative: ($1M). Your equity value would be $2M in stock minus ($1M) in cash loans, or $1M. Your returns at this point would be 0%: (current equity - starting equity) / starting equity

Our simulator allows borrowing, but a real broker caps the amount you can borrow. The way to track your borrowing is to track your leverage via context.account.leverage. We track gross leverage there. A 2-3x leverage is a reasonable limit in simulation.

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.

Edited 2015-09-02

Want to chime in here. Above it was said (current equity - starting equity) / starting equity

It can be pretty helpful to realize that Quantopian is unfortunately ignoring unused cash and margin in chart and Returns values calculations.

A different route would be (portfolio - maxspent) / maxspent [profit in relation to cash put into play].

The original algo above doesn't involve negative cash so this might not be the best place to highlight this point, it is a fairly common problem tho. Of 15 of the most recent algos posted that I checked, 12 of them (80%) had negative cash and as a result the charts and Returns values were more positive than would happen in the real world.
Then there's also the flipside, not using all of starting capital. If you start with $1M and spend only $1000 and wind up with $2M all in cash, Q would consider it to be only 100% Returns currently, however that is $1000 turned into $2M for nearly 200,000%.

If addressed, then I wonder if we will also find that Alpha, Beta, Sharpe et al will also better indicate the merits of the algo.
Currently those change with different input capital specified in the UI even if actual amount spent is the same. Thanks.

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
'''
Here's a simple example of how it can be
  if Quantopian makes the change in calculating chart values and Returns.

The Quantopian Returns value is often wildly wrong like this and users wind up confused.

This code ventures into negative cash, still makes money.
The custom chart is close to reality or accurate.
The Quantopian chart is incorrect because it **ignores negative cash**.

That creates false optimism in users sometimes where the real market could then bite them.

In my opinion it is a terrible bug and should be high priority.
This points in the direction of the fix.

Add two zeros to the initial capital and charts will align better because no negative cash.
The custom chart remains the same no matter what input capital.

Once fixed, then I think everyone will find that suddenly Alpha, Beta, Sharpe et al will 
  consistently reflect the true nature of an algo.
  Currently they change wildly with different input capital and can't be trusted.
  
With this change Q could make more certain and reliable determinations in
  the Hedge Fund Managers Program, and members will know better how they are really doing.
'''
def initialize(context):
    context.stock = symbol('AAPL')
    schedule_function(buy, date_rule=date_rules.month_start())
    
def handle_data(context, data):
    true_returns(context)

def true_returns(context):
    csh_strt   = context.portfolio.starting_cash
    csh_now    = context.portfolio.cash
    if 'cash_low' not in context:
        context.cash_low = csh_strt
    shares_val = context.portfolio.positions_value
    cash_val   = csh_now - csh_strt   # cash_val can be negative
    values     = shares_val + cash_val
    drawdown   = csh_strt - context.cash_low
    returns    = 0
    if drawdown:
        returns = 100 * values / drawdown
        
        # Q is doing this instead, uncomment to see
        #returns = 100 * (context.portfolio.portfolio_value - csh_strt) / csh_strt
        
    record(TrueReturns = returns)

    if csh_now < context.cash_low:
        context.cash_low = csh_now
        if csh_now < 0:
            log.info('Cash low: ' + str(int(csh_now)))
            
def buy(context, data):
    order(context.stock, 9)

    
    
There was a runtime error.

I think that there is no reason to complain about how Q calculates returns. Notice how it says "$100 initial CAPITAL", and the performance is percentage "return on capital". If you were given a million in capital and only deployed $100 of it, your return on capital would be pretty poor. Their nomenclature is correct.

Also edited 2015-09-02 because my thoughts have evolved on this.

I think a lot of folks are thinking if they have a million in the account at Interactive Brokers, it is invested and tied up.
However, today, you can transfer money from there to your home bank quickly, maybe 1 minute, and back again.
In the example, whether it sits unused at your bank, or at IB, either way it is not invested and not really part of a portfolio in my opinion, at least not an active part, or not yet.

I can see others' point of view, just that what's most useful to a developer is to know output vs input that led to that output, then he or she can know the real effect of iterations.

A matter of theoretical value (current) or real/used value (proposed). I'm suggesting basing on cash put at risk, put into use, traded, activated.

Outflow
Inflow

I want to move over to https://www.quantopian.com/posts/returns for more about this.

All the answers and comments are very interesting. Thanx

Well I am wondering if wouldn't be better (as metric of performance) calculating the integral of the returns or true returns as stressed by Gary.