Back to Community
New Video: Learn from the Experts Ep 1 -- Full Algorithm Creation with Vedran Rusman

In our latest video, Quantopian community member and multiple challenge winner Vedran Rusman gives an inside look into his research process. This video starts with Dr. Thomas Wiecki conducting a short interview about Vedran’s background as a finance professional in Bosnia and continues with Vedran walking the audience through the creation of an estimates factor all the way from inception to implementation, analysis, evaluation, and backtesting, generously sharing his hard-earned wisdom.

As a finance professional himself, Vedran shows how others can use their financial knowledge to help create challenge-worthy factors. He also gives an explanation of the reasoning behind his decisions, allowing you to walk away with a better understanding of how to develop and improve your own factors.

Check out our latest challenge here, where you can test out your skills and create a challenge ready algorithm.

Watch Vedran's factor-development video here, or below:

Learn more by subscribing to our YouTube channel to access all of our videos and be notified when a new one is posted.

As always, if there are any topics you would like us to focus on for future videos, please comment below or send us a quick note at [email protected].

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.

26 responses

Thank you soooo much! 👍👍👍

Null records notebook used in the video

Loading notebook preview...

Alphalens tearsheet used in the video

Loading notebook preview...

Example Estimates algorithm backtest

Clone Algorithm
146
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
# Template algorithm for the insiders challenge. Based on an algorithm provided by Leo M
# The algo uses documented example from: https://www.quantopian.com/docs/data-reference/ownership_aggregated_insider_transactions

from quantopian.algorithm import attach_pipeline, pipeline_output

import quantopian.optimize as opt
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.domain import US_EQUITIES

import quantopian.pipeline.data.factset.estimates as fe

import pandas as pd
import numpy as np

def initialize(context):
    """
    Called once at the start of the algorithm.
    """
    # Normally a contest algo uses the default commission and slippage
    # This is unique and only required for this 'mini-contest'
    set_commission(commission.PerShare(cost=0.000, min_trade_cost=0))   
    set_slippage(slippage.FixedSlippage(spread=0))
    
    # Rebalance every day, 1 hour after market open.
    schedule_function(
        rebalance,
        date_rules.every_day(),
        time_rules.market_open(hours=2),
    )
    # Create our dynamic stock selector.
    attach_pipeline(make_pipeline(context), 'pipeline') 
    
    # Record any custom data at the end of each day    
    schedule_function(record_positions, 
                      date_rules.every_day(),
                      time_rules.market_close())
    
    
def create_factor():
    # Base universe set to the QTradableStocksUS
    qtu = QTradableStocksUS()
    
    fq1_eps_cons = fe.PeriodicConsensus.slice('EPS', 'qf', 1)
    fq1_eps_cons_up = fq1_eps_cons.up.latest
    fq1_eps_cons_down = fq1_eps_cons.down.latest
    
    alpha_factor = fq1_eps_cons_up - fq1_eps_cons_down
    
    screen = qtu & ~alpha_factor.isnull() & alpha_factor.isfinite()
    
    return alpha_factor, screen

def make_pipeline(context):  
    alpha_factor, screen = create_factor()
    
    # Winsorize to remove extreme outliers
    alpha_winsorized = alpha_factor.winsorize(min_percentile=0.01,
                                              max_percentile=0.99,
                                              mask=screen)
    
    # Zscore and rank to get long and short (positive and negative) alphas to use as weights
    alpha_rank = alpha_winsorized.rank().zscore()
    
    return Pipeline(columns={'alpha_factor': alpha_rank}, 
                    screen=screen, domain=US_EQUITIES)
    

def rebalance(context, data): 
    # Get the alpha factor data from the pipeline output
    output = pipeline_output('pipeline')
    alpha_factor = output.alpha_factor
    log.info(alpha_factor)
    # Weight securities by their alpha factor
    # Divide by the abs of total weight to create a leverage of 1
    weights = alpha_factor / alpha_factor.abs().sum() 
    
    # Must use TargetWeights as an objective
    order_optimal_portfolio(
        objective=opt.TargetWeights(weights),
        constraints=[],
    )

    
