I wrote a python function I would expect to allow vectorization, using np.where and np.maximum. However, when attempting to call that function by passing dataframe columns, I get the error "ValueError: operands could not be broadcast together ..."
The function works fine when passing constants. I'm stuck on how to rewrite it to allow vectorization, ie accept pd.Series as arguments. I want to calculate the mean payoff for each row of the pandas.DataFrame, ie, an array of (2,1)
Update 2: Updated code slightly to fix a few issues
import numpy as np
import pandas as pd
np.random.seed(5)
times, dt = np.linspace(0, 1, 251, retstep=True)
B = np.random.normal(0, np.sqrt(dt), size=(100, 250)).T
S = np.exp((0 - .15 ** 2/ 2) * dt + .15 * B)
S = 4.5 * S.cumprod(axis=0)
df = pd.DataFrame({'days': [230,250], 'otype': ['c','p'], 'strike': [4.8,4.3], 'ko': [None, 'do'], 'b': [5,4.55]})
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
opt = opt.str.lower() 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
conditions = [np.logical_or(opt == 'c',opt == 'call')]
payoff = np.where(conditions, np.maximum(montecarlo[j] - k, 0), np.maximum(k - montecarlo[j], 0))
return payoff.mean(axis=1)
df = pd.DataFrame({'days': [230,250], 'otype': ['c','p'], 'strike': [4.8,4.3]})
payout = montecarlo_payouts(S, 250, df['otype'], 5)
I was able to get it working using suggestions from @jared on another post and properly handling my series arguments.
Working code:
def montecarlo_payouts(montecarlo, j, opt, k, kotype = None, b = 0, i=1):
#adjust daycount for index starting at 0
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()
kotype = kotype.str.lower().to_numpy() if isinstance(kotype, pd.Series) else kotype.lower()
k = k.to_numpy() if isinstance(k, pd.Series) else k
k = k[:,None] if isinstance(k, np.ndarray) else k
b = b.to_numpy() if isinstance(b, pd.Series) else b
b = b[:,None] if isinstance(b, np.ndarray) else b
kotype = kotype[:,None] if isinstance(kotype, np.ndarray) else kotype
#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)
payoffs = np.maximum(itm * callorput.transpose(), 0)
return payoffs