| //+------------------------------------------------------------------+
|
| //| StudyForecast.mq5 |
|
| //| Copyright 2026, DNG |
|
| //| https://www.mql5.com/ru/users/dng |
|
| //+------------------------------------------------------------------+
|
| #property copyright "Copyright 2026, DNG"
|
| #property version "1.00"
|
| #property description "DPCC Market representation training in four selectable phases"
|
| #property description "Uses terminal history to train the latent and price objectives"
|
| #property description "Saves the latest Market model checkpoint in Common Files"
|
| #property strict
|
| #define DPCC_TRAJECTORY_ENTRY_STUDY_FORECAST
|
| #include "Trajectory.mqh"
|
| #undef DPCC_TRAJECTORY_ENTRY_STUDY_FORECAST
|
|
|
| input group "---- Источник и общие параметры запуска ----"
|
| //--- Таймфрейм исторических баров; PERIOD_CURRENT — таймфрейм графика.
|
| input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT;
|
| //--- Максимум обновлений за запуск; 0 — без дополнительного ограничения.
|
| input ulong InpStopAfterUpdates = 0;
|
| //--- AUTO продолжает checkpoint; явное имя фазы запускает её на текущих весах.
|
| input string InpM05TrainingPhase = "AUTO";
|
| //--- Включить режим обучения Market по прямым параметрам M05.
|
| input bool InpUseM05 = true;
|
| input ENUM_DPCC_RESUME_MODE InpResumeMode = DPCC_RESUME_UNASSIGNED; // Режим восстановления сохранённой модели.
|
| input ENUM_DPCC_MODE InpMode = DPCC_P0; // Режим DPCC: P0, P1 или P2.
|
| //--- 0 — весь доступный набор fit 2025; больше 0 — указанное число обновлений.
|
| input uint InpMaxUpdates = 0;
|
|
|
| input group "---- Дополнительные режимы и параметры ценовой ошибки ----"
|
| input bool InpPriceForwardOnly = false; // Исторический H1 forward без обучения и сохранения моделей.
|
| input bool InpPriceJoint = false; // Совместная латентная и ценовая задача Market.
|
| input float InpPriceLambda = 0.0f; // Вес ценовой ошибки в дополнительном режиме.
|
| input float InpPriceHuberDelta = 0.0f; // Порог функции Huber для ошибки цены.
|
| input float InpPriceRhoTolerance = 0.0f; // Допуск суммы вероятностей rho.
|
|
|
| //input group "---- Идентификатор и файлы задачи M05 ----"
|
| /*input*/ string InpM05TaskId = "DPCC_M05_StudyForecast_20261017"; // Идентификатор запуска M05.
|
| /*input*/ ulong InpM05NoiseSeed = 20261007; // Seed для воспроизводимой случайной части обучения.
|
| //--- Максимальный размер читаемого или записываемого файла.
|
| /*input*/ ulong InpM05MaxFileBytes = 1073741824;
|
|
|
| input group "---- LATENT_PREPARE: период и число эпох ----"
|
| input datetime InpM05LatentStart = D'2024.01.01'; // Время сервера; начало окна LATENT_PREPARE включительно.
|
| input datetime InpM05LatentEnd = D'2026.01.01'; // Время сервера; исключительная граница окна LATENT_PREPARE.
|
| input uint InpM05LatentEpochs = 100; // Число эпох обучения LATENT_PREPARE.
|
|
|
| input group "---- OMPB_CALIBRATE: окна reference и calibration ----"
|
| input datetime InpM05ReferenceStart = D'2024.01.01'; // Время сервера; начало reference-окна OMPB включительно.
|
| input datetime InpM05ReferenceEnd = D'2024.10.01'; // Время сервера; исключительная граница reference-окна.
|
| input datetime InpM05CalibrationStart = D'2024.10.01'; // Время сервера; начало calibration-окна включительно.
|
| input datetime InpM05CalibrationEnd = D'2026.01.01'; // Время сервера; исключительная граница calibration-окна.
|
| input uint InpM05OMPBTrainingEpochs = 30; // Число эпох калибровки OMPB.
|
| input uint InpM05SourceAnchorPeriod = 10; // Интервал между исходными якорями OMPB.
|
|
|
| input group "---- OMPB_CALIBRATE: параметры распределительного обучения ----"
|
| input float InpM05Tau = 1.0f; // Параметр tau калибровки OMPB.
|
| input float InpM05LambdaDis = 0.01f; // Вес штрафа за disagreement OMPB.
|
| input float InpM05LambdaKL = 0.01f; // Вес штрафа KL-дивергенции OMPB.
|
| input float InpM05LambdaAlpha = 0.001f; // Вес регуляризации alpha OMPB.
|
| input float InpM05AlphaPrior = -6.0f; // Исходное значение alpha prior OMPB.
|
| input float InpM05MaxKL = 0.0f; // Максимальный KL для калибровки OMPB.
|
|
|
| input group "---- PRICE_JOINT и PRICE_ADAPT: цена и бюджет обучения ----"
|
| input float InpM05PriceLambda = 1.0f; // Вес ценовой ошибки Market.
|
| input float InpM05PriceHuberDelta = 1.0f; // Порог функции Huber в нормированной шкале цены.
|
| input float InpM05PriceRhoTolerance = 0.001f; // Допуск отклонения суммы rho от 1.
|
| input uint InpM05PriceJointEpochs = 1; // Число эпох PRICE_JOINT.
|
| input ulong InpM05PriceJointMaxUpdates = 0; // Лимит обновлений PRICE_JOINT; 0 — без отдельного лимита.
|
| input uint InpM05PriceAdaptEpochs = 1; // Число эпох PRICE_ADAPT.
|
| input ulong InpM05PriceAdaptMaxUpdates = 0; // Лимит обновлений PRICE_ADAPT; 0 — без отдельного лимита.
|
|
|
| input group "---- Пороговые значения VERIFY ----"
|
| input double InpM05VerifyAtol = 0.000001; // Абсолютный допуск сравнения прогнозов.
|
| input double InpM05VerifyRtol = 0.000001; // Относительный допуск сравнения прогнозов.
|
| input double InpM05VerifyMaxPriceError = 1.0; // Максимальная допустимая ошибка цены.
|
| input double InpM05VerifyMinScenarioCoverage = 0.80; // Минимальная доля целевых точек, покрытых сценариями.
|
| input uint InpM05VerifyMinDistinctScenarios = 2; // Минимум различных сценариев из набора модели.
|
|
|
| const string DPCC_M05_TASK_DIRECTORY = "DPCC/StudyForecast_M05_20261017";
|
| const bool DPCC_COMMON_FILES = true;
|
|
|
| CDPCCStudyForecastCore ExtTrainer;
|
| string ExtRoot;
|
| ulong ExtLastProgressMilestone = 0;
|
| SDPCCExecutionControl ExtExecutionControl;
|
| SDPCCM05OMPBProfile EXTM05DonorProfile;
|
| SDPCCM05VerifyProfile EXTM05VerifyProfile;
|
| float EXTM05PriceLambda = 0, EXTM05HuberDelta = 0, EXTM05RhoTolerance = 0;
|
| string EXTM05ProfileSHA = "", EXTM05DonorSHA = "";
|
| CDPCCStopButton ExtStopButton;
|
| bool ExtM05StopSaveFailed = false;
|
| //+------------------------------------------------------------------+
|
| //| M05Enabled selects the direct-input M05 Market training path |
|
| //+------------------------------------------------------------------+
|
| bool M05Enabled(void)
|
| {
|
| return(InpUseM05);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Persist one whole phase boundary without a second OnDeinit save |
|
| //+------------------------------------------------------------------+
|
| bool SaveM05Checkpoint(const string cause)
|
| {
|
| string path = "", reason = "", publication_reason = "";
|
| const bool saved = ExtTrainer.SaveM05Boundary(ExtExecutionControl, cause, path, reason);
|
| const bool consumer_ready = ExtTrainer.MarketConsumerReady(publication_reason);
|
| Print("DPCC_MARKET_CHECKPOINT cause=", cause, " stage=", ExtTrainer.PriceStudyStage(),
|
| " updates=", ExtTrainer.Updates(), " model_save=", (saved ? 1 : 0), " path=", path,
|
| " ompb_epochs=", ExtTrainer.OMPBTrainingEpochsCompleted(), "/", ExtTrainer.OMPBTrainingEpochLimit(),
|
| " ompb_budget=", (ExtTrainer.OMPBTrainingBudgetComplete() ? "COMPLETE" : "PARTIAL"),
|
| " ompb_eval_lanes=", ExtTrainer.OMPBStage02EvaluationLanes(), "/6",
|
| " ompb_quality=", (!ExtTrainer.OMPBStage02QualityEvaluated() ? "PENDING" :
|
| (ExtTrainer.OMPBStage02QualityPassed() ? "PASS" : "FAIL")),
|
| " quality_gate=ADVISORY",
|
| " consumer_ready=", consumer_ready, " technical_acceptance=NOT_RUN",
|
| " reason=", reason, " consumer_reason=", publication_reason);
|
| return(saved);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Function OnInit |
|
| //+------------------------------------------------------------------+
|
| int OnInit(void)
|
| {
|
| string control_reason = "";
|
| if(!DPCCConfigureExecutionControl(DPCC_M05_TASK_DIRECTORY, InpTimeframe, DPCC_STAGE_STUDYFORECAST, "",
|
| InpStopAfterUpdates, InpResumeMode, InpMode, DPCC_STAGE_STUDYFORECAST,
|
| ExtExecutionControl, control_reason))
|
| {
|
| Print("DPCC_STUDYFORECAST_BLOCKED phase=profile_control reason=", control_reason);
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| const bool use_m05 = M05Enabled();
|
| if(InpM05TrainingPhase != "AUTO" && InpM05TrainingPhase != "LATENT_PREPARE" &&
|
| InpM05TrainingPhase != "PRICE_JOINT" && InpM05TrainingPhase != "OMPB_CALIBRATE" &&
|
| InpM05TrainingPhase != "PRICE_ADAPT")
|
| {
|
| Print("DPCC_M05_ABORT phase=parameters reason=unknown_training_phase value=", InpM05TrainingPhase);
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| if(InpM05TrainingPhase != "AUTO" && !use_m05)
|
| {
|
| Print("DPCC_M05_ABORT phase=parameters reason=explicit_phase_requires_M05_inputs");
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| if((InpPriceJoint && InpPriceForwardOnly) || (use_m05 && (InpPriceJoint || InpPriceForwardOnly)))
|
| return(INIT_PARAMETERS_INCORRECT);
|
| if(InpPriceJoint &&
|
| (!MathIsValidNumber(InpPriceLambda) || InpPriceLambda <= 0 ||
|
| !MathIsValidNumber(InpPriceHuberDelta) || InpPriceHuberDelta <= 0 ||
|
| !MathIsValidNumber(InpPriceRhoTolerance) || InpPriceRhoTolerance <= 0 ||
|
| InpPriceRhoTolerance >= 1))
|
| {
|
| Print("DPCC_PRICE_JOINT_ABORT phase=parameters reason=positive_loss_profile_required");
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| if(use_m05)
|
| {
|
| string profile_reason = "";
|
| SDPCCM05DirectInputs direct;
|
| ZeroMemory(direct);
|
| direct.task_id = InpM05TaskId;
|
| direct.noise_seed = InpM05NoiseSeed;
|
| direct.timeframe = ExtExecutionControl.timeframe;
|
| direct.rsi_period = (uint)RSIPeriod;
|
| direct.cci_period = (uint)CCIPeriod;
|
| direct.price_atr_period = (uint)ATRPeriod;
|
| direct.fast_period = (uint)FastPeriod;
|
| direct.slow_period = (uint)SlowPeriod;
|
| direct.signal_period = (uint)SignalPeriod;
|
| direct.latent_start = InpM05LatentStart;
|
| direct.latent_end = InpM05LatentEnd;
|
| direct.reference_start = InpM05ReferenceStart;
|
| direct.reference_end = InpM05ReferenceEnd;
|
| direct.calibration_start = InpM05CalibrationStart;
|
| direct.calibration_end = InpM05CalibrationEnd;
|
| direct.latent_epochs = InpM05LatentEpochs;
|
| direct.ompb_epochs = InpM05OMPBTrainingEpochs;
|
| direct.source_anchor_period = InpM05SourceAnchorPeriod;
|
| direct.rsi_price = RSIPrice;
|
| direct.cci_price = CCIPrice;
|
| direct.macd_price = MACDPrice;
|
| direct.tau = InpM05Tau;
|
| direct.lambda_dis = InpM05LambdaDis;
|
| direct.lambda_kl = InpM05LambdaKL;
|
| direct.lambda_alpha = InpM05LambdaAlpha;
|
| direct.alpha_prior = InpM05AlphaPrior;
|
| direct.max_kl = InpM05MaxKL;
|
| direct.price_joint_epochs = InpM05PriceJointEpochs;
|
| direct.price_joint_max_updates = InpM05PriceJointMaxUpdates;
|
| direct.price_adapt_epochs = InpM05PriceAdaptEpochs;
|
| direct.price_adapt_max_updates = InpM05PriceAdaptMaxUpdates;
|
| direct.max_file_bytes = InpM05MaxFileBytes;
|
| direct.lambda_price = InpM05PriceLambda;
|
| direct.huber_delta = InpM05PriceHuberDelta;
|
| direct.rho_tolerance = InpM05PriceRhoTolerance;
|
| direct.verify_atol = InpM05VerifyAtol;
|
| direct.verify_rtol = InpM05VerifyRtol;
|
| direct.verify_max_price_error = InpM05VerifyMaxPriceError;
|
| direct.verify_min_scenario_coverage = InpM05VerifyMinScenarioCoverage;
|
| direct.verify_min_distinct_scenarios = InpM05VerifyMinDistinctScenarios;
|
| direct.task_directory = DPCC_M05_TASK_DIRECTORY;
|
| if(!DPCCBuildM05ExecutionProfileFromInputs(ExtExecutionControl, direct, DPCC_COMMON_FILES,
|
| EXTM05DonorProfile, EXTM05VerifyProfile, EXTM05PriceLambda, EXTM05HuberDelta,
|
| EXTM05RhoTolerance, profile_reason))
|
| {
|
| Print("DPCC_M05_ABORT phase=input_profile reason=", profile_reason);
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| EXTM05ProfileSHA = EXTM05DonorProfile.assigned_profile_sha256;
|
| EXTM05DonorSHA = EXTM05DonorProfile.calibration_preset_sha256;
|
| if(EXTM05DonorProfile.price_joint_epochs != 1 ||
|
| EXTM05DonorProfile.price_joint_max_updates != 0 ||
|
| EXTM05DonorProfile.price_adapt_epochs != 1 ||
|
| EXTM05DonorProfile.price_adapt_max_updates != 0)
|
| {
|
| Print("DPCC_M05_ABORT phase=donor_profile reason=one_full_2025_fit_pass_required");
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| if(!ExtTrainer.ConfigureM05OMPB(EXTM05DonorProfile, profile_reason))
|
| {
|
| Print("DPCC_M05_ABORT phase=donor_profile reason=", profile_reason);
|
| return(INIT_PARAMETERS_INCORRECT);
|
| }
|
| }
|
| ExtRoot = "DPCC_StudyEncoder_" + (string)GetMicrosecondCount();
|
| ExtLastProgressMilestone = 0;
|
| MathSrand(20261007);
|
| rnd_x = (uint)MathRand();
|
| rnd_y = (uint)MathRand();
|
| rnd_z = (uint)MathRand();
|
| rnd_w = (uint)MathRand();
|
| rnd_t = 0;
|
| if((rnd_x | rnd_y | rnd_z | rnd_w) == 0)
|
| return(INIT_FAILED);
|
| Print("DPCC_STUDYFORECAST_INITIAL_RNG seed=20261007 x=", rnd_x, " y=", rnd_y,
|
| " z=", rnd_z, " w=", rnd_w, " t=", rnd_t);
|
| datetime capture_from = StringToTime("2024.12.01 00:00");
|
| datetime capture_to = StringToTime("2026.02.15 00:00");
|
| if(use_m05)
|
| {
|
| const long context_seconds = 7 * 24 * 60 * 60;
|
| if(EXTM05DonorProfile.latent_start < (datetime)((long)capture_from + context_seconds))
|
| capture_from = (datetime)((long)EXTM05DonorProfile.latent_start - context_seconds);
|
| if(EXTM05DonorProfile.latent_end > (datetime)((long)capture_to - context_seconds))
|
| capture_to = (datetime)((long)EXTM05DonorProfile.latent_end + context_seconds);
|
| if(EXTM05DonorProfile.reference_start < (datetime)((long)capture_from + context_seconds))
|
| capture_from = (datetime)((long)EXTM05DonorProfile.reference_start - context_seconds);
|
| if(EXTM05DonorProfile.calibration_end > (datetime)((long)capture_to - context_seconds))
|
| capture_to = (datetime)((long)EXTM05DonorProfile.calibration_end + context_seconds);
|
| }
|
| string raw_path = "", raw_sha = "", reason = "";
|
| uint raw_rows = 0;
|
| const ENUM_TIMEFRAMES timeframe = ExtExecutionControl.timeframe;
|
| const bool capture_price_ticks = ((InpPriceForwardOnly || InpPriceJoint) && !use_m05);
|
| if(!DPCCCaptureStudyForecastRaw(_Symbol, timeframe, capture_from, capture_to, raw_path, raw_sha, raw_rows, reason,
|
| capture_price_ticks,
|
| (use_m05 ? EXTM05DonorProfile.rsi_price : RSIPrice),
|
| (use_m05 ? EXTM05DonorProfile.cci_price : CCIPrice),
|
| (use_m05 ? EXTM05DonorProfile.macd_price : MACDPrice), use_m05, use_m05))
|
| {
|
| Print("DPCC_STUDYFORECAST_ABORT phase=capture reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| if(InpPriceForwardOnly)
|
| {
|
| if(!ExtTrainer.InitializePriceForward(raw_path, raw_sha, timeframe, reason))
|
| {
|
| Print("DPCC_PRICE_FORWARD_ABORT phase=initialize reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| int completed = 0, normalized_count = 0, native_count = 0;
|
| ulong first_decision_id = 0, last_decision_id = 0;
|
| long first_quote_time = 0, last_quote_time = 0, first_quote_msc = 0, last_quote_msc = 0;
|
| double first_anchor = 0, first_atr14 = 0;
|
| string quote_basis = "UNRESOLVED", quote_time_resolution = "";
|
| float first_open = 0, first_high = 0, first_low = 0, first_close = 0;
|
| for(int i = 0; i < 2; i++)
|
| {
|
| float normalized[], native[];
|
| SDPCCHistoricalPriceSnapshot snapshot;
|
| if(!ExtTrainer.AdvancePriceForward(normalized, native, snapshot, reason))
|
| {
|
| Print("DPCC_PRICE_FORWARD_ABORT phase=forward reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| if(i == 0)
|
| {
|
| first_decision_id = snapshot.decision_id;
|
| first_quote_time = snapshot.quote_time_server;
|
| first_quote_msc = snapshot.quote_time_msc;
|
| first_anchor = snapshot.anchor;
|
| first_atr14 = snapshot.scale;
|
| quote_basis = snapshot.quote_basis;
|
| quote_time_resolution = snapshot.quote_time_resolution;
|
| if(ArraySize(native) >= 4)
|
| {
|
| first_open = native[0];
|
| first_high = native[1];
|
| first_low = native[2];
|
| first_close = native[3];
|
| }
|
| }
|
| last_decision_id = snapshot.decision_id;
|
| last_quote_time = snapshot.quote_time_server;
|
| last_quote_msc = snapshot.quote_time_msc;
|
| normalized_count = ArraySize(normalized);
|
| native_count = ArraySize(native);
|
| completed++;
|
| }
|
| Print("DPCC_PRICE_FORWARD_COMPLETE decisions=", completed, " updates=0 model_save=0 orders=0",
|
| " raw_sha256=", ExtTrainer.RawSHA(), " symbol=", _Symbol, " timeframe=", EnumToString(timeframe),
|
| " quote_basis=", quote_basis, " quote_time_resolution=", quote_time_resolution,
|
| " tick_quote_time_resolved=true first_decision_id=", first_decision_id,
|
| " last_decision_id=", last_decision_id, " first_quote_time_server=", first_quote_time,
|
| " last_quote_time_server=", last_quote_time, " first_quote_time_msc=", first_quote_msc,
|
| " last_quote_time_msc=", last_quote_msc, " first_anchor=", DoubleToString(first_anchor, 16),
|
| " first_ATR14=", DoubleToString(first_atr14, 16),
|
| " first_scenario_ohlc=", first_open, ",", first_high, ",", first_low, ",", first_close,
|
| " normalized_count=", normalized_count, " native_count=", native_count,
|
| " trained_market=false scope=historical_H1_first_tick readiness=NOT_CLAIMED");
|
| return(EventSetTimer(1) ? INIT_SUCCEEDED : INIT_FAILED);
|
| }
|
| if(InpPriceJoint || use_m05)
|
| {
|
| const bool initialized = (use_m05 ?
|
| ExtTrainer.InitializeM05(raw_path, raw_sha, EXTM05PriceLambda,
|
| EXTM05HuberDelta, EXTM05RhoTolerance, reason, true, timeframe) :
|
| ExtTrainer.InitializePriceJoint(raw_path, raw_sha, InpMaxUpdates, false, InpPriceLambda,
|
| InpPriceHuberDelta, InpPriceRhoTolerance, reason));
|
| if(!initialized)
|
| {
|
| Print("DPCC_PRICE_JOINT_ABORT phase=initialize reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| bool m05_restored = false;
|
| if(use_m05 && !ExtTrainer.RestoreM05Boundary(ExtExecutionControl, m05_restored, reason, InpM05TrainingPhase))
|
| {
|
| Print("DPCC_M05_ABORT phase=restore reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| if(use_m05 && m05_restored)
|
| Print("DPCC_M05_RESUME_READY stage=", ExtTrainer.PriceStudyStage(),
|
| " position=", ExtTrainer.PriceStudyPosition(), " / ", ExtTrainer.PriceStudyTotal(),
|
| " updates=", ExtTrainer.Updates(), " mode=",
|
| (InpM05TrainingPhase == "AUTO" ? "exact_checkpoint_resume" : "selected_phase_model_warm_start"),
|
| " weights=latest checkpoint Adam=preserved recurrence=",
|
| (InpM05TrainingPhase == "AUTO" ? "warmup" : "reset"));
|
| if(use_m05 && InpM05TrainingPhase != "AUTO")
|
| {
|
| if(!SaveM05Checkpoint("USER_SELECTED_PHASE"))
|
| return(INIT_FAILED);
|
| Print("DPCC_M05_PHASE_SELECTED stage=", ExtTrainer.PriceStudyStage(),
|
| " position=", ExtTrainer.PriceStudyPosition(), " / ", ExtTrainer.PriceStudyTotal(),
|
| " updates=", ExtTrainer.Updates(), " prior_quality=ADVISORY checkpoint=latest_weights_and_adam");
|
| }
|
| if(use_m05 && ExtTrainer.Finished())
|
| {
|
| if(!SaveM05Checkpoint("PHASE_COMPLETED"))
|
| return(INIT_FAILED);
|
| string publication_reason = "";
|
| const bool consumer_ready = ExtTrainer.MarketConsumerReady(publication_reason);
|
| Print("DPCC_M05_PHASE_COMPLETE stage=", ExtTrainer.PriceStudyStage(),
|
| " status=ALREADY_COMPLETED next_stage=COMPLETE updates=", ExtTrainer.Updates(), " model_save=1");
|
| Print("DPCC_M05_COMPLETE status=", ExtTrainer.PricePhaseTerminalStatus(),
|
| " stage=", ExtTrainer.PriceStudyStage(), " updates=", ExtTrainer.Updates(),
|
| " market_consumer_ready=", consumer_ready, " consumer_reason=", publication_reason,
|
| " price_verify=REMOVED_BY_USER action=remove_advisor");
|
| ExtStopButton.RemoveAdvisor();
|
| return(INIT_SUCCEEDED);
|
| }
|
| if(use_m05 && !ExtStopButton.Create("M05", "Stop and save"))
|
| {
|
| Print("DPCC_M05_ABORT phase=stop_button reason=chart_object_create_failed error=", GetLastError());
|
| return(INIT_FAILED);
|
| }
|
| if(!EventSetTimer(1))
|
| return(INIT_FAILED);
|
| if(use_m05)
|
| Print("DPCC_M05_PHASE_START requested=", InpM05TrainingPhase,
|
| " stage=", ExtTrainer.PriceStudyStage(), " epochs_completed=", ExtTrainer.PriceStudyEpochsCompleted(),
|
| " position=", ExtTrainer.PriceStudyPosition(), " / ", ExtTrainer.PriceStudyTotal(),
|
| " updates=", ExtTrainer.Updates(), " restored=", m05_restored);
|
| Print("DPCC_PRICE_JOINT_READY raw_path=", raw_path, " raw_sha256=", ExtTrainer.RawSHA(),
|
| " raw_common_files=", (use_m05 ? "true" : "false"), " fit_eligible=", ExtTrainer.FitCount(),
|
| " max_updates=", (use_m05 ? EXTM05DonorProfile.price_joint_max_updates : InpMaxUpdates),
|
| " lambda_price=", (use_m05 ? EXTM05PriceLambda : InpPriceLambda),
|
| " huber_delta=", (use_m05 ? EXTM05HuberDelta : InpPriceHuberDelta),
|
| " rho_tolerance=", (use_m05 ? EXTM05RhoTolerance : InpPriceRhoTolerance),
|
| " phase=", ExtTrainer.PriceStudyStage(), " quote_time_resolution=",
|
| (use_m05 ? "SERVER_BAR_OPEN_MSC" : "SERVER_FIRST_AVAILABLE_TICK_MSC"));
|
| if(use_m05)
|
| Print("DPCC_M05_ACSRM_PROFILE_ADAPTED profile_sha256=", ExtTrainer.OMPBProfileSHA256(),
|
| " raw_sha256=", ExtTrainer.RawSHA(),
|
| " direct_input_profile_sha256=", EXTM05ProfileSHA,
|
| " ompb_config_sha256=", EXTM05DonorSHA, " stage=2 smoke=false epochs=", EXTM05DonorProfile.epochs,
|
| " reference=", TimeToString(EXTM05DonorProfile.reference_start, TIME_DATE), "..",
|
| TimeToString(EXTM05DonorProfile.reference_end, TIME_DATE), " calibration=",
|
| TimeToString(EXTM05DonorProfile.calibration_start, TIME_DATE), "..",
|
| TimeToString(EXTM05DonorProfile.calibration_end, TIME_DATE),
|
| " source_period=", EXTM05DonorProfile.source_anchor_period,
|
| " RSIPrice=", EnumToString(EXTM05DonorProfile.rsi_price),
|
| " CCIPrice=", EnumToString(EXTM05DonorProfile.cci_price),
|
| " MACDPrice=", EnumToString(EXTM05DonorProfile.macd_price),
|
| " tau=", EXTM05DonorProfile.tau, " lambda_dis=", EXTM05DonorProfile.lambda_dis,
|
| " lambda_kl=", EXTM05DonorProfile.lambda_kl, " lambda_alpha=", EXTM05DonorProfile.lambda_alpha,
|
| " alpha_prior=", EXTM05DonorProfile.alpha_prior, " max_kl=", EXTM05DonorProfile.max_kl,
|
| " price_joint_epochs=", EXTM05DonorProfile.price_joint_epochs,
|
| " price_joint_max_updates=", EXTM05DonorProfile.price_joint_max_updates,
|
| " price_adapt_epochs=", EXTM05DonorProfile.price_adapt_epochs,
|
| " price_adapt_max_updates=", EXTM05DonorProfile.price_adapt_max_updates,
|
| " posterior_layer=CNeuronOMPBOCL",
|
| " forecast_layer=CNeuronScenarioForecastPriceOCL", " donor_checkpoint_loaded=false");
|
| return(INIT_SUCCEEDED);
|
| }
|
| if(!ExtTrainer.Initialize(raw_path, raw_sha, ExtRoot, InpMaxUpdates, reason))
|
| {
|
| Print("DPCC_STUDYFORECAST_ABORT phase=initialize reason=", reason);
|
| return(INIT_FAILED);
|
| }
|
| if(!EventSetTimer(1))
|
| {
|
| Print("DPCC_STUDYFORECAST_ABORT phase=timer reason=", GetLastError());
|
| return(INIT_FAILED);
|
| }
|
| Print("DPCC_STUDYFORECAST_READY root=", ExtRoot, " raw_sha256=", ExtTrainer.RawSHA(),
|
| " raw_rows=", raw_rows, " fit_eligible=", ExtTrainer.FitCount(),
|
| " holdout_eligible=", ExtTrainer.HoldoutCount(), " max_updates=", InpMaxUpdates,
|
| " stages=encoder_fit,frozen_latent_holdout",
|
| " server_time=2024.12.01..2026.02.15 timezone_resolution=NOT_CLAIMED");
|
| return(INIT_SUCCEEDED);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Function OnTimer |
|
| //+------------------------------------------------------------------+
|
| void OnTimer(void)
|
| {
|
| if(InpPriceForwardOnly)
|
| {
|
| EventKillTimer();
|
| ExtStopButton.RemoveAdvisor();
|
| return;
|
| }
|
| if(InpPriceJoint || M05Enabled())
|
| {
|
| double price_loss = 0, rho = 0;
|
| uint nonzero = 0, generator = 0, router = 0, confidence = 0;
|
| string reason = "";
|
| const string phase_before = ExtTrainer.PriceStudyStage();
|
| const uint epochs_before = (M05Enabled() ? ExtTrainer.PriceStudyEpochsCompleted() : 0);
|
| if(!ExtTrainer.AdvancePriceJoint(price_loss, rho, nonzero, generator, router, confidence, reason))
|
| {
|
| EventKillTimer();
|
| Print("DPCC_PRICE_JOINT_ABORT phase=advance reason=", reason, " updates=", ExtTrainer.Updates());
|
| return;
|
| }
|
| if(phase_before != ExtTrainer.PriceStudyStage())
|
| Print("DPCC_MARKET_PHASE_TRANSITION from=", phase_before, " to=", ExtTrainer.PriceStudyStage(),
|
| " graph_recreated=false parameters_retained=true updates=", ExtTrainer.Updates());
|
| const bool phase_completed = (phase_before != ExtTrainer.PriceStudyStage() ||
|
| (ExtTrainer.Finished() &&
|
| ExtTrainer.PricePhaseTerminalStatus() != "STOPPED_COMPLETE_UPDATE"));
|
| const bool selected_phase_completed = (M05Enabled() && InpM05TrainingPhase != "AUTO" && phase_completed);
|
| const bool epoch_completed = (M05Enabled() && phase_before == ExtTrainer.PriceStudyStage() &&
|
| ExtTrainer.PriceStudyEpochsCompleted() > epochs_before);
|
| const bool controlled_stop = (M05Enabled() && ExtExecutionControl.stop_after_updates > 0 &&
|
| ExtTrainer.Updates() >= ExtExecutionControl.stop_after_updates);
|
| if(M05Enabled() && (phase_before != ExtTrainer.PriceStudyStage() || ExtTrainer.Finished() ||
|
| controlled_stop || epoch_completed))
|
| {
|
| string cause = "PHASE_COMPLETED";
|
| if(controlled_stop || ExtTrainer.PricePhaseTerminalStatus() == "STOPPED_COMPLETE_UPDATE")
|
| cause = "CONTROLLED_STOP";
|
| else
|
| if(epoch_completed && !phase_completed)
|
| cause = "EPOCH_COMPLETED";
|
| if(!SaveM05Checkpoint(cause))
|
| {
|
| EventKillTimer();
|
| ExtM05StopSaveFailed = true;
|
| ExtStopButton.SetText("Save failed; click to retry");
|
| return;
|
| }
|
| if(phase_completed)
|
| Print("DPCC_M05_PHASE_COMPLETE stage=", phase_before, " status=PHASE_COMPLETED",
|
| " next_stage=", (ExtTrainer.Finished() ? "COMPLETE" : ExtTrainer.PriceStudyStage()),
|
| " ompb_epochs=", ExtTrainer.OMPBTrainingEpochsCompleted(), "/", ExtTrainer.OMPBTrainingEpochLimit(),
|
| " ompb_budget=", (ExtTrainer.OMPBTrainingBudgetComplete() ? "COMPLETE" : "PARTIAL"),
|
| " ompb_eval_lanes=", ExtTrainer.OMPBStage02EvaluationLanes(), "/6",
|
| " ompb_quality=", (!ExtTrainer.OMPBStage02QualityEvaluated() ? "PENDING" :
|
| (ExtTrainer.OMPBStage02QualityPassed() ? "PASS" : "FAIL")),
|
| " quality_gate=ADVISORY",
|
| " updates=", ExtTrainer.Updates(), " model_save=1");
|
| if(selected_phase_completed && !ExtTrainer.Finished())
|
| {
|
| EventKillTimer();
|
| Print("DPCC_M05_SELECTED_PHASE_COMPLETE requested=", InpM05TrainingPhase,
|
| " saved_next_stage=", ExtTrainer.PriceStudyStage(), " action=remove_advisor");
|
| ExtStopButton.RemoveAdvisor();
|
| return;
|
| }
|
| if(controlled_stop && !ExtTrainer.Finished())
|
| {
|
| EventKillTimer();
|
| Print("DPCC_M05_CONTROLLED_STOP saved=true updates=", ExtTrainer.Updates(),
|
| " stage=", ExtTrainer.PriceStudyStage(), " action=remove_advisor");
|
| ExtStopButton.RemoveAdvisor();
|
| return;
|
| }
|
| if(phase_completed && !ExtTrainer.Finished())
|
| Print("DPCC_M05_PHASE_START requested=AUTO stage=", ExtTrainer.PriceStudyStage(),
|
| " epochs_completed=", ExtTrainer.PriceStudyEpochsCompleted(),
|
| " position=", ExtTrainer.PriceStudyPosition(), " / ", ExtTrainer.PriceStudyTotal(),
|
| " updates=", ExtTrainer.Updates(), " restored=false");
|
| }
|
| const string display_stage = ExtTrainer.PriceStudyStage();
|
| const int display_position = ExtTrainer.PriceStudyPosition();
|
| const int display_total = ExtTrainer.PriceStudyTotal();
|
| string chart_status = StringFormat("DPCC %s %d/%d", display_stage, display_position, display_total);
|
| const bool same_phase = (display_stage == phase_before);
|
| if(M05Enabled())
|
| {
|
| uint epoch_limit = 0;
|
| if(display_stage == "LATENT_PREPARE")
|
| epoch_limit = EXTM05DonorProfile.latent_epochs;
|
| else
|
| if(display_stage == "PRICE_JOINT")
|
| epoch_limit = EXTM05DonorProfile.price_joint_epochs;
|
| else
|
| if(display_stage == "OMPB_CALIBRATE")
|
| epoch_limit = EXTM05DonorProfile.epochs;
|
| else
|
| if(display_stage == "PRICE_ADAPT")
|
| epoch_limit = EXTM05DonorProfile.price_adapt_epochs;
|
| uint epoch = ExtTrainer.PriceStudyEpochsCompleted();
|
| if(same_phase && display_position > 0 && display_position < display_total && epoch < epoch_limit)
|
| epoch++;
|
| chart_status = StringFormat("DPCC %s epoch %u/%u | %d/%d",
|
| display_stage, epoch, epoch_limit, display_position, display_total);
|
| }
|
| if(!same_phase)
|
| chart_status += "\nphase transition; next update will report new-phase metrics";
|
| else
|
| if(display_stage == "LATENT_PREPARE")
|
| chart_status += StringFormat("\nlatent: rho_mass=%.5g active_scenarios=%u optimizer_steps=%u/%u/%u",
|
| rho, nonzero, generator, router, confidence);
|
| else
|
| if(display_stage == "PRICE_JOINT")
|
| chart_status += StringFormat(
|
| "\nprice: loss=%.6g mean=%.6g rho_mass=%.5g active_scenarios=%u optimizer_steps=%u/%u/%u",
|
| price_loss, ExtTrainer.PriceJointMeanLoss(), rho, nonzero,
|
| generator, router, confidence);
|
| else
|
| if(display_stage == "PRICE_ADAPT")
|
| chart_status += StringFormat(
|
| "\nOMPB %s epochs=%u/%u eval=%u/6 quality=%s (advisory) | adaptation loss=%.6g rho_mass=%.5g active_scenarios=%u optimizer_steps=%u/%u/%u",
|
| (ExtTrainer.OMPBTrainingBudgetComplete() ?
|
| "budget complete" : "operator accepted"),
|
| ExtTrainer.OMPBTrainingEpochsCompleted(),
|
| ExtTrainer.OMPBTrainingEpochLimit(), ExtTrainer.OMPBStage02EvaluationLanes(),
|
| (!ExtTrainer.OMPBStage02QualityEvaluated() ? "PENDING" :
|
| (ExtTrainer.OMPBStage02QualityPassed() ? "PASS" : "FAIL")),
|
| price_loss, rho, nonzero, generator, router, confidence);
|
| else
|
| if(display_stage == "OMPB_CALIBRATE")
|
| {
|
| SDPCCM05ChartMetrics metrics;
|
| if(ExtTrainer.M05ChartStatus(metrics))
|
| {
|
| if(metrics.subphase == "CALIBRATION" || metrics.subphase == "SOURCE_ANCHOR")
|
| {
|
| const uint active_epoch = (metrics.epoch < metrics.epoch_limit ?
|
| metrics.epoch + 1 : metrics.epoch);
|
| chart_status = StringFormat("DPCC OMPB_CALIBRATE/%s epoch %u/%u | %d/%d",
|
| metrics.subphase, active_epoch, metrics.epoch_limit,
|
| display_position, display_total);
|
| }
|
| else
|
| if(StringFind(metrics.subphase, "EVALUATION_") == 0)
|
| chart_status = StringFormat("DPCC OMPB_CALIBRATE/%s lane %d/6 | %d/%d",
|
| metrics.subphase, metrics.evaluation_stage + 1,
|
| display_position, display_total);
|
| else
|
| chart_status = StringFormat("DPCC OMPB_CALIBRATE/%s | %d/%d",
|
| metrics.subphase, display_position, display_total);
|
| if(metrics.diagnostics_ready)
|
| chart_status += StringFormat(
|
| "\nlast disagreement=%.5g KL=%.5g alpha_prior=%.5g fallback=%u KL_reject=%u quality=%s",
|
| metrics.disagreement, metrics.kl, metrics.alpha_prior,
|
| metrics.invalid_fallbacks, metrics.kl_rejects,
|
| (!ExtTrainer.OMPBStage02QualityEvaluated() ? "pending" :
|
| (ExtTrainer.OMPBStage02QualityPassed() ?
|
| "PASS" : "FAIL (advisory)")));
|
| else
|
| chart_status += "\nOMPB metrics: waiting for first calibration update";
|
| string lane_names[6] = {"bypass-source", "bypass-target", "pre-source", "pre-target",
|
| "post-source", "post-target"
|
| };
|
| for(int lane = 0; lane < metrics.evaluation_stage && lane < 6; lane++)
|
| {
|
| double evaluation_loss = 0, evaluation_valid = 0, evaluation_invalid = 0;
|
| if(ExtTrainer.OMPBStage02Evaluation(lane, evaluation_loss,
|
| evaluation_valid, evaluation_invalid))
|
| chart_status += StringFormat(
|
| "\n%s loss=%.5g valid=%.0f invalid=%.0f",
|
| lane_names[lane], evaluation_loss,
|
| evaluation_valid, evaluation_invalid);
|
| }
|
| }
|
| else
|
| chart_status += "\nOMPB status unavailable";
|
| }
|
| else
|
| if(display_stage == "VERIFY")
|
| chart_status += StringFormat(
|
| "\nverify=%s snapshots=%u max_error=%.5g coverage=%.5g distinct=%u",
|
| ExtTrainer.PriceVerifyStatus(), ExtTrainer.PriceVerifySnapshots(),
|
| ExtTrainer.PriceVerifyMaxError(), ExtTrainer.PriceVerifyCoverage(),
|
| ExtTrainer.PriceVerifyMinDistinct());
|
| else
|
| if(!M05Enabled())
|
| chart_status += StringFormat("\nprice: loss=%.6g rho_mass=%.5g active_scenarios=%u",
|
| price_loss, rho, nonzero);
|
| Comment(chart_status);
|
| if(ExtTrainer.Finished())
|
| {
|
| EventKillTimer();
|
| const string terminal_status = ExtTrainer.PricePhaseTerminalStatus();
|
| if(M05Enabled())
|
| {
|
| string publication_reason = "";
|
| const bool consumer_ready = ExtTrainer.MarketConsumerReady(publication_reason);
|
| Print("DPCC_M05_COMPLETE status=", terminal_status, " stage=", ExtTrainer.PriceStudyStage(),
|
| " updates=", ExtTrainer.Updates(), " market_consumer_ready=", consumer_ready,
|
| " consumer_reason=", publication_reason, " price_verify=REMOVED_BY_USER",
|
| " action=remove_advisor");
|
| }
|
| else
|
| if(terminal_status == "STOPPED_COMPLETE_UPDATE")
|
| Print("DPCC_PRICE_PHASE_STOPPED stage=", phase_before, " status=", terminal_status,
|
| " updates=", ExtTrainer.Updates(), " phase_completed=false acceptance=NOT_CLAIMED");
|
| else
|
| Print("DPCC_PRICE_JOINT_COMPLETE updates=", ExtTrainer.Updates(),
|
| " mean_weighted_price_huber=", ExtTrainer.PriceJointMeanLoss(),
|
| " parameters=frozen next_stage=", ExtTrainer.PriceStudyNextStage(),
|
| " model_save=0 M05_complete=false acceptance=NOT_CLAIMED");
|
| if(M05Enabled() || terminal_status != "STOPPED_COMPLETE_UPDATE")
|
| ExtStopButton.RemoveAdvisor();
|
| }
|
| return;
|
| }
|
| if(ExtTrainer.PartialFitComplete())
|
| {
|
| EventKillTimer();
|
| Print("DPCC_STUDYFORECAST_PARTIAL root=", ExtRoot, " updates=", ExtTrainer.Updates(),
|
| " fit_eligible=", ExtTrainer.FitCount(), " holdout=NOT_RUN checkpoint=NOT_WRITTEN");
|
| Comment("DPCC StudyForecast partial fit: ", ExtTrainer.Updates(), " / ", ExtTrainer.FitCount());
|
| return;
|
| }
|
| double rho = 0;
|
| uint nonzero = 0, generator = 0, router = 0, confidence = 0;
|
| bool holdout_step = false;
|
| string reason = "";
|
| if(!ExtTrainer.Advance(rho, nonzero, generator, router, confidence, holdout_step, reason))
|
| {
|
| EventKillTimer();
|
| Print("DPCC_STUDYFORECAST_ABORT phase=advance reason=", reason, " updates=", ExtTrainer.Updates(),
|
| " holdout_examples=", ExtTrainer.HoldoutCompleted());
|
| return;
|
| }
|
| if(holdout_step)
|
| {
|
| Comment("DPCC StudyForecast frozen holdout: ", ExtTrainer.HoldoutCompleted(), " / ", ExtTrainer.HoldoutCount());
|
| if(ExtTrainer.Finished())
|
| {
|
| if(!ExtTrainer.SaveCompleted(reason))
|
| Print("DPCC_STUDYFORECAST_ABORT phase=save reason=", reason);
|
| else
|
| Print("DPCC_STUDYFORECAST_COMPLETE root=", ExtRoot, " fit_updates=", ExtTrainer.Updates(),
|
| " holdout_examples=", ExtTrainer.HoldoutCount(),
|
| " valid_examples=", ExtTrainer.HoldoutValidExamples(),
|
| " invalid_examples=", ExtTrainer.HoldoutInvalidExamples(),
|
| " latent_coordinate_mae=", DoubleToString(ExtTrainer.HoldoutLatentError(), 12),
|
| " teacher=fresh_frozen_untrained metric_scope=latent_diagnostics weights_changed_during_holdout=false");
|
| ExtStopButton.RemoveAdvisor();
|
| EventKillTimer();
|
| }
|
| return;
|
| }
|
| const ulong updates = ExtTrainer.Updates();
|
| const ulong progress_milestone = updates / 1000;
|
| if(progress_milestone > ExtLastProgressMilestone)
|
| {
|
| ExtLastProgressMilestone = progress_milestone;
|
| Print("DPCC_STUDYFORECAST_UPDATE updates=", updates, " / ", ExtTrainer.FitCount(),
|
| " rho_sum=", rho, " rho_nonzero=", nonzero,
|
| " generator_step=", generator, " router_step=", router, " confidence_step=", confidence);
|
| }
|
| Comment("DPCC StudyForecast fit ", ExtTrainer.Updates(), " / ", ExtTrainer.FitCount(),
|
| " rho=", rho, " heads=", generator, "/", router, "/", confidence);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Function OnChartEvent |
|
| //+------------------------------------------------------------------+
|
| void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
| {
|
| if(!M05Enabled() || !ExtStopButton.Clicked(id, sparam))
|
| return;
|
| EventKillTimer();
|
| ExtStopButton.SetText(ExtM05StopSaveFailed ? "Retrying save..." : "Saving and stopping...");
|
| if(!SaveM05Checkpoint("CONTROLLED_STOP"))
|
| {
|
| ExtM05StopSaveFailed = true;
|
| ExtStopButton.SetText("Retry save and stop");
|
| Comment("DPCC M05: save failed; click button to retry. Training is paused.");
|
| return;
|
| }
|
| ExtM05StopSaveFailed = false;
|
| Print("DPCC_M05_CONTROLLED_STOP saved=true action=remove_advisor");
|
| ExtStopButton.RemoveAdvisor();
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Function OnDeinit |
|
| //+------------------------------------------------------------------+
|
| void OnDeinit(const int reason)
|
| {
|
| EventKillTimer();
|
| ExtStopButton.Delete();
|
| Comment("");
|
| }
|
| //+------------------------------------------------------------------+ |