Back to Community
Simple example investment program available to share?

I read the entire getting started guide twice, and I still can’t build the program I want to build.
The tutorial really leaves a lot to be desired.
I’m looking for a program with examples of basic functions:

  • get stock data for a particular stock
    • use money from a ‘bank account’
    • buy the stock based on some kind of simple rule
    • sell based on some kind of simple rule
    • run the algorithm across a historical time slice of a few years with repeated buys and sells
    • print the outcome of the investment

That really shouldn’t be that hard right? It would be greatly appreciated if someone could share a simple example so that I have a foundation to work from.

3 responses

Here's an algo to maybe use as a starter. It's one approach and I'm sure many of our community members have their own. It's also just some random rules I put together for an example so don't be too critical of the results but rather look at the algo framework.

I believe it does what you wanted:

  • Gets stock data for a particular stock(s). The ticker(s) can be entered in line 31.
  • Use money from a 'bank account'. Quantopian starts with a fixed amount of cash in a portfolio. The amount is not set in the algo but rather in the backtest. Enter the starting cash in the text box near the upper right corner of the IDE before running a backtest.
  • Buy/Sell based upon simple rules. The rules are set up in this algo in the make_pipeline method. These can be arbitrarily complex.
  • Run the algo across a historical time slice. This is often referred to a backtest. The backtest dates are set in the two text boxes near the upper right corner of the IDE before running a backtest.
  • Print the outcome of the investment. The backtest page displays a wide variety of metrics about the backtest results. There is a pretty good writeup on it's features in this post https://www.quantopian.com/posts/improved-backtest-analysis .

This is just a framework that I've found helpful to start with. Note that orders can be placed one of two ways: 1) using order methods or 2) using optimize methods. One can switch between the two methods by putting the respective name in the schedule function. This was only done to show the two options and also a (not too subtle) encouragement to use the optimize method going forward. It's much more powerful as one begins to impose constraints. It's also required to enter the contest. Check out the docs https://www.quantopian.com/help#optimize-api .

Of course there can be a lot added to make this algo more robust, and to handle trades in a more complex way, and to do better reporting, and on and on... This was mostly meant to be a concise but real and functional algo which can be built upon.

It would be instructional if others in the community could also post their approaches to an algo framework. There really isn't a specific right way and a lot boils down to personal coding style.

Hope this helps.

Clone Algorithm
11
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 sample algorithm on Quantopian for you to test and adapt.

