1分k的8分鐘均線與17分鐘均線死亡交叉請問

  •   221 
  • 最後發表   阿哲DR5  2025 十月 03
阿哲DR5 發文於   2025/07/25

許老師和大家好!

我有一個做空的進場策略:在開盤後1分k的8分鐘均線死亡交叉17分鐘均線的時候我要進場做空,可是遇到一個問題是開盤17分鐘內發生的話我不知道如何使用XScript印出來。

截圖圖片

以這張圖為例,由於 9:14 的時候就已經觸發了,所以是在17分鐘以內。由於看盤軟體的線是延續昨天的,所以很清楚,想請問如何用XS取得值,謝謝大家!

value1 = getField("close", "1");
value2 = average(value1, 8);
value3 = average(value1, 17);

if value2 cross under value3 then print(date, time, value2, value3);

排序方式: 標準 | 最新
虎科大許教授 發文於   2025/07/25

想請問如何用XS取得值

Ans:取什麼數值?

阿哲DR5 發文於   2025/07/28

老師好

我想要的是上面圈起來的 SMA8 和 SMA17 的值,而且只要當天的第 1 筆就好。

我遇到的問題是要是 17 分鐘內遇到死亡交叉的話,由於是延續昨天的數字,因此看盤軟體可以顯示,但是我程式碼不知道如何寫出來,謝謝!

虎科大許教授 發文於   2025/07/28

由於你並沒有限制均線數值的計算從特定時間開始,因此17分鐘內計算的均線數值自動將昨天收盤前的各個1分鐘收盤價一起加入計算。

阿哲DR5 發文於   2025/07/28

謝謝老師的回答 那想請問老師要如何「限制均線數值的計算從特定時間開始 」呢?

虎科大許教授 發文於   2025/07/28

if barfreq<>"Min" or barinterval<>1 then raiseRunTimeError("限用1分鐘頻率");

if time>=091700 then

   begin

      value1=average(getField("收盤價"),8);

      value2=average(getField("收盤價"),17);

      if value1 cross under value2 then ret=1;

   end;

阿哲DR5 發文於   2025/07/28

老師我想要的是可以去抓取昨天的1分k,然後去算 ma17,也就是我想要抓到9:14分的這一筆資料。再請老師幫幫忙了,謝謝!

虎科大許教授 發文於   2025/07/28

if time=091400 then print(average(GetField("收盤價","1"),17));

阿哲DR5 發文於   2025/07/28

謝謝老師的回覆,不過老師因為我是要把這個策略拿去選擇標的,所以時間不能夠寫死,因為我不會知道未來每一天早上甚麼時候會觸發這個死亡交叉的進場訊號。我是想要每天早上第一筆觸發的時候進場,然後應用到上市櫃的所有個股,再請老師幫幫忙了,謝謝!

虎科大許教授 發文於   2025/07/28

已經被你弄糊塗了。請詳細說明你的需求,到底想要什麼。

阿哲DR5 發文於   2025/07/28

就是每天開盤的第一次ma8死亡交叉ma17的這一個進場訊號,以上圖為例我會抓不到9:14分的這一個進場訊號,會抓到下一個。因為9:14分的時候ma17還沒有完整的17分鐘,因此會用到昨天的1分k資料。想請問老師我要如何用XS取得每一個上市櫃個股每天的第一個進場訊號,不能是寫死time,而是要用每天第一次ma8死亡交叉ma17,因為有這一個進場訊號才有相對應的時間。

虎科大許教授 發文於   2025/07/28

預設的讀取資料筆數,警示腳本是200筆,交易腳本是100筆,9:17之前都可抓到17分鐘的均線數值,而非你所言的,9:14抓不到。以下的寫法就可以在9:17之前出現死亡交叉時警示。

If barfreq<>"Min" or barinterval<>1 then raiseRunTimeError("限用1分鐘");

value1=average(getField("收盤價"),8);

value2=average(getField("收盤價"),17);

if value1 cross under value2 then ret=1;

阿哲DR5 發文於   2025/07/28

再請問老師由於這個樣子寫會印出當日所有的死亡交叉,請問是否可以只印出當天的第一筆呢?謝謝老師

虎科大許教授 發文於   2025/07/28

If barfreq<>"Min" or barinterval<>1 then raiseRunTimeError("限用1分鐘");

var: intrabarpersist hasRet(false);

if isFirstCall("Date") then hasRet=false;

value1=average(getField("收盤價"),8);

value2=average(getField("收盤價"),17);

