TMP是臺灣證券交易所(TWSE)所使用的專屬傳輸協定,全名為Transaction Message Protocol,用於證券交易相關的訊息傳輸。此工具用於解析TMP提供的委託/成交/申報/檔案傳輸服務訊息內容,將序列化的字串資料轉為非序列化的資料物件後再加以利用。非序列化的資料亦可使用此工具轉換成COBOL可處理的序列化字串資料以用於系統間的資料交換。
const templar = require('templar');檔案傳輸
const message = templar.parse('20020508595900000084500003M01', { category: 'file-transfer' }
console.log(message);
// Message_t {
// body: [ { FileCode: 'M01', ResponseMessage: '' } ],
// raw: Uint8Array('20000008595900845000000011T3000000100'),
// header: {
// SubsystemName: '20',
// FunctionCode: '02',
// MessageType: '05',
// MessageTime: 2025-08-17T00:59:59.000Z,
// StatusCode: '00',
// SourceId: '0000',
// ObjectId: '8450',
// BodyLength: 3
// },
// id: 'F060',
// remained: Uint8Array('')
// }const message = {
id: 'F050',
header: {
SubsystemName: '20',
FunctionCode: '02',
MessageType: '05',
MessageTime: new Date('2025-08-15T00:59:59.000Z'),
StatusCode: '00',
SourceId: '8450',
ObjectId: '0000',
// BodyLength: 3, // 會自動根據body變化
},
body: [ { FileCode: 'M01', RequestMessage: '' } ],
};
console.log(templar.stringify(message, { category: 'file-transfer' });
// 20020508595900845000000003M01成交回報
const message = templar.parse('500000085959008450000001', { category: 'report' });
console.log(message);
// Message_t {
// body: [ { BrokerId: '8450', StartSeq: 1 } ],
// raw: Uint8Array('500000085959008450000001'),
// header: {
// SubsystemName: '50',
// FunctionCode: '00',
// MessageType: '00',
// MessageTime: 2025-08-15T00:59:59.000Z,
// StatusCode: '00'
// },
// id: 'R1',
// remained: Uint8Array('')
// }const message = {
id: 'R1',
header: {
SubsystemName: '50',
FunctionCode: '00',
MessageType: '00',
MessageTime: new Date('2025-08-15T00:59:59.000Z'),
StatusCode: '00'
},
body: [ { BrokerId: '8450', StartSeq: 1 } ],
};
console.log(templar.stringify(message, { category: 'report' }));
// '500000085959008450000001'交易所的TMP訊息採ASCII編碼,而中文字常用CP950的編碼方式傳入,故在字串切割上一個中文字實算兩個字元空間。
const { parse } = require('./lib/field/parse.js');
test('Parse CP950', async (t) => {
const buffer = iconv.encode('中文字', 'cp950')
t.equal(parse({ picStr: 'X(4)', dataType: DATA_TYPE.String, buffer }), '中文');
t.equal(parse({ picStr: 'X(5)', dataType: DATA_TYPE.String, buffer }), '中文�');
t.equal(parse({ picStr: 'X(6)', dataType: DATA_TYPE.String, buffer }), '中文字');
});復刻COBOL文字與數字不同的對齊方式 (文字靠左,數字靠右)。
const { parse } = require('./lib/field/parse.js');
test('Parse PIC 9', async (t) => {
t.equal(parse({ picStr: '9(5)', dataType: DATA_TYPE.Unsigned, buffer: Buffer.from('12345') }), 12345);
t.equal(parse({ picStr: '9(5)', dataType: DATA_TYPE.Unsigned, buffer: Buffer.from('123456') }), 23456);
});目前支援的解析格式
基本:
- PIC X
- PIC X(4)
- PIC 9999
- PIC 9(4)
混合:
- PIC 99V99
- PIC 9(3)V9(2)
- PIC 9(3)V99
- PIC S99V99
- PIC S9(3)V9(2)
- PIC S9(3)V99
| COBOL PIC | 說明 | Node 對應 |
|---|---|---|
PIC X(n) |
任意字元,長度 n | String |
PIC A(n) |
只允許字母 | String |
PIC AN(n) |
字母 + 數字 | String |
PIC G(n) |
雙位元組字元 (DBCS, EBCDIC) | String |
| COBOL PIC | 說明 | Node 對應 |
|---|---|---|
PIC 9(n) |
無號小數,整數 n 位 | Number |
PIC S9(n) |
有號小數,整數 n 位 | Number |
PIC 9(n)V9(m) |
無號小數,整數 n 位,小數 m 位 | Number |
PIC S9(n)V9(m) |
有號小數,整數 n 位,小數 m 位 | Number |
| COBOL PIC | 用途 | Node 對應 |
|---|---|---|
PIC X(8) (YYYYMMDD) |
日期 | Date |
PIC X(6) (HHmmss) |
時間 | Date |
PIC X(9) (HHmmssSSS) |
時間 | Date |
PIC X(14) (YYYYMMDDHHmmss) |
時間戳記 | Date |
在交易所提供的文件中,X(8)對應YYYYMMDD的DATE型別,而X(6)與X(9)分別對應HHmmss/HHmmssSSS的TIME型別。目前Node 22尚未支援Temporal.PlainTime與Temporal.PlainDate,故對於上述資料型態的轉換會統一轉換至JS的Date型別,其中X(6)與X(9)會自動補上當下執行的日期。
Signed overpunch源自Hollerith(赫爾曼·何樂禮)打孔卡編碼,為解決正負號帶來的字元浪費與孔位長度變動的問題,將數字與正負號整併至一個孔位解讀。目前已知COBOL的對應關係有:
| 數 字 | ca, cb, cm, cr Positive |
ci, cn Positive |
ca, ci, cn Negative |
cb Negative |
cm Negative |
cr Negative |
|---|---|---|---|---|---|---|
| 0 | '0' | '{' | '}' | '@' | 'p' | ' ' (space) |
| 1 | '1' | 'A' | 'J' | 'A' | 'q' | '!' |
| 2 | '2' | 'B' | 'K' | 'B' | 'r' | '"' (double-quote) |
| 3 | '3' | 'C' | 'L' | 'C' | 's' | '#' |
| 4 | '4' | 'D' | 'M' | 'D' | 't' | '$' |
| 5 | '5' | 'E' | 'N' | 'E' | 'u' | '%' |
| 6 | '6' | 'F' | 'O' | 'F' | 'v' | '&' |
| 7 | '7' | 'G' | 'P' | 'G' | 'w' | ''' (single-quote) |
| 8 | '8' | 'H' | 'Q' | 'H' | 'x' | '(' |
| 9 | '9' | 'I' | 'R' | 'I' | 'y' | ')' |
| 選 項 | 對 應 COBOL |
|---|---|
| ca | RM/COBOL (not RM/COBOL-85) |
| cb | MBP COBOL |
| ci | IBM COBOL (RM/COBOL-85) |
| cm | Micro Focus COBOL |
| cn | NCR COBOL |
| cr | Realia COBOL |
| cv | VAX COBOL |
COBOL的S9對正負號數字表示範例 (IBM COBOL)
PIC S9(3) VALUE -123.
TRAILING '1' '2' 'L'
TRAILING SEPARATE '1' '2' '3' '-'
LEADING 'J' '2' '3'
LEADING SEPARATE '-' '1' '2' '3'
PIC S9(5)V9 VALUE -12345.6.
TRAILING '1' '2' '3' '4' '5' 'O'
TRAILING SEPARATE '1' '2' '3' '4' '5' '6' '-'
LEADING 'J' '2' '3' '4' '5' '6'
LEADING SEPARATE '-' '1' '2' '3' '4' '5' '6'// IBM COBOL (-dci) and Trailing
'S9(3)V9': '12C' >> 12.3
'S9(3)V9': '12L' >> -12.3
'S9(1)V9': '12C' >> 2.3
'S9(1)V9': '12L' >> -2.3雖然支援Leading解析,但是會跟某些Overpunch查表定義衝突
// IBM COBOL (-dci) and Leading
'S9(3)V9': 'J23' >> -12.3
'S9(1)V9': 'J23' >> `Exception: Unknown overpunch char: '2'`// Micro Focus COBOL (-dcm) and Leading
'S9(1)V9': 'J23' >> 2.3PVC:Permanent Virtual Circuit(永久虛擬電路)
一條實體線上可建立多條PVC,每10條PVC為一組。
| PVC 或 PORT NO |
執行功能 |
|---|---|
| 01 | FT送 |
| 02 | FT收 |
| 03 | 成交回報 |
| 04 | 委託輸入 |
| 05 | 委託輸入 |
| 06 | 委託輸入 |
| 07 | 委託輸入 |
| 08 | 委託輸入 |
| 09 | 委託輸入 |
| PVC | 時 間 | 執 行 業 務 |
|---|---|---|
| (01) FT 送 |
07:30-19:00 | 單筆訊息及檔案傳輸 (證券商的傳送線路) |
| (02) FT 收 |
07:30-19:00 | 單筆訊息及檔案傳輸 (證券商的傳送線路) |
| (03) 成交回報 |
08:30-14:40 | 成交回報接收 |
| (04~09) 委託輸入 |
08:30-13:30 09:00-12:10 09:00-13:30 13:40-14:30 14:00-14:30 14:30-15:00 15:00-16:00 15:00-16:00 |
普通股交易 標借交易 盤中零股交易 盤後零股交易 盤後定價交易 證金標購交易 拍賣交易 標購交易 |
| 時 間 | 證 券 商 與 證 交 所 |
|---|---|
| 07:30 | 08:20 |
1.開機通知作業 2.登錄作業 準備進入連線狀態 |
| 08:20以後 | 完成連線進入各應用子統統 |
| 08:30 | 19:00 |
1.進行各項業務 2.若在各項業務處理中發現有任何異常狀況時 (1)開機通知作業 (2)登錄作業 重新進入連線狀態 |
| 19:00以後 | 1.完成各項業務 2.離線作業 雙方進入離線狀態 |
MESSAGE ID︰L010、L020、L030、L040、L050、L060、L070、L080
| 時 間 | 系 統 | 功 能 |
|---|---|---|
| 07:30 | 08:00 |
連線子系統 | 建立證交所與證券商的電腦連線作業,並進入業務系統。 |
| 08:00 | 19:00 |
單筆訊息與檔案傳輸子系統 結算作業 申購作業 投資人管理作業 |
提供交易報表。 補送成交回報資料給證券商。 申購作業。 處理結算業務。 處理申購業務。 處理與投資人管理有關之業務。 |
| 19:00 | 連線子系統 | 離線 |
MESSAGE ID︰F010、F020、F030(F210)、F040(F220)、F050、F060、F070、F080
MESSAGE ID︰F090、F100、F110(F230)、F120(F240)、F130、F140、F150、F160
MESSAGE ID︰F170、F180、F190、F200
| 時 間 | 系 統 | 功 能 |
|---|---|---|
| 08:00-08:30 | 連線子系統 | 建立證交所與證券商的電腦連線作業,並進入業務系統。 |
| 08:30-13:30 09:00-12:10 09:00-13:30 13:40-14:30 14:00-14:30 14:30-15:00 15:00-16:00 15:00-16:00 |
普通股交易子系統 標借交易子系統 盤中零股交易子系統 盤後零股交易子系統 盤後定價交易子系統 證金標購交易子系統 拍賣交易子系統 標購交易子系統 |
證券商輸入買賣委託,並接受證交所的委託回報。 |
| 16:00 | 連線子系統 | 結束委託輸入,回到連線子系統。 離線 |
MESSAGE ID︰T1、T2、T3、T4、T5、T6、T7
| 時 間 | 系 統 | 功 能 |
|---|---|---|
| 08:00 | 08:30 |
連線子系統 | 建立證交所與證券商的電腦連線作業,並進入業務系統。 |
| 08:30 | 14:00 |
成交回報接收子系統 | 接收普通股、盤中零股成交回報資料。 |
| 14:00 | 14:40 |
成交回報接收子系統 | 接收盤後定價、盤後零股成交回報資料。 |
| 14:40 | 連線子系統 | 結束委託輸入,回到連線子系統。 離線 |
MESSAGE ID︰R1、R2、R3、R4、R5、R6
{project-root}
├─ cli <-------------------- CLI工具
│ └─ ...
├─ lib
│ ├─ copybook <---------- 文件內容轉換
│ ├─ field <------------- 欄位轉換
│ ├─ message <----------- 訊息解析
│ ├─ spec
│ │ ├─ copybook <------ 各類FILE-CODE檔案內容定義
│ │ ├─ field <--------- 欄位基本資料結構
│ │ ├─ fields <-------- 欄位組成後定義
│ │ │ ├─ body
│ │ │ └─ header.js
│ │ └─ message <------- 訊息種類定義
│ │ ├─ otc.js
│ │ └─ tse.js
│ └─ meta.js
└─ templar.js-
打包
npm pack
> npm pack ... ... npm notice Tarball Details npm notice name: templar npm notice version: X.Y.Z npm notice filename: templar-X.Y.Z.tgz npm notice package size: 374.7 kB npm notice unpacked size: 1.6 MB npm notice shasum: ba2890224935e4a6a0ecdf91d9585c287a4c3073 npm notice integrity: sha512-3I975LfONtGXo[...]K22YKPtY5EZcQ== npm notice total files: 61 npm notice templar-X.Y.Z.tgz -
安裝
npm install ./templar-X.Y.Z.tgz