One can either use the plain order methods or the optimize methods.
"""

# Import necessary Pipeline modules
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output

# Import specific filters and factors which will be used
from quantopian.pipeline.filters import QTradableStocksUS, StaticAssets
from quantopian.pipeline.factors import RSI, SimpleMovingAverage

# Import datasets which will be used
from quantopian.pipeline.data.builtin import USEquityPricing

# import optimize
import quantopian.optimize as opt
 
# Import pandas
import pandas as pd

def initialize(context):
    """
    Initialize constants, create pipeline, and schedule functions
    This uses the default slippage and commission models
    """
    # Universe we wish to trade
    # Place one or more desired symbols below
    context.MY_STOCKS = symbols('SPY', 'GLD')
    
    # Create our weights (evenly weighted)
    context.WEIGHT = 1.0 / len(context.MY_STOCKS)
        
    # Constants for min and max RSI
    context.MIN_RSI = 30
    context.MAX_RSI = 70

    # Make our pipeline and attach to the algo
    attach_pipeline(make_pipeline(context), 'my_pipe')

    # Place orders
    schedule_function(
        func=place_orders_using_optimize,
        date_rule=date_rules.week_start(),
        time_rule=time_rules.market_open()
    )
    

def make_pipeline(context):
    """
    Define a pipeline.
    This not only defines the data but also the logic to determine longs and shorts
    
    We break this code out into its own function to make it easier to
    test and modify in isolation. In particular, this function can be
    copy/pasted into research and run by itself.
    Parameters
    -------
    context : AlgorithmContext

    Returns
    -------
    pipe : Pipeline
        Represents computations we would like to perform on the assets
    """
    my_universe = StaticAssets(context.MY_STOCKS)
    
    # Create any needed factors.
    rsi = RSI(window_length=10)
    sma_10 = SimpleMovingAverage([USEquityPricing.close], window_length=10)
    sma_25 = SimpleMovingAverage([USEquityPricing.close], window_length=25)
  
    # Create any filters based upon these factors
    rsi_between_min_max = (rsi > context.MIN_RSI) & (rsi < context.MAX_RSI)
    
    # Rules to long and short stocks
    # Open (long or short) any securities meeting these rules
    # Anything held which isn't in either of these will be closed
    longs = (
        my_universe
        & rsi_between_min_max
        & (sma_10 < sma_25)
        )
    
    shorts = (
        my_universe
        & rsi_between_min_max
        & (sma_10 > sma_25)
        )
      
    # Create our pipeline
    pipe = Pipeline(
        columns={
            'longs': longs,
            'shorts': shorts,
        },
        screen=my_universe,
    )
    
    return pipe  
        
def before_trading_start(context, data):
    """
    Run our pipeline to fetch the actual data. 
    It's a good practice to place the pipeline execution here. 
    This gets allocated more time than scheduled functions.
    """
    context.output = pipeline_output('my_pipe')
    
def place_orders_using_optimize(context, data):
    """
    Use Optimize to place orders all at once
    """
    # Make a series of the longs and shorts and associated weights
    # Ensure that all the short weights are negative (this is what tells opt to short them)
    longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
    shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

    # Combine the two
    weights = pd.concat([longs, shorts])
    
    # Create our TargetWeights objective
    target_weights = opt.TargetWeights(weights) 

    # Execute the order_optimal_portfolio method with above objective and constraint
    # No need to loop through the stocks. 
    # The order_optimal_portfolio does all the ordering at one time
    # Also closes any positions not in 'all_alphas'
    # As a bonus also checks for 'can_trade'
    # Could set constraints here if desired
    order_optimal_portfolio(
        objective = target_weights,
        constraints = []
    )
    
def place_orders_using_order_method(context, data):
    """
    Use order methods to place orders
    """
    # Make a series of the longs and shorts and associated weights
    # Ensure that all the short weights are negative (this is what tells order to short them)
    longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
    shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

    # Combine the two
    weights = pd.concat([longs, shorts])

    # Order the stocks
    for stock, weight in weights.iteritems():
        if data.can_trade(stock):
            order_target_percent(stock, weight)
            
    # Close any positions not in our long or short list
    for stock, position in context.portfolio.positions.iteritems():
        if data.can_trade(stock) and stock not in weights.index:
            order_target_percent(stock, 0)
There was a runtime error.
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.

Here is the same framework but modified to trade a universe of securities rather than pre-defined ones. This is the more common approach. It's also required for algos entered into the contest.

Again this is just some random rules I put together for an example so don't be too critical of the results but rather look at the algo framework.

Clone Algorithm
10
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 sample algorithm on Quantopian for you to test and adapt.

One can either use the plain order methods or the optimize methods.
"""

# Import necessary Pipeline modules
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output

# Import specific filters and factors which will be used
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.factors import RSI, SimpleMovingAverage

# Import datasets which will be used
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data.morningstar import Fundamentals

# import optimize
import quantopian.optimize as opt
 
# Import pandas
import pandas as pd

def initialize(context):
    """
    Initialize constants, create pipeline, and schedule functions
    This uses the default slippage and commission models
    """
    
    # Constants for min and max RSI
    context.MIN_RSI = 30
    context.MAX_RSI = 70
    
    # Constants for target qty of longs and shorts. Equally weight each security.
    context.LONG_QTY = 50
    context.SHORT_QTY = 50
    
    context.WEIGHT = 1.0 / (context.LONG_QTY + context.SHORT_QTY)
    
    # Make our pipeline and attach to the algo
    attach_pipeline(make_pipeline(context), 'my_pipe')

    # Place orders
    schedule_function(
        func=place_orders_using_order_method,
        date_rule=date_rules.week_end(),
        time_rule=time_rules.market_open()
    )
    