if hasRet=false and value1 cross under value2 then

   begin

      hasRet=true;

      ret=1;

   end;

阿哲DR5 發文於   2025/07/30

請問老師,由於您給的程式碼是去觸發警示的策略雷達。有沒有辦法是可以取得觸發時候的那一根1分k棒呢(收盤價就可以了)?謝謝老師

虎科大許教授 發文於   2025/07/30

若不勾選逐筆洗價,則會在該1分K收盤時觸發訊號,用close就可抓到收盤價。

阿哲DR5 發文於   2025/07/30

了解謝謝老師。

想再請問老師有沒有辦法取得觸發訊號的這一根 1 分 k 的前面「第五根」(也就是 5 分鐘前)那一個時候的 1 分 K 棒?

因為需求是要有足夠的價差才會進場,因此要取得 5 分鐘前的那一根 K 棒。再請老師幫幫忙了,非常感謝老師!

虎科大許教授 發文於   2025/07/30

用一個變數,例如mybar,在觸發時記錄K棒編號,再往前推5根即可。

mybar=currentBar;

.....

value1=c[currentBar-5];

阿哲DR5 發文於   2025/07/31

請問老師我不太理解 c[currentBar-5] 和上面的 mybar=currentBar 要如何在觸發時紀錄K棒編號?

虎科大許教授 發文於   2025/07/31

currentBar就是目前的K棒編號。

if hasRet=false and value1 cross under value2 then

   begin

      hasRet=true;

      myBar=currentBar;

      ret=1;

   end;

阿哲DR5 發文於   2025/07/31

請問老師 myBar 要如何宣告呢?編譯結果說要用 Vars 的方式,我試過 vars:myBar(0),不對。

虎科大許教授 發文於   2025/07/31

var: intrabarpersist myBar(0)

阿哲DR5 發文於   2025/07/31

老師我的程式碼如下:

var: intraBarPersist myBar(0);

var: intrabarpersist hasRet(false);

value1 = getField("close");
value2 = average(value1, 8);
value3 = average(value1, 17);

if isFirstCall("Date") then hasRet=false;

if hasRet=false and value2 cross under value3 then

   begin

      hasRet=true;

      myBar=currentBar;

//      ret=1;

      print(myBar);

   end;

以今天台積電為例的話:

截圖圖片

K棒的編號應該是會印出 14,對嗎?可是我印出來的結果是 17。

截圖圖片

指定頻率為 1 分鐘,洗價設定皆沒有勾選,isFirstCall("Realtime") 有試過結果也一樣,再請老師幫幫忙了!

 

 

 

 

 

 

虎科大許教授 發文於   2025/07/31

若你只是希望符合觸發條件時,抓前5根的收盤價,則程式可撰寫如下:

setTotalBar(300);
if barfreq<>"Min" or barinterval<>1 then raiseRunTimeError("限用1分鐘頻率");
var: intrabarpersist hasRet(false);
value1 = getField("close");
value2 = average(value1, 8);
value3 = average(value1, 17);
if isFirstCall("Date") then hasRet=false;
if date=currentDate then
    if hasRet=false and value2 cross under value3 then
        begin
            hasRet=true;
            print("觸發時間",numtoStr(datetime,0),"觸發前5分鐘的時間",numtoStr(datetime[5],0),"前5根1分K的收盤價",close[5]);
        end;

阿哲DR5 發文於   2025/08/11

請問老師,綜合以上的東西我的程式碼如下:

settotalBar(300);

var: intrabarpersist hasRet(false);

value1 = round(getField("close", "1"), 2);
value2 = round(average(value1, 8), 2);
value3 = round(average(value1, 17), 2);
value4 = round(average(value1, 68), 2);
value5 = round(high[getBarOffset(date,090000)], 2); // 取得開盤開始到目前的最高價
value6 = highest(round(getfield("open", "D"), 2), 1);
value7 = GetQuote("漲跌幅");

condition1 = average(getField("成交量", "D")[1], 5)>2000;
condition2 = value1 >= 100;
condition3 = value5 > value3 and value3 > value4;

if condition1 and condition2 and condition3 then 
    begin
    if isFirstCall("Date") then hasRet=false;

    if time >= 093000 and time < 133000 then
        begin
        if date=currentDate then
            begin
            if hasRet=false and value2 cross under value3 then

               begin

                  hasRet=true;

                  if value7 > 0 and value7 < 8 then setposition(-1);

               end;
             if hasRet=false and value1 <= value4 then 
                begin hasRet=true;
                      setposition(0); 
                end;
             if hasRet=false and value1 >= value5 then 
                begin hasRet=true;
                      setposition(0); 
                end;
             end;
         end;
    end;     