def record_positions(context, data):
    pos = pd.Series()
    for position in context.portfolio.positions.values():
        pos.loc[position.sid] = position.amount
        
    pos /= pos.abs().sum()
    
    # Show quantiles of the daily holdings distribution
    # to show if weights are being squashed to equal weight
    # or whether they have a nice range of sensitivity.
    quantiles = pos.quantile([.05, .25, .5, .75, .95]) * 100
    record(q05=quantiles[.05])
    record(q25=quantiles[.25])
    record(q50=quantiles[.5])
    record(q75=quantiles[.75])
    record(q95=quantiles[.95])
There was a runtime error.

Estimates EOD tearsheet

Loading notebook preview...

Thank you very much for your video and notebooks that you have attached!

Thanks a lot for this contribution @Vedran!
And @Thomas for the initiative!

Thank you Vedran.

Thank you so much!

Hi @Vedran,

When treating the alpha factor, you first winsorize it (to remove outliers), then rank and then zscore (to get the long and shorts). Why it's not enough to just windsorize and zscore? Do you rank to control the target weight for each stock?

Thanks in advance.

In this specific case I just used default insider competition algorithm template. Personally, I do not rank factors. Zscoring and winsorizing are finishing touches after alpha factor discovery phase is done. I just use them to squeeze most of already great alpha factor.

I see, thanks @Vedran!

Hi Vedran, nice interview. What is the short-term fast moving alpha?

Thank you Tien. When you discover that kind of alpha factor you need to act on it on the same moment in time/day. If you wait for next day or longer, performance will drop drastically. If it takes too long for a portfolio strategy to complete rebalancing cycle that type of behavior becomes the issue.

Ah ok, thanks for the explanation.

Very interesting, thank you both for sharing!

Thanks Vedran. Nice and informative!

Thanks Vedran for sharing!
Do you think that reducing the number of stocks traded to the two extreme percentiles would improve the performance of the algorithm?
Or any positive effect is already carried by the alpha that you have chosen?

You`re welcome.
I think that reduction of the number of stocks traded to the two extreme percentiles would increase volatility since the positions in portfolio end up larger so both maximum return and maximum drawdown would be amplified.

Could you please explain me a little better this fragment of code found in your second posted notebook?

THANKS

result = None

for name, (f,w) in factors.iteritems(): #.items() in Python 3.5  
        if result  == None:  
            result  = w*f(mask=universe)  
        else:  
            result  += w*f(mask=universe)  

This for loop iterates over factors dictionary with .iteritems() method (name of the method got changed in Python 3 version to .items()) by each stock as individual key and calculates corresponding multiplication between values for stocks in defined universe (f - factor value for stock, w - hardcoded weight which in this example was set to 1) into result zipline NumExprFactor variable .

Hi Vedra, Thank You very much for educating us and sharing the material. Could you please advise how we can remove Sector - 'Misc' from the trading universe? As the IC is negative for this group, perhaps removing that sector will improve the returns. It will be interesting to see.

I tried using this but it didnt work.

qtu = QTradableStocksUS() & (~Sector().eq(-1)))  

@Nadeem - I do not know what is the best optimal way to achieve that since that sector filter returns false because of NaN values.
What you can do is try to use explicit filter like this:

qtu = QTradableStocksUS() &
(sector.eq(101) |
sector.eq(102) |
sector.eq(103) |
sector.eq(104) |
sector.eq(205) |
sector.eq(206) |
sector.eq(207) |
sector.eq(308) |
sector.eq(309) |
sector.eq(310) |
sector.eq(311))

Hi Vedran in minute 13:11 you mention "basically there is one factor which is already known to you (Thomas) and the community, the short term fast moving alpha". I have some students participating in the challenges they are asking me about that "known short term fast moving alpha" and I can´t find any post. about. Could you please give us info about that known short term fast moving alpha factor.

Hello German,

That factor is known to some of the algorithm authors who also found it but not to the entire community.
I cannot give you information about that factor since that is 'secret sauce' which is already licensed and under intellectual property protection.

great stuff !