Responding to the above request for setting window_safe = True
. This can be done with a simple custom factor.
class Make_Window_Safe(CustomFactor):
window_safe = True
def compute(self, today, assets, out, input_factor):
out[:] = input_factor
# A factor can be set to 'window_safe' and then used as an input to another factor like this
my_window_safe_factor = Make_Window_Safe(inputs=[my_factor])
sma_my_factor = SimpleMovingAverage(inputs=[my_window_safe_factor], window_length=20)
However, BE CAREFUL. Ensure your factor truly is 'window_safe'. What does this mean exactly? Setting window_safe = True
flags the factor as invariant over different timeframes or 'windows' . As an example, take the built in factor SimpleMovingAverage
my_sma = SimpleMovingAverage(inputs=[USEquityPricing.close.latest], window_length=20)
This should produce the average close price over the given window of 20 trading days. On 1-9-2020 lets say the average price for stock XYZ was $20. If this factor were run on 1-10-2020 the average price should generally be pretty close, perhaps $20.10. But, what happens if XYZ has a 2:1 stock split (or dividend) on 1-10-2020? Pipeline always adjusts prices as of the pipeline date. The 1-9-2020 output will remain $20. However, because of the split, the 1-10-2020 output will be $10.05. This is exactly the data a trader would see on those two days which is exactly what pipeline is designed to do. It surfaces data to accurately represent what a trader would have seen on that day. This factor value though depends upon the timeframe or 'window' over which it is run. If one window includes a stock split (or dividend) and another doesn't, they cannot be directly compared. This is what we call not window_safe
and why the above SimpleMovingAverage
example generates an error.
Generally, latest
price and volume data is NOT window_safe unless it is a ratio. One cannot use USEquityPricing.close.latest.downsample('week_start')
as an input to SimpleMovingAverage
because the values are not uniformly adjusted for splits and dividends. For example, our stock XYZ may have closed at $20 before the split and $10 after the split. The 'adjusted' average price, accounting for the 2:1 split, would be $10. However, our SimpleMovingAverage
method doesn't know about splits. It simply averages the inputs. It averages $20 and $10 to get (incorrectly) $15.
If one wants to do technical analysis using 'adjusted' prices. Then create a custom factor and do the calculations within the 'compute' method. Within a factor, all inputs are adjusted as of the current pipeline date.