[TS懶人包] [保險服務]
顯示具有 1.6 EasyLanguage 教學 標籤的文章。 顯示所有文章
顯示具有 1.6 EasyLanguage 教學 標籤的文章。 顯示所有文章

2012年4月1日 星期日

ADE - All Data Everywhere for TradeStation 8 and Multicharts

剛好有人問到了二個 Chart 之間怎麼傳遞參數的問題…所以,就順便來寫寫關於 ADE 的教學吧。不過 TS 2000i 是不能用的…所以快升級吧…

ADE 是一個 TS 論壇上的高手開發出來的…能用到的功能實在太多…這邊就算單的講一下二個 Charts 間傳參數的方式~整個流程有點複雜,算是很進階的一課了,真的有需要的人再來玩會比較好。

首先,需要先下載兩個壓縮檔: ADE 和 ELCollection





下載完後,先解壓縮吧!



接下來的安裝步驟:

1. 將 ELCollections 資料夾內的 ELCollections.dll 放到 MC 的安裝資料夾內… (ex: C:\Program Files\TS Support\MultiCharts)

2. 打開 PowerLanguage 並把 ELCollections.ELD 匯入 (會匯入很多 Functions)

3. 在 C:\ 底下建立一個資料夾…該資料夾名稱為 ADE
C:\ADE

4. 在 C:\ADE 底下建立 Data 和 Classes 和 Code 三個資料夾
C:\ADE\Data
C:\ADE\Classes
C:\ADE\Code

5. 把剛剛從 ADE.rar 解壓縮出來的檔案放到 C:\ADE 資料夾內

6. 把 C:\ADE 資料夾內的 OHLCV.txt 檔案移到 C:\ADE\Classes 資料夾內

7. 打開 PowerLanguage 並匯入 AllDataEverywhere.ELD (一樣會匯入很多 Functions)

安裝流程就到這裡完畢了…如果你還想繼續走下去的話~那看來很有決心想要用一下 ADE…

再來就是程式碼了…首先,用到 ADE 主要是要在兩個 Charts 間傳遞參數…那簡單的說…就是 A, B 兩個 Charts 要傳參數,如果是 A 要傳給 B 的話,那就是要在 A 程式碼內把值「寫入」,然後在 B 程式碼內把值「讀出」。

先來看看「寫入」的程式碼:

Vars: Class("DK"), InfoMap(MapSN.New);

vars: var5( 0 ), var6( 0 ), var7( 0 ), var8( 0 ) ;

Value2 = Stochastic( High, Low, Close, StochLength, SmoothingLength1, SmoothingLength2, 1, var5, var6, var7, var8 ) ;

Value1 = MapSN.Put(InfoMap, "KDR", var7);
Value1 = MapSN.Put(InfoMap, "KDB", var8);

Value1 = ADE.PutBarInfo(Class, "DK-Day", ADE.BarInterval, ADE.BarID, InfoMap);


首先,第一行的 Vars 是變數宣告,這裡面宣告了 Class("DK") 和 InfoMap(MapSN.New)

InfoMap 的部份就照著用吧,而 Class 內的名稱則可以自己修改,你可以把這個名稱當成一個容器。

接下來兩行是計算 Stochastic Slow 用的,也就是慢速 KD 值。

再來的兩行 Value1 開頭的程式碼是把要的值丟進容器裡… MapSN.Put <-- 看到 Put 應該可以理解…就是把資料放進去的意思… 而後面帶的參數第一個就照著用…

第二個參數(比如說上面的 "KDR") 你可以看成在大容器內的小箱子…,而第三個參數就是要丟進去的值。

最後一行則是把 BarInfo 也放進去…這樣在拿資料的時候才不會拿錯…當然…第二個參數的 "DK-Day" 也可以自行修改名稱 寫入的部份大概就這樣了…應該是已經可以滿足大部份的使用需求。


接下來看一下拿資料的程式碼:
Vars: Class("DK"), InfoMap(MapSN.New);
Vars: DayKDR(0), DayKDB(0);

Value1 = ADE.GetBarInfo(Class, "DK-Day", 0, ADE.BarID, InfoMap);

DayKDR = MapSN.Get(InfoMap, "KDR");
DayKDB = MapSN.Get(InfoMap, "KDB");


首先,第一行的宣告是跟寫入時用的一樣的…要注意的是,Class 大容器的名稱需要和寫入那邊宣告的一樣。

第二行的宣告我是拿來記錄數值用的…

接下來的 Value1 是拿取資料用的程式碼…在寫入時我們最後寫入了 BarInfo, 而這邊就是先判斷一下 BarInfo ,再把相對應的資料拿出來

所以第三行程式碼這邊的第二個參數,就是要和上面寫入 BarInfo 的第二個參數一樣囉…比較要注意的是第三個參數…這個參數我們在寫入時用的是 ADE.BarInterval

如果你寫入時是開 5 分 K…那這邊讀取時的第三個參數就是 5,如果是 30 分K,那就是 30,因為我寫入時是用日線資料…所以這邊代入的參數就放上了 0。

最後兩行的 MapSN.Get (Get…很明顯的就是拿了…) 代進的參數就是小箱子的名子囉…

這樣就把參數從一個 Charts 傳到另一個 Charts 囉!很簡單吧~~~~(其實難的要死…)


想要做 Pair Trade、想要跑多週期、想要在程式內參考一些其它的市場資料的…都建議來用 ADE 比較好。

最後的成果就會像這樣啦:


2010年3月28日 星期日

狀態的區分

再回到教學的部份…這邊要講的是利用變數達到一些狀態區分的情況。雖然寫到這部份我會覺得有點太特意為了某些情況去執行某些條件…不過偶爾還是會用到的。

比較常見的當然是以開盤跳空位址在哪邊來記錄…另外還有依指標等情況來記錄的情形。


我自己對於跳空還滿在意的。所以對於開盤價來說…我會有一些特定的方式作進出場。在這邊先以指標來講…

以 MACD 來說…一開盤就可以區分為兩種情況。一種就是指標在 0 軸下方…另一種就是指標在 0 軸上方。


vars: status(0);

Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if date <> date[1] and Value1 < 0 then
status = -1;
if date <> date[1] and Value1 > 0 then
status = 1;


在分成這兩種狀態後…或許還可以對 MACD 均線的情況再下去分成個別的另外兩種情況:


if date <> date[1] and status = -1 and Value2 < Value1 then
status = -2;
if date <> date[1] and status = -1 and Value2 > Value1 then
status = -3;

if date <> date[1] and status = 1 and Value2 > Value1 then
status = 2;
if date <> date[1] and status = 1 and Value2 < Value1 then
status = 3;


所以現在的 status 會有 2, 3, -2, -3 這四種情況,分別代表 MACD 和 MACD 均線在一開盤的四種區別。

接下來就可以對這四種狀況分別寫上進出場的判斷了。

例如:

if status = 3 and Value1 cross under Value2 then
sell next bar at market;

if status = -3 and Value1 cross over Value2 then
buy next bar at market;


等等…可以運用的東西也不少…

不過這樣子的寫法是不是好?我很難用肯定的方式去回答。也許只當作一個教學會比較好吧…

2010年3月16日 星期二

跳空對日內行情的影響

最近的盤有點悶…剛在吃飯時想到,是不是因為沒跳空…所以才沒什麼行情。也就因為這樣…所以無聊來作一下計算。當然不是我自己去算…而是交給電腦去算。

