回檔再進場回測總是沒執行

  •   82 
  • 最後發表   XQYi  2025 八月 12
XQYi 發文於   2025/08/11

最多進場2次,為何當沖獲利後,以下
第二次(再進場)回測總是沒執行到?
// B. 第二次(再進場)邏輯 (僅在狀態為 2:等待再進場 時觸發)

    if StrategyState = 2 then begin

        time_passed = TimeDiff(CurrentTime, LastProfitExitTime, "M") >= ReentryDelayMinutes;

        price_pulled_back = Close <= LastProfitExitPrice * (1 - ReentryPullbackPercent/100);

                if time_passed and price_pulled_back then begin

            SetPosition(1, Market, label:="二次進場-獲利後回檔");

            Alert("觸發二次進場條件,送出買單。");

        end;

    end;

// 腳本名稱:Two_Stage_Entry_Strategy_Final
// 說明:此版本採用「狀態機」邏輯,徹底解決再進場條件判斷錯誤的問題。

//----------------------------------------------------------------------
// 輸入參數區塊
//----------------------------------------------------------------------
Input:
    // === 首次進場參數 ===
    BollingerLength(10, "布林中軌天期"),
    TowerLength(3, "寶塔線天期"),

    // === 再次進場參數 ===
    ProfitTargetForReentry(2.5, "觸發再進場的獲利率(%)"),
    ReentryDelayMinutes(30, "再進場等待時間(分鐘)"),
    ReentryPullbackPercent(2, "再進場價格回檔(%)"),

    // === 風控出場參數 ===
    StopLossPercent(30, "最終停損率(%)");

//----------------------------------------------------------------------
// 變數宣告區塊
//----------------------------------------------------------------------
Var: 
    // === 狀態變數 (使用IntrabarPersist確保當日K棒內資料能持續保存) ===
    // StrategyState 策略狀態:0=待命中, 1=持倉中, 2=等待再進場, 3=當日已結束
    IntrabarPersist StrategyState(0),
    IntrabarPersist MyCostPrice(0),
    IntrabarPersist LastProfitExitTime(0),
    IntrabarPersist LastProfitExitPrice(0),

    // === 指標與條件變數 ===
    MiddleBand_D(0),
    Condition_DailyRedK(False),
    Condition_BollingerRedK(False),
    Condition_PagodaRedK(False),
    time_passed(False),
    price_pulled_back(False);

//----------------------------------------------------------------------
// 每日初始化區塊:每天開盤時,重置所有狀態變數
//----------------------------------------------------------------------
if Date <> Date[1] then begin
    StrategyState = 0; // 每日重置為「待命中」狀態
    MyCostPrice = 0;
    LastProfitExitTime = 0;
    LastProfitExitPrice = 0;
end;

//----------------------------------------------------------------------
// 資料讀取與指標計算
//----------------------------------------------------------------------
SetBarBack(maxlist(BollingerLength, TowerLength), "D");

MiddleBand_D = Average(GetField("Close", "D"), BollingerLength);
Condition_DailyRedK = GetField("Close", "D") > GetField("Open", "D");
Condition_BollingerRedK = GetField("Close", "D") > MiddleBand_D;
Condition_PagodaRedK = GetField("Close", "D") > Highest(GetField("High", "D"), TowerLength)[1];

//----------------------------------------------------------------------
// 交易邏輯主體
//----------------------------------------------------------------------

// 1. 進場邏輯 (只在空手時判斷)
if Position = 0 then begin

    // A. 首次進場邏輯 (僅在狀態為 0:待命中 時觸發)
    if StrategyState = 0 and Condition_DailyRedK and Condition_BollingerRedK and Condition_PagodaRedK then begin
        SetPosition(1, Market, label:="首次進場-三紅K條件");
        Alert("觸發首次進場條件,送出買單。");
    end;

    // B. 第二次(再進場)邏輯 (僅在狀態為 2:等待再進場 時觸發)
    if StrategyState = 2 then begin
        time_passed = TimeDiff(CurrentTime, LastProfitExitTime, "M") >= ReentryDelayMinutes;
        price_pulled_back = Close <= LastProfitExitPrice * (1 - ReentryPullbackPercent/100);

        if time_passed and price_pulled_back then begin
            SetPosition(1, Market, label:="二次進場-獲利後回檔");
            Alert("觸發二次進場條件,送出買單。");
        end;
    end;
