I was able to get it working for the first part - it now accepts pandas series for all required arguments. Still trying to figure out if it can be done with an added dimension, so instead of slice montecarlo[j], use say the maximum of slice i:j.
Working code:
def montecarlo_payouts(montecarlo, j, opt, k, kotype = None, b = 0, i=1):
#adjust daycount for index starting at 0
i = i - 1
j = j - 1
#deal wih argument types
j = j.to_numpy() if isinstance(j, pd.Series) else j
opt = opt.str.lower().to_numpy() if isinstance(opt, pd.Series) else opt.lower()
k = k.to_numpy() if isinstance(k, pd.Series) else k
k = k[:,None] if isinstance(k, (pd.Series, np.ndarray)) else k
#vanilla option payoffs for call and put
itm = montecarlo[j] - k
conditions = [np.logical_or(opt == 'c',opt == 'call')]
callorput = np.where(conditions, 1, -1)
payoff = np.maximum(itm * callorput.transpose(), 0)
return payoff.mean(axis=1)