首先是有跳空的程式碼:

vars: count(0), highlow(0), flag(0);

if date <> date[1] then
flag = 0;

if time = 900 and (highd(0) < lowd(1) or lowd(0) > highd(1)) then
flag = 1;

if time = 1330 and flag = 1 then begin
count = count + 1;
highlow = highlow + highd(0) - lowd(0);
end;

if lastbaronchart then
print(count, highlow, highlow/count);



主要就是以九點時的高低點和前一天的高低點作比較。如果低點比昨天高點高或是高點比昨天低點低…那就當成是有跳空。

再來是沒有跳空的程式碼:

vars: count(0), highlow(0), flag(0);

if date <> date[1] then
flag = 0;

if time = 900 and (highd(0) < highd(1) and lowd(0) > lowd(1)) then
flag = 1;

if time = 1330 and flag = 1 then begin
count = count + 1;
highlow = highlow + highd(0) - lowd(0);
end;

if lastbaronchart then
print(count, highlow, highlow/count);


沒跳空就是九點時的高低點是被包在前一天的高低點內的。

這樣計算出來…得出來的結果是:

623.00 71257.00 114.38
1050.00 114381.00 108.93

有跳空佔了 623 天,高低值為 71257,所以相除後得到 114.38 點。
而沒有跳空佔了 1050 天,高低值為 114381,相除後得到 108.93 點。

嗯…程式計算的結果大概符合我的想法…雖然我本來以為會相差很多的…結果才差了 6 點。

既然這個想法目前沒想到用處…那就先歸到程式教學吧…

想教的是…不過什麼想法都可以測試。只要你能把邏輯定義出來。
再來就是… Print 這個指令真的很重要…三不五時請把它拿出來用一下。

2010年3月10日 星期三

K 線根數的記錄 (MACD 背離) II

經過了上一篇的講解…我想要另外寫出多方背離應該只是再把程式碼 copy 一下改一些地方就行了。主要想說的…我想還是這寫程式的過程,從想法 - 到邏輯 - 到程式碼。這中間的過程並不是這麼的容易,想法可以很天馬行空的說…我要作波浪的第三波!

這個想法一定可行…不過重點就在於你怎麼定義所謂的"波浪的第三波",這個東西。

今天甲說了:我要作 MACD 背離!

當然可以…接下來我就要請你定義出:什麼叫 MACD 背離。

甲又說了:(指著圖上)就這個價格比那個價格高,這個 MACD 值比那個 MACD 值低啊…應該很簡單吧?

然後我心理就會想:又來一個應該很簡單了。

扯遠了…還是先把上次的程式完成吧:

array: highPoint[2](0), highMACD[2](0), highK[2](0);
array: lowPoint[2](0), lowMACD[2](0), lowK[2](0);


Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if Value1 cross under Value2 then begin
highPoint[0] = highPoint[1];
highMACD[0] = highMACD[1];
highK[0] = highK[1];

for Value3 = 0 to 10 begin
if high[Value3] = highest(high, 10) then begin
highPoint[1] = high[Value3];
highMACD[1] = Value1[Value3];
highK[1] = barnumber[Value3];
end;
end;

if highPoint[1] > highPoint[0] and highMACD[1] < highMACD[0] and highK[1] > highK[0] + 20 then begin
sell next bar at market;
end;
end;

if Value1 cross over Value2 then begin
lowPoint[0] = lowPoint[1];
lowMACD[0] = lowMACD[1];
lowK[0] = lowK[1];

for Value4 = 0 to 10 begin
if low[Value4] = lowest(low, 10) then begin
lowPoint[1] = low[Value4];
lowMACD[1] = Value1[Value4];
lowK[1] = barnumber[Value4];
end;
end;

if lowPoint[1] < lowPoint[0] and lowMACD[1] > lowMACD[0] and lowK[1] > lowK[0] + 20 then begin
buy next bar at market;
end;
end;


setexitonclose;


那接下來這邊是不是還可以變型?我想還是可以有非常多的想法再加進去的…比如說,我不要作當沖了,我要進場一直放到另一個交叉才出場、比如說我希望兩個死亡交叉中間還要再加一個穿越 0 軸的條件、比如說我希望第一個交叉是在 30 以上或 70 以下…

太多了…想到什麼就寫什麼吧。記得在圖上對照訊號是否正確囉。

2010年3月9日 星期二

K 線根數的記錄 (MACD 背離)

K 線根數在使用上我想有很多的方式,因為程式只知道對量化產生一個結果…在沒給程式一個很明確的定義情況下,程式是無法了解需要怎麼去運作的…(通常也沒辦法寫成程式)。舉個例子來說明…當你用眼睛看出一個 MACD 背離的情況下,因為你知道 MACD 背離的條件,所以很容易的就可以指出目前是 MACD 背離:



如上圖,我想應該是個很清楚的 MACD 背離條件,價格創新高但指標沒有跟著創新高。但是你很容易了解的東西,並不代表可以很容易的轉化為程式條件。

因為你不知道怎麼量化他。

所以這邊比較簡單的作法,就是利用 K 棒的根數來區隔二個高點,分別記錄下當時的價位和指標的位置。

以上面那個例子來說…也許你希望二個高點中間是隔著 20 根 K 棒,這個背離條件才算成立。所以就試著把這樣的背離條件寫出來吧:

array: highPoint[2](0), highMACD[2](0), highK[2](0);


Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if Value1 cross under Value2 then begin
highPoint[0] = highPoint[1];
highMACD[0] = highMACD[1];
highK[0] = highK[1];

for Value3 = 0 to 10 begin
if high[Value3] = highest(high, 10) then begin
highPoint[1] = high[Value3];
highMACD[1] = Value1[Value3];
highK[1] = barnumber[Value3];
end;
end;

if highPoint[1] > highPoint[0] and highMACD[1] < highMACD[0] and highK[1] > highK[0] + 20 then begin
sell next bar at market;
end;
end;

setexitonclose;


這個程式我想又比之前的東西難度更高了一點…

首先我用到了 Array 來宣告變數。在這邊我宣告了三個變數等著來儲存高點、MACD值、和當時的 K 棒。

接下來就是熟悉的 MACD 計算式。

再來的 if 這區塊可能稍微難一點…不過慢慢看應該還是懂我在寫什麼。首先是判斷 MACD 是否死亡交叉。

如果產生死亡交叉後,把 Array 的值給移動一下,因為 Array[1] 這個值我們要拿來儲存最新的值,所以把這個值丟到 Array[0] 裡面去。

在來是一個 For 迴圈,在這邊我假設產生的高點會出現在離交叉出現前的十根 K 線之內。所以我用了一個 For 來去抓出最高價( high[Value3] = highest(high, 10) ) ,當抓出最高價後,就把最高價的值丟進 highPoint[1] 裡面,順便把 MACD 的值和 K 線的值也分別丟進 array 內。

接下來就是比較目前的交叉前所產生的高點和前一個高點,是不是有背離的條件產生。有的話就是空單進場。



當然同樣的…這績效並不怎麼樣。


整個想法化為程式的過程就在上面了…接下來就是多思考、多練習吧。當你有一個想法想實際測試一下的時候…請注意是不是能夠量化。因為用講的總是很簡單…可惜電腦沒這麼聰明。

練習的話…就把多單完成吧。

2010年3月4日 星期四

變數的運用(五)