if time = 132400 then setposition(0);

我是在 1 分 k 的 8 線死亡交叉 17 線的時候進場,然後想要在 1 分 k 跌到 68 線的時候停利(回補),在 1 分 k 漲到「開盤開始到目前的最高價」(一般來說就是漲到開盤價,不過為了要因應漲上去又跌下來的情況,因此才這樣寫。)的時候停損(回補)。
我進場沒有問題,但是我一直沒有出場,可以再請老師幫我看一下程式碼哪裡有問題嗎?非常謝謝老師!

 

 

虎科大許教授 發文於   2025/08/11

(1)high[getBarOffset(date,090000)]並非開盤至今的最高價,而是開盤第一根K的最高價。

(2)你的進場或出場的前提是condition1、condition2、condition3都必須是True。可能是這個原因造成沒有出場。

(3)進場後會讓hasRet=True,而出場的前提上hasRet=false,這樣也會造成無法出場。

阿哲DR5 發文於   2025/08/11

請問老師開盤至今的最高價要怎麼寫?我試了很多方法還是不對

虎科大許教授 發文於   2025/08/11

value1=SimpleHighest[h[1],getBarOffset(date,090000)];

XS小編 發文於   2025/08/13

Hello 阿哲DR5,

 

小編補充,開盤至今的最高價 = 當日的最高價,您可以直接使用 GetField("High", "D") 來取得。

阿哲DR5 發文於   2025/08/14

謝謝老師!
另外想再請問老師「if hasRet=false and value2 cross under value3

請問要如何取得交叉時的點位?

虎科大許教授 發文於   2025/08/14

if hasRet=false and value2 cross under value3 then
    begin
        hasRet=true;
        value100=close;
        if value7 > 0 and value7 < 8 then setposition(-1);
    end;

阿哲DR5 發文於   2025/08/18

請問老師我的程式碼如下:

settotalBar(300);

var: intrabarpersist hasRet(false);

value1 = round(getField("close", "1"), 2);
value2 = round(average(value1, 8), 2);
value3 = round(average(value1, 17), 2);
value4 = q_DailyHigh; 
value5 = highest(round(value4, 2), 1); 
value6 = GetQuote("漲跌幅");

condition1 = average(getField("成交量", "D")[1], 5)>2000;
condition2 = value1 >= 100;
condition3 = value1 <= 500;
condition4 = value4 > value2 and value4 > value3;

if condition1 and condition2 and condition3 and condition4 then 
    begin
    if isFirstCall("Date") then hasRet=false;

    if time >= 093000 and time < 133000 then
        begin
        if date=currentDate then
            begin
            if hasRet=false and value2 cross under value3 then

               begin

                  hasRet=true;

                  value7 = round(average(round(getField("close", "1"), 2), 8), 2);

                                  if value6 > 0 and value6 < 8 then setposition(-1);

               end;

                        if position = -1 and value1 <= value7*0.985 then 
                                 begin hasRet=true;
                     setposition(0); 
                                 end;
                        if position = -1 and value1 >= value5 then 
                                 begin hasRet=true;
                                    setposition(0); 
                                 end;

             end;
         end;
    end;     
if time = 132400 then setposition(0);

可是我一直沒有觸發

if position = -1 and value1 <= value7*0.985 then 
begin hasRet=true;
setposition(0); 
end;

這一個停利。

我是想要在死亡交叉時的 1 分 K 的 MA8 這一個點位往下跌到「點位乘以 0.985」時就停利出場,可是盤中去跑卻沒有觸發。

可以再請老師幫我看程式碼要如何修改嗎?
非常謝謝老師!

 

 

 

 

虎科大許教授 發文於   2025/08/18

(1)使用報價欄位要注意一點,那就是它沒有[1]。

(2)運算時,不需要用Round去除小數點。系統會自己運算。你這樣做只會增加系統的負擔。只有在顯示的時候才需要用到Round。

(3)你原本的value5是多餘的,我把它改到isFirstCall的IF裡面,接收過去5天均量的數值,過去5天均量這個數值並不需要盤中一直計算。

(4)符合四個條件才進來判斷是否進出場時間,這個邏輯有問題。應該把控制時間的IF放外面。

(5)計算死亡交叉時候的value2,應直接將value2賦予value7,不需要重新計算8期均線數值。你的停利沒有觸發,是因為value7的緣故。value7在死亡交叉之後接收value2的數值,但下一個Tick它又恢復成0,而value1不可能小於等於0。這裡不應該用value7,而應自行用intrabarpersist宣告變數。

