---
name: mql5-dashboard-survive-tf-change
description: >
  ทำให้ Dashboard edit fields และ runtime values อยู่รอดเมื่อ user เปลี่ยน
  timeframe (OnDeinit + OnInit re-run) โดยใช้ JSON file persistence.
  รวมถึงวิธีแก้ข้อจำกัดของ MQL5 ที่ห้ามมี input declarations ใน .mqh files.
---

# MQL5 Dashboard: ทำให้ค่าบน Chart Objects อยู่รอดเมื่อเปลี่ยน Timeframe

## ปัญหา
เมื่อ user เปลี่ยน timeframe บน MetaTrader, terminal จะ:
1. เรียก `OnDeinit(reason)`
2. เรียก `OnInit()` ใหม่

ถ้า `OnInit()` อ่านค่าจาก `input` parameters หรือ global variables ที่ไม่ได้ persist, ค่าที่ user พิมพ์ผ่าน dashboard edit fields จะ **หายหมด**เมื่อเปลี่ยน TF

## วิธีแก้: Persistent Storage ด้วย JSON File

### 1. บันทึกก่อน OnDeinit
```mql5
string MakeRuntimeFilePath() {
    string path = TerminalInfoString(TERMINAL_DATA_PATH);
    string safeSymbol = StringReplace(g_symbol, "/", "_");
    return path + "\\MQL5\\Files\\SmartEntry_" + safeSymbol + "_runtime.json";
}

bool SaveRuntimeValues() {
    string path = MakeRuntimeFilePath();
    int handle = FileOpen(path, FILE_WRITE | FILE_ANSI | FILE_COMMON);
    if(handle == INVALID_HANDLE) return false;

    string json = StringFormat(
        "{\"upperZone\":%.5f,\"lowerZone\":%.5f,\"sl\":%.5f,\"tp\":%.5f,\"beOffset\":%d,\"isBuySetup\":%s}",
        g_upperZone, g_lowerZone, g_SL, g_TP, (int)g_beOffset, g_isBuySetup ? "true" : "false");

    FileWriteString(handle, json + "\n");
    FileClose(handle);
    return true;
}

void OnDeinit(const int reason) {
    SaveRuntimeValues();  // ← บันทึกก่อน cleanup ทุกครั้ง
    // ... release handles, destroy panel
}
```

### 2. โหลดกลับตอน OnInit
```mql5
bool LoadRuntimeValues() {
    string path = MakeRuntimeFilePath();
    int handle = FileOpen(path, FILE_READ | FILE_ANSI | FILE_COMMON);
    if(handle == INVALID_HANDLE) return false;  // ไม่มีไฟล์ = first run

    string json = FileReadString(handle);
    FileClose(handle);

    g_upperZone = StringToDouble(ParseJsonField(json, "upperZone"));
    g_lowerZone = StringToDouble(ParseJsonField(json, "lowerZone"));
    // ...
    return true;
}

int OnInit() {
    // Load ก่อน ถ้าไม่มีไฟล์ค่อย fallback ไป input defaults
    if(!LoadRuntimeValues()) {
        g_upperZone = InputUpperZone;
        // ...
    }
    // ...
}
```

### 3. Parse JSON field (MQL5 ไม่มี native JSON)
```mql5
string ParseJsonField(string json, string fieldName) {
    string search = "\"" + fieldName + "\":";
    int pos = StringFind(json, search);
    if(pos < 0) return "0";

    int start = pos + StringLen(search);
    while(start < StringLen(json) && json[start] == ' ') start++;

    if(json[start] == '"') {
        int end = start + 1;
        while(end < StringLen(json) && json[end] != '"') end++;
        return StringSubstr(json, start + 1, end - start - 1);
    } else {
        int end = start;
        while(end < StringLen(json) && json[end] != ',' && json[end] != '}' && json[end] != '\n') end++;
        return StringSubstr(json, start, end - start);
    }
}
```

## ข้อควรระวัง: `input` ใน .mqh File

**MQL5 ไม่อนุญาต `input` declarations ใน .mqh include files** — compile error

### ผิด (compile error):
```mql5
// Dashboard.mqh
input double InputUpperZone = 0;  // ← ERROR: input not allowed in .mqh
```

### ถูก:
```mql5
// Dashboard.mqh — ไม่มี input declarations ที่นี่

// สร้าง method ให้ EA เรียกหลัง Init
void CDashboard::SetInitialEditTexts(double upperZone, double lowerZone,
                                     double sl, double tp, int beOffset) {
    if(upperZone > 0)
        ObjectSetString(0, m_prefix + "EREdit", OBJPROP_TEXT, DoubleToString(upperZone, _Digits));
    // ...
}

// SmartEntryEA.mq5
g_dashboard.Init(g_symbol, true);
g_dashboard.SetInitialEditTexts(g_upperZone, g_lowerZone, g_SL, g_TP, (int)g_beOffset);
```

## ข้อควรระวัง: Chart Objects หายเมื่อ RecreatePanel

`CreatePanel()` สร้าง objects ใหม่ทุกครั้งที่ `ObjectFind() < 0` check อยู่แล้ว — safe สำหรับ TF change เพราะ OnDeinit จะ `DestroyPanel()` ก่อน

## Symbols
- `g_symbol` — ต้องกำหนดก่อนเรียก `MakeRuntimeFilePath()`
- File path ใช้ `FILE_COMMON` flag เพื่อเขียนได้ทุก profile