其實我不太知道這一系列的文章看的人到底多還是少…也許會有人覺得寫這些東西根本一點用也沒有…因為寫出來的策略都是虧損的…不過既然已經說是教學了…那就不要太再意績效了吧。延續上一篇文章的例子,先把程式碼寫出來:



vars: crossStatus(0), openStatus(0);
vars: mc(0), longLine(0), shortLine(0);

mc = marketposition * currentcontracts;

if date <> date[1] then begin
crossStatus = 0;
openStatus = 0;
longLine = 0;
shortLine = 0;
end;

Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if opend(0) > closed(1) then begin
openStatus = 1;
end;

if opend(0) < closed(1) then begin
openStatus = -1;
end;

if openStatus = 1 and Value1 cross under Value2 then begin
crossStatus = 1;
end;

if openStatus = -1 and Value1 cross over Value2 then begin
crossStatus = -1;
end;

if time < 1300 and crossStatus = 1 and Value1 cross over Value2 and Value1 < 50 then begin
longLine = high;
end;

if time < 1300 and crossStatus = -1 and Value1 cross under Value2 and Value1 > 50 then begin
shortLine = low;
end;

if longLine <> 0 then begin
buy next bar at LongLine stop;
end;

if shortLine <> 0 then begin
sell next bar at shortLine stop;
end;

if time = 1330 then begin
exitlong next bar at market;
exitshort next bar at market;
end;

if mc <> mc[1] then begin
openStatus = 0;
crossStatus = 0;
longLine = 0;
shortLine = 0;
end;

setstoploss(10000);



還真是愈寫愈長了…看的下去的人應該也漸漸變少了吧。在上一篇提出練習的時候其實我還沒動手寫這隻程式…寫了才發現…原來符合我一開始預定的條件的交易次數實在少的可憐。

所以這邊就動手修改了一下條件…變成不管第一次交易的 MACD 值,而在第二次 MACD 交叉時,才去限制。作多的第二次限制在 MACD < 50 ,而作空的第二次交叉則限制在 MACD > 50 的情況下。

主要程式碼並沒有太大幅度的修改…不過是把之前的抓高低點再放進來而已。

這隻程式到目前算是結束囉。等我再想下一個主題吧。

2010年3月3日 星期三

變數的運用(四)

這篇主要講解上一篇的練習題目,因為程式碼稍微的長了一些。而這一篇的練習題目會再從這邊發展下去…所以,真的想要學習的就跟上進度吧。

首先是練習程式的程式碼:

vars: crossStatus(0), openStatus(0);
vars: mc(0);

mc = marketposition * currentcontracts;

if date <> date[1] then begin
crossStatus = 0;
openStatus = 0;
end;

Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if opend(0) > closed(1) then begin
openStatus = 1;
end;

if opend(0) < closed(1) then begin
openStatus = -1;
end;

if openStatus = 1 and Value1 cross under Value2 then begin
crossStatus = 1;
end;

if openStatus = -1 and Value1 cross over Value2 then begin
crossStatus = -1;
end;

if time < 1300 and crossStatus = 1 and Value1 cross over Value2 then begin
buy next bar at market;
end;

if time < 1300 and crossStatus = -1 and Value1 cross under Value2 then begin
sell next bar at market;
end;

if time = 1340 then begin
exitlong next bar at market;
exitshort next bar at market;
end;

if mc <> mc[1] then begin
openStatus = 0;
crossStatus = 0;
end;

setstoploss(10000);


首先我另外宣告了一個變數 mc,之前提到過,這是用來記錄倉位變化用的。當然你也可以取別的名字。

前半段程式大概沒多大的差別,首先是開高開低的判斷…再這邊我開高的情況記錄為 1,而開低的情況我記錄為 -1;因為這個開高、開低是不會產生衝突的,所以利用一個變數來記錄二個狀態。到最後也許一個變數會記錄多種狀態也說不定。

接下來則是第一次交叉的狀態記錄,在開高的時候第一次交叉的狀態記錄為 1,而在開低的時候第一次交叉記錄為 -1,同樣的,這二種情況是不會衝突的,所以也是利用一個變數來記錄就可以了。

再來就是進場條件了,進場條件沒什麼更動,所以只要狀態正確、接下來的交叉就是進場作單了。

然後是一個收盤平倉的程式碼。

再來則是當倉位改變的時候,我把狀態歸零了,這可以避免掉停損後,又產生另一次的進場。在前面的文章提到過,倉位轉變記錄的用法…這邊就用到了。

最後…則是一個停損的保留字語法…偷懶一下,在停損的部份就直接用保留字完成了。關於幾個出場好用的保留字請參考:程式交易 - TradeStation 幾個好用的保留字


接下來練習的時間到了…讓我們再搞得複雜一點,進場的時候以交叉的高低點作突破進場,並限制產生第一次交叉時的 MACD 值在 50 上(開高的死亡交叉)或 50 下(開低的黃金交叉),第二次交叉時 MACD 值在 50 下(開高的黃金交叉)或 50 上(開低的死亡交叉)。

2010年3月2日 星期二

變數的運用(三)

這一篇要來講狀態的記錄了…程式也開始慢慢複雜了起來…雖然我自己比較喜歡簡單的程式。不過還是來講一下複雜的程式該怎麼寫了。首先,什麼叫狀態?舉一個還不算複雜的例子:今日開高、當 MACD 死亡交叉後,作下一個 MACD 黃金交叉。

這也許可以當成一個當沖程式的進場。也就是只要開高,然後發生 MACD 死亡交叉後的下一個黃金交叉,就買進。

這時候,程式該判斷的東西就慢慢多起來了,你必需在 MACD 發生死亡交叉的時候記錄下已經發生死亡交叉的狀態了,而在這個狀態後的黃金交叉才作單。

先來把這個程式寫出來:


vars: crossStatus(0), openStatus(0);

if date <> date[1] then begin
crossStatus = 0;
openStatus = 0;
end;

Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if opend(0) > closed(1) then begin
openStatus = 1;
end;

if openStatus = 1 and Value1 cross under Value2 then begin
crossStatus = 1;
end;

if time < 1300 and crossStatus = 1 and Value1 cross over Value2 then begin
buy next bar at market;
end;

if time = 1340 then begin
exitlong next bar at market;
end;


在這個程式裡面,首先宣告了 crossStatus 和 openStatus 兩個變數,crossStatus 是儲存是不是已經產生死亡交叉的情況;而 openStatus 則是儲存開盤是否為開高的情況。

接下來就是換日的時候把這兩個變數都作歸零的動作。

然後是熟悉的 MACD 計算式。

再來是如果今天開高( opend(0) > closed(1) ),也就是今日的開盤價大於昨日的收盤價,就把 openStatus 這個變數設為 1。

而在 openStatus 這個變數為 1 的情況下,如果產生死亡交叉,就把 crossStatus 也設為 1。

接下來的進場條件,我設下了時間限制,也同時限制 crossStatus 在 1 的情況下, MACD 黃金交叉才買進。

最後則是一個出場條件。


變數的運用是個很有趣的東西,如何利用變數來達到想要的目地,則考驗著大家的邏輯能力。當你把進場條件列出來後,有時候卻不知道該怎麼動手…所以,多寫程式吧。

練習題就是把上面的程式加上空單訊號和停損條件。空單訊號則是相反,開低後等待黃金交叉後的死亡交叉進場,而停損則先利用固定停損 50 點吧。