end;

// 2. 部位狀態更新 (根據成交回報更新策略狀態)
if Filled > Filled[1] then begin // 當買單成交時
    MyCostPrice = FilledAvgPrice;
    StrategyState = 1; // 無論是首次還是再次進場,成交後狀態都變為「持倉中」
end;

// 3. 出場邏輯 (只在持倉中,且狀態為 1 時判斷)
if Position > 0 and Filled > 0 and MyCostPrice > 0 and StrategyState = 1 then begin

    // A. 獲利出場 (觸發二次進場的條件)
    if Close >= MyCostPrice * (1 + ProfitTargetForReentry/100) then begin
        Alert(Text("達成", NumToStr(ProfitTargetForReentry, 1), "%獲利目標,執行平倉。"));
        LastProfitExitTime = CurrentTime;   // 記錄出場時間與價格
        LastProfitExitPrice = Close;        
        StrategyState = 2;                  // 將狀態切換為「等待再進場」
        SetPosition(0, Market, label:="獲利平倉(觸發再進場)");
    end

    // B. 最終停損出場
    else if Close <= MyCostPrice * (1 - StopLossPercent/100) then begin
        Alert(Text("觸及", NumToStr(StopLossPercent, 1), "%最終停損,執行平倉。"));
        StrategyState = 3;                  // 停損後,將狀態切換為「當日已結束」
        SetPosition(0, Market, label:="最終停損");
    end;
end;

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

第二次進場的條件需要這三個條件都符合:

StrategyState = 2 and time_passed and price_pulled_back

你可以用Print指令Print這三個條件,並針對該第二次進場卻沒有進場的K棒比對這三個條件,看看哪個條件為false,就可慢慢找出問題在哪裡。

XQYi 發文於   2025/08/11

以4931為例,都是False ,但StrategyState 是有切換的

Time 90000.000000 StrategyState 0.000000 time_passed FALSE price_pulled_back FALSE 

Time 90100.000000 StrategyState 1.000000 time_passed FALSE price_pulled_back FALSE 

......同上

Time 123100.000000 StrategyState 2.000000 time_passed FALSE price_pulled_back FALSE 

=>此時StrategyState =2 等待時間和回檔後,應該要二次進場,但以下123200卻不知為何又轉為0 ?

Time 123200.000000 StrategyState 0.000000 time_passed FALSE price_pulled_back FALSE 

Time 123300.000000 StrategyState 1.000000 time_passed FALSE price_pulled_back FALSE 

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

你的程式除了第一根分K將StrategyState設為0之外,看不出來有其他機會會變成0。找一下你沒提供的程式碼裡面,有沒有哪裡會將它設為0。

XQYi 發文於   2025/08/11

回測是用日 K逐筆,每分鐘最多交易1次。

提供的是完整的程式碼。

交易如print所示,有0轉1轉2又轉0轉1共四次變換。

測過也改過很多可能的問題點,但都沒成功。

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

日頻率之下,不應該使用 Date <> Date[1] 條件讓變數歸零,因為這個條件在日頻率之下永遠成立,亦即每個Tick都會將StrategyState歸零。

XQYi 發文於   2025/08/11

感謝教授!

改為

isfirstcall("Date") 較正確做法

CurrentBar = 1 不確定的做法

後都OK。

IsFirstCall("Realtime") 未測試不確定

 

不過還是不解明明實際狀態StrategyState都有依買賣變化及保持,為何會突然2轉為0

 

 

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

(1)StrategyState從2轉為0,是因為date<>date[1]的條件在每個Tick都成立,所以每次洗價,StrategyState都歸零。

(2)歸零之後,第二次再進場的條件就不符合,所以沒有再次進場。

XQYi 發文於   2025/08/11

可是print的結果只有090000未進場和突然2轉0那次之外,都是1

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

因為進場之後,filled一直大於filled[1],所以一直是1,直到2出現才改成2。

發表回覆
Close