Back to Community
Having trouble creating trading signals with Pipeline

Hi,

I am trying to create a simple strategy that buys AAPL when the 50 day Simple Moving Average (SMA) crosses above the 100 day SMA (as much as possible with available cash) and sells AAPL (all positions) when the 50 day SMA crosses below the 100 day SMA. In the code below, the log output shows the correct calculations for the moving averages each day and shows that they barely cross each other, as expected. However, the algorithm is erroneously trading very frequently, every couple of days. I think that there is something wrong with the reference to the moving average calculations, which are calculated using Pipeline.

Looking at the log output of the attached backtest, the algorithm should create the following transactions; these are the only times that the moving averages cross:
Buy 1/5/15
Sell 8/5/15
Buy 12/9/15
Sell 1/15/16

Would anyone be able to help? Thank you! Much appreciated :)

-Tommy

Clone Algorithm
17
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
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline import CustomFactor  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data import morningstar  
from quantopian.pipeline.factors import SimpleMovingAverage

# Create custom factor subclass to calculate a market cap based on yesterday's  
# close  
class MarketCap(CustomFactor):

    # Pre-declare inputs and window_length  
    inputs = [morningstar.valuation.market_cap]  
    window_length = 1

    # Compute market cap value  
    def compute(self, today, assets, out, mkt_cap):  
        out[:] = mkt_cap[-1]


def initialize(context):

    pipe = Pipeline()  
    attach_pipeline(pipe, 'example')

    # Construct the custom factor  
    mkt_cap = MarketCap()  
    pipe.add(mkt_cap, 'mkt_cap')

    # Create and apply a filter representing the top 500 equities by MarketCap. Couldn't get this to work without narrowing down universe first.  
    mkt_cap_top_500 = mkt_cap.top(500)

    # Narrow the universe  
    pipe.set_screen(mkt_cap_top_500)

    context.stock=symbol('AAPL')  
    set_benchmark(sid(24))
    
    context.sma_short= SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50)  
    pipe.add(context.sma_short, "sma_short")  
    context.sma_long= SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=100)  
    pipe.add(context.sma_long, "sma_long")
    
    schedule_function(trading, date_rule=date_rules.every_day(),            time_rule=time_rules.market_open(hours=1))
    
def before_trading_start(context, data):
    
    # get the output of my pipeline  
    context.output = pipeline_output('example')

    # index into it searching for just the security I'm looking for  
    aapl = context.output.loc[symbols('AAPL')]  
    log.info(aapl)

    update_universe(context.output.index) 

def trading(context, data):
    
    #If SMA short crosses above SMA long, then buy as much as possible.  
    if context.sma_short > context.sma_long and                 context.portfolio.positions_value == 0:  
        order_value(context.stock, context.portfolio.cash)
        
    #If SMA short crosses below SMA long, then sell everything.  
    if context.sma_short < context.sma_long and context.portfolio.positions_value>0:  
        order_target(context.stock, 0)  
def handle_data(context, data):  
     record(positions=context.portfolio.positions_value,  
          cash=context.portfolio.cash)
There was a runtime error.
3 responses

You could also add record(SMA_diff=context.sma_short-context.sma_long) inside trading (not handle_data) and see when it crosses 0.

Hi Andre,

When I tried that, I got the following error:

ValueError: Record only supports numeric values. Non-numeric value passed for key 'SMA_diff'  

I get the same error when trying to record context.sma_short and context.sma_long directly. I wonder if these are variables are arrays and I need to be referencing some element of the arrays?

Yes, you may have to use float(context.sma_short) and likewise with sma_long. Each factor in Pipeline output is a pandas.Series indexed by securities; when you only have one security, it's still a one-element Series, but you can convert it to a regular float as above.