2010年3月1日 星期一

變數的運用(二)

上一篇提到了如何運用變數來儲存進出場價位,也順便給了個練習題是使用 MACD 交叉來記錄交叉時的高低點,利用這個高低點來作進出場。這邊先把這個練習的程式給大家。

基本上…換湯不換藥…其實只有把 Value1 和 Value2 換成 MACD 的計算而已,而 MACD 計算又在前幾篇提到過…根本應該是簡單到不行才對。

vars: longLine(0), shortLine(0);

Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if Value1 cross over Value2 then begin
longLine = high;
shortLine = 0;
end;

if Value1 cross under Value2 then begin
shortLine = low;
longLine = 0;
end;

if longLine <> 0 then
buy next bar at longLine stop;
if shortLine <> 0 then
sell next bar at shortLine stop;


夠簡單了吧…而且寫到這裡我們也偷偷的寫出了一隻能夠獲利的程式了。以六十分線來回測會得到這樣的結果:






接下來我想提一下倉位的記錄。目前的倉位可以用 marketposition 這個保留字來獲得…它可以取得目前當根的倉位。

不過當我們需要上一根 k 線的倉位的時候怎麼辦呢? Marketposition 可不能用 Marketposition[1] 啊…所以,簡單一點我們就另外宣告一個變數來儲存倉位吧。


vars: mc(0);

mc = marketposition * currentcontracts;


首先,marketposition 在 TS 內代表的是多單、空單或是空手,也就是以 1、-1 和 0 三個數字來記錄,而 currentcontracts 呢,則代表目前的口數,如果是多單十口,那 currentcontracts 就會等於 10,不過 currentcontracts 卻沒有帶正負號的…也就是說如果今天是空單 10 口,那 currentcontracts 還是會等於 10,所以這邊我們就把這兩個數值相乘。

記錄倉位有什麼用處…比如說我們今天需要在倉位有轉變的時候作一些動作,那就可以用這樣:

if mc <> mc[1] then begin
xxx
end;


這邊我通常會作的動作是把一些變數作設定,歸零、重設某個數值等。至於要怎麼樣運用…就看大家的想法囉。

2010年2月27日 星期六

變數的運用(一)

程式教學到目前…大家應該對寫程式有一個基本的概念了。接下來的部份,應該是著重在一些寫程式的小技巧了。在這個部份,我自己用到很多的變數,利用變數記錄目前的狀況、倉位、進出場價位等。許多的地方都需要用到變數。

一開始先來講進出場價位,這代表什麼?這代表著也許某個條件已經成立了,所以我們利用變數把預計的進出場價位先存下來,接下來我們會等待著第二個條件成立,也許第二個條件成立後會進場等。

以一個簡單的例子來說明狀況的儲存,假設我們在均線交叉的時候,記錄下當交叉當根 k 線的高低點,接下來,我們就以這個高低點來進出場。

這樣的程式該怎麼寫呢?首先是均線交叉的寫法,這應該要沒問題了。如果你對這個均線的交叉還有問題的話,那你應該要重頭開始看這系列的文章。

接下來在交叉的時候,我們利用一個變數把高、低點存下來。再來就是等待突破進場了。

整個說起來應該不難才對,所以就直接來寫吧:


vars: longLine(0), shortLine(0);

Value1 = average(close, 10);
Value2 = average(close, 30);

if Value1 cross over Value2 then begin
longLine = high;
shortLine = 0;
end;

if Value1 cross under Value2 then begin
shortLine = low;
longLine = 0;
end;

if longLine <> 0 then
buy next bar at longLine stop;
if shortLine <> 0 then
sell next bar at shortLine stop;



在這個程式可以看到我宣告了二個變數分別是 longLine 和 shortLine,這二個變數分別記錄著多單進場的價位和空單進場的價位。

再下來是二條均線的運算式。

然後是當均線有交叉動作發生時,需要作的動作。在這邊可以看到不再是一交叉就直接進場了,而只是在有交叉動作發生時,記錄下當根 k 線的高或低點。

比較需要注意的是,因為變數一設定值進去後,如果沒再去變動它,那麼那個值就會一直存在,所以什麼時候需要把變數作歸零的動作,是很值得注意的一件事情。

如果在這邊我沒有把另一邊的進場點作歸零的話,那麼在下面的進場語法就會產生不可預期的狀況囉。

沒把變數歸零的狀況:


在這邊所謂的歸零,是指在進場條件你必需排除掉的數值,可以看到我在進場條件的寫法是排除掉 longLine 或 shortLine = 0 的情況。

那就練習一下吧…來寫個 MACD 交叉後以交叉時的高低點作為進場點吧。

2010年2月23日 星期二

函數講解 - TrueRange

接下來提到的是 TrueRange,這個函數實在滿簡單的…因為打開它來看只有一行程式碼。

TrueRange = TrueHigh - TrueLow;


所謂的 TrueRange 翻譯為真實區間。他是利用目前的高低點和前一根 k 線的收盤價來計算。所以又可以看到二個新函數了, TrueHigh 和 TrueLow。

這邊以 TrueHigh 來說明:

If Close[1] > High Then
TrueHigh = Close[1]
Else
TrueHigh = High;



也是很簡單的一個判斷,如果前一根的收盤價比目前的高點高,那 TrueHigh 就是以前一根收盤價為主。如果目前的高點比前一根收盤高,那 TrueHigh 就是目前的高點。

再由 TrueHigh 和 TrueLow 二個值相減,就可以得到 TrueRange 了。

整個從 ADX 函數追程式碼追到這邊,算是一個完結了。這樣整個過程其實是有點無趣的…不過他卻很有意義。因為如果你覺得某個函數很好用…但是在其它平台上面卻沒有提供…你就必需這樣一個函數一個函數去作轉換。

函數講解應該會到這邊結束,我希望大家能多去看看其它的函數…照樣子去追幾個比較常見的函數內容。並去了解他的程式寫法。會對寫程式有一些幫助的。

2010年2月22日 星期一

函數講解 - DMI (DMIPlus)

在上一篇文章內提到了 ADX 這個函數,而 ADX 又使用到了 DMI 這個函數…所以這邊主要就是來講一下 DMI 這個函數的內容囉。其實打開 DMI 函數的程式碼你會發現其內容並不複雜…因為主要的計算是放在 DMIPlus 和 DMIMinus 這兩個函數裡面…這邊會順便用 DMIPlus 來說明一下。

首先是 DMI 的程式碼:

Inputs: Length(NumericSimple);
Variables: DMIP(0), DMIM(0);

DMIP = DMIPlus(Length);
DMIM = DMIMinus(Length);

If DMIP + DMIM = 0 Then
DMI = 0
Else
DMI = 100 * AbsValue(DMIP - DMIM) / (DMIP + DMIM);



同樣的在一開始用了 input 和 vars 宣告一些變數,input 的部份還是週期,而二個變數 DMIP 和 DMIM 則呼叫了另外二個函數來計算得到數值。

最後的 If 判斷,則是簡單的計算囉。所以這邊就跳過啦。直接打開 DMIPlus 來講解了。


Inputs: Length(NumericSimple) ;
Variables: Counter(0), TRange(0), MyRange(Length), PlusDM14(0), PlusDM(0), MinusDM(0);