def make_pipeline(context):
    """
    Define a pipeline.
    This not only defines the data but also the logic to determine longs and shorts
    
    We break this code out into its own function to make it easier to
    test and modify in isolation. In particular, this function can be
    copy/pasted into research and run by itself.
    Parameters
    -------
    context : AlgorithmContext

    Returns
    -------
    pipe : Pipeline
        Represents computations we would like to perform on the assets
    """
    tradable_universe = QTradableStocksUS()
    
    # Create any needed factors.
    close_price = USEquityPricing.close.latest
    value_score = Fundamentals.value_score.latest
    rsi = RSI(window_length=10)
    sma_10 = SimpleMovingAverage([USEquityPricing.close], window_length=10)
    sma_25 = SimpleMovingAverage([USEquityPricing.close], window_length=25)
  
    # Create any filters based on these factors
    reasonable_price = (close_price > 5) & (close_price < 1000)
    my_universe = tradable_universe & reasonable_price
    
    rsi_between_min_max = (rsi > context.MIN_RSI) & (rsi < context.MAX_RSI)
    
    # Rules to long and short stocks
    # Open (long or short) any securities meeting these rules
    # Anything held which isn't in either of these will be closed
    longs = (
        my_universe
        & rsi_between_min_max
        & (sma_10 < sma_25)
        & value_score.percentile_between(0, 30)
        )
    
    shorts = (
        my_universe
        & rsi_between_min_max
        & (sma_10 > sma_25)
        & value_score.percentile_between(70, 100)
        )
      
    # Now that we have a big pool of potential longs and shorts
    # Create filters to select only the quantity of each we want to hold
    # Here we just take the lowest and highest RSI respectively
    best_longs = rsi.bottom(context.LONG_QTY, mask=longs)
    best_shorts = rsi.top(context.SHORT_QTY, mask=shorts)
    
    # Create our pipeline
    pipe = Pipeline(
        columns={
            'longs': longs,
            'shorts': shorts,
        },
        screen=best_longs | best_shorts,
    )
    
    return pipe  
        
def before_trading_start(context, data):
    """
    Run our pipeline to fetch the actual data. 
    It's a good practice to place the pipeline execution here. 
    This gets allocated more time than scheduled functions.
    """
    context.output = pipeline_output('my_pipe')
    
def place_orders_using_optimize(context, data):
    """
    Use Optimize to place orders all at once
    """
    # Make a series of the longs and shorts and associated weights
    # Ensure that all the short weights are negative (this is what tells opt to short them)
    longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
    shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

    # Combine the two
    weights = pd.concat([longs, shorts])
    
    # Create our TargetWeights objective
    target_weights = opt.TargetWeights(weights) 

    # Execute the order_optimal_portfolio method with above objective and constraint
    # No need to loop through the stocks. 
    # The order_optimal_portfolio does all the ordering at one time
    # Also closes any positions not in 'all_alphas'
    # As a bonus also checks for 'can_trade'
    # Could set constraints here if desired
    order_optimal_portfolio(
        objective = target_weights,
        constraints = []
    )
    
def place_orders_using_order_method(context, data):
    """
    Use order methods to place orders
    """
    # Make a series of the longs and shorts and associated weights
    # Ensure that all the short weights are negative (this is what tells order to short them)
    longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
    shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

    # Combine the two
    weights = pd.concat([longs, shorts])

    # Order the stocks
    for stock, weight in weights.iteritems():
        if data.can_trade(stock):
            order_target_percent(stock, weight)
            
    # Close any positions not in our long or short list
    for stock, position in context.portfolio.positions.iteritems():
        if data.can_trade(stock) and stock not in weights.index:
            order_target_percent(stock, 0)
There was a runtime error.

Great thank you! Good to have a comprehensive starting point.