程式

將 1 sim 常式擴展到模擬數量的有效方法?Brownian Bridge 在 MC 模擬中與多個標的資產一起使用,

  • October 28, 2021

我相信對於那些熟悉量化金融和復雜期權定價的 MC/QMC 方法的人來說,這是一個(相當)簡單的問題。或者可能只是一個簡單的 Python 循環向量化問題,不需要量化金融知識。

所以我試圖理解布朗橋技術。我使用了最好的程式碼範例,其中一個很棒的範例在這裡(感謝作者 Kenta Oono):https ://gist.github.com/delta2323/6bb572d9473f3b523e6e - 在評論中是對常式的更正,它似乎正確實現從我讀到的關於路徑建設的內容。這是重寫的,所以它對我正在做的事情更有意義。這是為了在平均 21 天的時間內模擬一籃子 12 種標的資產。請注意,它僅針對 1 個模擬路徑編寫:

import numpy as np
from matplotlib import pyplot
import timeit


steps = 21
underlyings = 12



#seed = 0 # fix your seed for calcing Greeks
#np.random.seed(seed)


def sample_path_batch(underlyings, steps):
   dt = 1.0 / (steps-1)
   dt_sqrt = np.sqrt(dt)
   B = np.empty((underlyings, steps), dtype=float)
   B[:, 0] = 0
   for n in range(steps - 2):
       t = n * dt
       xi = np.random.randn(underlyings) * dt_sqrt
       B[:, n + 1] = B[:, n] * (1 - dt / (1 - t)) + xi
   B[:, -1] = 0 # set last step to 0
   return B

start_time = timeit.default_timer()
B = sample_path_batch(underlyings, steps)
print('\n' + 'Run time for 1 simulation steps * underlyings: ', int(timeit.default_timer() - start_time), ' seconds')
pyplot.plot(B.T)
pyplot.show()

那麼,什麼是一種有效的方法(而不是循環這個單一的常式)來建構這條通往任意數量模擬的路徑?我正在使用 Sobol,因此以 1024 模擬為例。儘管我希望使用更多,因此希望刪除此循環,因為我已將所有內容放入另一個 j 循環並使其饋入 3D NumPy 數組,但這會迅速減慢(隨著模擬的數量):

#Now my inefficient way to generate multiple simulations of the Brownian Bridges:
sims = pow(2,17) # 131,072 simulations
def sample_path_batches(underlyings, steps, sims):
   dt = 1.0 / (steps-1)
   dt_sqrt = np.sqrt(dt)
   B = np.empty((underlyings, steps, sims), dtype=float)
   B[:,:, 0] = 0
   for n in range(steps - 2):
       for j in range(sims):
           t = n * dt
           xi = np.random.randn(underlyings) * dt_sqrt
           B[:, n + 1, j] = B[:, n, j] * (1 - dt / (1 - t)) + xi
           B[:, -1, j] = 0 # set last step to 0
   return B

start_time = timeit.default_timer()
B = sample_path_batches(underlyings, steps, sims)
print('\n' + 'Run time for ', sims, ' simulation steps * underlyings: ', 
int(timeit.default_timer() - start_time), ' seconds')

pow(2,17) = 131,072 次模擬需要 13 秒,因此我想加快速度。有任何建議總比沒有好。我認為這更像是一個普通的 Python 問題,而不是真正的量化金融問題。當然,我可以在 Cython 中執行常式並使循環並行,但我只是在尋找一種在 Python 和標準庫中執行此操作的有效方法。

基於will評論的潛在解決方案,最初(在我將 np.random.randn 更改為(基礎,sims)之前)所有“隨機”數字在模擬中都是相同的。無論如何,這“看起來”工作得非常快,儘管隨機數的矩陣(在固定種子之後)不一樣(j 循環與這個矢量化修改)。不幸的是,我不擅長用 matplotlib 繪製 3D 數組。當我單獨繪製它們時,它們似乎仍然是布朗橋pyplot.plot(B[:,:,sim#].T); pyplot.show()並在每次模擬中獲取統計資訊,儘管它們與 j 循環方法不同(可能是因為在循環中,我有迭代隨機數,而這裡,它們是在 2D 中生成的)。它們仍然“看起來”是有效的布朗橋,但我沒有複製 j 循環產生的相同序列(即改變了衝擊產生的序列)。我顯然無法逐一查看 21 條路徑中 12 個底層證券的 131,072 次模擬……儘管如此,這是修改,我想一旦我嘗試實施它,我就會知道它有多“好”(不確定我是否應該為此使用 Mersenne Twister(如圖所示)或 RQMC 點,但在這裡,可能對其他人有用) - 現在,如果我只能將布朗循環矢量化,那麼,也許在另一天:

import numpy as np
from matplotlib import pyplot

steps = 21
underlyings = 12
sims = 131072

def sample_path_batches(underlyings, steps, sims):
   dt = 1.0 / (steps-1)
   dt_sqrt = np.sqrt(dt)
   B = np.empty((underlyings, steps, sims), dtype=float)
   B[:, 0, :] = 0 # set first step to 0
   for n in range(steps - 2):
# =============================================================================
# Slow j loop before vectorization:
#
#         for j in range(sims):
#             t = n * dt
#             xi = np.random.randn(underlyings) * dt_sqrt
#             B[:, n + 1, j] = B[:, n, j] * (1 - dt / (1 - t)) + xi
#             B[:, -1, j] = 0 # set last step to 0
# =============================================================================

# Change the generation of random numbers to be done in 1 step of the Brownian Bridge,
# for a huge speedup in computational time; note the random numbers differ from the j loop

       t = n * dt
       xi = np.random.randn(underlyings, sims) * dt_sqrt
       B[:, n + 1, :] = B[:, n, :] * (1 - dt / (1 - t)) + xi
       B[:, -1, :] = 0 # set last step to 0
   return B

1 個模擬步驟的執行時間 * 底層證券:0.022 秒

131072 個模擬步驟的執行時間 * 底層證券:1.131 秒

引用自:https://quant.stackexchange.com/questions/68492