feat(altdata): EIA wired, 24-instrument symbol catalog, mapping dialog for unknown symbols
EIA (user directive: "the NN might find patterns in it for both oil and regular
symbols"). Weekly Petroleum Status Report via the v2 API - crude stocks ex-SPR,
field production, refinery utilization - three features (1y percentile, 4w
change, utilization) on EVERY catalog symbol, not just oil. EIA screened NULL on
WTI's short 7y sample, so these ship as EXPLORATORY inputs: the deploy gate, not
the screen, decides whether a model trained on them trades. Publication stamp
observed+6d mirrors research/altdata/eia.py.
Symbol handling was hardcoded to three if-blocks; it is now a catalog of 24
instruments x alias lists covering The5ers/FTMO/AvaTrade/Dukascopy/OANDA/IC
Markets naming, with prefix matching for the broker suffix zoo (US500.cash,
XAUUSDm, EURUSD.r). Adding an instrument is one AddSpec row. COT caches are
named by CANONICAL so two brokers' names for one contract share a download.
Unrecognised symbol -> a chart dialog (Panel\AltDataMapDialog.mqh, CAppDialog +
dropdown) asks which instrument it is; the answer persists in symbol_map.cfg and
"No alternative data" is a recorded choice, not a nag. Non-blocking by design:
an unmapped symbol contributes 0 features and must never hold up a chart.
Also: UrlEncodePart now escapes '%' - SoQL like-predicates use it as the
wildcard and an unescaped one corrupts the query; docs/ gains the whitelist
URLs, an API-key backup, and the catalog reference.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 16:18:29 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| AltDataMapDialog.mqh |
|
|
|
|
|
//| AnimateDread |
|
2026-08-22 00:30:14 -04:00
|
|
|
//| 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. |
|
feat(altdata): EIA wired, 24-instrument symbol catalog, mapping dialog for unknown symbols
EIA (user directive: "the NN might find patterns in it for both oil and regular
symbols"). Weekly Petroleum Status Report via the v2 API - crude stocks ex-SPR,
field production, refinery utilization - three features (1y percentile, 4w
change, utilization) on EVERY catalog symbol, not just oil. EIA screened NULL on
WTI's short 7y sample, so these ship as EXPLORATORY inputs: the deploy gate, not
the screen, decides whether a model trained on them trades. Publication stamp
observed+6d mirrors research/altdata/eia.py.
Symbol handling was hardcoded to three if-blocks; it is now a catalog of 24
instruments x alias lists covering The5ers/FTMO/AvaTrade/Dukascopy/OANDA/IC
Markets naming, with prefix matching for the broker suffix zoo (US500.cash,
XAUUSDm, EURUSD.r). Adding an instrument is one AddSpec row. COT caches are
named by CANONICAL so two brokers' names for one contract share a download.
Unrecognised symbol -> a chart dialog (Panel\AltDataMapDialog.mqh, CAppDialog +
dropdown) asks which instrument it is; the answer persists in symbol_map.cfg and
"No alternative data" is a recorded choice, not a nag. Non-blocking by design:
an unmapped symbol contributes 0 features and must never hold up a chart.
Also: UrlEncodePart now escapes '%' - SoQL like-predicates use it as the
wildcard and an unescaped one corrupts the query; docs/ gains the whitelist
URLs, an API-key backup, and the catalog reference.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 16:18:29 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#ifndef WARRIOR_ALTDATA_MAP_DIALOG_MQH
|
|
|
|
|
#define WARRIOR_ALTDATA_MAP_DIALOG_MQH
|
|
|
|
|
|
|
|
|
|
#include <Controls\Dialog.mqh>
|
|
|
|
|
#include <Controls\Label.mqh>
|
|
|
|
|
#include <Controls\ComboBox.mqh>
|
|
|
|
|
#include <Controls\Button.mqh>
|
|
|
|
|
|
|
|
|
|
#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
|