了解 C++ 語言的特性,奠定程式語言的基礎。
了解如何運用C++程式語言解決金融計算中的問題和挑戰。
學習如何使用C++進行金融模型的實現與演算法的設計。
金融計算程式運用(一)屬於『初階C++』介紹,並加上更多相關財務案例的討論。
金融計算程式運用(二)將介紹更多關於物件導向、模板設計、C++ 標準程式庫、QuantLib程式庫原始碼的介紹。
透過了解高品質的 C++ 量化金融程式庫(QuantLib),強化實作觀念與能力。
上課內容:
案例分析:
Armstrong, J. (2017). C++ for financial mathematics. CRC Press.
Pitt-Francis, J., & Whiteley, J. (2017). Guide to scientific computing in C++. Springer.
基礎:
進階:
C++ 是由 AT&T Bell 實驗室的 Bjarne Stroustrup 博士及其同事於80年代在 C 語言的基礎上開發成功而誕生。
C++ 語言是一門經典、靈活、功能強大、野心勃勃的計算機程式語言,但也是公認具有一定學習難度的電腦程式語言。
即便是那些不使用 C++ 語言進行開發的職業,很多也要求求職者具備 C++ 程式功力,究其原因,主要就是因為凡是對 C++ 語言開發有良好駕馭能力的人,整體開發實力明顯要比從未接觸過 C++ 語言編程的開發者強出許多。
C 語言為 C++ 的子集合,具備 C 的強大功能並擴展了物件導向特性。
兼具低階與高階程式語言特性,適用於系統開發與應用程式開發。
可直接存取記憶體位址,進行位元操作,如位元運算子(bitwise operator)。
可用來開發系統軟體、嵌入式系統、資料庫管理系統、遊戲引擎等。
執行速度快,適合高效能計算與即時處理。
運用廣泛,涵蓋金融、科學計算、人工智慧、區塊鏈、量子計算等領域。
支援多種程式設計範式:過程導向、物件導向、泛型程式設計、函數式程式設計。
與多種外部庫整合良好:如 Boost、Eigen、OpenMP、CUDA、QuantLib。
C++(物件導向)為編譯式語言,其為 C 語言(過程導向)的增強版。
1998年,C++ 標準委員會正式發佈第一個 C++ 標準,此版本被認為「標準 C++」,又稱「C++ 98」(1.0)。
2003年發布 C++ 標準第二版,也叫「C++ 03」。
2011年,新的 C++ 標準正式發佈,稱「C++ 11」(2.0)。
C++98(1998) 版本以及之前的版本,一般稱為『傳統 C++』。
C++03(2003):小幅修訂,修正 C++98 的問題。
C++11 (2011)版本之後,一般稱為『現代 C++』。
C++14(2014):增強 C++11,改進泛型與
constexpr。
C++17(2017):引入
std::optional、if constexpr、結構化綁定。
C++20(2020):提供
concepts、ranges、coroutines,大幅提升泛型能力。
因需要 Visual Studio C++ 編譯器(Microsoft Visual C++,簡稱 MSVC),故建議安裝。否則需安裝其他 C++編譯器(如 MinGW-w64,乃 Windows 版本的 GNU Compiler Collection(GCC)。其提供一個在Windows上使用的 GNU工具鏈,包括C++編譯器)。
Visual Studio 是 Microsoft 官方提供的整合開發環境(IDE),非常適合在Windows電腦上進行 C++ 程式開發。
Visual Studio 2022 是最新版本,支援 Windows 11。
提供豐富的功能,包括程式碼編輯、調試、自動完成、視覺化設計和內建的 CMake 支援。
Visual Studio 2022 還支援許多擴展,可擴展其功能,且社區版是免費的,適用於大多數開發者。
Windows環境下,使用 QuantLib C++ 程式庫時推薦使用。
安裝過程中,記得勾選 C++ 工作負載所需的核心功能,以確保安裝 Visual Studio C++ 編譯器(MSVC)。
Visual Studio Code(VS Code)是一個輕量級的代碼編輯器。
可透過安裝 C/C++ 與 CMake 相關延伸模組,可以使 VS Code 成為一個強大的 C++ 開發工具。
VS Code 是免費的,且社群與插件生態環境相當活躍。
CMake 是一個用於自動生成跨平台應用程式的建構(Build)工具。
可管理 C++ 或其他程式語言專案的構建過程。
使用 CMake,可在不同的作業系統上產生相對應的構建文件,例如 Makefile(用於 Linux 和 macOS)或 Visual Studio 專案建構文件(用於 Windows)。
使得不同平台上的專案能夠保持一致性且易於管理。
安裝 CMake:
下載 CMake 安裝程式:
前往 CMake 官方網站下載頁面:https://cmake.org/download/
在下載頁面中,下載 cmake-3.27.6-windows-x86_64.msi。大多數情況下,您可以選擇 64 位版本,但請根據您的系統選擇一個版本並下載。
執行安裝程式:
雙擊下載的安裝執行檔,接著按照安裝步驟進行操作。
在安裝過程中,可選擇安裝路徑、加入快捷方式等選項。通常,預設選項是最合適的。
設定環境變數以完成安裝:
安裝完成後,確保將 CMake 的安裝路徑添加到系統的 PATH 環境變數中。
如果需要手動添加到 PATH,請按照以下步驟:
打開「設定」。
選擇「系統」。
下拉到畫面最後,選擇「系統資訊」。
在「系統資訊」畫面尋找「進階系統設定」後並點擊之。
進入「系統內容」視窗後,點擊「環境變數」按鈕。
在「系統變數」的區域中,下拉尋找名為 Path 變數。
在「編輯環境變數」對話框中,按一下「新建」,然後加入
CMake 的安裝路徑(一般都是放在
C:\Program Files\CMake\bin,請確認 CMake
在你電腦的位置)。
點擊「確定」儲存變更。
打開命令提示列(cmd)或 PowerShell。
在命令提示列輸入下列指令檢查 CMake 是否成功安裝,並顯示版本資訊,若成功安裝,則會看到 cmake 版本:
cmake --version
Xcode:
Homebrew 是 macOS 上的一個套件管理器,可以幫助您輕鬆安裝和管理軟件包。您可以使用以下命令安裝 Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
(若安裝失敗,請先看終端機上的錯誤訊息提示並進行操作。)
C++ 編譯器:
使用 Homebrew 安裝最新版本的 GCC 或 Clang(Xcode 內建)。您可以選擇其中一個來編譯 C++ 程式。
安裝 GCC:
brew install gcc
使用 Xcode 內建的 Clang。
下載 macOS 版本: 點擊下載頁面上的「macOS」按鈕,以下載 macOS 版本的 Visual Studio Code。
安裝 VS Code: 下載完成後,您會在下載目錄中找到一個名為「Visual Studio Code.app」的應用程式檔案。將該檔案拖曳至「應用程式」資料夾中,以完成安裝。
啟動 VS Code: 前往「應用程式」資料夾,找到安裝完成的 Visual Studio Code 應用程式,接著雙擊打開。
安裝插件(擴展): 第一次啟動 VS Code 時,將看到歡迎畫面。可在左側的側邊欄中找到插件圖示(方塊和箭頭)。點擊該圖示,然後在搜索欄中輸入欲安裝的插件名稱。例如,想進行 C++ 開發,需安裝「C/C++」擴展。單擊「安裝」按鈕以安裝所選的擴展。另外,請同時安裝 CMake 插件。
方法一:使用 Homebrew 安裝 CMake
打開終端機應用程式(Terminal)。若未安裝 Homebrew,可在終端機執行以下命令來安裝:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安裝 CMake,只需在終端機執行以下命令:
brew install cmake
可在終端機執行以下命令來驗證 CMake 是否安裝成功:
cmake --version
若安裝成功,終端機將顯示 CMake 的版本訊息。
方法二:從官方網站下載並安裝 CMake
前往 CMake 官方網站的下載頁面
滾動到 “Binary distributions” 部分,找到 macOS 的選項,通常會有一個 .dmg 檔案的下載連結,點擊它下載最新版本的 CMake。
雙擊下載的 .dmg 檔案,它會在 Finder 中打開一個新的視窗。
在打開的視窗中,將 “CMake” 應用程式圖標拖放到 “Applications” 資料夾中,以完成安裝。
可關閉 .dmg 視窗,並在「應用程式」資料夾中找到 CMake 應用程式。第一個 C++ 程式
可在終端機執行以下命令來驗證 CMake 是否安裝成功:
cmake --version
若安裝成功,終端機將顯示 CMake 的版本訊息。
CMake 是一個開源跨平台『自動化專案建構』的工具,其不依賴於特定的編譯器或作業系統。
CMake 主要任務是生成適用於不同建構系统的『建構文件檔』。依系統不同有以下格式:
Makefiles:Make工具上的建構文件檔
Visual Studio 專案的建構文件檔
Ninja 的建構文件檔等。
CMake 的配置文件稱為
CMakeLists.txt,其用來定義專案的各種屬性、依賴關係和建構的規則等。
Ninja 是一個跨平台的軟體專案建構系统,其用於『專案的構建』。最初由 Google 團隊開發使用。
與 Make 或其他建構工具不同,Ninja 的設計目的是快速執行與平行化建構方式。
Ninja 以建構文件檔 —— build.ninja
形式使用,而這些文件檔由 CMake 工具所產生。
當使用 CMake 專案時,CMake 工具會根據專案的配置產生適用於 Ninja 的建構文件檔。意指你可以指定使用 Ninja 作為實際建構專案的工具,而非採 Make 或 Visual Studio 等其他建構工具。
在 macOS 上使用 CMake 工具一般不需要額外安裝 Ninja。
macOS 內建 make 建構工具,一般情況下足以完成大部分 CMake 專案的構建。
因 macOS 預設安裝 make 工具(GNU Make)。故可在終端機中執行 “make” 命令。
為確認已經正確安裝。請執行下列指令:
make --version補充:安裝Ninja(可選):
macOS:
可使用套件管理器進行安裝,如 Homebrew。以下是使用 Homebrew 安裝 Ninja 的步驟:
brew install ninja驗證安裝:
ninja --versionWindows:
安裝 Chocolatey(可選):
以『系統管理員身分執行』打開 PowerShell 。
執行以下指令安装 Chocolatey:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))安裝 Ninja(可選):
當 Chocolatey 安装完成,可使用 Chocolatey 來安裝 Ninja。
同樣以『系統管理員身分執行』打開的 PowerShell 或命令提示列視窗執行以下指令:
choco install ninja驗證安裝:
在命令提示列或 PowerShell 執行以下指令:
ninja --version要在 CMake 中配置使用 make 或 ninja 作為建構工具,或是在 Windows 系統下使用 Visual Studio 2022 的生成器,可透過執行 CMake 指令時指定生成器(Generator)來達成。
生成器決定了 CMake 將使用哪種建構工具。
指定使用 Make
建構工具:cmake -S . -B build -G "Unix Makefiles"(Mac
可用)
指定使用 Ninja
建構工具:cmake -S . -B build -G "Ninja"(Mac、Windows
可用,建構速度較快,建議 Mac 使用)
指定使用 Visual Studio 2022
建構工具:cmake -S . -B build -G "Visual Studio 17 2022”(建議
Windows 使用)
上述指令用於配置和生成 CMake 專案的配置文件:
cmake:這是 CMake
的命令行工具,用於執行各種 CMake 相關的操作。
-S .:這部分指定了 CMake
的來源目錄(Source Directory)。.
表示當前目錄,也就是執行該命令的目錄。這個目錄應包含
CMakeLists.txt 文件,因為它告訴 CMake
哪裡可以找到專案的配置相關設定。
-B build:這部分指定 CMake
的建構目錄(Build Directory)。在上述範例中,將建構文件存儲在名為
“build”
的子目錄中。建構目錄是用於儲存產生的中間檔案和建構檔案的位置。您可以選擇不同的目錄名稱,但通常建議將生成文件存儲在專門的子目錄中,以保持專案的整潔與一致性。
-G "Unix Makefiles":這部分指定了生成器(Generator)。在上述範例中,若使用的生成器為
“Unix Makefiles”,此生成器用於產生可由 Unix 系統上的 Make
指令使用的建構文件。這表示希望使用 “make” 作為建構工具來編譯和構建你的
C++ 專案。
CMake 建構指令:
cmake --build build
此指令使用 CMake 設定的建構工具來進行建構的命令。
CMake 會根據之前指定的生成器來選擇適用的建構工具。
以下為該指令各部分的解釋:
cmake:這是 CMake
的命令行工具,用於執行各種 CMake 相關的操作。
--build:這是 CMake
的一個子命令,用於執行實際的建構操作。
build:這是之前使用
-B 選項指定的生成目錄的名稱。建構目錄是
CMake 用來儲存生成的中間檔案和建構檔案的位置。
當執行 cmake --build build
時,CMake 將使用預設的生成工具(例如 make 或
ninja,取決於之前配置的生成器)來自動編譯和連結 C++ 專案。
該指令會在建構目錄中查找 CMake 已經生成的建構指令,接著執行這些指令以完成建構過程。
程式語言實際上就是一套規範的集合,主要包含該語言使用的字元集合、直接或間接支援的資料型態集合、運算子集合、關鍵字集合、指令集合、語法規則,以及特定構造的支援,例如:函數的定義,抽象資料型態的定義、繼承、模板、例外處理等。
main 函數(主函數)為C++程式的「入口點」。
main 函數為使用者運行程式時所執行的函數。
C++程式常用的副檔名:
.cpp、cxx、cc:原始檔(source
file)。
.h、.hpp:標頭檔(header
file)
『函數(function)』可以接收輸入、執行某些指令並回傳結果的程式碼區塊。
// test.cpp,放入src資料夾
// 這是單行註解
/*
* 這是多行註解
* 這是多行註解
* 這是多行註解
*/
#include <iostream> // 包含iostream標頭檔。
int main(int argc, char* argcv[])
{
std::cout << "Hello Quant World" << std::endl; // std為C++標準程式庫的命名空間(namesapce)名稱。
return 0;
}
建議『QuantLib範例』專案資料夾,專案名為:
MyProj,資料夾內建立子資料夾:
src:存放c++原始檔(source file, ex: 副檔名為
.cpp、.cxx、.cc)。
include:存放標頭檔(header file, ex: 副檔名為
.h、.hpp)。
external:存放外部程式庫原始檔,例如:QuantLib-1.37。
data:存放外部資料檔,例如 .txt,
.json檔案。
bin:執行檔放置的位置。
CMakeLists.txt:
在專案資料夾 MyProj 建立名稱為
CMakeLists.txt
的檔案,用於描述專案的結構和如何構建該專案。
定義原始檔、編譯選項、連結庫、目標(target)和其他構建相關的設置。
CMakeLists.txt 使用 CMake
語法,其包含一系列命令和變數設置。
不含 QuantLib C++ Library
cmake_minimum_required(VERSION 3.10)
project(CppProject
VERSION 1.0.0
DESCRIPTION "Study C++"
LANGUAGES CXX
)
# 指定 C++ 的版本
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 設定專案的目錄結構
set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
set(EXTERNAL_DIR ${CMAKE_SOURCE_DIR}/external)
set(DATA_DIR ${CMAKE_SOURCE_DIR}/data)
set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
# 設定執行檔名稱與原始檔名稱 #################################
# set(SOURCE_FILES ${SRC_DIR}/main.cpp) # 原始檔名稱
set(EXECUTABLE_NAME MyApp) # 執行檔名稱
##############################################################
# 使用 GLOB 收集原始檔案
file(GLOB SOURCE_FILES "${SRC_DIR}/*.cpp")
# 設定可執行檔案的輸出目錄
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR})
# 設定執行檔名稱和源文件
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
# MyApp 是要創建的執行檔名稱(目標target),main.cpp 是該執行檔所依賴的源文件。
# 這個指令告訴 CMake 創建一個名為 MyApp 的執行檔,該執行檔的源文件是 main.cpp。
# 將 include 目錄添加到編譯器的包含路徑中
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${INCLUDE_DIR})
message(STATUS "Binary output directory: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
# 最後將測試資料複製一份到輸出目錄(bin資料夾)
file(COPY ${DATA_DIR} DESTINATION ${BIN_DIR})包含 QuantLib C++ Library
cmake_minimum_required(VERSION 3.10)
project(QuantLibExample
VERSION 1.0.0
DESCRIPTION "An example project using QuantLib"
LANGUAGES CXX
)
# 指定 C++ 的版本
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 設定專案的目錄結構
set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
# set(EXTERNAL_DIR ${CMAKE_SOURCE_DIR}/external)
set(DATA_DIR ${CMAKE_SOURCE_DIR}/data)
set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
# 設定執行檔名稱與原始檔名稱 #################################
# set(SOURCE_FILES ${SRC_DIR}/main.cpp) # 原始檔名稱
set(EXECUTABLE_NAME MyApp) # 執行檔名稱
##############################################################
# 使用 GLOB 收集原始檔案
file(GLOB SOURCE_FILES "${SRC_DIR}/*.cpp")
# 設定 QuantLib 的原始碼路徑
set(QUANTLIB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/QuantLib-1.37)
# ${CMAKE_CURRENT_SOURCE_DIR} 是 CMake 內建的變數,表示當前 CMakeLists.txt 文件所在的目錄的路徑。
# 假設 CMakeLists.txt 文件位於您的專案的根目錄下,這條命令將把 QUANTLIB_SOURCE_DIR 設置為 ${專案根目錄}/external/QuantLib-1.37。
# 將 QuantLib 的原始碼添加到您的專案中
add_subdirectory(${QUANTLIB_SOURCE_DIR})
# 在這個例子中,${QUANTLIB_SOURCE_DIR} 是一個變數,表示 QuantLib 的原始碼所在的目錄路徑,是之前使用 set() 命令設定的。
# ${QUANTLIB_SOURCE_DIR} 的值應該是 QuantLib 原始碼的根目錄。
# 設定可執行檔案的輸出目錄
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR})
# 設定執行檔名稱和源文件
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
# MyApp 是要創建的執行檔名稱(目標target),main.cpp 是該執行檔所依賴的源文件。
# 這個指令告訴 CMake 創建一個名為 MyApp 的執行檔,該執行檔的源文件是 main.cpp。
# 連接 QuantLib 程式庫
target_link_libraries(${EXECUTABLE_NAME} ql_library)
# 將目標 MyApp 連接(link)到 ql_library 程式庫。
# 在這裡,使用了 add_subdirectory(${QUANTLIB_SOURCE_DIR}) 命令將 QuantLib 的原始碼目錄添加到專案中,從而生成了 ql_library 程式庫。
# target_link_libraries() 命令確保了 MyApp 執行檔在編譯時能夠找到 ql_library 程式庫的二進位檔案,並在執行時能夠使用它提供的函數和功能。
# 在連接程式庫時,CMake 將根據目標平台和編譯器使用適當的連接器(例如 g++、clang++、Visual Studio 等)來建立連接。
# 將 QuantLib 的頭文件目錄添加到編譯器的包含路徑
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${QUANTLIB_SOURCE_DIR})
# 將 include 目錄添加到編譯器的包含路徑中
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${INCLUDE_DIR})
message(STATUS "Binary output directory: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
# 最後將測試資料複製一份到輸出目錄(bin資料夾)
file(COPY ${DATA_DIR} DESTINATION ${BIN_DIR})每個 C++ 程式包含一個或多個函數(function)。其中一個必須命名為
main。
main 函數為程式的入口點(entry
point),作業系統是透過 main 函數來執行 C++ 程式。
一個函數的定義包含四個部分:
回傳型態(return type)
函數名(function name)
(形式)參數列表(parameter list,可為空)
函數體(function body)
main 函數回傳值必須為
int,即為整數型態;其為一種內建型態(built-in
type)。
函數體由左大括弧({)開始,以右大括弧結束(})。
#include <iostream> 告訴編譯器我們想要使用
iostream 程式庫。< >內指定標頭檔(header
file)名稱。而#include指令與標頭檔名稱必須寫在同一行,且一般出現在所有函數之外(含main函數)。
return 語句(statememt)結束函數的執行。
請注意 return
語句末尾的分號(;)。大多數
C++的語句以分號(;)表示該語句的結束。
在大部分系統中,main
函數的回傳值表示『執行狀態』。回傳 0 代表執行成功,非 0
的回傳值則由系統定義,通常代表錯誤的類型。
C++程式由資料數據(常數、變數,含物件等)與函數等所組成。
因 C++ 為『編譯程式語言』,故編寫程式之後則需進行『編譯』。
編譯器如何進行編譯端看所使用的作業系統與編譯器:
亦可透過命令提示列進行。
建構過程:
編輯器(editor):將程式設計的想法轉換為程式碼。
若為語法方面的錯誤,則會在程式編譯過程中出錯,且編譯器會出現錯誤提示。
若為邏輯方面的錯誤(例如程式輸出結果不如預期時),或執行效率低落,則不會有明顯的錯誤提示。
預處理器(preprocesser):
編譯器在正式編譯之前,遍歷整個原始碼檔案,先處理 C/C++
原始檔案中的預處理命令,即以 # 開頭的指令。
預處理的含義將後面提及的檔案(標頭檔)『複製』至當前原始碼檔案中。並進行下列處理:
刪除所有的 #define 並展開所有
macro。
處理所有的預編譯條件,例如 #ifdef ,
#include (展開引用文件)
刪除所有 註解。
增加 行號以及
文件識別名,讓編譯器在編譯失敗時可以顯示錯誤的行號。
常見預處理指令:
#include
#ifndef … #else …#endif
#define
#pragma
編譯器(compiler):
雖然 C++ 標準是唯一的,但各編譯器的實現未必完全一致。
因不同電腦的硬體系統未必相同,故一種編譯器一般是針對一種或某些作業系統所設計。
某種平台下所編譯的程式,一般無法在另一個作業系統上執行。
此階段編譯器會將展開後的程式碼轉換成『組合語言』。
預編譯完成後,編譯器會編譯每個原始檔(.cpp、.cxx、.cc、.c),如果編譯成功,會產生對應的『目標檔(object
file)』,Linux平台為 .o 檔,Windows平台下為
.obj 檔。
編譯完成的目標檔還不可執行。還需要『連結器』進一步進行連結處理。
連結器(linker):連結器將多個目標檔與多個靜態程式庫處理成『執行檔』。
執行程式:
連結任務完成後即可產生執行檔。但仍需檢驗程式能否正常運行,並符合設計的要求。
很少有程式能一次執行成功,總會有一些意想不到的錯誤發生。
錯誤發生後則需回頭檢查原始碼、重新編譯、連結,試執行等。
安裝 WSL ,此指令會啟用 WSL 並安裝 Linux Ubuntu 作業系統:
wsl --install設定『使用者帳號』與密碼。
打開 Ubuntu 命令列,並安裝 C++ 編譯器(g++):
sudo apt update
sudo apt install g++安裝 C++ boost 程式庫:
sudo apt-get install libboost-all-dev安裝 CMake 工具:
sudo apt install cmake安裝 Visual Studio Code:
sudo apt install code在 Ubuntu
路徑上(/home/[你的使用者帳號]/)建立『專案資料夾』,例如命名為
[QuantExamples]:
cd /home/[你的使用者帳號]
mkdir QuantExamples切換路徑專案資料內,並建立五個子資料夾(bin, data, src, include, external):
cd QuantExamples
mkdir bin
mkdir data
mkdir src
mkdir include
mkdir external將 QuantLib 1.37 壓縮檔下載至 external 資料夾,並進行解壓縮:
cd external
sudo apt install wget
wget https://github.com/lballabio/QuantLib/releases/download/v1.37/QuantLib-1.37.tar.gz
tar xzf QuantLib-1.37.tar.gz將路徑切回專案資料夾,並以 Visual Studio Code 打開此專案:
cd /home/[你的使用者帳號]/QuantExamples
code .安裝 Visual Studio Code 必要的『延伸模組』:如與 cmake相關、WSL 相關延伸模組等。
建立 CMakeLists.txt 檔案。將講義上的 CMakeLists.txt 內容複製貼上至新建立的 CMakeLists.txt 檔案中。
在 src 資料夾內建立主程式檔案供測試使用,如 test.cpp:
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*!
Copyright (C) 2008 Allen Kuo
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
/* This example sets up a callable fixed rate bond with a Hull White pricing
engine and compares to Bloomberg's Hull White price/yield calculations.
*/
#include <ql/qldefines.hpp>
#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
# include <ql/auto_link.hpp>
#endif
#include <ql/experimental/callablebonds/callablebond.hpp>
#include <ql/experimental/callablebonds/treecallablebondengine.hpp>
#include <ql/models/shortrate/onefactormodels/hullwhite.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <vector>
#include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
using namespace QuantLib;
ext::shared_ptr<YieldTermStructure>
flatRate(const Date& today,
const ext::shared_ptr<Quote>& forward,
const DayCounter& dc,
const Compounding& compounding,
const Frequency& frequency) {
return ext::make_shared<FlatForward>(today,
Handle<Quote>(forward),
dc,
compounding,
frequency);
}
ext::shared_ptr<YieldTermStructure>
flatRate(const Date& today,
Rate forward,
const DayCounter& dc,
const Compounding &compounding,
const Frequency &frequency) {
return flatRate(today,
ext::make_shared<SimpleQuote>(forward),
dc,
compounding,
frequency);
}
int main(int, char* [])
{
try {
Date today = Date(16,October,2007);
Settings::instance().evaluationDate() = today;
cout << endl;
cout << "Pricing a callable fixed rate bond using" << endl;
cout << "Hull White model w/ reversion parameter = 0.03" << endl;
cout << "BAC4.65 09/15/12 ISIN: US06060WBJ36" << endl;
cout << "roughly five year tenor, ";
cout << "quarterly coupon and call dates" << endl;
cout << "reference date is : " << today << endl << endl;
/* Bloomberg OAS1: "N" model (Hull White)
varying volatility parameter
The curve entered into Bloomberg OAS1 is a flat curve,
at constant yield = 5.5%, semiannual compounding.
Assume here OAS1 curve uses an ACT/ACT day counter,
as documented in PFC1 as a "default" in the latter case.
*/
// set up a flat curve corresponding to Bloomberg flat curve
Rate bbCurveRate = 0.055;
DayCounter bbDayCounter = ActualActual(ActualActual::Bond);
InterestRate bbIR(bbCurveRate,bbDayCounter,Compounded,Semiannual);
Handle<YieldTermStructure> termStructure(flatRate(today,
bbIR.rate(),
bbIR.dayCounter(),
bbIR.compounding(),
bbIR.frequency()));
// set up the call schedule
CallabilitySchedule callSchedule;
Real callPrice = 100.;
Size numberOfCallDates = 24;
Date callDate = Date(15,September,2006);
for (Size i=0; i< numberOfCallDates; i++) {
Calendar nullCalendar = NullCalendar();
Bond::Price myPrice(callPrice, Bond::Price::Clean);
callSchedule.push_back(
ext::make_shared<Callability>(
myPrice,
Callability::Call,
callDate ));
callDate = nullCalendar.advance(callDate, 3, Months);
}
// set up the callable bond
Date dated = Date(16,September,2004);
Date issue = dated;
Date maturity = Date(15,September,2012);
Natural settlementDays = 3; // Bloomberg OAS1 settle is Oct 19, 2007
Calendar bondCalendar = UnitedStates(UnitedStates::GovernmentBond);
Real coupon = .0465;
Frequency frequency = Quarterly;
Real redemption = 100.0;
Real faceAmount = 100.0;
/* The 30/360 day counter Bloomberg uses for this bond cannot
reproduce the US Bond/ISMA (constant) cashflows used in PFC1.
Therefore use ActAct(Bond)
*/
DayCounter bondDayCounter = ActualActual(ActualActual::Bond);
// PFC1 shows no indication dates are being adjusted
// for weekends/holidays for vanilla bonds
BusinessDayConvention accrualConvention = Unadjusted;
BusinessDayConvention paymentConvention = Unadjusted;
Schedule sch(dated, maturity, Period(frequency), bondCalendar,
accrualConvention, accrualConvention,
DateGeneration::Backward, false);
Size maxIterations = 1000;
Real accuracy = 1e-8;
Integer gridIntervals = 40;
Real reversionParameter = .03;
// output price/yield results for varying volatility parameter
Real sigma = QL_EPSILON; // core dumps if zero on Cygwin
auto hw0 = ext::make_shared<HullWhite>(termStructure,reversionParameter,sigma);
auto engine0 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw0,gridIntervals);
CallableFixedRateBond callableBond(settlementDays, faceAmount, sch,
vector<Rate>(1, coupon),
bondDayCounter, paymentConvention,
redemption, issue, callSchedule);
callableBond.setPricingEngine(engine0);
cout << setprecision(2)
<< showpoint
<< fixed
<< "sigma/vol (%) = "
<< 100.*sigma
<< endl;
cout << "QuantLib price/yld (%) ";
cout << callableBond.cleanPrice() << " / "
<< 100. * callableBond.yield(bondDayCounter,
Compounded,
frequency,
accuracy,
maxIterations)
<< endl;
cout << "Bloomberg price/yld (%) ";
cout << "96.50 / 5.47"
<< endl
<< endl;
sigma = .01;
cout << "sigma/vol (%) = " << 100.*sigma << endl;
auto hw1 = ext::make_shared<HullWhite>(termStructure,reversionParameter,sigma);
auto engine1 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw1,gridIntervals);
callableBond.setPricingEngine(engine1);
cout << "QuantLib price/yld (%) ";
cout << callableBond.cleanPrice() << " / "
<< 100.* callableBond.yield(bondDayCounter,
Compounded,
frequency,
accuracy,
maxIterations)
<< endl;
cout << "Bloomberg price/yld (%) ";
cout << "95.68 / 5.66"
<< endl
<< endl;
////////////////////
sigma = .03;
auto hw2 = ext::make_shared<HullWhite>(termStructure, reversionParameter, sigma);
auto engine2 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw2,gridIntervals);
callableBond.setPricingEngine(engine2);
cout << "sigma/vol (%) = "
<< 100.*sigma
<< endl;
cout << "QuantLib price/yld (%) ";
cout << callableBond.cleanPrice() << " / "
<< 100. * callableBond.yield(bondDayCounter,
Compounded,
frequency,
accuracy,
maxIterations)
<< endl;
cout << "Bloomberg price/yld (%) ";
cout << "92.34 / 6.49"
<< endl
<< endl;
////////////////////////////
sigma = .06;
auto hw3 = ext::make_shared<HullWhite>(termStructure, reversionParameter, sigma);
auto engine3 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw3,gridIntervals);
callableBond.setPricingEngine(engine3);
cout << "sigma/vol (%) = "
<< 100.*sigma
<< endl;
cout << "QuantLib price/yld (%) ";
cout << callableBond.cleanPrice() << " / "
<< 100. * callableBond.yield(bondDayCounter,
Compounded,
frequency,
accuracy,
maxIterations)
<< endl;
cout << "Bloomberg price/yld (%) ";
cout << "87.16 / 7.83"
<< endl
<< endl;
/////////////////////////
sigma = .12;
auto hw4 = ext::make_shared<HullWhite>(termStructure, reversionParameter, sigma);
auto engine4 = ext::make_shared<TreeCallableFixedRateBondEngine>(hw4,gridIntervals);
callableBond.setPricingEngine(engine4);
cout << "sigma/vol (%) = "
<< 100.*sigma
<< endl;
cout << "QuantLib price/yld (%) ";
cout << callableBond.cleanPrice() << " / "
<< 100.* callableBond.yield(bondDayCounter,
Compounded,
frequency,
accuracy,
maxIterations)
<< endl;
cout << "Bloomberg price/yld (%) ";
cout << "77.31 / 10.65"
<< endl
<< endl;
return 0;
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}完成後,可關閉並重新開啟 Visual Studio Code。CMake 工具即自動建立編譯設定檔,並建立在 build 中。
即可進行『建置』,測試編譯是否成功。