(6)不應該用四個condition控制出場。若商品價格從499漲到500以上,難道就不出場?

(7)想確認交易的日期是今天,不需要盤中都用date=currentdate判斷,這樣很沒效率,可在程式上面加一行程式碼,排除歷史K棒(回測時需要拿掉,不然不會有回測結果):

if getinfo("IsRealTime")=0 then return;

(8)你仔細閱讀我寫的程式,然後對照你原本的程式碼,學習如何有效率地寫程式。

settotalBar(300);
var: intrabarpersist hasRet(false);
var: intrabarpersist RetValue(0);
if getinfo("IsRealTime")=0 then return;
if isFirstCall("Date") then 
    begin
        hasRet=false;
        value5=average(getField("成交量", "D")[1], 5);
    end;
value1 = getField("close", "1");
value2 = average(value1, 8);
value3 = average(value1, 17);
value4 = q_DailyHigh; 
value6 = GetQuote("漲跌幅");
condition1 = value5 > 2000;
condition2 = value1 >= 100;
condition3 = value1 <= 500;
condition4 = value4 > value2 and value4 > value3;
if time >= 093000 and time < 132400 then
    begin
        if condition1 and condition2 and condition3 and condition4 then 
            begin
                if hasRet=false and value2 cross under value3 then
                    begin
                        hasRet = true;
                        RetValue = value2;
                        if value6 > 0 and value6 < 8 then setposition(-1);
                    end;
            end;
        if position = -1 then 
            if value1 <= RetValue * 0.985 or value1 >= value4 then 
                begin 
                    hasRet=true;
                    setposition(0); 
                end;
    end
else if position < 0 and time >= 132400 then setposition(0);

  • 按讚來自於
  • johnlintw
阿哲DR5 發文於   2025/08/22

謝謝老師!我修改完程式碼可以正常運作了

想再請問老師由於目前的設計在盤中只會一個標的「進場一次、出場一次」就結束了,但是實測下來這樣子績效不好。

請問要如何修改成同一檔標的可以重複觸發呢?

我試過取消進場限制的方法是行不通的,再請老師幫幫忙了,謝謝!

虎科大許教授 發文於   2025/08/22

settotalBar(300);
var: intrabarpersist RetValue(0);
if getinfo("IsRealTime")=0 then return;
if isFirstCall("Date") then 
    begin
        value5=average(getField("成交量", "D")[1], 5);
    end;
value1 = getField("close", "1");
value2 = average(value1, 8);
value3 = average(value1, 17);
value4 = q_DailyHigh; 
value6 = GetQuote("漲跌幅");
condition1 = value5 > 2000;
condition2 = value1 >= 100;
condition3 = value1 <= 500;
condition4 = value4 > value2 and value4 > value3;
if time >= 093000 and time < 132400 then
    begin
        if condition1 and condition2 and condition3 and condition4 then 
            begin
                if position=0 and value2 cross under value3 then
                    begin
                        RetValue = value2;
                        if value6 > 0 and value6 < 8 then setposition(-1);
                    end;
            end;
        if position = -1 then 
            if value1 <= RetValue * 0.985 or value1 >= value4 then 
                begin 
                    setposition(0); 
                end;
    end
else if position < 0 and time >= 132400 then setposition(0);

阿哲DR5 發文於   2025/08/28

謝謝老師的回答!

另外想再請問老師我要將這個策略反過來,死亡交叉時變成黃金交叉,停利變成上漲 5 %,停損變成下跌 2 %。

我直接改的結果會變成只進場一次,沒有多次觸發。

請問老師是出現甚麼問題?謝謝老師

settotalBar(300);
var: intrabarpersist RetValue(0);
if getinfo("IsRealTime")=0 then return;
if isFirstCall("Date") then 
    begin
        value5=average(getField("成交量", "D")[1], 5);
    end;
value1 = getField("close", "1");
value2 = average(value1, 8);
value3 = average(value1, 17);
condition1 = value5 > 2000;
condition2 = value1 >= 100;
condition3 = value1 <= 500;
if time >= 093000 and time < 132400 then
    begin
        if condition1 and condition2 and condition3 then 
            begin
                if position=0 and value2 cross above value3 then
                    begin
                        RetValue = value2;
                        setposition(1);
                    end;
            end;
        if position = 1 then 
            if value1 <= RetValue * 0.98 or value1 >= RetValue * 1.05 then 
                begin 
                    setposition(0); 
                end;
    end
