Hi

i have done my version of the piotroski skore model.

In my code the last year value of fundamental data is 200 bars (days) ago and new shares are calculated with a minus sign (line 65) to check that no new shares has been created from last year.

The stock selection has no filter beside the classic piotroski score an it's limited to 100 stock on the long side and 100 stock on the short side.

So actually the question, is.. why does it perform so bad, do you see some issue in the code or something?...

Clone Algorithm

39

Loading...

There was an error loading this backtest.

Backtest from
to
with
initial capital

Cumulative performance:

Algorithm
Benchmark

Custom data:

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 |

""" Creating an algorithm based off the Piotroski Score index which is based off of a score (0-9) Each of the following marks (-) satisfied means one point. And in the end we'll long the stocks with a score of >= 8 Profitability - Positive ROA - Positive Operating Cash Flow - Higher ROA in current year versus last year - Cash flow from operations > ROA of current year Leverage - Current ratio of long term debt < last year's ratio of long term debt - Current year's current_ratio > last year's current_ratio - No new shares issued this year Operating Efficiency - Higher gross margin compared to previous year - Higher asset turnover ratio compared to previous year This algorithm demonstrates how to grasp historical fundamental data by storing it in a Pandas Panel similar to how the Quantopian 'data' is currently structured """ import numpy as np 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 class Piotroski(CustomFactor): def compute(self, today, assets, out, values): if self.window_length >1: out[:] = values[-1] - values[0] else: out[:] = values[-1] def initialize(context): # number of stocks to buy = number of stocks to sell context.num_of_stocks = 100 # approximate last year as 200 bars back last_year_length = 200 pipe = Pipeline() attach_pipeline(pipe, name='my_pipeline') # ROA this year versus ROA last year ROA_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.roa],window_length = last_year_length ) # ROA current value ROA = Piotroski(inputs= [morningstar.operation_ratios.roa],window_length = 1 ) # CASH FLOW current value cash_flow = Piotroski(inputs = [morningstar.cash_flow_statement.operating_cash_flow],window_length = 1 ) # R ratio_long_term_debt = Piotroski(inputs= [morningstar.operation_ratios.long_term_debt_equity_ratio],window_length = 1 ) ratio_long_term_debt_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.long_term_debt_equity_ratio],window_length = last_year_length ) current_ratio = Piotroski(inputs= [morningstar.operation_ratios.current_ratio],window_length = 1 ) current_ratio_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.current_ratio],window_length = last_year_length ) shares_outstanding_current_vs_last = Piotroski(inputs= [morningstar.valuation.shares_outstanding],window_length = last_year_length ) gross_margin_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.gross_margin],window_length = last_year_length ) asset_turnover_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.assets_turnover],window_length = last_year_length ) pipe.add(ROA_current_vs_last, name= 'ROA var') pipe.add(ROA, name = 'ROA') pipe.add(cash_flow , name= 'cash flow') pipe.add(ratio_long_term_debt, name= 'debt ratio') pipe.add(ratio_long_term_debt_current_vs_last, name= 'debt ratio var') pipe.add(current_ratio, name='Cur Ratio') pipe.add(current_ratio_current_vs_last, name= 'Cur ratio var') pipe.add(-shares_outstanding_current_vs_last, name= 'New shares') pipe.add(gross_margin_current_vs_last, name= 'Gross var') pipe.add(asset_turnover_current_vs_last, name= 'Turnover var') schedule_function(rebalance, date_rules.month_start(), time_rules.market_close()) def before_trading_start(context, data): context.output = pipeline_output('my_pipeline') context.scores_df = context.output.applymap(turn_values_into_points) context.piotroski_series = context.scores_df.sum(axis=1).sort(inplace=False, ascending=False) long_stocks = context.piotroski_series.ix[context.piotroski_series > 7].iloc[:context.num_of_stocks] short_stocks = context.piotroski_series.ix[context.piotroski_series < 2].iloc[-context.num_of_stocks:] context.long_stocks = long_stocks.index context.short_stocks = short_stocks.index update_universe(np.union1d(context.long_stocks, context.short_stocks)) def rebalance(context, data): #print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in context.long_stocks],[i.symbol for i in context.short_stocks]) set_long = set(context.long_stocks) set_short = set(context.short_stocks) set_data = set(data.keys()) long_list = set.intersection(set_data, set_long) short_list = set.intersection(set_data, set_short) print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in long_list],[i.symbol for i in short_list]) long_weight = (.9/len(long_list))/2 short_weight = -(0.9/len(short_list))/2 for s in long_list: if s not in get_open_orders(): order_target_percent(s, long_weight) for s in short_list: if s not in get_open_orders(): order_target_percent(s, short_weight) for s in context.portfolio.positions.iterkeys(): if s not in get_open_orders(): if s not in long_list and s not in short_list: order_target(s, 0) record(leverage = context.account.leverage) def handle_data(context, data): pass def turn_values_into_points(x): if x > 0: return 1 else: return 0