標籤:

MATLAB 高級數據結構連載 1:金融時間序列Financial Time Series (Part A)

考慮如下 excel 表格中數據:

上表是 50ETF(上海證券交易所掛牌交易的股票型基金) 2016/3/1 至 2016/3/4 間的一分鐘數據:第一列為時刻,第二至五列分別為 50ETF 在該分鐘的開盤價(該分鐘開始時的價格)、最高價、最低價、收盤價(該分鐘結束時的價格)。這種按時間先後順序排列而成的金融數列,被稱為「金融時間序列」(Financial Time Series)。對金融時間序列的分析,是量化金融領域的一大熱點,其在證券市場上常見的應用有:對股票價格時間序列進行分析以期預測後市,或計算技術指 標(如MACD、KD、RSI等)來擇時出入場。

要在 MATLAB 中做量化分析首先要解決的問題是:如何在 MATLAB 中表示如上的時間序列數據? 並且,如何方便地操作這類數據,比如抽樣、繪製移動平均線,等等?

首先考慮保存數據用的數據結構問題。可以確定的是,時刻列和價格數據(上表的 open、high、low、close)應當存放在同一個變數中,因為價格數據是和時刻相關聯的,沒有時間序列,價格數據沒有實際的意義。此外,如果我們需要同時研究很多支股票,每支股票都的時刻列都可能不一樣,如果分開存放的,會引起混亂。那麼,什麼數據結構可以把時刻和價格有效地存在一起呢?以下討論這幾個數據結構的可行性:

  • matrix
  • cell (元胞數組 )
  • containers.Map (映射表數據結構)
  • Financial Time Series(金融時間序列數據結構)

使用 matrix

顯然,直接把時刻和價格數據保存在同一個 matrix 中是不可行的,例如, 「2016-03-01 09:30」和 「1.940」 不是一種數據類型——前者是字元串,後者是浮點數。它們不能被存在同一個matrix 中。如果要解決這個問題,可以用 datenum 把字元串形式的日期變成數字,這樣一來,時刻和價格數據都為浮點數,可以保存在同一個 matrix 中。舉例如下:

>> tmpdata = 2016-03-01 09:25 % 原始數據ntmpdata =n 2016-03-01 09:25 nn>> tmpData_Num = datenum( tmpdata ) % 把字元串轉成浮點ntmpData_Num =n 736390.392361111n

顯然這不是好的解決方案,因為 「736390.392361111」 這種時刻表示方式不直觀。

使用 cell 元胞數組

元胞數組 cell 可以把不同類型的數據存到。設本文開頭的表格為 「myDB_50ETF.csv」,以下 通過xlsread的方法把時刻和價格數據存在cell中:

>> [~,~,cellData ] = xlsread(myDB_50ETF)ncellData = n 2016-03-01 09:25 [ 1.94] [ 1.94] [ 1.94] [ 1.94]n 2016/3/1 9:30:00 [ 1.94] [1.942] [1.932] [1.932]n 2016/3/1 9:31:00 [1.932] [1.932] [1.929] [1.931]n 2016/3/1 9:32:00 [1.931] [1.936] [1.931] [1.936]n 2016/3/1 9:33:00 [1.935] [1.942] [1.935] [1.942]n ...n

然而,正如《MATLAB 映射表數據結構》一文所述,元胞數組 cell 有許多操作上的局限性,如:

  • 不方便添加缺失內容、不方便作為函數的參數(數組,元胞和結構體的局限性)

  • 無法自動驗證重複數據。例如,以下表格第 7、8 行有錯誤的數據:

上表數據有誤:50ETF 在 2016-03-01 9:35:00 的開盤價,不可能既是 1.949,又是 1.942。而這個問題,cell 是不會自動檢查出來的,觀察讀取到的 cellData 的 7、8 行:

>> cellData(7:8,:)nans = n 2016/3/1 9:35:00 [1.949] [1.949] [1.942] [1.943]n 2016/3/1 9:35:00 [1.942] [1.944] [1.942] [1.944]n

可以看到,兩個 9:35 的數據都被保留了,這不是我們所希望見到的結果。

使用 containers.Map

在《MATLAB 映射表數據結構》一 文中介紹的映射表,在一定程度上能夠勝任這個「把時刻和價格存放在統一的變數中」的工作,也可以有效解決「不方便作為函數的參數」的問題,此外,由於 containers.Map 可以確保 「key」 的唯一性,把時刻作為 「key」 來儲存時刻-價格數據,可以避免同一個時刻有多組數據。

但是,containers.Map 不夠直觀,無法看到數據全貌。例如,當 key 為時刻時,用

變數名( 時刻 )n

的方式,只能提取到該指定時刻的數據,比如,令:

>> myMap = containers.Map();n>> myMap (2016-03-12 9:30:00) = [1.94 1.942 1.932 1.932]; n

則一次只能查看一個時刻的數據:

>> myMap(2016-03-12 9:30:00)nans = n 1.94 1.942 1.932 1.932n

那麼,有沒有更加合適的「高級數據結構」的?答案是肯定的。 MATLAB 引入了專門的 Finacial Time Series 數據結構(以下簡稱 FINTS),用來存放諸如股票價格這類金融時間序列數據,並有許多金融相關的方法可供調用,詳述如下。

