我试图从python中的http://jheusser.github.io/2013/09/08/hawkes.html重现这项工作,除了不同的数据.我编写了代码来模拟泊松过程以及他们描述的霍克斯过程.
为了做霍克斯模型MLE,我将对数似然函数定义为
def loglikelihood(params, data): (mu, alpha, beta) = params tlist = np.array(data) r = np.zeros(len(tlist)) for i in xrange(1,len(tlist)): r[i] = math.exp(-beta*(tlist[i]-tlist[i-1]))*(1+r[i-1]) loglik = -tlist[-1]*mu loglik = loglik+alpha/beta*sum(np.exp(-beta*(tlist[-1]-tlist))-1) loglik = loglik+np.sum(np.log(mu+alpha*r)) return -loglik
使用一些虚拟数据,我们可以计算Hawkes过程的MLE
atimes=[58.98353497, 59.28420225, 59.71571013, 60.06750179, 61.24794134, 61.70692463, 61.73611983, 62.28593814, 62.51691723, 63.17370423 ,63.20125152, 65.34092403, 214.24934446, 217.0390236, 312.18830525, 319.38385604, 320.31758188, 323.50201334, 323.76801537, 323.9417007] res = minimize(loglikelihood, (0.01, 0.1,0.1),method='Nelder-Mead',args = (atimes,)) print res
但是,我不知道如何在python中执行以下操作.
我怎样才能获得相同的evalCIF来获得类似的拟合与经验强度图?
如何计算Hawkes模型的残差,使其等效于他们拥有的QQ图.他们说他们使用一个名为ptproc的R包但我找不到python等价物.
Aleksander L.. 11
好的,所以你可能希望做的第一件事是绘制数据.为了简单起见,我已经复制了这个数字,因为它只发生了8个事件,因此很容易看到系统的行为.以下代码:
import numpy as np import math, matplotlib import matplotlib.pyplot import matplotlib.lines mu = 0.1 # Parameter values as found in the article http://jheusser.github.io/2013/09/08/hawkes.html Hawkes Process section. alpha = 1.0 beta = 0.5 EventTimes = np.array([0.7, 1.2, 2.0, 3.8, 7.1, 8.2, 8.9, 9.0]) " Compute conditional intensities for all times using the Hawkes process. " timesOfInterest = np.linspace(0.0, 10.0, 100) # Times where the intensity will be sampled. conditionalIntensities = [] # Conditional intensity for every epoch of interest. for t in timesOfInterest: conditionalIntensities.append( mu + np.array( [alpha*math.exp(-beta*(t-ti)) if t > ti else 0.0 for ti in EventTimes] ).sum() ) # Find the contributions of all preceding events to the overall chance of another one occurring. All events that occur after t have no contribution. " Plot the conditional intensity time history. " fig = matplotlib.pyplot.figure() ax = fig.gca() labelsFontSize = 16 ticksFontSize = 14 fig.suptitle(r"$Conditional\ intensity\ VS\ time$", fontsize=20) ax.grid(True) ax.set_xlabel(r'$Time$',fontsize=labelsFontSize) ax.set_ylabel(r'$\lambda$',fontsize=labelsFontSize) matplotlib.rc('xtick', labelsize=ticksFontSize) matplotlib.rc('ytick', labelsize=ticksFontSize) eventsScatter = ax.scatter(EventTimes,np.ones(len(EventTimes))) # Just to indicate where the events took place. ax.plot(timesOfInterest, conditionalIntensities, color='red', line, marker=None, markerfacecolor='blue', markersize=12) fittedPlot = matplotlib.lines.Line2D([],[],color='red', line, marker=None, markerfacecolor='blue', markersize=12) fig.legend([fittedPlot, eventsScatter], [r'$Conditional\ intensity\ computed\ from\ events$', r'$Events$']) matplotlib.pyplot.show()
虽然我有点随意选择了事件时期,但是相当准确地再现了这个数字:
这也可以通过对数据进行分箱并将每个箱视为事件来应用于5000个交易的一组示例数据集.但是,现在发生的事情是,每个事件的权重都略有不同,因为每个仓位都会发生不同的交易次数.这也是在比特币交易到达霍克斯过程部分的文章中提到的,提出了克服这个问题的方法:这包含在下面的代码中:The only difference to the original dataset is that I added a random millisecond timestamp to all trades that share a timestamp with another trade. This is required as the model requires to distinguish every trade (i.e. every trade must have a unique timestamp).
import numpy as np import math, matplotlib, pandas import scipy.optimize import matplotlib.pyplot import matplotlib.lines " Read example trades' data. " all_trades = pandas.read_csv('all_trades.csv', parse_dates=[0], index_col=0) # All trades' data. all_counts = pandas.DataFrame({'counts': np.ones(len(all_trades))}, index=all_trades.index) # Only the count of the trades is really important. empirical_1min = all_counts.resample('1min', how='sum') # Bin the data so find the number of trades in 1 minute intervals. baseEventTimes = np.array( range(len(empirical_1min.values)), dtype=np.float64) # Dummy times when the events take place, don't care too much about actual epochs where the bins are placed - this could be scaled to days since epoch, second since epoch and any other measure of time. eventTimes = [] # With the event batches split into separate events. for i in range(len(empirical_1min.values)): # Deal with many events occurring at the same time - need to distinguish between them by splitting each batch of events into distinct events taking place at almost the same time. if not np.isnan(empirical_1min.values[i]): for j in range(empirical_1min.values[i]): eventTimes.append(baseEventTimes[i]+0.000001*(j+1)) # For every event that occurrs at this epoch enter a dummy event very close to it in time that will increase the conditional intensity. eventTimes = np.array( eventTimes, dtype=np.float64 ) # Change to array for ease of operations. " Find a fit for alpha, beta, and mu that minimises loglikelihood for the input data. " #res = scipy.optimize.minimize(loglikelihood, (0.01, 0.1,0.1), method='Nelder-Mead', args = (eventTimes,)) #(mu, alpha, beta) = res.x mu = 0.07 # Parameter values as found in the article. alpha = 1.18 beta = 1.79 " Compute conditional intensities for all epochs using the Hawkes process - add more points to see how the effect of individual events decays over time. " conditionalIntensitiesPlotting = [] # Conditional intensity for every epoch of interest. timesOfInterest = np.linspace(eventTimes.min(), eventTimes.max(), eventTimes.size*10) # Times where the intensity will be sampled. Sample at much higher frequency than the events occur at. for t in timesOfInterest: conditionalIntensitiesPlotting.append( mu + np.array( [alpha*math.exp(-beta*(t-ti)) if t > ti else 0.0 for ti in eventTimes] ).sum() ) # Find the contributions of all preceding events to the overall chance of another one occurring. All events that occur after time of interest t have no contribution. " Compute conditional intensities at the same epochs as the empirical data are known. " conditionalIntensities=[] # This will be used in the QQ plot later, has to have the same size as the empirical data. for t in np.linspace(eventTimes.min(), eventTimes.max(), eventTimes.size): conditionalIntensities.append( mu + np.array( [alpha*math.exp(-beta*(t-ti)) if t > ti else 0.0 for ti in eventTimes] ).sum() ) # Use eventTimes here as well to feel the influence of all the events that happen at the same time. " Plot the empirical and fitted datasets. " fig = matplotlib.pyplot.figure() ax = fig.gca() labelsFontSize = 16 ticksFontSize = 14 fig.suptitle(r"$Conditional\ intensity\ VS\ time$", fontsize=20) ax.grid(True) ax.set_xlabel(r'$Time$',fontsize=labelsFontSize) ax.set_ylabel(r'$\lambda$',fontsize=labelsFontSize) matplotlib.rc('xtick', labelsize=ticksFontSize) matplotlib.rc('ytick', labelsize=ticksFontSize) # Plot the empirical binned data. ax.plot(baseEventTimes,empirical_1min.values, color='blue', line, marker=None, markerfacecolor='blue', markersize=12) empiricalPlot = matplotlib.lines.Line2D([],[],color='blue', line, marker=None, markerfacecolor='blue', markersize=12) # And the fit obtained using the Hawkes function. ax.plot(timesOfInterest, conditionalIntensitiesPlotting, color='red', line, marker=None, markerfacecolor='blue', markersize=12) fittedPlot = matplotlib.lines.Line2D([],[],color='red', line, marker=None, markerfacecolor='blue', markersize=12) fig.legend([fittedPlot, empiricalPlot], [r'$Fitted\ data$', r'$Empirical\ data$']) matplotlib.pyplot.show()
这会产生以下拟合图: 一切看起来不错,但是,当你看到细节时,你会看到通过简单地采用交易数量的一个向量并减去拟合的数据来计算残差,因为它们具有不同的长度: 然而,有可能在与经验数据记录时相同的时期提取强度,然后计算残差.这使您能够找到经验数据和拟合数据的分位数,并将它们相互绘制,从而生成QQ图:
""" GENERATE THE QQ PLOT. """ " Process the data and compute the quantiles. " orderStatistics=[]; orderStatistics2=[]; for i in range( empirical_1min.values.size ): # Make sure all the NANs are filtered out and both arrays have the same size. if not np.isnan( empirical_1min.values[i] ): orderStatistics.append(empirical_1min.values[i]) orderStatistics2.append(conditionalIntensities[i]) orderStatistics = np.array(orderStatistics); orderStatistics2 = np.array(orderStatistics2); orderStatistics.sort(axis=0) # Need to sort data in ascending order to make a QQ plot. orderStatistics is a column vector. orderStatistics2.sort() smapleQuantiles=np.zeros( orderStatistics.size ) # Quantiles of the empirical data. smapleQuantiles2=np.zeros( orderStatistics2.size ) # Quantiles of the data fitted using the Hawkes process. for i in range( orderStatistics.size ): temp = int( 100*(i-0.5)/float(smapleQuantiles.size) ) # (i-0.5)/float(smapleQuantiles.size) th quantile. COnvert to % as expected by the numpy function. if temp<0.0: temp=0.0 # Avoid having -ve percentiles. smapleQuantiles[i] = np.percentile(orderStatistics, temp) smapleQuantiles2[i] = np.percentile(orderStatistics2, temp) " Make the quantile plot of empirical data first. " fig2 = matplotlib.pyplot.figure() ax2 = fig2.gca(aspect="equal") fig2.suptitle(r"$Quantile\ plot$", fontsize=20) ax2.grid(True) ax2.set_xlabel(r'$Sample\ fraction\ (\%)$',fontsize=labelsFontSize) ax2.set_ylabel(r'$Observations$',fontsize=labelsFontSize) matplotlib.rc('xtick', labelsize=ticksFontSize) matplotlib.rc('ytick', labelsize=ticksFontSize) distScatter = ax2.scatter(smapleQuantiles, orderStatistics, c='blue', marker='o') # If these are close to the straight line with slope line these points come from a normal distribution. ax2.plot(smapleQuantiles, smapleQuantiles, color='red', line, marker=None, markerfacecolor='red', markersize=12) normalDistPlot = matplotlib.lines.Line2D([],[],color='red', line, marker=None, markerfacecolor='red', markersize=12) fig2.legend([normalDistPlot, distScatter], [r'$Normal\ distribution$', r'$Empirical\ data$']) matplotlib.pyplot.show() " Make a QQ plot. " fig3 = matplotlib.pyplot.figure() ax3 = fig3.gca(aspect="equal") fig3.suptitle(r"$Quantile\ -\ Quantile\ plot$", fontsize=20) ax3.grid(True) ax3.set_xlabel(r'$Empirical\ data$',fontsize=labelsFontSize) ax3.set_ylabel(r'$Data\ fitted\ with\ Hawkes\ distribution$',fontsize=labelsFontSize) matplotlib.rc('xtick', labelsize=ticksFontSize) matplotlib.rc('ytick', labelsize=ticksFontSize) distributionScatter = ax3.scatter(smapleQuantiles, smapleQuantiles2, c='blue', marker='x') # If these are close to the straight line with slope line these points come from a normal distribution. ax3.plot(smapleQuantiles, smapleQuantiles, color='red', line, marker=None, markerfacecolor='red', markersize=12) normalDistPlot2 = matplotlib.lines.Line2D([],[],color='red', line, marker=None, markerfacecolor='red', markersize=12) fig3.legend([normalDistPlot2, distributionScatter], [r'$Normal\ distribution$', r'$Comparison\ of\ datasets$']) matplotlib.pyplot.show()
这会生成以下图表:
经验数据的分位数图与文章中的不完全相同,我不确定为什么因为我对统计数据不满意.但是,从编程的角度来看,这就是你如何做到这一点.