If CurrentBar = 1 Then Begin
MyRange = Length;
DMIPlus = 0;
PlusDM14 = 0;
TRange = 0;
For Counter = 0 To MyRange - 1 Begin
If High[Counter] - High[Counter+1] < 0 Then
PlusDM = 0
Else
PlusDM = High[Counter] - High[Counter+1];
If Low[Counter+1] - Low[Counter] < 0 Then
MinusDM = 0
Else
MinusDM = Low[Counter+1] - Low[Counter];
If MinusDM >= PlusDM Then
PlusDM = 0;
{MinusDM not set to 0 because it is not used}
TRange = TRange + TrueRange[Counter];
PlusDM14 = PlusDM14 + PlusDM;
End;
If TRange <> 0 Then
DMIPlus = 100 * PlusDM14 / TRange
Else
DMIPlus = 0 ;
End
Else
If CurrentBar > 1 Then Begin
If High[0] - High[1] < 0 Then
PlusDM = 0
Else
PlusDM = High[0] - High[1];
If Low [1] - Low [0] < 0 Then
MinusDM = 0
Else
MinusDM = Low[1] - Low[0];
If MinusDM >= PlusDM Then
PlusDM = 0;
{MinusDM not set to 0 because it is not used}
If MyRange > 0 Then Begin
TRange = TRange[1] - (TRange[1] / MyRange) + TrueRange;
PlusDM14 = PlusDM14[1] - (PlusDM14[1] / MyRange) + PlusDM;
End;
If TRange <> 0 Then
DMIPlus = 100 * PlusDM14 / TRange
Else
DMIPlus = 0 ;
End ;


很長的一段程式碼…不過其實慢慢拆解起來的話…也沒什麼難懂的地方才對。

首先的 If 判斷在之前也遇到過了,主要是判斷目前的 K 線是不是圖上的第一根 k 線,如果是第一根 k 線的話就是執行那個部份的運算,不是第一根 k 線就是執行下面的 else 部份運算。

我很強烈的建議大家在寫程式的時候好好的排一下版,因為版面排的好,以後再修改程式的時候會少花很多的時間。在 blog 上貼出來的程式碼會整個縮排縮到最左邊…所以還是打開 PowerEditor 來對照程式會比較容易了解。

以一張圖來說明…首先我會先把這個程式拆成二個部份來看:



首先就是第一個大段的 If 和後面的 Else 先拆開…再接著看第一段 If 的內容。

接下來這第一個大段的 If 先執行了一些變數歸零的動作後,進到了一個 For 迴圈作運算,接下來又分為兩個 If .. Else

If High[Counter] - High[Counter+1] < 0 Then
PlusDM = 0
Else
PlusDM = High[Counter] - High[Counter+1];
If Low[Counter+1] - Low[Counter] < 0 Then
MinusDM = 0
Else
MinusDM = Low[Counter+1] - Low[Counter];

這邊可以看到他判斷了如果 High[0] - High[1] < 0 的話,PlusDM 就設為 0;那如果 High[0] - High[1] >= 0 的話,PlusDM 就會等於 High[0] - High[1]。

接著算完了 PlusDM 和 MinusDM 後,在比較這二個值。

接下來又看到了一個新函數了,就是 TrueRange,這邊也是先跳過,我們下一篇再來看這個函數。只要先知道他計算了一個值出來就行了。

接著就是運算 DMIPlus 的過程了。而另一個大區塊就是當 CurrentBar 不等於 1 的時候的運算囉。


我想整個拆解的過程並不太需要了解他背後運算的意義到底何在…因為那是一大堆數學公式,你並不需要知道為什麼 High[0] - High[1] < 0 的時候 PlusDM 會等於 0。主要我希望大家看的是程式的寫法,為什麼要這樣子寫、還有各種 If、For 的運算等等。

2010年2月21日 星期日

函數講解 - ADX

接下來的幾篇文章會是函數的程式碼講解…看懂了別人的程式碼…對自己寫程式的功力也會有進步的。所以這篇先來講解 ADX 函數的程式碼。一開始就先看看 ADX 這個函數吧。


Inputs: Length(NumericSimple);
Variables: Counter(0), CummDMI(0), Return(0);

Return = 0;

If CurrentBar >= 1 AND Length > 0 Then Begin
If CurrentBar < Length Then begin
CummDMI = 0;
for Counter = 0 To CurrentBar - 1 Begin
CummDMI = CummDMI + DMI(Length)[Counter];
End;
Return = CummDMI / CurrentBar;
End
Else
Return = (ADX[1] * (Length - 1) + DMI(Length)) / Length;
End;

ADX = Return;


這個函數一開始是變數宣告。有 input 和 vars,input 代表要傳遞進去的參數…這邊是一個 Length 代表著要計算的 ADX 週期。

接下來程式把 Return 這個變數歸零。

接著就是一個 If 的判斷,在這邊用到了個 CurrentBar >= 1 代表著目前的 K 線是大於或等於第一根 K 線,假如你開出了 500 根 K 線,那第一根 K 線的 CurrentBar 就會等於 1。這邊是一個計算上的錯誤預防…避免沒有 K 線資料程式還進到運算式裡面。

接下來是另一個 If 判斷,這邊寫下了 CurrentBar < Length ,假如目前的 Length 是使用 9 的話,那前 9 根 K 線就會進到這個判斷式裡面。

這邊我利用均線的方式說明一下…如果你今天要計算的是 20 日線均的話,那表示你必需最少需要有 20 根 K 線的資料才能計算,也就是說如果 CurrentBar < 20 的話…你必需要有另外的計算方式,或是直接跳過這 20 根 K 線,計算出來的值才會正確。

所以這邊是表示如果 CurrentBar < Length ,也就是說目前的 K 線是在你要計算的週期之內的話…就用下面的方式計算。

而這邊的計算方式是先把 CummDMI 歸零後,進到一個 For 的迴圈裡面。

在這個 For 迴圈裡,用了一個 Counter,Counter 從 0 一直到 CurrentBar - 1,假如目前的 CurrentBar 是 5 的話…那 Counter 就會是從 0 到 4,並計算 CummDMI 這個值。

這邊就用到了 CummDMI = CummDMI + DMI(Length)[Counter]; 大家應該還記得盒子裡的東西和盒子的名字這個例子。

不過這邊又用到另一個函數,也就是 DMI,先暫時把它放到一邊,下一篇文章我們再來看 DMI 這個函數在作什麼。

接下來回到如果 CurrentBar 是 5 的話,那個 For 迴圈的計算,就會是 CummDMI = CummDMI + DMI(Length)[0] 一直到 CummDMI = CummDMI + DMI(Length)[4]。在 For 迴圈計算完之後,有個 Return = CummDMI / CurrentBar;

這邊就算計算完成後。而最後的 Return 值就會回傳到你呼叫這個 ADX 函數的地方了。

如果 CurrentBar >= Length 的話…就是另外的計算方式。也就是:

Return = (ADX[1] * (Length - 1) + DMI(Length)) / Length;

這個部份。可以看出來他相對比較簡單一點…沒有用到 For 迴圈了。這邊是直接把上一根的 ADX 值拿出來運用。有一點遞迴的想法在裡面…比較常見的遞迴是費波南希係數,大概的想法是這樣:

A = 1
B = 1
C = A + B

也就是除了第一個和第二個數之外,其餘的數都是前二個數值相加,所以可以得到 1, 1, 2, 3, 5, 8, ... 這樣的數列。

