With the correct setting of all that the TS described, you can see in advance a few hours that either the trend or correction is coming to an end. Plus, the time of the end of the trend can be calculated in advance.
How to set up correctly, everyone knows for himself.
P.S. - Gunn has everything in his works (mathematics of models), you will not find or invent anything new, 2x2 will always be 4. It is better to go deeper into the study of the source material.
No guard against copy_rates_range returning None. If the symbol/timeframe/history isn't available, mt5.copy_rates_range returns None, and pd.DataFrame(None) will blow up with an unhelpful error.
shuffle=True in train_test_split causes data leakage. Each feature row shares 14 of its 15 angle_j values with its neighboring row (heavily overlapping rolling windows) and the data is time-ordered. Shuffling scatters near-duplicate windows across train and test, so the reported accuracy/RMSE will look much better than the model actually performs out-of-sample.
Off-by-one mismatch between the feature window and its label, in both prepare_features and the (duplicated) logic in backtest_signals: window = filtered_df.iloc[i-lookback:i] covers bars i-lookback … i-1, but the target is read from filtered_df.iloc[i]['future_direction_24'] / future_change_pct_24 — which describes the move from bar i (not i-1) to i+24. So current_price and every window-derived feature is anchored one bar behind the actual thing being predicted, throughout training and backtesting.
predict_future_movement doesn't anchor the same way. It uses angular_df.tail(lookback) and treats the last bar of that window as "current price" for the live signal — but per #3, the model was trained with "current price" one bar earlier than the true label anchor. Live predictions and training labels aren't computed on the same convention.
Possible division by zero in create_angular_features: if time_range (max time − min time) is 0 (e.g. duplicate/bad timestamps), scale_factor becomes inf/nan and propagates into every angle.
CatBoostClassifier.predict() return shape — depending on the installed catboost version this can come back as (n, 1) instead of (n,). It's fed straight into accuracy_score/classification_report with no reshape check, so it's worth verifying against whatever version ends up installed.
Minor: the figsize=(750/100, 750/200)-style calls produce non-round inch dimensions (7.5×3.75, 7.5×6.0, 7.5×5.0) — not broken, just an odd way to express figure size.
Once again, the mice cried, stabbed, pooped, but persistently continued to eat the cactus! ;)
Here is a more or less finalised Gann template for MT4, the code is open.
https://disk.yandex.ru/d/7YhmKzcqttnQnQ
With the correct setting of all that the TS described, you can see in advance a few hours that either the trend or correction is coming to an end. Plus, the time of the end of the trend can be calculated in advance.
How to set up correctly, everyone knows for himself.
P.S. - Gunn has everything in his works (mathematics of models), you will not find or invent anything new, 2x2 will always be 4. It is better to go deeper into the study of the source material.
There's another confirmation in the pattern there that the trend was fading and it was worth waiting for a reaction.