股池盤中排行問題

  •   68 
  • 最後發表   WIJU0509  3 天前
WIJU0509 發文於   2026/03/31

想請教各位大神下面有底線部分寫法是否正確

   要做一個在幾個特定時間點找出股池裡跌幅最高的前3名要進場的策略

   但前3名的條件是跌幅不能大於7%以及價格不能小於CDP的追賣點(AL)且是可買賣現沖股票,若有則往後遞延

   目前測試困境是進場的股票是跌幅排名出來未依跌幅數值排列

----------------------------------------------------------------------------

input:mygroup(group,"股池");

var: mygroupsize(0),i(0);

var:intraBarPersist groupratio(0);

var:intraBarPersist symbolratio(0);

array:rankRT[1500,3](0);

mygroupsize=groupSize(mygroup);

var:intraBarPersist flag1(false);

var:intraBarPersist AL(0);

var:intraBarPersist Price(0);

var:intraBarPersist count(0);

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

if GetSymbolInfo("買賣現沖")=false then return;

if date<>date[1] then 

begin

flag1=false;

                count=0;

end;

 

if (currenttime>=090600 and currenttime<091000) or (currenttime>=091100 and currenttime<091500)  and flag1=true then    begin

         flag1=false;

         count=0;

   end;

for i=1 to mygroupsize

begin

symbolratio = (getsymbolField(mygroup[i], "收盤價","1")-getsymbolField(mygroup[i], "參考價","D"))/getsymbolField(mygroup[i], "參考價","D")*100; //計算平均漲跌幅

AL = (GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1]+2*getsymbolField(mygroup[i], "收盤價","D")[1])/4 - GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1]; //計算CDP追賣點

rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));

rankRT[i,2] = symbolratio;

rankRT[i,3] = AL;

print(time,rankRT[i, 1],rankRT[i,2],rankRT[i,3]);

end;

Array_Sort2d(rankRT, 1, mygroupsize, 2, true);

if (currenttime>=090500 and currenttime<090600) or (currenttime>=091000 and currenttime<091100) or (currenttime>=091500 and currenttime<091600) or (currenttime>=100000 and currenttime<100100) and flag1 = false then

begin

flag1=true;

for i=1 to mygroupsize

begin

                               //現價不小於CDP追賣點以及跌幅不超過7%才開始排名

if getsymbolField(mygroup[i], "收盤價","1")>=rankRT[i, 3] and rankRT[i, 2]>-7 then

begin

print(time,text("排名", numtostr(i, 0), "商品: "),

text(numtostr(rankRT[i, 1], 0), ".TW"),rankRT[i, 2],rankRT[i, 3]);

end;

if count<3 then

begin

if symbol = text(numtostr(rankRT[i, 1], 0), ".TW") and GetSymbolInfo("買賣現沖") = true and filledAtBroker<0  then 

begin

setposition(-1);

count+=1;

end;

end;

 

end;

 

end;

 

排序方式: 標準 | 最新
虎科大許教授 發文於   2026/04/01

(1)看起來排序應該沒問題,比較可能會有邏輯錯誤的地方是setposition(-1)。策略部位的設定會影響實際的庫存。另外,若送單之後尚未成交且該商品馬上又洗價,會有無效指令的問題。這裡最好用Position變數來控制。

(2)若組合的商品數量太多,你的程式又每個Tick都重新計算組合裡面每個商品的漲跌幅及CDP,這樣會很耗資源。比較有效率的做法是用Once在第一次洗價時計算組合內所有商品的漲跌幅及CDP。後面就只針對洗價商品計算漲跌幅並重新對陣列進行排序。

WIJU0509 發文於   2026/04/01

教授好,

請教

(1) 請是在進場條件多加position=filled這個條件嗎?

if count<3 then

   begin

if symbol = text(numtostr(rankRT[i, 1], 0), ".TW") and GetSymbolInfo("處置股") = false and filledAtBroker<0  and position=filled then 

   begin

   setposition(-1);

   count+=1;

   end;

print(time,count,position,filled,filledAtBroker);

   end;

(2) 已新增Once在第一次洗價時計算組合內所有商品的CDP,

   但想請問要如何在陣列後面就只針對洗價商品計算漲跌幅並重新對陣列進行排序?

   我的策略邏輯是針對group內的組合商品>AL and 跌幅<7% 的股票 找出跌幅排名前3名且已有庫存 才進場

once(currentTime>=090000)

begin

for i=1 to mygroupsize

begin

                                 //計算CDP-AL

AL = (GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1]+2*getsymbolField(mygroup[i], "收盤價","D")[1])/4 - GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1];

rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));

rankRT[i,3] = AL;

print(time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"CDP追賣點",numtoStr(rankRT[i,3],2));

