Back to Community
net debt to ebitda ratio algo

Questions/comments/improvements welcome.

Clone Algorithm
19
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
# https://www.quantopian.com/posts/$10k-third-party-challenge-design-a-factor-for-a-large-us-corporate-pension
# Backtest range: 1/4/2014 to 8/29/2018

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
import quantopian.optimize as opt
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.data import Fundamentals
from quantopian.pipeline.classifiers.morningstar import Sector
import numpy as np
import pandas as pd

def normalize(x):
    
    r = x - x.mean()
    
    return r/r.abs().sum()
    
def factor_pipeline():
    
    QTU = QTradableStocksUS()
    sectors = [101,102,103,104,205,206,207,308,309,310,311]
    
    net_debt = Fundamentals.net_debt.latest
    ebitda = Fundamentals.ebitda.latest
    debt_over_ebitda = net_debt / ebitda
    
    fhg = Fundamentals.financial_health_grade.latest
    
    fhg_scores = [fhg.eq('C'),fhg.eq('D')]
    fhg_scores_num = [3,2]
    
    pipeline_columns = {}
    for sector in sectors:
        for k,score in zip(fhg_scores_num,fhg_scores):
            m = (QTU & Sector().eq(sector) & (score) & (net_debt > 0) & (ebitda > 0))
            pipeline_columns['alpha_'+str(sector)+'_'+str(k)] = -debt_over_ebitda.zscore(mask=m)
    
    pipe = Pipeline(columns = pipeline_columns, screen = QTU)
    
    return pipe
    
def initialize(context):    
    
    attach_pipeline(factor_pipeline(), 'factor_pipeline')
    
    # Schedule my rebalance function
    schedule_function(func=rebalance,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(),
                      half_days=True)
    # record my portfolio variables at the end of day
    schedule_function(func=recording_statements,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(),
                      half_days=True)
    
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))

def recording_statements(context, data):
 
    record(num_positions=len(context.portfolio.positions))
    record(leverage=context.account.leverage) 
    
def rebalance(context, data):
    
    alphas = pipeline_output('factor_pipeline').replace([np.inf, -np.inf], 0).replace(np.nan, 0)
    
    alpha = normalize(alphas.sum(axis=1))
    
    alpha = normalize(pd.Series().append(alpha.nsmallest(125)).append(alpha.nlargest(125)))
    
    objective = opt.TargetWeights(alpha)
    
    order_optimal_portfolio(objective=objective,
                            constraints=[]
                           )
There was a runtime error.
2 responses

Cool stuff. Have you tried out looking at interest coverage ratios or acid tests as well?

@ Harry - No, but thanks for the suggestion. My overall angle is that perhaps companies are taking on more debt than they should to buyback shares or somehow otherwise boost their performance.