thanks for your advice… vectorizing the function solved my issue with building out the model.
I’ve now built out the model that I want, and have two further questions to help my understanding,.
For background, the model is describing afree cash flow model to value a company. The fade function is used to help fade revenue and ebit etc, to change through time… the starting and ending points are determined by the priors rev_g_st and rev_g_lt and ebit_m_st and ebit_m_lt…
def fade(start, end, periods):
#vectorised function.. ie, its passing i as a vector, not as a loop.
t = 1+np.arange(periods)
halfway = periods / 2
return start + (end - start) / ( 1 + np.exp(-(t - halfway)))
with pm.Model() as fcf_model:
#Priors
#revenue and margins
rev_g_st = pm.Normal('rev_g_st',.25,.01)
rev_g_lt = pm.Normal('rev_g_lt',.12,.04)
ebit_m_st = pm.Normal('ebit_m_st', -0.2, 0.01)
ebit_m_lt = pm.Normal('ebit_m_lt', 0.22, 0.03)
#working capital turn, and depreciation and amortization as a percentage of cashflow
wc = pm.Uniform('wc', 0.05, 0.09)
da = pm.Uniform('da', 0.07, 0.10)
#other inputs
wacc = pm.Normal('wacc',0.12,0.02)
tax = pm.Normal('tax',0.27,0.01)
lt_g = 0.05
period = 10
shs_on_issue = 160
BASE_REVENUE = 75
#calculate free cash flows for the interval described by the period - ie years 1 to 10 - at each sample.
rev_growth = pm.Deterministic('rev_growth',fade(rev_g_st, rev_g_lt, period))
rev = pm.Deterministic('rev', (1+rev_growth).cumprod(0) * BASE_REVENUE)
ebit = pm.Deterministic('ebit', rev * fade(ebit_m_st, ebit_m_lt, period))
fcf = pm.Deterministic('fcf', ebit*(1-tax) - wc - da)
#terminal cash flow - at each sample.
term_fcf = pm.Deterministic('term_fcf', fcf[period-1]/(wacc-lt_g))
#calculate present value - for all years described by period, at each sample.
disc_factor = 1/((1+wacc)**(np.arange(period)))
pv_fcf = pm.Deterministic('pv_fcf',fcf * disc_factor)
pv_term_fcf = pm.Deterministic('pv_term_fcf', term_fcf / ((1+wacc)**(period+1)))
#calculate value per share
value = pm.Deterministic('value', (pv_fcf.sum() + pv_term_fcf)/shs_on_issue)
If I plot the values sampled from the model for the deterministic functions, they follow the general shape of that I would expect.
Question 1:
In the first instance, I know I am doing a sort of monte carlo type of simulation, and so am only really interested in the deterministic variables. Note there is no observed data in the model yet.
For the deterministic variable - ‘value’ - plotted as a histogram at the bottom left of the figure, I want to work out the probability of a specific value occurring, and so tried the following:
value.logp({'value':1.445})
but got the following error:
AttributeError: 'TensorVariable' object has no attribute 'logp'
Do we have to fit a distribution to this to calculate the pdf or can pymc3 do this automatically?
Question 2:
The histogram at the bottom right of the figure is actual observed prices for the security I am modelling out above using the theoretical FCF model.
I am interested to know, that given my model above, if we are able to work backwards, given the observed data and work out the rev_g_st, rev_g_lt, ebit_m_st, ebit_m_lt etc using beysian inference. (I am aware that these are transformed using the fade function to get the deterministic variables rev_g and ebit…)
I tried setting the observed parameter in the deterministic variable as follows:
value = pm.Deterministic('value', (pv_fcf.sum() + pv_term_fcf)/shs_on_issue, observed=obs_data)
but that didnt work…
Is what I am trying to achieve here possible?? It feels like to me that it is, based on my very limited knowledge of pymc3… thanks for all suggestions so far, its really helping me deepen my knowledge of pymc3.