Back to Community
Search someone to help or work with me to make my algo backtestable, i am learning..

Hi !

I am writting this algo below, and i need your help to make it backtestable :)

i am currently at the line losstrade for a syntax error that i don't understand because the syntax pass for the order_size_after_loss line just before with the same syntax.

Loading notebook preview...
Notebook previews are currently unavailable.
15 responses

Can you make it any more legible?

Hi Jamie, i put it through notebook :)

Upload post !

After a weekend and this morning on it, i share with you the progress of my work.

Bilan :
- no error backtest (it's already huge for me lol) But.. balance still flat, need help to determine that... Debugger can't :'(
- code simplified and clarified

My goal :
- Make this version backtastable
- Add module slippage and commision
- Make it tradable on multiple continuous future

my ultimate goal, use this strategy with an LSTM, and see if the percentage of success can be improved

Before that, see what is doing on equities.

I let you read it, me i'am going to drink a full coffee pot

Loading notebook preview...
Notebook previews are currently unavailable.

Hi quant team,

I am remi guérin, my account is down, but like you see i will be able to create an other. Could you check what's wrong ? thanks :)
Fearing about to losse my work.. i send you a message at the feedback adress.

@Guer Rem / @guerin remi

Sorry for any inconvenience. You should have gotten a support email stating your account is now restored along with access to all your previous notebooks and algos. Quantopian automatically checks for attempts to import modules which are blacklisted or not supported. Too many attempts and a lock is placed on one's account. In cases like this, simply send an email to support and the lock can be manually lifted.

Again, sorry about that and also didn't intend to highjack this thread.

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.

Hi Dan, thanks that works !

Hi all,

Post update!
My first report :)
I am still out of the constraints contest.
Now work on that. If you see something wrong, don't hesitate to tell me !

Loading notebook preview...
Notebook previews are currently unavailable.

Hi !

The previous post was backtested just on AAPL.
Since i have built my pipeline with all constraints for the contest, and i have an error that i can not fix :

TypeError: zipline.pipeline.term.getitem() expected a value of type zipline.assets._assets.Asset for argument 'key', but got int instead.
There was a runtime error on line 87.

line 87 : algo.attach_pipeline(make_pipeline(), 'my_pipeline')

If someone can help me :)

Loading notebook preview...
Notebook previews are currently unavailable.

Hi !

I find the problem for my previous post, it was the StockWit. i removed it and search later a custom factor to determine the alpha to optimize.
Now i have an other prob for :


AttributeError: 'list' object has no attribute 'referenced_assets'
There was a runtime error on line 285.


I dont understand, because i have no term refering to 'referenced_assets' at line 285.

Loading notebook preview...
Notebook previews are currently unavailable.

It was bracket to remove for 'objective=[opt.TargetWeights(target_weights)],' objective=opt.TargetWeights(target_weights),

Best practice to screen out nans within the pipe as a rule:

screen=(beta.notnull() & securities_to_trade),

Hi BS,

I put .dropna() on all my pipeline_output lol

I noticed that i dont use correctly the constraint in my signal code "SignalUp" and "SignalDown".
The pipeline return True securities where it shouldn't
I attached the pipe. If someone can explain me :)

Loading notebook preview...
Notebook previews are currently unavailable.

The pipe use apparently any() by default to determine if a list of bool is True or False and i cant get ahead to use all()... help ???!

Several issues...