end;

end;

for i=1 to mygroupsize

   begin

      //計算漲跌幅

symbolratio = (getsymbolField(mygroup[i], "收盤價","1")-getsymbolField(mygroup[i], "參考價","D"))/getsymbolField(mygroup[i], "參考價","D")*100;

rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));

rankRT[i,2] = symbolratio;

print(time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"個股漲跌幅",numtoStr(rankRT[i,2],2));

   end;

虎科大許教授 發文於   2026/04/01

你這個需求,希望count變數扮演的是跨域變數的角色。在XQ系統,是無法使用跨域變數的。若A商品符合下單條件,count變成1,但B商品洗價時,count仍然是0。

WIJU0509 發文於   2026/04/02

請問教授 有其他方法可以解決嗎? 目前我想到較無效率的方法是在以下迴圈裡變數限制只執行3次,但每次找出的3檔都不同...,且如果要找出多檔商品的話,好像也不能用此寫法

for i=1 to mygroupsize

   begin

     //現價不小於CDP追賣點以及跌幅不超過7%才開始排名

      if getsymbolField(mygroup[i], "收盤價","1")>=rankRT[i, 3] and rankRT[i, 2]>-7  and  count<3   then

            begin

               print(time,text("排名", numtostr(i, 0), "商品: "),

               text(numtostr(rankRT[i, 1], 0), ".TW"),rankRT[i, 2],rankRT[i, 3]);

            end;

      if count=1 then syb = i ;

      if count=2 then syb1 = i;

      if count=3 then syb2 = i;

   end;

      if symbol = text(numtostr(rankRT[syb, 1], 0), ".TW")  and filledAtBroker<0 and position=filled then setposition(-1);

if symbol = text(numtostr(rankRT[syb1, 1], 0), ".TW") and filledAtBroker<0 and position=filled then setposition(-1);

if symbol = text(numtostr(rankRT[syb2, 1], 0), ".TW") and filledAtBroker<0 and position=filled then setposition(-1);

 

 

 

 

 

 

附加文件

虎科大許教授 發文於   2026/04/02

你的情況只能透過自動交易中心的安控設定的「策略整體」的「最多持有商品」限制下單商品數。跑迴圈判斷洗價商品是否排名前三名,若是,就下單。若下單超過三檔,系統安控會自動阻擋下單。

WIJU0509 發文於   2026/04/02

了解 謝謝教授~

虎科大許教授 發文於   2026/04/02

在有作空部位的情況下,你用setposition(-1),可能會進行減碼而非建立一張空單。例如你已有兩張空頭部位,若setposition(-1)會回補1張,讓最後的部位變為1張空單。若想加碼放空,應使用setposition(position-1)。

  • 按讚來自於
  • WIJU0509
WIJU0509 發文於   2026/04/02

收到,謝謝教授提醒

此加碼放空的策略我是另外寫成獨立的腳本,沒有跟原始進場的腳本寫一起~

WIJU0509 發文於   2026/04/15

教授好

 

我的腳本完整內容如附件

使用安控設定進場最多3檔商品,但進場的商品不是想要的,3481也未出現在排名上,請教我該如何排錯

截圖圖片

排名與計算漲跌幅部分內容如下:

once(currentTime>=090000) //計算AL

begin

for i=1 to mygroupsize

begin

AL = (GetsymbolField(mygroup[i],"High", "D")[1] + GetsymbolField(mygroup[i],"LOW", "D")[1] + 2*getsymbolField(mygroup[i], "收盤價","D")[1])/4 - GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1];

rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));

rankRT[i,3] = AL;

print(file("D:\print\[date]策略AL計算(0413修改).csv"),time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"CDP追賣點",numtoStr(rankRT[i,3],2));

end;

end;

if mytime<>time then  //計算跌幅

begin

mytime=time;

for i=1 to mygroupsize

begin

symbolratio = (getsymbolField(mygroup[i], "收盤價","1")[1]-getsymbolField(mygroup[i], "參考價","D"))/getsymbolField(mygroup[i], "參考價","D")*100;

rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));

rankRT[i,2] = symbolratio;

print(file("D:\print\[date]策略跌幅(0413修改).csv"),time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"個股漲跌幅",numtoStr(rankRT[i,2],2));

end;

end;

Array_Sort2d(rankRT, 1, mygroupsize, 2, true);

if (currenttime>=090500 and currenttime<090600) {or (currenttime>=091000 and currenttime<091100) or (currenttime>=091500 and currenttime<091600) or (currenttime>=093300 and currenttime<093400))} and flag1 = false then

begin

flag1=true;

for i=1 to mygroupsize

begin

//if i<11 then