else if position > 0 and time >= 132400 then setposition(0);

 

 

 

 

 

 

虎科大許教授 發文於   2025/08/28

程式這樣寫,平倉之後會再次進場,只要時間在執行期間之內、價格在100至500之間,且再次均線黃金交叉。

阿哲DR5 發文於   2025/08/29

可是老師我只有觸發一次而已,請問是自動交易中心要設定甚麼東西嗎?

虎科大許教授 發文於   2025/08/29

自動交易中心不需要設定。看看安控設定是否設定只交易一次。若沒有,請提供只觸發一次的細節。

阿哲DR5 發文於   2025/08/29

老師我附上截圖如下,再請老師幫幫忙了,謝謝!

 

 

 

 

 

 

虎科大許教授 發文於   2025/08/29

請舉反證,說明應該交易一次以上,卻只交易一次的例子。

阿哲DR5 發文於   2025/09/01

截圖圖片

老師比方說我上面的那一張圖他的進場明細是這樣子,那目前的程式碼是只會進場與出場一次而已。

那按照上面的 K 線圖在 10 點多的時候要再進場一次這樣子。再請老師幫幫忙了,非常謝謝老師!

 

 

虎科大許教授 發文於   2025/09/01

進場的條件是condition1、condition2、condition3、position=0以及均線黃金交叉。從K線圖看來,均線有黃金交叉。請先確認condition1、condition2、condition3、position=0這四個條件是否為True。若確認為True,則只剩下一種可能,那就是補K。由於你使用1分鐘頻率,在1分K裡面,可能都沒有交易發生,這時,系統會進行補K。系統進行補K的K棒剛好黃金交叉,由於補K時不會執行交易指令,造成黃金交叉時沒有進場。下一根K可以下單時,卻不是黃金交叉。

阿哲DR5 發文於   2025/09/01

老師我確定是補K的問題,想請問老師那我要如何修正這個問題呢?

虎科大許教授 發文於   2025/09/01

settotalBar(300);
var: intrabarpersist RetValue(0);
var: intraBarPersist hasCrossOver(false);
if getinfo("IsRealTime")=0 then return;
if isFirstCall("Date") then 
    begin
        value5=average(getField("成交量", "D")[1], 5);
        hasCrossOver=false;
    end;
value1 = getField("close", "1");
value2 = average(value1, 8);
value3 = average(value1, 17);
condition1 = value5 > 2000;
condition2 = value1 >= 100;
condition3 = value1 <= 500;
if time >= 093000 and time < 132400 then
    begin
        if condition1 and condition2 and condition3 then 
            if position=0 and (value2 cross above value3 or hasCrossOver=true) then
                begin                        
                    setposition(1);
                    RetValue = value2;
                    hasCrossOver=true;
                end;
        if position = 1 then 
            if value1 <= RetValue * 0.98 or value1 >= RetValue * 1.05 then setposition(0); 
    end
else if position > 0 and time >= 132400 then setposition(0);

阿哲DR5 發文於   2025/09/02

老師我用這個程式碼還是不行,會出現跟上面一樣的情況。

請問關於補K的部分要如何 debug???

有辦法 print 出來嗎?還是要用其他的辦法?

虎科大許教授 發文於   2025/09/02

我測試了,程式是OK的。8/29進場兩次。

阿哲DR5 發文於   2025/09/23

截圖圖片

可是老師以回測結果來說第二次進場應該會是在 10:47 而不是報表的 10:28 對吧!?

 

 

虎科大許教授 發文於   2025/09/23

建議你在程式最後一行加上下列程式碼以驗證這102800是否有進場訊號:

print(date, time, condition1, condition2, condition3, value2 cross above value3, hasCrossOver);

按照你程式的邏輯,第一次進場之後,會讓hasCrossOver=true,代表第二次進場只需要position=0(第一次進場的部位已出場)及condtion1、condition2、condition3都是true,就會再進場,並不需要均線黃金交叉。

阿哲DR5 發文於   2025/10/03

想請問老師 intrabarpersist 的宣告,數值型和布林型的差別在哪裡呢?
在這裡 hasCrossOver 是布林型態的。

虎科大許教授 發文於   2025/10/03

(1)數值變數與布林變數的差異在於數值變數只能接收數值,而布林變數只能接收True或False。加intrabarpersist宣告只是希望變數能保留上一次洗價的數值。

(2)你這篇貼文已經太長了。若與原本貼文主題不同時,請改發新的帖子。

發表回覆
Close