Back to Community
Simple Algorithm for Exploiting Market Correction: QQQ 350% Return Over 4 Years

When I say simple I mean reallllly simple. I mean 47 lines with comments and spacing. As in it most likely is severely flawed and needs a lot more work to protect itself from the market's many moods.

One know weakness is gradual price growth following an upward price jump. This will trigger a sell and short and then continue to lose money because there was no fall after the spike.

I will let this one live trade for a few months and see what happens. I'm betting it does best in highly volatile markets.

Clone Algorithm
66
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
def initialize(context):
    
    context.security = symbol('qqq')
    
def handle_data(context, data):
    
    # Do nothing if there are open orders (thanks to Alisa Deychman):
    if has_orders(context,data):
        print('has open orders - doing nothing!')
        return

    
    mav125= data[context.security].mavg(125)
    mav30= data[context.security].mavg(30)
    current_price = data[context.security].price
    
    cash = context.portfolio.cash
    
    #if trading 5% above the 30 day moving average
    if current_price/mav30>1.05:
        #sell everything and short as much as possible
        order_target_percent(context.security, -1)
        log.info("Selling %s" % (context.security.symbol))
        
    #if trading 5% below the 30 day moving average    
    if current_price/mav30<0.95 and cash>current_price:
        #buy as much as 97% of your cash will allow
        order_target_value(context.security, cash*0.97)
        log.info("Buying %s" % (context.security.symbol))
        
    record(stock_price=data[context.security].price)
    record(cash=cash)
    
#this section graciously provided by Alisa Deychman    
def has_orders(context,data):
    # Return true if there are pending orders.
    has_orders = False
    for sec in data:
        orders = get_open_orders(sec)
        if orders:
            for oo in orders:                  
                message = 'Open order for {amount} shares in {stock}'  
                message = message.format(amount=oo.amount, stock=sec)  
                log.info(message)

            has_orders = True
    return has_orders   
There was a runtime error.
5 responses

The algorithm is highly leveraged and in a live trading scenario, it's unlikely that a broker will allow your margin account to hold $50,000 on a $10,000 balance. To improve it, take a look at this post to help limit the leverage: https://www.quantopian.com/posts/template-limit-leverage-in-your-algos

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.

What if I just reduce the amount that I short during a sell/short cycle?

I'd suggest that you use the history function and pandas to calculate the moving averages, data[stock].mavg() is being depreciated because it requires a warm-up period. It was a pretty easy change in your case, so I went ahead and did it.

Clone Algorithm
35
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
def initialize(context):
    
    context.security = symbol('qqq')
    
def handle_data(context, data):
    
    # Do nothing if there are open orders (thanks to Alisa Deychman):
    if has_orders(context,data):
        print('has open orders - doing nothing!')
        return

    prices = history(125, '1d', 'price')[context.security]
    mav125= prices.mean()
    mav30= prices.iloc[-30:].mean()
    current_price = data[context.security].price
    
    cash = context.portfolio.cash
    
    #if trading 5% above the 30 day moving average
    if current_price/mav30>1.05:
        #sell everything and short as much as possible
        order_target_percent(context.security, -1)
        log.info("Selling %s" % (context.security.symbol))
        
    #if trading 5% below the 30 day moving average    
    if current_price/mav30<0.95 and cash>current_price:
        #buy as much as 97% of your cash will allow
        order_target_value(context.security, cash*0.97)
        log.info("Buying %s" % (context.security.symbol))
        
    record(stock_price=data[context.security].price)
    record(cash=cash)
    
#this section graciously provided by Alisa Deychman    
def has_orders(context,data):
    # Return true if there are pending orders.
    has_orders = False
    for sec in data:
        orders = get_open_orders(sec)
        if orders:
            for oo in orders:                  
                message = 'Open order for {amount} shares in {stock}'  
                message = message.format(amount=oo.amount, stock=sec)  
                log.info(message)

            has_orders = True
    return has_orders   
There was a runtime error.

Also, to get your leverage under control you only need to change line 17. context.portfolio.cash ==> context.portfolio.portfolio_value. When you short sell, you raise cash, so when you used your cash value when going long again, it was investing your original cash (equity), and the proceeds from the short sale. That was causing you to be over leveraged.

Clone Algorithm
35
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
def initialize(context):
    
    context.security = symbol('qqq')
    
def handle_data(context, data):
    
    # Do nothing if there are open orders (thanks to Alisa Deychman):
    if has_orders(context,data):
        print('has open orders - doing nothing!')
        return

    prices = history(125, '1d', 'price')[context.security]
    mav125= prices.mean()
    mav30= prices.iloc[-30:].mean()
    current_price = data[context.security].price
    
    cash = context.portfolio.portfolio_value
    
    #if trading 5% above the 30 day moving average
    if current_price/mav30>1.05:
        #sell everything and short as much as possible
        order_target_percent(context.security, -1)
        log.info("Selling %s" % (context.security.symbol))
        
    #if trading 5% below the 30 day moving average    
    if current_price/mav30<0.95 and cash>current_price:
        #buy as much as 97% of your cash will allow
        order_target_value(context.security, cash*0.97)
        log.info("Buying %s" % (context.security.symbol))
        
    record(stock_price=data[context.security].price)
    record(cash= context.portfolio.cash,
           portfolio_value=cash)
    
#this section graciously provided by Alisa Deychman    
def has_orders(context,data):
    # Return true if there are pending orders.
    has_orders = False
    for sec in data:
        orders = get_open_orders(sec)
        if orders:
            for oo in orders:                  
                message = 'Open order for {amount} shares in {stock}'  
                message = message.format(amount=oo.amount, stock=sec)  
                log.info(message)

            has_orders = True
    return has_orders   
There was a runtime error.

if you testing from 2005, the result have big difference, the strategy seems only work on bull market.

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
def initialize(context):
    
    context.security = symbol('qqq')
    
def handle_data(context, data):
    
    # Do nothing if there are open orders (thanks to Alisa Deychman):
    if has_orders(context,data):
        print('has open orders - doing nothing!')
        return

    prices = history(125, '1d', 'price')[context.security]
    mav125= prices.mean()
    mav30= prices.iloc[-30:].mean()
    current_price = data[context.security].price
    
    cash = context.portfolio.portfolio_value
    
    #if trading 5% above the 30 day moving average
    if current_price/mav30>1.05:
        #sell everything and short as much as possible
        order_target_percent(context.security, -1)
        log.info("Selling %s" % (context.security.symbol))
        
    #if trading 5% below the 30 day moving average    
    if current_price/mav30<0.95 and cash>current_price:
        #buy as much as 97% of your cash will allow
        order_target_value(context.security, cash*0.97)
        log.info("Buying %s" % (context.security.symbol))
        
    record(stock_price=data[context.security].price)
    record(cash= context.portfolio.cash,
           portfolio_value=cash)
    
#this section graciously provided by Alisa Deychman    
def has_orders(context,data):
    # Return true if there are pending orders.
    has_orders = False
    for sec in data:
        orders = get_open_orders(sec)
        if orders:
            for oo in orders:                  
                message = 'Open order for {amount} shares in {stock}'  
                message = message.format(amount=oo.amount, stock=sec)  
                log.info(message)

            has_orders = True
    return has_orders   
There was a runtime error.