//+------------------------------------------------------------------+ //| AltDataMapDialog.mqh | //| AnimateDread | //+------------------------------------------------------------------+ //| Asks the user which alt-data instrument an UNRECOGNISED broker | //| symbol corresponds to. Every broker invents its own index | //| tickers - Dukascopy calls the S&P 500 "USA500IDX", OANDA calls it | //| "SPX500", FTMO "US500.cash" - and the CFTC/FRED/EIA universes | //| have no naming rule that could map them automatically. The | //| catalog in AltDataFetch.mqh covers the common cases; this dialog | //| covers the rest, once, and remembers the answer in symbol_map.cfg.| //| | //| NON-BLOCKING BY DESIGN: the EA initialises, trains and trades | //| normally while the dialog is open. An unmapped symbol simply | //| contributes 0 alt-data features (the panel 0-fills, exactly as it | //| does when a feed is temporarily down) - it must never be able to | //| hold up a chart. The user can also close the dialog outright; | //| "No alternative data" records that choice so it never asks again. | //| | //| Follows ControlPanel.mqh's conventions: CAppDialog subclass, an | //| EVENT_MAP for the buttons, and the EA forwards chart events to it | //| from OnChartEvent then polls Done(). | //+------------------------------------------------------------------+ #ifndef WARRIOR_ALTDATA_MAP_DIALOG_MQH #define WARRIOR_ALTDATA_MAP_DIALOG_MQH #include #include #include #include #define ADM_PANEL_W 400 #define ADM_PANEL_H 215 #define ADM_MARGIN 12 #define ADM_ROW_H 20 #define ADM_BTN_H 26 #define ADM_PREFIX "WarriorAltMap_" class CAltDataMapDialog : public CAppDialog { protected: CLabel m_lineA, m_lineB, m_lineC, m_lineD; CComboBox m_combo; CButton m_okBtn; CButton m_noneBtn; string m_symbol; string m_canonicals[]; // combo index -> canonical name bool m_done; string m_result; // canonical chosen, or "NONE" bool MakeLabel(CLabel &lbl, string suffix, int y, string text) { if(!lbl.Create(m_chart_id, m_name + suffix, m_subwin, ADM_MARGIN, y, ADM_PANEL_W - ADM_MARGIN, y + ADM_ROW_H)) return false; lbl.Text(text); return Add(lbl); } void OnClickOk(void) { long v = m_combo.Value(); int idx = (int)v; if(idx >= 0 && idx < ArraySize(m_canonicals)) m_result = m_canonicals[idx]; else m_result = "NONE"; m_done = true; } void OnClickNone(void) { m_result = "NONE"; m_done = true; } public: CAltDataMapDialog(void) : m_symbol(""), m_done(false), m_result("") {} bool Done(void) const { return m_done; } string Result(void) const { return m_result; } virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); //--- Build and show. `labels` are what the dropdown displays, `canonicals` the values //--- they map to (parallel arrays, same length). bool Show(const string symbol, const string &labels[], const string &canonicals[]) { m_symbol = symbol; m_done = false; m_result = ""; ArrayCopy(m_canonicals, canonicals); int x1 = 30, y1 = 30; if(!CAppDialog::Create(0, ADM_PREFIX + symbol, 0, x1, y1, x1 + ADM_PANEL_W, y1 + ADM_PANEL_H)) { Print("AltDataMapDialog: Create() failed, error " + IntegerToString(GetLastError())); return false; } Caption("Warrior EA - map " + symbol + " to alternative data"); int y = ADM_MARGIN; if(!MakeLabel(m_lineA, "L1", y, "This chart's symbol is not in the alt-data catalog:")) return false; y += ADM_ROW_H; if(!MakeLabel(m_lineB, "L2", y, " " + symbol)) return false; y += ADM_ROW_H + 4; if(!MakeLabel(m_lineC, "L3", y, "Which instrument is it? (e.g. USA500IDX -> SP500)")) return false; y += ADM_ROW_H; if(!MakeLabel(m_lineD, "L4", y, "Alt data is optional - the EA trains and trades either way.")) return false; y += ADM_ROW_H + 6; if(!m_combo.Create(m_chart_id, m_name + "Combo", m_subwin, ADM_MARGIN, y, ADM_PANEL_W - ADM_MARGIN, y + ADM_ROW_H)) { Print("AltDataMapDialog: combo Create() failed, error " + IntegerToString(GetLastError())); return false; } if(!Add(m_combo)) return false; for(int i = 0; i < ArraySize(labels); i++) m_combo.ItemAdd(labels[i], i); if(ArraySize(labels) > 0) m_combo.Select(0); y += ADM_ROW_H + 10; int half = (ADM_PANEL_W - ADM_MARGIN * 3) / 2; if(!m_okBtn.Create(m_chart_id, m_name + "Ok", m_subwin, ADM_MARGIN, y, ADM_MARGIN + half, y + ADM_BTN_H)) return false; m_okBtn.Text("Use this mapping"); if(!Add(m_okBtn)) return false; if(!m_noneBtn.Create(m_chart_id, m_name + "None", m_subwin, ADM_MARGIN * 2 + half, y, ADM_MARGIN * 2 + half * 2, y + ADM_BTN_H)) return false; m_noneBtn.Text("No alternative data"); if(!Add(m_noneBtn)) return false; if(!Run()) { Print("AltDataMapDialog: Run() failed, error " + IntegerToString(GetLastError())); return false; } return true; } }; EVENT_MAP_BEGIN(CAltDataMapDialog) ON_EVENT(ON_CLICK, m_okBtn, OnClickOk) ON_EVENT(ON_CLICK, m_noneBtn, OnClickNone) EVENT_MAP_END(CAppDialog) #endif // WARRIOR_ALTDATA_MAP_DIALOG_MQH