2026-09-13 14:32:40 -04:00 | | | //+------------------------------------------------------------------+
|
| | | //| ManagementNet.mqh |
|
| | | //| AnimateDread |
|
| | | //| |
|
| | | //| THE ONE QUESTION NO RULE COULD ANSWER. |
|
| | | //| |
|
| | | //| A trade is +0.5R in front. Does it run to target, or give it all |
|
| | | //| back to the stop? |
|
| | | //| |
|
| | | //| Measured on 9,770 resolved firings: 46.0% continue to +2R, 54.0% |
|
| | | //| retrace. A balanced label on a large sample, and a PERFECT caller |
|
| | | //| would be worth +0.540 R per firing - against a pooled deficit of |
|
| | | //| -0.13 to -0.18 R. A quarter of it flips the sign of the strategy. |
|
| | | //| |
|
| | | //| WHY A MODEL AND NOT A RULE. Three rules were tried and all three |
|
| | | //| lost money: an ATR trail (+150.67 -> +90.56, worse as it widened),|
|
| | | //| a nearer target (-20.32), and a breakeven stop (-22.35 at +0.5R, |
|
| | | //| monotonically worse the earlier it fired). They fail for one |
|
| | | //| shared reason - a give-back and a pullback-before-a-run look |
|
| | | //| IDENTICAL at the moment you must act. That is a classification |
|
| | | //| problem wearing a rule's clothes, and a threshold on one number |
|
| | | //| cannot separate two populations that overlap on that number. |
|
| | | //| |
|
| | | //| ⚠ IT DOES NOT PREDICT DIRECTION, and that is the point. Direction |
|
| | | //| was measured dead in this project at bar level (rho 0.00-0.02) |
|
| | | //| and every architecture thrown at it returned no information out |
|
| | | //| of sample. This asks a CONDITIONAL question - given the move has |
|
| | | //| already happened, does it extend or exhaust - which is a question |
|
| | | //| about persistence and volatility, and volatility is the one thing |
|
| | | //| here that has ever been predictable. |
|
| | | //| |
|
| | | //| ⚠ AND IT TRAINS ON THE CROSSING, NOT ON THE ENTRY. The features |
|
| | | //| describe the bar where +0.5R was first touched: how fast it got |
|
| | | //| there, how much pain came first, what the market was doing at |
|
| | | //| that moment. Using the entry bar's state would be answering a |
|
| | | //| different question with the wrong evidence. |
|
| | | //| |
|
| | | //| ⚠ maeR AS STORED IN THE JOURNAL IS LOOKAHEAD FOR THIS. It is the |
|
| | | //| worst excursion over the WHOLE trade, including after the |
|
| | | //| crossing, and it separates the two classes beautifully (0.51 vs |
|
| | | //| 1.21) precisely because it contains the answer. The adverse |
|
| | | //| excursion used here is measured only up TO the crossing bar. |
|
| | | //+------------------------------------------------------------------+
|
| | | #ifndef WARRIOR_MANAGEMENT_NET_MQH
|
| | | #define WARRIOR_MANAGEMENT_NET_MQH
|
| | |
|
| | | #include "WarriorNet.mqh"
|
| | |
|
| | | #define MGMT_FEATURES 10
|
| | | //--- The crossing this model is asked about, in R. Matched to the measurement above.
|
| | | #define MGMT_TRIGGER_R 0.5
|
| | | //--- How long a virtual trade may stay open before it is abandoned unlabelled.
|
| | | #define MGMT_HORIZON 60
|
| | |
|
| | | class CManagementNet
|
| | | {
|
| | | private:
|
| | | CWarriorNet m_net;
|
| | | bool m_ready;
|
| | | string m_why;
|
| | |
|
| | | public:
|
| | | CManagementNet(void) : m_ready(false), m_why("not trained") {}
|
| | | ~CManagementNet(void) {}
|
| | |
|
| | | bool Ready(void) const { return m_ready; }
|
| | | string Why(void) const { return m_why; }
|
| | | double AUC(void) const { return m_net.AUC(); }
|
| | |
|
| | | static string FeatureName(const int i);
|
| | | //--- P(this trade continues to target). <0 when there is no usable model.
|
| | | double Score(double &x[]) { return m_ready ? m_net.Score(x) : -1.0; }
|
| | |
|
| | | //--- TRAINED IN MEMORY, NEVER SERIALISED.
|
| | | //---
|
| | | //--- ALGLIB's MQL5 serializer under-allocates its output buffer and dies inside
|
| | | //--- CSerializer::Stop() - "array out of range in ap.mqh (1996,17)" - which killed three of four
|
| | | //--- H4 runs stone dead AFTER the model had trained and reported a perfectly good AUC. The same
|
| | | //--- family of bug already bit DFSerialize on compressed forests in this repo.
|
| | | //---
|
| | | //--- Nothing is lost by skipping it: the fit is deferred and walk-forward by design, so it is
|
| | | //--- rebuilt from history-so-far on every run regardless. A file would only be a cache of
|
| | | //--- something cheap, bought at the price of a crash.
|
| | | bool Train(CMatrixDouble &xy, const int rows, const string &names[])
|
| | | {
|
| | | //--- Embargo = the horizon. A virtual trade is a 60-bar window; rows closer than that to the
|
| | | //--- boundary overlap the validation set's first rows. In the training matrix each ENTRY bar
|
| | | //--- contributes two rows (long and short), so one horizon of bars is two horizons of rows.
|
| | | m_ready = m_net.Train(xy, rows, MGMT_FEATURES, names, MGMT_HORIZON * 2);
|
| | | m_why = m_net.Why();
|
| | | return m_ready;
|
| | | }
|
| | | };
|
| | | //+------------------------------------------------------------------+
|
| | | string CManagementNet::FeatureName(const int i)
|
| | | {
|
| | | switch(i)
|
| | | {
|
| | | //--- HOW IT GOT HERE. A move that reached +0.5R in one bar is a different animal from one
|
| | | //--- that ground there over fifteen, and nothing about the entry bar can express that.
|
| | | case 0: return "bars_to_cross";
|
| | | case 1: return "mae_before_cross_r"; // pain paid BEFORE the gain - never after it
|
| | | case 2: return "cross_speed_r_per_bar";
|
| | | //--- WHAT THE MARKET IS DOING AT THE CROSSING. Persistence is the whole question, and these
|
| | | //--- two are the direct measures of it: efficient and compounding, or cancelling.
|
| | | case 3: return "er_at_cross";
|
| | | case 4: return "vr_at_cross";
|
| | | case 5: return "regime_at_cross";
|
| | | //--- THE CROSSING BAR ITSELF. A wide bar closing at its extreme is an extension; a wide bar
|
| | | //--- closing mid-range is exhaustion, and they look the same in R.
|
| | | case 6: return "range_atr_at_cross";
|
| | | case 7: return "close_in_bar_at_cross";
|
2026-09-30 18:36:33 -04:00 | | | case 8: return "rvol_tod_at_cross";
|
2026-09-13 14:32:40 -04:00 | | | //--- Which way the trade is facing, so one model serves both sides rather than two models
|
| | | //--- each trained on half the data.
|
| | | case 9: return "is_long";
|
| | | }
|
| | | return "?";
|
| | | }
|
| | | #endif // WARRIOR_MANAGEMENT_NET_MQH
|