而這邊則是用到了上一根的 ADX 數值,再去計算出目前的 DMI 數值,兩個相加再去除以 Length 來得到目前的 ADX。

最後就是 ADX = Return ,把計算得到的 Return 值回傳到 ADX 去囉。

下一篇就來說說 DMI 吧。

2010年2月20日 星期六

指標的運用 - MACD 交叉程式

在寫完了均線的交叉程式後…我想 MACD 就變的很簡單了…只要知道 MACD 的運算方式…再把均線交叉的兩條線換成是 MACD 線和 MACD 均線即可。在上一篇文章內已經提到了 MACD 的運算方式了…所以這邊就直接把進出場程式寫出來吧。


Value1 = MACD(close, 12, 26);
Value2 = XAverage(MACD(close, 12, 26), 9);

if Value1 cross over Value2 then begin
buy next bar at market;
end;
if Value1 cross under Value2 then begin
sell next bar at market;
end;


績效依舊不太好…所以依舊只能算是個例題。

指標的運用講解到這邊…我猜想大家應該可以簡單的了解到原理了…其它的指標方式都可以這樣子使用。如果不是內建指標的話…那只要在網路上找到計算的方式…也可以直接的用進來。

比如說 TradeStation 內沒提供的 KDJ 指標,只要找到計算方式(可以 Google 一下),就可以找到 KDJ 的計算是這樣:

KDJ的计算
        今日收盘价-N日内最低价
今(N)日RSV=(—————————————)× 100 ;
       N日内最高价-N日内最低价

今(N)日K值=2/3昨日K值+1/3今(N)日RSV ;

今(N)日D值=2/3昨日D值+1/3今(N)日K值 ;

今(N)日J值=3今(N)日D值-2今(N)日K值 。

K、D初始值取50。

知道了公式後…其實要寫成指標就簡單了:

Input: N(13), M1(7), M2(3);
Vars:KDJRSV(0), KDJK(0), KDJD(0), KDJJ(0);

If CurrentBar = 1 Then begin

KDJRSV = 0;
KDJK = 50;
KDJD = 50;
KDJJ = 0;
end
Else begin
KDJRSV = (Close - Lowest(Low, 9)) / iff((Highest(High, 9) - Lowest(Low, 9)) = 0, 1, (Highest(High, 9) - Lowest(Low, 9))) * 100;

KDJK = KDJK[1] * 0.66 + KDJRSV * 0.34;
KDJD = KDJD[1] * 0.66 + KDJK * 0.34;
KDJJ = (3 * KDJK) - (2 * KDJD);
End;

Plot1(KDJK, "K", Red, 2);
Plot2(KDJD, "D", Green, 2);
Plot3(KDJJ, "J", Blue, 1);


或是不要寫成指標直接運用在策略裡面…也應該不會是問題才對囉。

有興趣的就用 KDJ 寫個進出場策略吧。接下來的文章會轉到一些內建函數的程式碼講解。多看一下內建程式碼其實對一開始不會寫程式的人會有很大的幫助的。

2010年2月17日 星期三

指標的運用 - 均線交叉程式

相信這個程式只要知道均線的運算方式…要寫出來應該不是問題才對…首先就是 20 日均線和 60 日均線的計算方式:Average(close, 20) 和 Average(close, 60)。運算出來後…接下來就是寫進場囉。

這樣的程式可以很簡單的寫成:

if average(close, 20) cross over average(close, 60) then
buy next bar at market;
if average(close, 20) cross under average(close, 60) then
sell next bar at market;


我想應該沒什麼人會看上這隻程式的績效的…雖然在 30 分 K 上執行還可以算獲利…不過在其它週期上就有點慘了…所以當然這還是只能算是個例題而已。


接下來我想談一下指標的運用…我想應該很多人在作進出場判斷的時候會運用到指標…那指標該怎麼寫進策略裡呢?

來以 MACD 為例…首先…你應該要知道怎麼去新增一個指標進入 TradeStation 的 k 線圖上。所以現在你應該可以在 k 線圖上看到 MACD 的指標了。

不管什麼樣的指標…只要是 k 線圖上顯示的出來的…那就表示你可以參考這個指標的程式寫法…並把這個寫法放到你的策略裡面。所以…就讓我們打開指標 MACD 的程式碼吧:



Inputs: FastMA(12), SlowMA(26), MacdMA(9);

Plot1(MACD(Close, FastMA, SlowMA), "MACD");
Plot2(XAverage(MACD(Close, FastMA, SlowMA), MacdMA), "MACDAvg");
Plot3(Plot1 - Plot2, "MADiff", iff(plot3>0, yellow, blue));

{Alert Criteria}
If Plot3 Crosses Over 0 Then
Alert("MACD has generated a bullish alert")
Else
If Plot3 crosses under 0 Then
Alert("MACD has generated a bearish alert");

{MACD Expert Commentary}
#BeginCmtry
Commentary(ExpertMACD(Plot1));
#End;


上面就是 TradeStation 的 MACD 指標程式碼。你必需去解讀這個程式碼的寫作過程…所幸…大部份的指標程式內容都相當的容易。

以 MACD 來說…指標程式比較重要的其實就三行而已…

Plot1(MACD(Close, FastMA, SlowMA), "MACD");
Plot2(XAverage(MACD(Close, FastMA, SlowMA), MacdMA), "MACDAvg");
Plot3(Plot1 - Plot2, "MADiff", iff(plot3>0, yellow, blue));


Plot 是畫線指令…它只能運用在指標內…所以這邊可以看到這三行就是畫出三條線。這三條線分別包含了 MACD 線、MACD均線和 Diff等。

從這裡面…你就可以簡單的找出 MACD 的計算方式了。

所以,假設我們的策略裡面需要 MACD,那就會是 MACD(Close, FastMA, SlowMA),括號裡面的三個變數分別是收盤價和二個參數…如果你策略裡面是固定的參數…那其實就直接打上去就行了。

通常我會這樣用:

MACD(Close, 12, 26);


這樣是比較多人使用的 MACD 參數;如果你需要的是 MACD 均線…那就是在把 MACD 去算平均囉:XAverage(MACD(Close, 12, 26), 9);

這邊用到的 XAverage 是個新函數…你應該去看看他的函數程式碼。

現在,你要在策略裡面使用 MACD 應該沒問題了。接下來我再用 RSI 作一個例子,首先…打開 RSI 的指標程式碼:

Inputs: Price(Close), Length(14), BuyZone(30), SellZone(70), BZColor(Green), SZColor(Magenta);

Plot1(RSI(Price, Length), "RSI");
Plot2(BuyZone, "BuyZone");
Plot3(SellZone, "SellZone");

If Plot1 > SellZone then Begin
Alert("The RSI is in overbought territory");
SetPlotColor(1, SZColor);
End
Else
If Plot1 < BuyZone then Begin
Alert("The RSI is in oversold territory");
SetPlotColor(1, BZColor);
End;

{RSI Expert Commentary }
#BeginCmtry
Commentary(ExpertRSI(Plot1, Plot2, Plot3));
#End;


重要的是什麼呢?沒錯…還是那 Plot 指令:

Plot1(RSI(Price, Length), "RSI");
Plot2(BuyZone, "BuyZone");
Plot3(SellZone, "SellZone");


在這邊可以看到其實 RSI 的運算更簡單了…在 RSI 函數裡面都作完了…所以你只需要這樣:RSI(Close, 9) 就可以計算出 9 日的 RSI 值了。