使用 FINTS存儲金融時間序列

1 FINTS 對象的構造

給定數據,我們可以用 fints 構造函數生成 Financial Time series 對象。仍以本文開頭數據 myDB_50ETF.csv 為例,用 importdata 讀取該 excel 文件、再用 fints 生成儲存時刻和價格數據的變數 myFTS 的代碼如下 :

>> DataSets = importdata( myDB_50ETF.csv ); n>> myFTS = fints( DataSets.rowheaders, DataSets.data, {open,high,low,close }); % 返回Financial Timer Series對象n

所得到的 myFTS 對象在 MATLAB命令行中的 disp 非常得直觀:

>> myFTS nmyFTS = n desc: (none)n freq: Unknown (0) % freq的默認值是 Unknowndates:(967)times:(967)open:(967)high:(967)low:(967)close:(967)n 01-Mar-2016 09:25 [1.94] [1.94] [1.94] [1.94]n " 09:30 [1.94] [1.942] [1.932] [1.932]n " 09:31 [1.932] [1.932] [1.929] [1.931]n " 09:32 [1.931] [1.936] [1.931] [1.936]n ...n

現對以上結果作些說明:

  • myFTS 的第三行是 MATLAB 幫助自動生成的默認的數據表頭,其中,dates 和 times 分別指日期和時刻,open、high、low、close 為價格數據的名稱(在生成 myFTS 時被指定)。表頭後面括弧中的數據(967),代表這一列數據的長度(數據個數)。
  • dates 一列中的 " ,代表該行的 dates 和上一行一致。
  • myFTS 的前兩行(desc、frec)為對象的兩個屬性,其中 desc(description) 屬性可用來儲存對用戶對該對象的簡短的描述, freq( frequency)屬性可用來描述該對象的頻率,它們都可以用 「dot indexing」 直接賦值,如:

>> myFTS.desc = 50ETF 價格;n>> myFTSnmyFTS = n ddesc: 50ETF 價格n ...n

可見,使用金融時間序列(FINTS)這一數據結構,可以做到:

  • 把「字元串形式的時刻」和「浮點數形式的價格數據」存儲在同一個 FINTS 對象中
  • 數據結構一目了然。
  • 沒有重複的數據,比如前文所述的兩組 9:35 分的數據,在生產 FINTS 對象時,MATLAB會對時間做排序,如有重複,取第一個出現的時刻的數據,並且移除其餘重複行。

>> myFTS(7:8) nans = n desc: 50ETF 價格n freq: Unknown (0) ndates:(2)times:(2)open:(2)high:(2)low:(2)close:(2)n 01-Mar-2016 09:35 [1.949] [1.949] [1.942] [1.943]n " 09:37 [1.945] [1.956] [1.945] [1.952]n

除了使用 FINTS 的構造函數 fints 以外,還可以用 ascii2fts 來生成 FINTS 對象。

2 訪問 FINTS 對象中的數據

我們可以使用傳統的 MATLAB 的 indexing 方式對 FINTS 對象的數據作訪問,比如:

>> myFTS([1 3 4]) nans = n desc: 50ETF 價格n freq: Unknown (0) ndates:(3)times:(3)open:(3)high:(3)low:(3)close:(3)n 01-Mar-2016 09:25 [1.94] [1.94] [1.94] [1.94]n " 09:31 [1.932] [1.932] [1.929] [1.931]n " 09:32 [1.931] [1.936] [1.931] [1.936]n

注意,index 的只能是行數。

也可以使用 DOT indexing,需要指定數據列:

>> myFTS.close nans = n desc: 50ETF 價格n freq: Unknown (0)n dates: (967) times: (967) close: (967) n 01-Mar-2016 09:25 [ 1.94]n " 09:30 [ 1.932]n " 09:31 [ 1.931]n ...n

或者兩者結合:

>> myFTS.close(1:3) nans = n desc: 50ETF 價格n freq: Unknown (0)n dates: (3) times: (3) close: (3)n 01-Mar-2016 09:25 [ 1.94]n " 09:30 [ 1.932] n " 09:31 [ 1.931]n

注意,無論使用什麼方式訪問,最後得到的,仍舊是一個 FINTS 對象

3. FINTS 的運算

FINTS 的運算和普通的矩陣運算基本相同,例如,以下運算都是支持的:

>> myFTS.close+1;n>> myFTS.close - myFTS.open;n>> myFTS.high ./ myFTS.low;n

不能直接做的運算,可以用 fts2mat 方法,把 FINTS 對象的數據先轉換成矩陣,再進行運算,如:

sum( fts2mat(myFTS.close) )n

此外,FINTS 擁有一系列方法,可供我們快速操作數據,如抽樣、計算移動平均值,等。這將在 Part B 中介紹。


推薦閱讀:

[matDL框架開發直播:1]matDL概述和基本使用
【Matlab基礎】04. 自定義函數
理工科女生筆記本選購諮詢?
[MATLAB R2017a 搶鮮報道] : 自動駕駛工具箱(1)
MATLAB圖像處理:把照片變成動漫風格

TAG:MATLAB |