(已解決) 為什麼我寫的自訂函數,用以累計每分鐘成交量,在邏輯if time>110000 else裡的行為是錯誤的?答案是:不同時機,呼叫相同的自訂函數,會產生不同的獨立副本。

  •   383 
  • 最後發表   Sadless  2020 八月 18
Sadless 發文於   2020/08/13

我在函數裡面,寫了一個自訂函數,名為 f_Accumulated_Volume_In_Minute,回傳為數值

這是一個基於分K棒,計算當日累計成交量的函數

程式碼如下:

//宣告
SetBarMode(1);

variable:currentbar_flag(0);

//計算當日累計成交量
if currentbar_flag < currentbar //控制此腳本在每根K棒只會被計算一次
then begin
    currentbar_flag = currentbar; 

    if date > date[1]
    then begin 
            f_accumulated_volume_in_minute = volume; //當日第一根分K棒的成交量
    end

    else begin
            f_accumulated_volume_in_minute += volume; //當日第二根分K棒,及之後的成交量
    end;
end;

 

然後,我在指標裡面,寫了一個指標,名為 Test.累計成交量.函數,來測試這個自訂函數f_accumulated_volume_in_minute 

程式碼如下:

variable:buf_1(0);
variable:buf_2(0);

//buf_1,使用邏輯if else,來選擇承接 f_accumulated_volume_in_minute //==========
if time > 110000 then
    buf_1 = f_accumulated_volume_in_minute
else 
    buf_1 = f_accumulated_volume_in_minute;

plot1(buf_1,"buf_1");


//buf_2,不使用邏輯if,直接承接 f_accumulated_volume_in_minute     //===========
buf_2 = f_accumulated_volume_in_minute;

plot2(buf_2,"buf_2");

 

buf_1 使用了 if else 來分別承接自訂函數 f_accumulated_volume_in_minute 的值,但是在 if 和 else 裡面都承接了,因此包含了所有的情況,並利用 plot1(buf_1,"buf_1"); 畫出來。

buf_2 則是直接承接了  並利用 plot2(buf_2,"buf_2"); 畫出來。

 

邏輯上,plot1(buf_1,"buf_1");plot2(buf_2,"buf_2"); 應該要出現一樣的圖形,但是卻不同。

但這卻不合理,因此想要請教助教,是不是我在哪裡理解錯誤了?

 

plot1(buf_1,"buf_1"); 如下:

 

plot2(buf_2,"buf_2"); 如下:

 

排序方式: 標準 | 最新
XQ小幫手 發文於   2020/08/13

Sadless大 您好

小幫手用您提供的方法幫您測試了一下,

發現數值會是相同的

附圖如下

如果您有重新編譯過,

 

請先刪除指標圖,再重新加入一次。

如果還是有問題,

1. 想詢問您是在什麼時候測試時,會發生此現象(盤中or盤後)

2. 是否有做其他操作(ex 切換商品....之類的)

3. 有同時疊不同指標?

以上

 

 

Sadless 發文於   2020/08/13

我剛剛已經重新刪除指標,重新編譯後,再加入指標,但是還是有一樣的問題。

我目前使用的平台是

1. 我在盤中與盤後都有測試過,一樣的情形

2. 沒有做其他操作

3. 為求簡化 debug,所以沒有疊不同的指標

那我應該怎麼做,才能讓你們重現問題呢?

以上

Sadless 發文於   2020/08/13

我發現我是使用1分K線的圖,而助教使用的是日K線的圖。

麻煩小幫手,請你使用1分K線的圖來試試看,是否能夠重現此問題。

以上

 

Sadless 發文於   2020/08/14

我更新一下我目前的研究,探討[自訂函數]為什麼在同一個指標腳本裡面裡面不同時機點執行,卻會有不同結果。我猜測是因為[自訂函數]裡面的宣告變數的記憶行為與時間有關,而每一個時機點所呼叫的自訂函數,都會產生一個獨立的副本。

為了驗證這個猜測,我寫了一個測試的指標腳本,和兩個測試的自訂函數,來驗證這個猜想。

 

先講我猜測的結論,再麻煩小幫手幫我確認跟指正。

以下是我的猜測:

 

在指標腳本內,每呼叫一次自訂函數,會產生一個獨立的副本。

不同時機,呼叫相同的自訂函數,會產生不同的獨立副本。

假設有一個指標腳本,裡面呼叫了一個自訂函數三次,時機分別為時機A、時機B、和時機C

那麼,就會產生三個獨立副本,分別為副本A、副本B、和副本C

這三個副本,雖然源自於相同的自訂函數,可是卻是獨立且不互相關聯的。

 

每經過一根K棒,由於指標腳本會重新運算一次,所以這三個獨立副本也會重新運算一次。

不過,副本內宣告的區域變數,會記憶上一次運算的結果。

所以,副本A、副本B、和副本C,裡面的區域變數會各自記憶上一次運算的結果。

 

三個副本雖然擁有有名字相同的變數,但是這些變數卻也是獨立而不相關聯的,因為三個副本是獨立的。

所以,就會造成在指標腳本內在不同時機去呼叫同一個自訂函數,可是卻得到不同的結果。

因為,如果這個函數運算的邏輯,有牽涉到時機點的問題,而指標腳本的邏輯又牽涉到時間的問題,就會導致在不同的時機點產生的自訂函數腳本會回答不同的數值。因為,不同的時間點,就會產生不同的邏輯。

Sadless 發文於   2020/08/14

指標腳本的程式碼如下:

在指標腳本中,我留下了plot1~4,後面分別討論這四個plot代表的意義。出圖的方式,就是把其他的plot註解掉。

variable:buf_1(0);
variable:buf_2(0);
variable:buf_3(0);
variable:buf_4(0);