最後,練習時間又到啦…來寫個 MACD 交叉進場的進出場策略吧。

2010年2月13日 星期六

移動平均線的交叉

上一篇文章最後希望大家能動手計算一下 20 日的移動平均線資料…並給了一個簡單的提示…就是用上 Average 的函數。當然…如果你使用一開始介紹的 Summation 函數並自行去作運算其實也是可以的。

首先先來看看 Average 這個函數的內容:

Inputs: Price(NumericSeries), Length(NumericSimple);
Variables: Sum(0), Counter(0);

Sum = 0;

For counter = 0 To Length - 1 Begin
Sum = Sum + Price[counter];
End;

If Length > 0 Then
Average = Sum / Length
Else
Average = 0;


以上為 TradeStation 在 Average 函數的程式碼。基本上如果對 For 迴圈和 If 判斷都了解的話,這個程式其實沒什麼難度的。首先一開始先把 Sum 這個變數歸零,接著利用一個 For 迴圈來計算出總和,最後再除以個數就得到我們需要的平均價了。

那一開始的 Input 代表什麼呢,我們在呼叫 Average 這個函數的時候會這樣子用:

var = Average(close, 20);

可以看到在 Average 後面我輸入了 (close, 20) 這樣子的程式碼,這代表著我傳了二個參數,分別是收盤價(close)和我所需要計算的週期(20)到 Average 這個函數裡面。

而 Average 就用 Input 來接收這二個參數。

函數的運算過程會如下面的方式:


而最後的回傳方式則會類似 Average 函數程式碼最後的那部份,也就是它把函數的名字直接套用進來,並給他一個數值。

簡單的介紹完了 Average 這個函數後,接著要怎麼計算上一篇文章提到的例題呢,其實很簡單,一點難度都沒有:

var = Average(close, 20);


這樣就搞定了…其它的事情都在 Average 這個函數內完成了。

再來要介紹一下大家常用到的交叉,所謂的交叉又分為黃金交叉和死亡交叉,通常所謂的黃金交叉代表著短均線向上穿越長均線,而死亡交叉代表著短均線向下穿越長均線。

所以這邊要介紹二個指令,分別是:cross over 和 cross under。

其實這個從字面上來解釋就行了…所謂的 cross over 就是往上穿越的意思,而 cross under 就是往下穿越了。

在這兩個指令的前面你必需放上兩個數值…因為必需要有兩個數值的比較才會有所謂的穿越情況產生…所以如果我們簡單以 20均線往上穿越 60均線的話…應該會是這樣子:

Average(close, 20) cross over Average(close, 60);


在穿越的這個比較方式…是以前一根的數值和目前這根 k 線的數值來作比較的…所以如果你要複雜一點的寫法的話…可以寫成下面這樣:

Average(close, 20)[1] < Average(close, 60)[1] And Average(close, 20) > Average(close, 60);


簡單的說就是前一根的 20 均小於 前一根的 60 均,而目前這根的 20均 大於 目前這根的 60 均。

練習時間又到了:請寫出一個 20 日均線和 60 日均線的程式…黃金交叉則買進,死亡交叉則賣出。

2010年2月12日 星期五

簡易的換日判斷(第一個練習程式)

在這邊先介紹一下怎麼簡單的判斷是否換日了?換日可以很簡單的想到日期變的不一樣了,那從 k 線上怎麼判斷呢?我們可以很簡單的抓出 k 線的日期來作是否已經換日的判斷。

換日的判斷如下:

if date <> date[1] then begin
end;


上面的 if 判斷抓出了日期,而 date <> date[1] 代表著目前這根 k 線的日期和上一根 k 線的日期不一樣!

什麼時候會相鄰的兩根 k 線日期會得到不一樣的結果呢?那當然就是今天的第一根 k 線和昨天的最後一根 k 線啦。透過這樣子的判斷我們可以很簡單的得到是否已經換日的條件出來了。

那麼以這樣子的判斷再加上一些條件…就可以很簡單的寫出跳高買、跳低賣囉:


if date <> date[1] and open > close[1] then begin
buy next bar at markte;
end;
if date <> date[1] and open < close[1] then begin
sell next bar at market;
end;


簡單說明一下:
假如目前的 k 線日期不等於上一根 k 線的日期,而且目前的開盤價大於上一根的收盤價,則買進。

是不是有感覺到寫程式有愈來愈簡單的樣子了…基本上只要你能夠把邏輯條件想出來、量化出來…要轉成程式碼其實並不是這麼困難的事。


除了上面的寫法外…再介紹一個更簡單的寫法,因為這樣子的條件並不會因為每日 k 線波動的差異產生不一樣的結果…因為昨天的收盤價是固定的、今天的開盤價也是固定的。所以簡單的寫成這樣:

if opend(0) > closed(1) then begin
buy next bar at market;
end;
if opend(0) < closed(1) then begin
sell next bar at market;
end;


這邊用到了二個新函數,順便介紹一下,分別是 opend(0) 和 closed(1)。

opend(0) 代表著今日的開盤價
closed(1) 代表著昨日的收盤價

簡單的記法 open 代表開盤價,而 d(day) 代表天,所以 opend 就代表著某一天的開盤價,後面接上 (0) 代表就是今日的開盤價,如果用上了 (1) 那就表示是昨天的開盤價囉。

在分線週期內要取得日線的開高低收,就可以分開用上 opend、highd、lowd和 closed 等四個函數。


最後一個跳高買、跳低賣的方式…如果希望是以開盤價觸價就進場,而不是等待第一根 k 線收完呢?要觸價進場…也就是需要用到 stop 單囉…而 stop 單只能在當根判斷的時候就立刻進場…透過這樣的想法繞回來後,你就知道這個進場必需寫在昨天的最後一根 k 線上才能在隔天的開盤立刻進場了。


if time = 1345 then begin
buy next bar at close + 1 stop;
end;
if time = 1345 then begin
sell next bar at close - 1 stop;
end;


這是以 5 分線為例子…5 分線的最後一根 k 線時間為 1345,所以上面的例子判斷是在最後一根 k 線的時候,寫下了進場的條件:下一根買進在目前收盤價 + 1 點,或是賣出在目前收盈價 - 1 點的價位。

下一根其實就是隔天開盤的那根 k 線囉,所以買進在目前收盤價 + 1 點…代表的就是隔天是開高的意思。

不過如果實際的去跑上面的例子…會發現有時候在第一根 k 線又買又賣的…那是因為隔天開盤的第一根 k 線把買進和賣出的點位都碰到了…

所以這只是個例子…通常我會特別避免掉同一根 k 線同時產生二個交易訊號出場。因為這樣在 k 線圖上是沒辦法分的出哪個先、哪個後的。這也會在回測或實際執行上出現一些問題。


下一個練習題:計算出20根k線移動平均線。(hint:移動平均線的計算為 Average 函數)

2010年2月11日 星期四

進出場指令

介紹到這邊…總算是進入程式交易的核心了。那就是進場和出場…基本上進場的指令就是 buy 和 sell,分別是買進和賣出。而出場則是 exitlong 和 exitshort,分別是多單出場和空單出場。下面分別介紹幾種進場和出場的模式。

首先是下一根 k 線進出場,那為什麼需要等到下一根 k 線呢?因為在盤中的時候,k 線是會一直跳動的…所以如果不是等待 k 線收完線就立刻進場,那可能會因為 k 線跳動的情況使得成立的條件又消失了。

