XQ交易語法,是專門為XQ量化交易平台所設計的交易語法,使用者可以透過這個語法,來讓電腦在指定的價位或條件下,自動執行進場,加碼,減碼,平倉等各種不同成交數量的交易動作。
XQ交易語法主要是由幾個核心的語法所建構而成
一,Setposition(數量,價格)
Position代表的是這個商品在這個策略內的’預期部位’, Position是一個整數, 可以大於0, 也可以小於0. **請注意: 一個交易策略內可以跑多個商品,每個商品的Position是獨立的**
當我們想要執行交易時, 就呼叫SetPosition這一個函數, 傳入我們預期的部位(同時也可以傳入委託價格). 腳本開始執行時, 商品的Position預設數值是0, 當我們想要買進時, 就透過SetPosition把Position變大, 想要賣出時, 就透過SetPosition把Position變小. 系統收到了SetPosition()的呼叫之後, 就會依照目前的Position, 目前委託/成交的執行狀態, 決定如何送單, 來讓你的策略可以達到(成交)這個新的預期的部位.
SetPosition()可以接受兩個參數: 第一個參數是預期的部位, 第二個參數是委託的價格, 這個參數如果不傳的話, 則會採用策略的預設買進/賣出價格 請看以下範例,把部位(Position)變成1, 如果原先部位是0的話, 則等於買進1張 第二個參數(委託價格)如果不傳的話, 則使用策略設定內的預設價格 SetPosition(1);
第二個參數可以傳入價格, MARKET是系統保留字, 代表是’市價'(期貨的話則會是’範圍市價’)
SetPosition(1, MARKET);
也可以傳入K棒的價格, 例如Close
SetPosition(1, Close);
也可以傳入數值運算式
SetPosition(1, Close + 1.0);
也可以傳入絕對值, 例如100.0
SetPosition(1, 100.0);
支援檔位換算功能(AddSpread) AddSpread(Close, 1)表示是Close價格往上加1檔, AddSpread(Close, 2)表示加2檔 AddSpread(Close, -1)表示是Close價格往下減1檔 AddSpread也可以用在警示腳本, 以及指標腳本,例如我們如果在空手時要用現價加一檔買進一張,就可以像下面這麼寫
SetPosition(1, AddSpread(Close, 1));
Position也可以是負的, 如果原先部位是0的話, 則等於賣出1張
SetPosition(-1);
除了可以SetPosition之外, 也可以讀到目前的Position,所以如果要加碼一張,可以像下面這樣的寫法
SetPosition(Position+1)
表示是加碼1張
SetPosition的價格如果不符合商品的交易規則的話, 系統會自動轉換, 例如: 如果超過漲停價, 則只會送出漲停價, 例如: 如果不符合跳動點的話, 則會自動轉換到符合跳動點價格 SetPosition(1, 123.1);
如果是買進台股的話, 因為上百元的話是每0.5元一檔,所以會送出委託價格=123
看到這裡,各位應該可以了解,XQ的交易語法,基本上就是透過Setposition這個函數,去把部位調整到你心目中的理想部份,像如你想全部平倉,你不用記目前庫存有多少張,只要直接寫setposition(0,market),就代表用市價平倉,寫setposition(0,AddSpread(Close, -2))就代表用現價低兩檔平倉,把個股的庫存部位砍到0
這樣的語法非常簡潔,不必在那邊buy 啦 sell啦,@market啦,巴啦吧啦的寫的落落長,例如我們如果要在股價突破月線時市價進場買進一張,那就可以直接寫
if close cross over average(close,22) then setposition(1,market);
這樣是不是很簡潔且易於處理呢?
二,filled
Filled是Position的另外一個朋友, 代表這個策略內/這個執行商品的成交部位
當腳本執行SetPosition(1)後, 會送出一筆買進1張的委託,
如果此時尚未成交的話, Position會等於1, 可是Filled會等於0
如果這一筆委託單成交的話, 則Position會等於1, Filled也會等於1
如果腳本內想要判斷目前成交狀態的話, 就可以透過讀取Filled這個變數來判斷.例如當目前部位是零的時候,下面的幾種寫法,代表不同的意義
if Position = 1 and Filled = 1 then begin { 已經送出一筆買進1張的委託, 而且這一筆委託已經成交 } end;
if Position = 1 and Filled = 0 then begin { 已經送出一筆買進1張的委託, 可是還沒有成交} end;
if Position = -1 and Filled = 0 then begin { 已經送出一筆賣出1張的委託, 可是還沒有成交 } end;
if Position = -1 and Filled = -1 then begin { 已經送出一筆賣出1張的委託, 而且這一筆委託已經成交 } { Filled跟Position一樣, 可能會大於0, 也可能會小於0 } end;
三,filledavgprice
除了可以使用Filled來知道目前的成交部位之外,也可以透過FilledAvgPrice這個函數來取得目前”未平倉”部位的成本
範例: 多單1口進場後, +1.5%停利, -1.5%停損
var: long_condition(false); { 是否做多 } if Position = 0 and long_condition then SetPosition(1); if Position = 1 and Filled = 1 then begin { 多單已經買進1口 } { 計算損益% } var: plratio(0); { 請注意: 不管Filled是大於0還是小於0, FilledAvgPrice的數值都是'正數'(>0) } plratio = 100 * (Close - FilledAvgPrice) / FilledAvgPrice; if plratio >= 1.5 then SetPosition(0); { 停利 } if plratio <= -1.5 then SetPosition(0); { 停損 } end;
目前計算未平倉成本的方式是採用**先進先出的沖銷方式**來計算, 以下是沖銷順序的範例:
範例#1
假設策略執行過程總共產生三筆成交, 依照時間先後順序, 資料分別為
– 第一筆: 買進1張, 成交價100元,
– 第二筆: 買進1張, 成交價102元,
– 第三筆: 賣出1張, 成交價101元
在第一筆成交時, Filled = 1, FilledAvgPrice = 100
在第二筆成交時, Filled = 2, FilledAvgPrice = (100 + 102) / 2 = 101
在第三筆成交時, Filled = 1, FilledAvgPrice = 102 (第三筆-1沖銷第一筆+1, 所以未平倉剩下第二筆1張, 未平倉成本=102)
範例#2
假設策略執行過程總共產生四筆成交, 依照時間先後順序, 資料分別為
– 第一筆: 買進2張, 成交價100元,
– 第二筆: 買進2張, 成交價101元,
– 第三筆: 買進2張, 成交價102元,
– 第四筆: 賣出3張, 成交價101元,
在第一筆成交時, Filled = 2, FilledAvgPrice = 100
在第二筆成交時, Filled = 4, FilledAvgPrice = (100*2 + 101*2) / 4 = 100.5
在第三筆成交時, Filled = 6, FilledAvgPrice = (100*2 + 101*2 + 102*2) / 6 = 101
在第四筆成交時, Filled = 3, FilledAvgPrice = (101*1 + 102 * 2) / 3 = 101.66666
(第一筆成交的2張被沖銷, 第二筆成交的1張被沖銷)
}
四,FilledRecord函數
除了Filled跟FilledAvgPirce之外, 系統也提供FilledRecord相關的函數, 讓腳本可以取得每一筆成交的詳細資料
FilledRecordCount: 取得商品執行迄今的成交筆數
請注意:
成交筆數會對應到真實的交易紀錄, 例如買進5張, 如果分三次成交, 分別成交2張, 2張, 1張,
那麼FilledRecordCount會是3
value1 = FilledRecordCount; { 回傳成交筆數 }
取得成交筆數之後, 就可以一筆一筆把成交紀錄資料讀出來
FilledRecordDate(n): 回傳第n筆成交紀錄的日期, 格式是YYYYMMDD, 例如20200727 (2020年7月27日)
FilledRecordTime(n): 回傳第n筆成交紀錄的時間, 格式是HHMMSS, 例如103000 (10點30分0秒)
FilledRecordBS(n): 回傳第n筆成交紀錄的買賣別, 買進的話是1, 賣出的話是-1
FilledRecordPrice(n):回傳第n筆成交紀錄的成交價格, 請注意這個數值的正負跟買進/賣出無關(以台股來說都會 > 0)
FilledRecordQty(n): 回傳第n筆成交紀錄的成交數量, 請注意不管是買進或是賣出, 這個數值都是 > 0的整數
FilledRecordIsRealtime(n): 回傳第n筆成交紀錄是否是在即時區間成交的, 如果是的話回傳1, 否則回傳0
n的範圍從1到FilledRecordCount
var: idx(0); for idx = 1 to FilledRecordCount begin value2 = FilledRecordDate(idx); value3 = FilledRecordTime(idx); value4 = FilledRecordBS(idx); value5 = FilledRecordPrice(idx); value6 = FilledRecordQty(idx); value7 = FilledRecordIsRealtime(idx); end;
根據以上這四個基礎語法,接下來就跟大家分享一些演算法交易常用的程式例子
一,GAT買進單
GAT是Good-after-Time/Date的簡稱,意思是直到設定的日期/時間才送出委託單
下面是XQ量化平台的PM寫的範例,供大家參考
//Good-after-Time/Date (GAT)直到設定的日期/時間才送出 input:d1(20200115,"請輸入生效日格式yyyymmdd"); input:t1(090000,"請輸入生效時間格式hhmmss"); input:v1(1,"請輸入買進張數"); if d1 < currentdate or d1 > dateAdd(currentdate,"Y",1) or d1 > 99999999 then RaiseRunTimeError("請檢查生效日期"); if t1 > 240000 then RaiseRunTimeError("請檢查生效時間"); if v1 <= 0 then RaiseRunTimeError("買進張數需大於0"); if currentdate * 1000000 + currenttime >= d1 * 1000000 + t1 then setposition(v1,market);
二,GAT平倉單
這種下單的方式是用在像是除權前,或是法說會結束日等指定特定日期要平倉的下單方式,範例如下
//Good-after-Time/Date (GAT)直到設定的日期/時間才送出 input:d1(20200115,"請輸入生效日格式yyyymmdd"); input:t1(090000,"請輸入生效時間格式hhmmss"); if d1 < currentdate or d1 > dateAdd(currentdate,"Y",1) or d1 > 99999999 then RaiseRunTimeError("請檢查生效日期"); if t1 > 240000 then RaiseRunTimeError("請檢查生效時間"); if currentdate * 1000000 + currenttime >= d1 * 1000000 + t1 then setposition(0,market);
三,GTC買進單
GTC 是Good till cancel的縮寫,使用者可以設定特定價位和張數,然後讓系統幫你盯盤買到你設定的量
input:theposition(50,"交易金額,單位萬元"); input:taprice(130,"目標價位"); value1=IntPortion(theposition*10/open); if filled < value1 then setposition(value1,taprice);
四,MIT買進單
//Market-if-Touched(MIT)若觸到特定價格即轉為市價單。 input:v1(1,"買進張數"); input:p1(50,"觸發價位"); if close>=p1 then setposition(v1,market);
五,MPM買單
//Midpoint Match (MPM)以買賣報價的的中間價格交易 input:v1(1,"請輸入買進張數"); setposition(v1, (q_BestAsk1+q_BestBid1)/2);
六,作多掃單
value1=q_BestAskSize1; value2=value1+q_BestAskSize2; value3=value2+q_BestAskSize3; value4=value3+q_BestAskSize4; value5=value4+q_BestAskSize5; input:v1(499,"掃單張數"); if v1<value1 then setposition(q_BestAsk1,v1) else if v1<value2 then setposition(q_BestAsk2,v1) else if v1<value3 then setposition(q_BestAsk3,v1) else if v1<value4 then setposition(q_BestAsk4,v1) else if v1<value5 then setposition(q_BestAsk5,v1);
七,開盤市價買進
input:theposition(50,"買進金額,單位萬元"); input:t1(090000,"請輸入執行時間,格式hhmmss"); value1=IntPortion(theposition*10/open); if time>=090000 then setposition(value1,market);
八,收盤市價平倉
input:t1(132955,"請輸入執行時間,格式hhmmss"); if time>=t1 then setposition(0,market);
以上是XQ量化平台的交易語法,未來有新的範例或語法,也會增加在這一篇說明中。
XQ全球贏家下載連結