if time > 110000
then begin
        //時機點A ====================================
        buf_1 = f_session_first_bar_global_number_1;
        buf_2 = f_session_first_bar_global_number_2;
end

else begin
        //時機點B ====================================
        buf_1 = f_session_first_bar_global_number_1;
        buf_2 = f_session_first_bar_global_number_2;
end;

plot1(buf_1,"buf_1");
plot2(buf_2,"buf_2");

//時機點C ========================================
buf_3 = f_session_first_bar_global_number_1;
plot3(buf_3,"buf_3");

buf_4 = f_session_first_bar_global_number_2;
plot4(buf_4,"buf_4");

 

一號自訂函數 f_session_first_bar_global_number_1 的程式碼如下:

setbarmode(1);

if IsSessionFirstBar = true
then begin
        //==紀錄當日第一根分K棒的編號==============================
        //==f_session_first_bar_global_number_1 承接 currentbar===========
        //==f_session_first_bar_global_number_1 在副本內沒有記憶=========
        f_session_first_bar_global_number_1 = currentbar; 
end
else begin
        f_session_first_bar_global_number_1 = 0;
end;

 

二號自訂函數 f_session_first_bar_global_number_2 的程式碼如下:

setbarmode(1);

variable:v_session_first_bar_global_number(0);

if IsSessionFirstBar = true
then begin
        //====紀錄當日第一根分K棒的編號=================================
        //====v_session_first_bar_global_number 承接 currentbar================
        //====v_session_first_bar_global_number 在副本內有記憶================
        v_session_first_bar_global_number = currentbar; 

end;
        //====f_session_first_bar_global_number_2 承接了有記憶的 v_session_first_bar_global_number
        f_session_first_bar_global_number_2 = v_session_first_bar_global_number;

 

Sadless 發文於   2020/08/14

 

首先,先看一下自訂函數f_session_first_bar_global_number_1 和 f_session_first_bar_global_number_2 的差別。

差異就是 f_session_first_bar_global_number_1  是直接承接 currentbar,因此不具備副本內記憶。

而 f_session_first_bar_global_number_2  先由自訂函數內變數 v_session_first_bar_global_number承接 currentbar,使得v_session_first_bar_global_number 有副本內記憶,所以v_session_first_bar_global_number會記住上一次運算的currentbar

因此,當 f_session_first_bar_global_number_1  再承接 v_session_first_bar_global_number後,也取得上一次有記憶的 currentbar,而不是0

根據這個邏輯,在指標腳本裡面,我分別在時機點A、時機點B、和時機點C,分別執行自訂函數 f_session_first_bar_global_number_1   與 f_session_first_bar_global_number_2 。我們可以從 plot1plot2plot3、和plot4了解到,不同的時機點,執行相同的自訂函數,其實每個自訂函數都會產生獨立的副本空間。

時機點A落在if time > 110000 裡面,時機點B落在 else 裡面,而時機點C落在if time > 110000 else的外面。由於if time > 110000 else 的條件包含了全部的條件,所以邏輯上,時機點A 加上時機點B的的結果,應該與時機點C的結果相同。也就是說 plot1 應該要和 plot3 的結果相同,而plot2 應該要和 plot4 的結果相同。

但是實際上卻是不同的。因為雖然是相同的自訂函數,可是不同時機點會產生獨立的副本。而副本裡面的邏輯運算,和時機點if IsSessionFirstBar = true有關聯,所以不同時機點產生的副本,就會產生不同的結果。

 

這使得,雖然在邏輯上,時機點A 加上 時機點B,應該要與時機點C的結果相同,可是卻完全不同。

Sadless 發文於   2020/08/14

Plot1的圖如下:

Plot1 是時機點A 加上 時機點B,而自訂函數裡面沒有記憶前一次找尋currentbar的變數。

所以Plot只有在time=90000的時候,符合了if IsSessionFirstBar = true,而其他的時間都為0

Sadless 發文於   2020/08/14

Plot2的圖如下:

Plot2 是時機點A 加上 時機點B,而自訂函數裡面有記憶前一次找尋currentbar的變數 v_session_first_bar_global_number

所以Plotelse 裡面,time<=110000的區間執行的自訂函數副本,有符合if IsSessionFirstBar = true,而取得了其currentbar,所以f_session_first_bar_global_number_2 有值。

而在time>110000的區間,執行的自訂函數副本,因為其第一根分K棒時間為110100,所以不符合if IsSessionFirstBar = true,而v_session_first_bar_global_number仍預設為0。因此就算有記憶變數v_session_first_bar_global_number,  但f_session_first_bar_global_number_2 的值仍承接自v_session_first_bar_global_number的預設為0

Sadless 發文於   2020/08/14

Plot3的圖如下:

Plot3 是時機點C,而自訂函數裡面沒有記憶前一次找尋currentbar的變數。

所以Plot只有在time=90000的時候,符合了if IsSessionFirstBar = true,而其他的時間都為0

Sadless 發文於   2020/08/14

Plot4的圖如下:

Plot4 是時機點C,建立buf_4 = f_session_first_bar_global_number_2 自訂函數副本,而該自訂函數副本裡面有記憶前一次找尋currentbar的變數 v_session_first_bar_global_number

所以Plot4else 裡面,time=90000的第一根分K棒,有符合if IsSessionFirstBar = true,而取得了其currentbar,所以f_session_first_bar_global_number_2 有值。

而之後的時間,執行的自訂函數副本,雖然其第一根分K棒時間不為90000,所以不符合if IsSessionFirstBar = true,然而v_session_first_bar_global_number記憶著currentbar。因此,f_session_first_bar_global_number_2 的值仍承接自v_session_first_bar_global_number的記憶。

顯示更多回應 發表回覆
Close