if getsymbolField(mygroup[i], "收盤價","1")>=rankRT[i, 3] and rankRT[i, 2]>-7 and rankRT[i, 2]<0 then //現價>AL & 跌幅<7%

begin

print(file("D:\print\[date]策略跌幅排名結果(0413修改).csv"),time,text("排名", numtostr(i, 0), "商品: "),

text(numtostr(rankRT[i, 1], 0), ".TW"),rankRT[i, 2],rankRT[i, 3],count);

 

end;

if symbol = text(numtostr(rankRT[i, 1], 0), ".TW")  and filledAtBroker<0 and position=filled  then setposition(-1);

end;

end;

附加文件

虎科大許教授 發文於   2026/04/15

(1)我猜測你使用1分鐘頻率。若是,則090000開始計算AL,用[1]抓的是昨天收盤的最後一根K棒。這樣的運算邏輯是否是你想要的?

(2)計算跌幅的迴圈不需要再寫入商品代號。

(3)空單加碼應該使用setposition(position-1),而非setposition(-1)。

(4)既然只針對跌幅最大的三檔下單,最後一個迴圈只要跑三圈。

(5)以下的程式沒有驗證,請自行驗證是否符合需求。

if barFreq<>"Min" or Barinterval<>1 then raiseRunTimeError("限用1分鐘");
input:mygroup(group,"股池");
var: mygroupsize(0),i(0);
var:intraBarPersist groupratio(0);
var:intraBarPersist symbolratio(0);
array:rankRT[1500,3](0);
mygroupsize=groupSize(mygroup);
var:intraBarPersist flag1(false);
var: intraBarPersist AL(0);
var:intraBarPersist Price(0);
var:intraBarPersist count(0);
var:intraBarPersist syb(0);
var:intraBarPersist syb1(0);
var:intraBarPersist syb2(0);
var:intraBarPersist mytime(090000);
if getinfo("isrealtime")=0 then return;
if GetSymbolInfo("買賣現沖")=false then return;
if date<>date[1] then 
    begin
        flag1=false;
        count=0;
        mytime=090000;
    end;
if (currenttime>=090600 and currenttime<091000) or (currenttime>=091100 and currenttime<091500)  and flag1=true then
    begin
        flag1=false;
        count = 0;
        syb = 0;
        syb1 = 0;
        syb2 = 0;
    end;
once(currentTime>=090000) //計算SL
    begin
        for i=1 to mygroupsize
            begin
                AL = (GetsymbolField(mygroup[i],"High", "D")[1] + GetsymbolField(mygroup[i],"LOW", "D")[1] + 2*getsymbolField(mygroup[i], "收盤價","D")[1])/4 - GetsymbolField(mygroup[i],"High", "D")[1]+GetsymbolField(mygroup[i],"LOW", "D")[1];
                rankRT[i, 1] = strtonum(leftStr(mygroup[i], 4));
                rankRT[i, 3] = AL;
                print(file("D:\print\[date]王董策略AL計算(0413修改).csv"),time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"CDP追賣點",numtoStr(rankRT[i,3],2));
            end;
    end;
if mytime<>time then  //計算跌幅
    begin
        mytime=time;
        for i=1 to mygroupsize
            begin
                symbolratio = (getsymbolField(mygroup[i], "收盤價","1")[1]-getsymbolField(mygroup[i], "參考價","D"))/getsymbolField(mygroup[i], "參考價","D")*100;
                rankRT[i, 2] = symbolratio;
                print(file("D:\print\[date]王董策略跌幅(0413修改).csv"),time,text(numtostr(rankRT[i, 1], 0), ".TW") ,"個股漲跌幅",numtoStr(rankRT[i,2],2));
            end;
    end;
Array_Sort2d(rankRT, 1, mygroupsize, 2, true);
if (currenttime>=090500 and currenttime<090600) {or (currenttime>=091000 and currenttime<091100) or (currenttime>=091500 and currenttime<091600) or (currenttime>=093300 and currenttime<093400))} and flag1 = false then
    begin
        flag1 = true;
        for i = 1 to 3
            begin
                if symbol = text(numtostr(rankRT[i, 1], 0), ".TW") and
                    getsymbolField(mygroup[i], "收盤價","1")>=rankRT[i, 3] and 
                    rankRT[i, 2]>-7 and 
                    rankRT[i, 2]<0 then //現價>AL & 跌幅<7%
                    begin
                        print(file("D:\print\[date]王董策略跌幅排名結果(0413修改).csv"),time,text("排名", numtostr(i, 0), "商品: "),
                        text(numtostr(rankRT[i, 1], 0), ".TW"),rankRT[i, 2],rankRT[i, 3],count);
                        if filledAtBroker<0 and position=filled  then setposition(position-1);
                    end;
            end;
    end;    

 

發表回覆
Close