Back to Community
Misleading results?

How could it be that my algorithm buying Facebook stocks is outperforming itself if I set Facebook itself as a benchmark (Total Returns 0.77 vs. Benchmark returns 0.58)?

Clone Algorithm
2
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
import numpy as np

# Called once at the start of the simulation.
def initialize(context):
    # Reference to the AAPL security.
    set_benchmark(sid(42950)) 
    context.stock = sid(42950)
    context.counter = 0
    context.seed = [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  0,  0,  1,  1,  0,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,]
    # Rebalance every day, an hour and a half after market open.
    schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open())

# This function was scheduled to run once per day at 11AM ET.
def my_rebalance(context, data):
    should_buy = context.seed[context.counter]
    #should_buy = 1
    # Take a 100% long position in AAPL. Readjusts each day to 
    # account for price fluctuations.
    if data.can_trade(context.stock):
        if should_buy == 0:
            #order_target_percent(context.fb, 1.00)
            #order(context.fb, 100)
            order_percent(context.stock, -0.01)
        else:
            order_percent(context.stock, 0.01)
    else:
        print('Non posso comprare!')
    context.counter += 1
There was a runtime error.
6 responses

It's an example of the achilles heel: Margin becomes illusory profit.

Notice in the beginning the returns curve is below bench. That's because not all of the initial capital had been spent yet.
Then when cash goes negative, returns appear to rise above the benchmark, however the broker is owed then, so the profits are not real.

If you negate commissions you'll see the pure version of that.

set_commission(commission.PerTrade(cost = 0.0))

The simplest way to protect from letting accidental margin lead one to believe that a change is positive when it really isn't (and visa-versa) would be to always record cash:

record(cash = context.portfolio.cash)

To illustrate the point in terms that might be easier to understand, this backtest appears to be a terrific strategy at 20% profit in 20 days.
Take a look at the code by clicking on the 'Source Code' tab.

Clone Algorithm
65
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
# https://www.quantopian.com/posts/misleading-results?utm_campaign=misleading-results

def initialize(context):
    schedule_function(trade, date_rules.every_day(), time_rules.market_open(minutes=1))

def trade(context, data):
    order(sid(8554), 3)

    #record(cash = context.portfolio.cash)    # uncomment to reveal the margin
There was a runtime error.

Simply recording cash, while advisable, has some limitations. A precise solution and more info can be found here and maybe start with the minimal version. This adds something like that to your code (hover over the custom chart) and commissions are off. I would have expected the two traces in the main chart to cross over at the point where all capital was used, not sure why it isn't so. Note however, when 100% of initial capital is used, pvr matches the Algorithm trace. It is at all times indicating what I would call risk-adjusted returns except that term appears to be taken already in the industry and tied to benchmarks.

It is incredibly useful to be able to see when a change is good or bad. My real money algo has more than doubled in 5 months. Perhaps the tool has something to do with that, being able to see clearly.

Clone Algorithm
0
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
import numpy as np

# Called once at the start of the simulation.
def initialize(context):
    # Reference to the AAPL security.
    set_benchmark(sid(42950)) 
    context.stock = sid(42950)
    context.counter = 0
    context.seed = [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  0,  0,  1,  1,  0,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,]
    # Rebalance every day, an hour and a half after market open.
    schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open())

    for i in range(1, 391):
        schedule_function(
            pvr,        date_rules.every_day(), time_rules.market_open(minutes=i))
    schedule_function(  
        _pvr_chart,     date_rules.every_day(), time_rules.market_open())

    set_commission(commission.PerTrade(cost = 0.0))
    
# This function was scheduled to run once per day at 11AM ET.
def my_rebalance(context, data):
    should_buy = context.seed[context.counter]
    #should_buy = 1
    # Take a 100% long position in AAPL. Readjusts each day to 
    # account for price fluctuations.
    if data.can_trade(context.stock):
        if should_buy == 0:
            #order_target_percent(context.fb, 1.00)
            #order(context.fb, 100)
            order_percent(context.stock, -0.01)
        else:
            order_percent(context.stock, 0.01)
    else:
        print('Non posso comprare!')
    context.counter += 1

    
    
    
    
    
    
    
    
def pvr(context, data):
    ''' Minimal custom chart of profit_vs_risk returns
    '''
    c = context  # Brevity, readability
    if 'pvr' not in c:
        # For real money, you can modify this to total cash input minus any withdrawals
        manual_cash = c.portfolio.starting_cash
        c.pvr = {
            'chart_pvr'      : 1,
            'chart_cash_low' : 1,
            'chart_max_shrt' : 0,
            'chart_max_risk' : 1,
            'start'          : manual_cash,
            'cash_low'       : manual_cash,
            'max_shrt'       : 0,
            'max_risk'       : 0,
        }
    c.pvr['cash_low'] = min(c.pvr['cash_low'], c.portfolio.cash)
    c.pvr['max_shrt'] = max(c.pvr['max_shrt'], abs(sum([z.amount * z.last_sale_price for s, z in c.portfolio.positions.items() if z.amount < 0])))
    c.pvr['max_risk'] = max(0, c.pvr['max_risk'], c.pvr['start'] - c.pvr['cash_low'], c.pvr['max_shrt'])

def _pvr_chart(context, data):
    # Profit_vs_Risk returns based on max amount actually invested, risked, long or short
    c = context
    if c.pvr['max_risk'] != 0: # Avoid zero-divide
        if c.pvr['chart_pvr']:  record(PvR = 100 * (c.portfolio.portfolio_value - c.pvr['start']) / c.pvr['max_risk'])
    if c.pvr['chart_cash_low']: record(CashLow = c.pvr['cash_low'])
    if c.pvr['chart_max_shrt']: record(MxShrt  = c.pvr['max_shrt'])
    if c.pvr['chart_max_risk']: record(MxRisk  = c.pvr['max_risk'])
    
    
