XQ交易語法專章

By | 2021-03-17

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超人氣加值模組介紹

XQ手機版支援下單

XQ量化交易平台學習地圖

統一證券開戶連結

群益金鼎證券開戶連結

XQ全球贏家下載連結