What you are asking is 'can one have recursive factors'? The answer is yes with a big caveat. Factors can be recursive but cannot be 'infinitely recursive'. They must have an independent initial value.
Both cases above are basically the same. The first case is something like this (using pseudo code)
# Here a factor depends upon the previous value of the factor
factor1[1] <- factor1[0]
The second case is the same but interjects an 'intermediary' factor
# Here an intermediate factor (factor2) is used but basically the same as above
factor1[1] <- factor2[1]
factor2[1] <- factor1[0]
# Really have this situation (the same as above)
factor1[1] <- factor1[0]
So, yes one can use a factor as an input (even the same factor). However, there must be a finite number of 'recursions'. Take a simple custom factor which adds one to the previous input value. If the input is the same factor it will add one to the previous value of the factor.
class Plus_1(CustomFactor):
window_length=2
window_safe = True
def compute(self, today, assets, out, factor_value):
out[:] = factor_value[0] + 1
However, there must be a finite number of times this is called, and it must be given an initial value. Something like this
constant_0 = Constant_0()
plus_1 = Plus_1(inputs=[constant_0])
plus_2 = Plus_1(inputs=[plus_1])
plus_3 = Plus_1(inputs=[plus_2])
my_pipe = Pipeline(columns={'plus_3': plus_3} )
Notice the first time it uses a constant as an input but after that it simply 'calls' itself. This could also be done in a for loop so no need to explicitly write out each iteration. However, don't do this. This isn't the best approach.
The best approach is to put all the recursion into a single custom factor. There is no escaping a for loop. Almost by definition, recursive calculations cannot be 'vectorized'. So something like this
class Plus_N(CustomFactor):
"""
Set the window_length to the N value. This will get the function value after N days.
The initial value is set in self.initial_value
"""
inputs = []
window_safe = True
initial_value = 0
def my_function(self, x):
"""
This is the recursive function.
Here it just adds 1 but it could be any function.
The input x is the previous value used to generate the new value.
"""
return x+1
def compute(self, today, assets, out,):
# First set the starting value
value = self.initial_value
# Iterate to get the final value
for i in range(0, self.window_length):
value = self.my_function(value)
out[:] = value
The attached notebook shows this in more detail. To customize the factor simply define your own code in my_function
.