所以會有以下的程式碼:

buy next bar at market;
sell next bar at market;

exitlong next bar at market;
exitshort next bar at market;


這樣的程式分別代表:
在下一根 k 線開盤買進。
在下一根 k 線開盤賣出。

在下一根 k 線開盤多單出場。
在下一根 k 線開盤空單出場。

那如果希望能夠用 this bar 的方式呢? TradeStation 2000i 只支援 this bar at close 的方式,也就是進出場在目前這根 k 線的收盤價。

不過其實在交易執行的過程中…程式是沒辦法知道 k 線什麼時候才算收盤的…所以它的判斷方式還是需等待下一根 k 線出場後,它才知道原來上一根 k 線已經收線了。

也就是 next bar at market 其實是和 this bar at close 是一樣的。只是在 k 線圖上面標示的進出場點位會不同而已。這點還請特別注意一下…因為有時候收盤價你是買不到的,以日線程式來說…你程式寫著你要進場在今天的收盤價,可是你必需等待明天開盤後才知道原來今天已經收盤了。所以其實你能進場的價位是在明天的開盤價。

不過程式回測卻是把你進場的點位標示在今天的收盤價,所以這就會產生了回測時候績效是錯誤的情況了。


再來就是,如果我希望是觸點就進出場的話呢?那就必需用到 stop 或是 limit 了。關於 stop 和 limit 的分別…請先參考一下:搞清楚 Stop 和 Limit

這個部份在進出場的話會寫成這樣:

buy next bar at 9000 stop;
sell next bar at 6000 stop;

exitlong next bar at 9000 stop;
exitshort next bar at 6000 stop;

等…分別代表著:
從下一根 k 線開始觸價 9000 點買進。
從下一根 k 線開始觸價 6000 點賣出。

從下一根 k 線開始觸價 9000 點多單出場。
從下一根 k 線開始觸價 6000 點空單出場。

當然你可以把 9000 或 6000 等固定的點位在程式內用一個變數取代它…而這個變數可能會是你計算出來的某個價位。

比較需要注意的是…即使是用觸價就進出場的方式…你還是必需等待下一根 k 線才會開始執行你的命令。假如你開的是 5 分 k 並寫下這樣的程式碼:

if time = 900 then
buy next bar at 6000 stop;


這樣最早的進場會是在 9:00 那根 k 線的下一根。並不會在當根 k 線就產生訊號。


基本上我是不太建議用 this bar 的方式來寫策略,因為會有回測的訊號和即時的訊號不一樣的情況產生。


總算可以有讓大家練習的機會了…請寫一下跳空開高就買進,跳空開低就賣出的程式吧。至於怎麼判斷開高、開低,那就動動頭腦想一下囉。下一篇會把這個練習程式寫出來。

2010年2月10日 星期三

函數的運用

這篇將介紹怎麼運用函數。首先…什麼是函數呢?想像一下你是一個原古時候的人…現在你需要砍一顆樹…然而你手邊什麼樣的工具都沒有,所以也許你會找一塊石頭,並想辦法把它磨成一把斧頭來砍那顆樹。當你成功的把樹砍倒了之後呢?你會順手把這把斧頭丟掉嗎?並不會…你會把斧頭留著等下次還需要砍樹的時候再拿出來用。

所以函數就產生了,那把斧頭就是一個函數。當你需要砍樹的時候你就會把那個函數拿出來用。

你可以建立很多的函數…因為你並不是只需要砍樹而已…你也許還要撈魚、生火、打獵等等。

經過這樣子的說明…應該會對函數有一個基本的了解。而在 TradeStation 裡面提供了很多的基本函數可以讓你運用。打開 PowerEditor 並選擇 File - Open 後進到 Function 內你就可以看到它所提供的函數。

基本數值運算 這篇提到了均價的算法。裡面的範例我寫到了五根 K 線的收盤價均價計算的程式。可是當你需要計算到 100 根 K 線的時候怎麼辦呢?難不成還真的寫了一大串程式碼去計算嗎?我想這當然也是可以,不過也太花時間了點。

所以讓我們來運用一下函數來計算吧:

var = Summation(close, 100) / 100

這樣是不是簡單多了呢。

這邊用到的函數是 Summation,它的程式碼加下:

Inputs: Price(NumericSeries), Length(NumericSimple);
Variables: Counter(0), Sum(0);

Sum = 0;

For Counter = 0 To Length - 1 Begin
Sum = Sum + Price[Counter];
End;

Summation = Sum;

可以看到程式其實是用了個 For 迴圈來累加出你所要的數值和,接著我們只要再把總和除以個數就可以得到均價了。

透過這樣子的函數運用…將可以大大的簡少寫程式所花的時間。

不過如果你今天所需要的功能 TradeStation 內並沒有提供…那該怎麼辦?如果這個功能不是很常用到…那也許你考慮直接在你目前的程式碼實作出來即可;不過如果是很常會運用到的東西…那還是花點時間把這個功能直接寫成函數會減少未來寫其它程式所花的時間。

2010年2月9日 星期二

基本迴圈運用

所謂的迴圈,就是重覆的去執行某一段的程式碼。比較常用到的是 For 迴圈。這邊就基本的介紹一下 For 迴圈的運用。

一個 For 迴圈的程式會像下面這樣:

var = 0;

For Value1 = 1 to 10 Begin
var = var + 1;
End;


上面的程式碼執行後會變怎麼樣子呢?首先一開始看到的是我把 var 設定為 0 ,之後進到了一個 For 的迴圈,在這邊設定了 Value1 = 1 開始,然後一直執行到 Value = 10,也就是執行了 10 次。

所以,當一開始進入到迴圈的時候 var = var + 1; 所以會等於 var = 0 + 1。在這邊也許又會有個問題出現,為什麼第一個 var 不是代表 0 呢?

這邊簡單的說明的話…你宣告了一個 var 的變數後,電腦會在記憶體裡面保留一個空間在儲存 var 的資料,你可以想像一個盒子,這個盒子被你取名叫作 var,盒子裡面可以裝你想裝的東西。

而在一個運算式被系統讀取到了之後,等號的左邊,系統抓到的是叫作 var 的這個盒子出來;而等號的右邊,則是把 var 盒子裡的東西取出來。

也就是:
等號的左邊為盒子的名子
等號的右邊為盒子裡的東西

所以 var = var + 1 代表著我現在要把東西裝進名字叫作 var 的這個盒子,那我要裝的東西是什麼?我要裝的東西是 var 這個盒子裡面目前有的東西再加上 1。

(希望大家可以了解這個很不容易了解的說明…)

回到 For…

所以這個 For 迴圈一直在執行著 var = var + 1 的動作,執行了十次。也就是:
var = 0 + 1; (var 目前裝的東西是0)接下來是
var = 1 + 1; (var 目前裝的東西是1)再來是
var = 2 + 1; (var 目前裝的東西是2)
...

所以最後得到的結果會是 var = 10 這個答案。

For 的運用在一些基本進出場邏輯是不太會用到的…不過卻在很多的函數裡面會出現。當未來你需要拆解函數的時候,還是需要了解這個 For 迴圈的。

以上的介紹希望大家對 For 迴圈有一個基本的了解。下一篇將介紹函數的運用。
Related Posts Plugin for WordPress, Blogger...