That's right.
Try this style folks. It might seem odd at first. Doesn't take very long to become accustomed to it. Fast & efficient development.
I like this route ...
def initialize(context):
attach_pipeline(make_pipeline(), 'pipe')
def make_pipeline():
f = Fundamentals
m = QTradableStocksUS() # mask
gs = f.growth_score .latest.zscore(mask=m) ; m &= (gs.percentile_between(50, 90))
vs = f.value_score .latest.zscore(mask=m) ; m &= (vs.percentile_between(50, 90))
gg = f.growth_grade .latest ; m &= (gg.eq('A') | gg.eq('B'))
hg = f.financial_health_grade.latest ; m &= (hg.eq('A') | hg.eq('B'))
pg = f.profitability_grade .latest ; m &= (pg.eq('A') | pg.eq('B'))
return Pipeline(
screen = m,
columns = {
'gs': gs,
'vs': vs,
'gg': gg,
'hg': hg,
'pg': pg,
}
)
def before_trading_start(context, data):
context.out = pipeline_output('pipe')
if 'log_data_done' not in context: # show values once
log_data(context, data, context.out, 6) # all fields (columns) if unspecified
Adds to mask progressively, which I think ought to be more efficient (each fundamental operating on the next smaller set of stocks, or the first two in this case, the ones with zscore. I added zscore as a way to be able to use mask, rank(mask=m) is another, and actually I probably should have also done percentile_between(50, 90, mask=m), forgot).
Easy to modify. Two comment characters can remove an entire fundamental, due to the semi-colons, two lines in one, and then there's also its column. The &= is and-equal, shorthand, the same as m = m & (something), adding to the mask.
Vertical alignment for easy reading.
log_data() is a preview of what's you've got. min, mean & max for those with numeric values. And some examples (currently set to 6) with symbols showing high & low values.
That preview can catch things. For example I wonder why growth_grade is so often 'B'. You might know.
You might want to change to percentile_between(90, 99). See what that does to the number of rows. That's the number of stocks that make it through the filters (only 21 right now). If you set percentile_between(0, 100) you'll see the entire range in the preview.
Notice with the import of Fundamentals (upper case), there is no need to remember or look up the category of each fundamental. For example fundamentals.valuation.shares_outstanding becomes simply Fundamentals.shares_outstanding (valuation category dropped).
At a certain point when you're satisfied with the 'A's & 'B's you can comment out those columns, the mask will still be in place.
If you'd rather have the log_data() output gone and out of the way after awhile, I prefer to do this as a way of turning that off:
if 0 and 'log_data_done' not in context: # show values once
The '0 and' makes that always false.
2018-06-20 05:45 log_data:44 INFO $10,000,000 2018-06-20 to 2018-06-22
2018-06-20 05:45 log_data:111 INFO Rows: 21 Columns: 5
min mean max
gs 0.114249484021 0.742931755782 1.28431644656
vs 0.00806275550685 0.586417734418 1.34426626765
2018-06-20 05:45 log_data:126 INFO _ _ _ gg _ _ _
... gg highs
gg gs hg pg vs
Equity(24794 [MMS]) B 0.460806 A A 0.306865
Equity(45656 [GLPI]) B 0.114249 A B 0.387484
Equity(693 [AZO]) B 0.620327 B B 0.826385
Equity(4521 [LOW]) B 0.967748 B A 0.317739
Equity(4589 [LUV]) B 1.284316 B B 1.344266
Equity(10869 [TSCO]) B 0.341208 B A 0.364232
... gg lows
gg gs hg pg vs
Equity(41928 [FBHS]) B 0.423992 A B 0.635489
Equity(42125 [VAC]) B 0.857381 B B 0.073454
Equity(43981 [NCLH]) B 1.162103 B B 1.244516
Equity(45007 [CDW]) B 0.481913 A A 0.237116
Equity(19909 [MKSI]) A 0.927223 B B 0.633637
Equity(49543 [FCPT]) A 1.062826 A B 0.417714
2018-06-20 05:45 log_data:126 INFO _ _ _ gs _ _ _
... gs highs
gg gs hg pg vs
Equity(4589 [LUV]) B 1.284316 B B 1.344266
Equity(337 [AMAT]) B 1.219054 B B 0.999890
Equity(43981 [NCLH]) B 1.162103 B B 1.244516
Equity(21429 [ON]) B 1.142671 B B 0.752519
Equity(14277 [OTEX]) B 1.084832 A B 0.550737
Equity(49543 [FCPT]) A 1.062826 A B 0.417714
... gs lows
gg gs hg pg vs
Equity(24794 [MMS]) B 0.460806 A A 0.306865
Equity(41928 [FBHS]) B 0.423992 A B 0.635489
Equity(13777 [AEIS]) B 0.383860 B B 0.355959
Equity(10869 [TSCO]) B 0.341208 B A 0.364232
Equity(41047 [HCA]) B 0.213464 B A 1.301880
Equity(45656 [GLPI]) B 0.114249 A B 0.387484
2018-06-20 05:45 log_data:126 INFO _ _ _ hg _ _ _
... hg highs
gg gs hg pg vs
Equity(337 [AMAT]) B 1.219054 B B 0.999890
Equity(693 [AZO]) B 0.620327 B B 0.826385
Equity(43981 [NCLH]) B 1.162103 B B 1.244516
Equity(42125 [VAC]) B 0.857381 B B 0.073454
Equity(4521 [LOW]) B 0.967748 B A 0.317739
Equity(41047 [HCA]) B 0.213464 B A 1.301880
... hg lows
gg gs hg pg vs
Equity(45656 [GLPI]) B 0.114249 A B 0.387484
Equity(32483 [EVR]) B 0.642545 A B 0.618744
Equity(39063 [KAR]) B 0.718611 A B 0.417312
Equity(41928 [FBHS]) B 0.423992 A B 0.635489
Equity(45007 [CDW]) B 0.481913 A A 0.237116
Equity(24794 [MMS]) B 0.460806 A A 0.306865
2018-06-20 05:45 log_data:126 INFO _ _ _ pg _ _ _
... pg highs
gg gs hg pg vs
Equity(49543 [FCPT]) A 1.062826 A B 0.417714
Equity(45656 [GLPI]) B 0.114249 A B 0.387484
Equity(693 [AZO]) B 0.620327 B B 0.826385
Equity(4589 [LUV]) B 1.284316 B B 1.344266
Equity(13777 [AEIS]) B 0.383860 B B 0.355959
Equity(14277 [OTEX]) B 1.084832 A B 0.550737
... pg lows
gg gs hg pg vs
Equity(40159 [VC]) B 0.512977 B A 0.008063
Equity(41047 [HCA]) B 0.213464 B A 1.301880
Equity(10869 [TSCO]) B 0.341208 B A 0.364232
Equity(4521 [LOW]) B 0.967748 B A 0.317739
Equity(45007 [CDW]) B 0.481913 A A 0.237116
Equity(24794 [MMS]) B 0.460806 A A 0.306865
2018-06-20 05:45 log_data:126 INFO _ _ _ vs _ _ _
... vs highs
gg gs hg pg vs
Equity(4589 [LUV]) B 1.284316 B B 1.344266
Equity(41047 [HCA]) B 0.213464 B A 1.301880
Equity(43981 [NCLH]) B 1.162103 B B 1.244516
Equity(337 [AMAT]) B 1.219054 B B 0.999890
Equity(693 [AZO]) B 0.620327 B B 0.826385
Equity(21429 [ON]) B 1.142671 B B 0.752519
... vs lows
gg gs hg pg vs
Equity(13777 [AEIS]) B 0.383860 B B 0.355959
Equity(4521 [LOW]) B 0.967748 B A 0.317739
Equity(24794 [MMS]) B 0.460806 A A 0.306865
Equity(45007 [CDW]) B 0.481913 A A 0.237116
Equity(42125 [VAC]) B 0.857381 B B 0.073454
Equity(40159 [VC]) B 0.512977 B A 0.008063
The actual growth & value score ranges without zscore ...
gs = f.growth_score .latest ; m &= (gs.percentile_between(0, 100, mask=m))
vs = f.value_score .latest ; m &= (vs.percentile_between(0, 100, mask=m))
2018-06-20 05:45 log_data:111 INFO Rows: 111 Columns: 5
min mean max
gs 13.14057 68.765334955 98.12893
vs 6.05222 34.0799184685 79.5777
With zscore ...
gs = f.growth_score .latest.zscore(mask=m) ; m &= (gs.percentile_between(0, 100, mask=m))
vs = f.value_score .latest.zscore(mask=m) ; m &= (vs.percentile_between(0, 100, mask=m))
2018-06-20 05:45 log_data:111 INFO Rows: 111 Columns: 5
min mean max
gs -1.66829310266 0.706101613519 1.9595139197
vs -1.72748830041 -0.486653071619 1.52761328777