First, one cannot use the and operator with factors. Use & instead. Factors can only be manipulated with a small set of methods and operators (see the list here https://www.quantopian.com/help#quantopian_pipeline_factors_Factor ). Using the and operator doesn't generate an error which often makes this hard to catch. Seems like everything is working but it really isn't.

Second, the & operator has a higher precedence than the comparison operators > and <. Put parenthesis around the factor comparisons to force python to evaluate those first. (see the python docs for info on precedence https://docs.python.org/3/reference/expressions.html#operator-precedence).

So, in the notebook replace the following:

SignalUp = (volume < (volume1/2) and close < close1 and close1 > close2 and close2 > close3 and close3 > close4 and close4 > close5 and close5 > close6 and close6 > close7 and close7 > close8 and close8 > close9 and close9 > close10 and close10 > close11 and close11 > close12 and close12 > close13 and close13 > close14)

With this. Notice the use of & instead of and and the parenthesis around any factor comparisons

    SignalUp = ((volume < (volume1/2))  
                & (close < close1)  
                & (close1 > close2)  
                & (close2 > close3)  
                & (close3 > close4)  
                & (close4 > close5)  
                & (close5 > close6)  
                & (close6 > close7)  
                & (close7 > close8)  
                & (close8 > close9)  
                & (close9 > close10)  
                & (close10 > close11)  
                & (close11 > close12)  
                & (close12 > close13)  
                & (close13 > close14))

Attached is a notebook with these changes. Hope this helps.

Good luck.

Loading notebook preview...
Notebook previews are currently unavailable.

Hi Dan, many thanks, works fine !

I attach my first backtest in positive with a simple strategy.
I will incorporate other simple strat.

Clone Algorithm
1
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
from quantopian.pipeline.experimental import risk_loading_pipeline
import quantopian.algorithm as attach_pipeline
import quantopian.algorithm as pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import AverageDollarVolume
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.filters import QTradableStocksUS
import quantopian.algorithm as order_optimal_portfolio
from quantopian.pipeline.factors import SimpleBeta
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data import Fundamentals
import quantopian.algorithm as algo
import quantopian.optimize as opt
import numpy as np

MAX_GROSS_LEVERAGE = 1

MAX_SHORT_POSITION_SIZE = 0.1  # 1%
MAX_LONG_POSITION_SIZE = 0.1  # 1%

class CloseOnN(CustomFactor):
    base_universe = QTradableStocksUS()
    inputs = [USEquityPricing.close]  
    window_length = 1
    mask=base_universe
    def compute(self, today, assets, out, close):  
        out[:] = close[0]
        
class OpenOnN(CustomFactor):
    base_universe = QTradableStocksUS()
    inputs = [USEquityPricing.open]  
    window_length = 1 
    mask=base_universe
    def compute(self, today, assets, out, open):  
        out[:] = open[0]
        
class HighOnN(CustomFactor):
    base_universe = QTradableStocksUS()
    inputs = [USEquityPricing.high]  
    window_length = 1
    mask=base_universe
    def compute(self, today, assets, out, high):  
        out[:] = high[0]

class LowOnN(CustomFactor):
    base_universe = QTradableStocksUS()
    inputs = [USEquityPricing.low]  
    window_length = 1
    mask=base_universe
    def compute(self, today, assets, out, low):  
        out[:] = low[0]
        
class VolumeOnN(CustomFactor):
    base_universe = QTradableStocksUS()
    inputs = [USEquityPricing.volume]  
    window_length = 1
    mask=base_universe
    def compute(self, today, assets, out, volume):  
        out[:] = volume[0]
        
class MarketCap(CustomFactor):
    inputs = [USEquityPricing.close, Fundamentals.shares_outstanding]
    window_length = 1
    def compute(self, today, assets, out, close, shares):
        out[:] = close[0] * shares[0]
        
class Close1Close(CustomFactor):
    inputs = [USEquityPricing.close, USEquityPricing.open]
    window_length = 1
    def compute(self, today, assets, out, close, open):
        out[:] = close[-1] - open[0]
        
class MinTargetUp(CustomFactor):
    inputs = [USEquityPricing.open, USEquityPricing.low]
    window_length = 1
    def compute(self, today, assets, out, open, low):
        out[:] = (open[0] - low[0]) * 1.236
        
class MinTargetDown(CustomFactor):
    inputs = [USEquityPricing.open, USEquityPricing.high]
    window_length = 1
    def compute(self, today, assets, out, open, high):
        out[:] = (high[0] - open[0]) * 1.236

def initialize(context):

    set_slippage(us_equities=slippage.FixedBasisPointsSlippage(basis_points=5, volume_limit=0.1))
    set_commission(commission.PerShare(cost=0.01, min_trade_cost=0))

    schedule_function(
            my_record_vars,
            date_rules.every_day(),
            time_rules.market_open(minutes=1),
            half_days = True
    )
        
    schedule_function(
            my_rebalance,
            date_rules.every_day(),
            time_rules.market_open(hours = 0, minutes = 1)
    )
    
    schedule_function(
            before_trading_start,
            date_rules.every_day(),
            time_rules.market_open(hours = 0, minutes = 1)
    )
    
    # Define the beta-to-SPY factor in Pipeline.
    beta = SimpleBeta(
                    target=sid(8554),
                    regression_length=260,
                    )
    
    algo.attach_pipeline(make_pipeline(), 'my_pipeline')
    algo.attach_pipeline(make_pipeline(), 'data_pipe')
    algo.attach_pipeline(make_pipeline(), 'pipe')
    algo.attach_pipeline(risk_loading_pipeline(), 'risk_pipe')
    # Attach the risk loading pipeline to our algorithm.
    algo.attach_pipeline(risk_loading_pipeline(), 'risk_loading_pipeline')

def make_pipeline():

    mkt_cap = MarketCap()
    mkt_cap_top_5000 = mkt_cap.top(5000)
    dollar_volume = AverageDollarVolume(window_length=30)
    high_dollar_volume = dollar_volume.percentile_between(90, 100)
    high_cap_high_dv = mkt_cap_top_5000 & high_dollar_volume
    
    close = USEquityPricing.close.latest
    close1 = CloseOnN(window_length = 2)
    close2 = CloseOnN(window_length = 3)
    close3 = CloseOnN(window_length = 4)
    close4 = CloseOnN(window_length = 5)
    close5 = CloseOnN(window_length = 6)
    close6 = CloseOnN(window_length = 7)
    close7 = CloseOnN(window_length = 8)
    close8 = CloseOnN(window_length = 9)
    close9 = CloseOnN(window_length = 10)
    close10 = CloseOnN(window_length = 11)
    close11 = CloseOnN(window_length = 12)
    close12 = CloseOnN(window_length = 13)
    close13 = CloseOnN(window_length = 14)
    close14 = CloseOnN(window_length = 15)
    
    open = USEquityPricing.open.latest
    open1 = OpenOnN(window_length = 2)
    open2 = OpenOnN(window_length = 3)
    open3 = OpenOnN(window_length = 4)
    open4 = OpenOnN(window_length = 5)
    open5 = OpenOnN(window_length = 6)
    open6 = OpenOnN(window_length = 7)
    open7 = OpenOnN(window_length = 8)
    open8 = OpenOnN(window_length = 9)
    open9 = OpenOnN(window_length = 10)
    open10 = OpenOnN(window_length = 11)
    open11 = OpenOnN(window_length = 12)
    open12 = OpenOnN(window_length = 13)
    open13 = OpenOnN(window_length = 14)
    open14 = OpenOnN(window_length = 15)
    
    high = USEquityPricing.high.latest
    high1 = HighOnN(window_length = 2)
    high2 = HighOnN(window_length = 3)
    high3 = HighOnN(window_length = 4)
    high4 = HighOnN(window_length = 5)
    high5 = HighOnN(window_length = 6)
    high6 = HighOnN(window_length = 7)
    high7 = HighOnN(window_length = 8)
    high8 = HighOnN(window_length = 9)
    high9 = HighOnN(window_length = 10)
    high10 = HighOnN(window_length = 11)
    high11 = HighOnN(window_length = 12)
    high12 = HighOnN(window_length = 13)
    high13 = HighOnN(window_length = 14)
    high14 = HighOnN(window_length = 15)
    
    low = USEquityPricing.low.latest
    low1 = HighOnN(window_length = 2)
    low2 = HighOnN(window_length = 3)
    low3 = HighOnN(window_length = 4)
    low4 = HighOnN(window_length = 5)
    low5 = HighOnN(window_length = 6)
    low6 = HighOnN(window_length = 7)
    low7 = HighOnN(window_length = 8)
    low8 = HighOnN(window_length = 9)
    low9 = HighOnN(window_length = 10)
    low10 = HighOnN(window_length = 11)
    low11 = HighOnN(window_length = 12)
    low12 = HighOnN(window_length = 13)
    low13 = HighOnN(window_length = 14)
    low14 = HighOnN(window_length = 15)
    
    volume = USEquityPricing.volume.latest
    volume1 = VolumeOnN(window_length = 2)
    volume2 = VolumeOnN(window_length = 3)
    volume3 = VolumeOnN(window_length = 4)
    volume4 = VolumeOnN(window_length = 5)
    volume5 = VolumeOnN(window_length = 6)
    volume6 = VolumeOnN(window_length = 7)
    volume7 = VolumeOnN(window_length = 8)
    volume8 = VolumeOnN(window_length = 9)
    volume9 = VolumeOnN(window_length = 10)
    volume10 = VolumeOnN(window_length = 11)
    volume11 = VolumeOnN(window_length = 12)
    volume12 = VolumeOnN(window_length = 13)
    volume13 = VolumeOnN(window_length = 14)
    volume14 = VolumeOnN(window_length = 15)

    fibcoef = 1.236

    close1close = Close1Close(window_length = 1)
    mintargetup = MinTargetUp(window_length = 1)
    mintargetdown = MinTargetDown(window_length = 1)

    mindiffup = (close1close <= 0.01)
    mintargetupup = (mintargetup > (close * 0.001))

    pricetargetup = (close1 + ((close1 - low1) * 1.236))
    range_stoplossup = (close1 / 2)
    pricestoplossup = (close1 - (close1 / 2))
    
    mindiffdown = (close1close <= 0.01)
    mintargetdowndown = (mintargetdown > (close * 0.001))
    
    pricetargetdown = (close1 - ((high1 - close1) * 1.236))
    range_stoplossdown = (close1 / 2)
    pricestoplossdown = (close1 + (close1 / 2))

    SignalUp = ((volume/6 > volume1)
                & (close > close1)
                & (close1 < close2)
                & (mindiffup)
                & (mintargetupup))
        
    SignalDown = ((volume/6 > volume1) 
                  & (close < close1) 
                  & (close1 > close2)
                  & (mindiffdown)
                  & (mintargetdowndown))

    securities_to_trade = (SignalUp|SignalDown)

    return Pipeline(
        columns={

            'open': open,
            'open1': open1,
            'open2': open2,
            'open3': open3,
            'open4': open4,
            'open5': open5,
            'open6': open6,
            'open7': open7,
            'open8': open8,
            'open9': open9,
            'open10': open10,
            'open11': open11,
            'open12': open12,
            'open13': open13,
            'open14': open14,
            
            'close': close,
            'close1': close1,
            'close2': close2,
            'close3': close3,
            'close4': close4,
            'close5': close5,
            'close6': close6,
            'close7': close7,
            'close8': close8,
            'close9': close9,
            'close10': close10,
            'close11': close11,
            'close12': close12,
            'close13': close13,
            'close14': close14,
            
            'high': high,
            'high1': high1,
            'high2': high2,
            'high3': high3,
            'high4': high4,
            'high5': high5,
            'high6': high6,
            'high7': high7,
            'high8': high8,
            'high9': high9,
            'high10': high10,
            'high11': high11,
            'high12': high12,
            'high13': high13,
            'high14': high14,
            
            'low': low,
            'low1': low1,
            'low2': low2,
            'low3': low3,
            'low4': low4,
            'low5': low5,
            'low6': low6,
            'low7': low7,
            'low8': low8,
            'low9': low9,
            'low10': low10,
            'low11': low11,
            'low12': low12,
            'low13': low13,
            'low14': low14,
            
            'volume': volume,
            'volume1': volume1,
            'volume2': volume2,
            'volume3': volume3,
            'volume4': volume4,
            'volume5': volume5,
            'volume6': volume6,
            'volume7': volume7,
            'volume8': volume8,
            'volume9': volume9,
            'volume10': volume10,
            'volume11': volume11,
            'volume12': volume12,
            'volume13': volume13,
            'volume14': volume14,
            
            'mindiffup': mindiffup,
            'mindiffdown': mindiffdown,
            
            'mintargetupup': mintargetupup,
            'pricetargetup' : pricetargetup,
            'pricestoplossup': pricestoplossup,
            
            'mintargetdown': mintargetdown,
            'pricetargetdown': pricetargetdown,
            'pricestoplossdown': pricestoplossup,
                        
            'SignalUp': SignalUp,
            'SignalDown': SignalDown,
            
            'high_cap_high_dv': high_cap_high_dv,
        },
        screen=(securities_to_trade),
    )

def compute_target_weights(context, data):
    """
    Compute ordering weights.
    """

    # Initialize empty target weights dictionary.
    # This will map securities to their target weight.
    weights = {}

    # If there are securities in our longs and shorts lists,
    # compute even target weights for each security.
    if context.SignalUp and context.SignalDown:
       SignalUp_weight = 0.5 / len(context.SignalUp)
       SignalDown_weight = -0.5 / len(context.SignalDown)
    else:
        return weights

    # Exit positions in our portfolio if they are not
    # in our longs or shorts lists.
    for security in context.portfolio.positions:
        if security not in context.SignalUp and security not in context.SignalDown and data.can_trade(security):
           weights[security] = 0

    for security in context.SignalUp:
        weights[security] = SignalUp_weight

    for security in context.SignalDown:
        weights[security] = SignalDown_weight

    return weights

def before_trading_start(context, data):

    # Gets our pipeline output every day.
    context.pipe_results = algo.pipeline_output('my_pipeline').dropna()
    
    context.pipeline_data = algo.pipeline_output('data_pipe').dropna()
    
    #Get the risk loading data every day.
    context.risk_loading_pipeline = algo.pipeline_output('risk_loading_pipeline').dropna()
    
    context.pipeline_data = algo.pipeline_output('pipe').dropna()
    
    # Go long in securities for which the 'longs' value is True,
    # and check if they can be traded.
    context.SignalUp = []
    for sec in context.pipe_results[context.pipe_results['SignalUp']].index.tolist():
        if data.can_trade(sec):
            context.SignalUp.append(sec)

    # Go short in securities for which the 'shorts' value is True,
    # and check if they can be traded.
    context.SignalDown = []
    for sec in context.pipe_results[context.pipe_results['SignalDown']].index.tolist():
        if data.can_trade(sec):
            context.SignalDown.append(sec)
    

def my_rebalance(context, data):
    
    # Constrain our risk exposures. We're using version 0 of the default bounds
    # which constrain our portfolio to 18% exposure to each sector and 36% to
    # each style factor.
    constrain_sector_style_risk = opt.experimental.RiskModelExposure(  
        risk_model_loadings=context.risk_loading_pipeline,  
        version=0,
    )

    constrain_sector_style_risk = opt.experimental.RiskModelExposure(
    risk_model_loadings=context.risk_loading_pipeline,
    version=0,
    min_momentum=-0.1,
    max_momentum=0.1,
    )
    
    # Define the max leverage constraint.
    constrain_gross_leverage = opt.MaxGrossExposure(MAX_GROSS_LEVERAGE)
    
    # Define the dollar neutral constraint.
    dollar_neutral = opt.DollarNeutral()
    
    # Define the position concentration constraint.
    constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
    -MAX_SHORT_POSITION_SIZE,
    MAX_LONG_POSITION_SIZE,
    )
    
    # Calculate target weights to rebalance
    target_weights = compute_target_weights(context, data)

    # Supply the constraint to order_optimal_portfolio.
    algo.order_optimal_portfolio(  
        objective=opt.TargetWeights(target_weights),
        constraints=[
            constrain_sector_style_risk,
            constrain_gross_leverage,
            dollar_neutral,
            constrain_pos_size, 
            ],  
    )
    
    
def my_record_vars(context, data):
    """
    Record variables at the end of each day.
    """

    SignalU = SignalD = 0
    for position in context.portfolio.positions.itervalues():
        if position.amount > 0:
           SignalU += 1
        elif position.amount < 0:
             SignalD += -1

    record(
        leverage=context.account.leverage,
        SignalU_count=SignalU,
        SignalD_count=SignalD
    )
There was a runtime error.