There was a runtime error.

Thank you Blue, that was crystal clear!

What do you think about this Blue?
I limited the amount of stock to buy so that I never go below zero with cash and resell just the stock I already have in my portfolio. Still my system outperforms the benchmark itself.

Clone Algorithm
1
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
import numpy as np

# Called once at the start of the simulation.
def initialize(context):
    context.counter = 0
    context.stock = sid(42950)
    set_benchmark(context.stock)
    context.signals = [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
  0,  0,  0,  1,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  0,  0,  1,  1,  0,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,]
    # Rebalance every day, an hour and a half after market open.
    schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open())

# This function was scheduled to run once per day at 11AM ET.
def my_rebalance(context, data):
    should_buy = context.signals[context.counter]
    n = 5
    #should_buy = 1
    # Take a 100% long position in AAPL. Readjusts each day to 
    # account for price fluctuations.
    if data.can_trade(context.stock) and context.portfolio.cash >= data.current(context.stock, 'price')*n:
        if should_buy == 0:
            #order_value(context.stock, -context.portfolio.cash*0.1)
            order(context.stock, -n)
        else:
            #order_value(context.stock, context.portfolio.positions_value*0.1)
            order(context.stock, n)
    elif data.can_trade(context.stock) and context.portfolio.cash < data.current(context.stock, 'price')*n:
        if should_buy == 0:
            #order_value(context.stock, -context.portfolio.cash*0.1)
            order(context.stock, -n)
        else:
            pass
    else:
        print('Cannot trade')
    context.counter += 1
    record(Cash = context.portfolio.cash,
           Portfolio_Value = context.portfolio.portfolio_value,
           Profit = context.portfolio.portfolio_value - context.portfolio.starting_cash,
           Positions_value = context.portfolio.positions_value,
           #Price = data.current(context.stock, 'price'),
          )
           
           
           
           
           
           
            
    
    
    
    
    
    
    
    
    
    
    
    
    
There was a runtime error.

Some comments in the code. This adds a loop so you can experiment with more than one stock to some degree. Think toward pipeline.
You'll want to direct future questions to the community as my personal fitness haha trainer fee is market. :|
The scheduling of cash_low is time-consuming so you can turn that off by uncommenting the break, to prevent that, the other loop.
Hopefully you'll find some of this exercise educational, useful.

Clone Algorithm
1
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
import numpy as np

def initialize(context):    # Called once at the start of the backtest.
    context.counter  = 0
    context.cash_low = context.portfolio.starting_cash
    context.stocks   = [sid(42950), sid(39840)]   # [sid(42950), sid(39840)]
    context.signals  = signals()
    set_benchmark(context.stocks[0])    # first one listed
    schedule_function(balance, date_rules.every_day(), time_rules.market_open())

    ''' An alternative to run something every minute instead of handle_data.
        This is easier to turn off. The 391 is necessary to include minute 390. '''
    for i in range(1, 391):
        #break         # comment to turn this ON
        schedule_function(
            cash_low, date_rules.every_day(), time_rules.market_open(minutes=i))

    '''
    Couple of notes you can delete (of course) ...
    Whenever I see "my_rebalance" it always makes me think, wait a second,
      excuse me sirs, if it isn't your rebalance, who's is it?
      You mean I can't just assume that it is yours?
      Does "my_rebalance" mean I'm not allowed to look at it?
      Too many questions are raised by "my"-anything.
    Anyway ...
    Next, the first time rebalance runs, the "re" part of that doesn't apply,
      so technically "rebalance" is a misconception. So I call that "balance".
      Besides the fact that it requires less typing and has fewer syllables,
        "balance" keeps the uber-nerd-perfectionist in my head from bouncing off the walls so much.
    '''

def balance(context, data):
    c = context  # huh?
    ''' I know. The first time I saw c = context, I had the same reaction.
        The first time I saw that was in an example from a Quantopian representative.
        I made it beyond that first reaction and gave it a try and now I love c = context.
        Merely a matter of habit.
        One-seventh the amount of typing.
        Makes code far easier to read also.
    '''
    cash = c.portfolio.cash / len(c.stocks)     # equally divided cash
    should_buy = c.signals[c.counter]
    #should_buy = 1
    n = 5

    # Take a proportional long position in stocks. Readjusts each day to
    #   account for price fluctuations.
    for s in c.stocks:
        if not data.can_trade(s):
            # Only happens if sid isn't listed yet or has delisted ...
            log.info('Cant trade {}'.format(s.symbol))
            continue    # skip. "continue" is Python for don't continue, eh-hem
        if cash >= data.current(s, 'price') * n:
            if should_buy:
                order(s, n)
                #order_value(s, c.portfolio.positions_value*0.1)
            else:
                order(s, -n)
                #order_value(s, -cash*0.1)
        else:
            if not should_buy:
                order(s, -n)
                #order_value(s, -cash*0.1)

    c.counter += 1
    record(
        Cash      = cash,
        PnL       = c.portfolio.pnl,
        Portfolio = c.portfolio.portfolio_value,
        Positions = c.portfolio.positions_value,
    )

def signals():
    return [
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
        0,  0,  0,  1,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
        0,  0,  1,  1,  0,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
        0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
        0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
    ]

def cash_low(context, data):
    if context.portfolio.cash < context.cash_low:
        context.cash_low = context.portfolio.cash
        record(CashLow = context.cash_low)
There was a runtime error.

Thanks man, really appreciate that!